「毎日Unity」の技術ブログ

開発で役立つ情報を発信する

【Processing】P3Dを使わずに三次元の物体の描画を試みる(2)

再びP3Dを使わずに三次元の物体の描画に挑戦してみました。

[ 実行結果 ]

[ プログラム ]

wasdで移動、tfghで立方体を回転できます。

final int Width_Window = 600;
final int Height_Window = 600;

final HashMap<Character, Boolean> InputMap = new HashMap<Character, Boolean>()
{{
    put('w', false);
    put('s', false);
    put('d', false);
    put('a', false);
    put('t', false);
    put('g', false);
    put('h', false);
    put('f', false);
}};

final int FrameRate = 60;

final int FieldOfView = 60;

final int MoveAmount = 3;
final int RotateAmount = 10;

Cube3D Cube3D_ = new Cube3D(new Vector3(0, 0, 100), new Vector3(0, 0, 0), 15, color(0, 127, 255, 255));

void settings()
{
    size(Width_Window, Height_Window);
}

void setup()
{
    frameRate(FrameRate);
}

void draw()
{
    background(255);

    Cube3D_.Draw();

    if(InputMap.get('w')) 
    {
        Cube3D_.Add_Pos(new Vector3(0, -MoveAmount, 0));
    }
    if(InputMap.get('s')) 
    {
        Cube3D_.Add_Pos(new Vector3(0, MoveAmount, 0));
    }
    if(InputMap.get('d')) 
    {
        Cube3D_.Add_Pos(new Vector3(MoveAmount, 0, 0));
    }
    if(InputMap.get('a')) 
    {
        Cube3D_.Add_Pos(new Vector3(-MoveAmount, 0, 0));
    }

    if(InputMap.get('t')) 
    {
        Cube3D_.Add_Rot(new Vector3(-RotateAmount, 0, 0));
    }
    if(InputMap.get('g')) 
    {
        Cube3D_.Add_Rot(new Vector3(RotateAmount, 0, 0));
    }
    if(InputMap.get('h')) 
    {
        Cube3D_.Add_Rot(new Vector3(0, -RotateAmount, 0));
    }
    if(InputMap.get('f')) 
    {
        Cube3D_.Add_Rot(new Vector3(0, RotateAmount, 0));
    }

    for (Character key : InputMap.keySet()) 
    {
        InputMap.replace(key, false);
    }
}

Vector2[] Get_Verts2D(Vector3[] _Verts3D) 
{
    final Vector2[] Verts2D = new Vector2[_Verts3D.length];

    for (int i = 0; i < _Verts3D.length; i++) 
    {
        final float Fov = 1 / tan(radians(FieldOfView / 2));
        final float Size = (Width_Window > Height_Window ? Width_Window : Height_Window) / 2;

        final Vector3 CuurentVert2D = _Verts3D[i].Copy();

        Vector2 NewVert2D = new Vector2(0, 0);
        NewVert2D.X += (CuurentVert2D.X / CuurentVert2D.Z) * Fov * Size;
        NewVert2D.X += Width_Window / 2;
        NewVert2D.Y += (CuurentVert2D.Y / CuurentVert2D.Z) * Fov * Size;
        NewVert2D.Y += Height_Window / 2;

        Verts2D[i] = NewVert2D;
    }

    return Verts2D;
}

void keyPressed() 
{
    if(InputMap.containsKey(key))
    {
        InputMap.replace(key, true);
    }
}

class Vector2
{
    float X = 0;
    float Y = 0;

    Vector2(float _X, float _Y)
    {
        X = _X;
        Y = _Y;
    }

    Vector2 Add(Vector2 _Vector2)
    {
        return new Vector2(X + _Vector2.X, Y + _Vector2.Y);
    }
    Vector2 Minus()
    {
        return new Vector2(-X, -Y);
    }
    Vector2 Copy()
    {
        return new Vector2(X, Y);
    }
}
class Vector3
{
    float X = 0;
    float Y = 0;
    float Z = 0;

    Vector3(float _X, float _Y, float _Z)
    {
        X = _X;
        Y = _Y;
        Z = _Z;
    }

    Vector3 Add(Vector3 _Vector3)
    {
        return new Vector3(X + _Vector3.X, Y + _Vector3.Y, Z + _Vector3.Z);
    }
    Vector3 Mult(float _Value)
    {
        return new Vector3(X * _Value, Y * _Value, Z * _Value);
    }
    Vector3 Cross(Vector3 _Vector3)
    {
        return new Vector3(Y * _Vector3.Z - Z * _Vector3.Y, Z * _Vector3.X - X * _Vector3.Z, X * _Vector3.Y - Y * _Vector3.X);
    }
    Vector3 Minus()
    {
        return new Vector3(-X, -Y, -Z);
    }
    Vector3 Copy()
    {
        return new Vector3(X, Y, Z);
    }

    float Dot(Vector3 _Vector3)
    {
        return X * _Vector3.X + Y * _Vector3.Y + Z * _Vector3.Z;
    }
}
class Cube3D
{
    Vector3 Pos = new Vector3(0, 0, 0);
    Vector3 Rot = new Vector3(0, 0, 0);
    float Scale = 1;
    color Color = color(0);
    
    Vector3[] Verts3D = new Vector3[]
    {
        new Vector3(-0.5, -0.5, 0.5),
        new Vector3(0.5, -0.5, 0.5),
        new Vector3(-0.5, 0.5, 0.5),
        new Vector3(0.5, 0.5, 0.5),
        new Vector3(-0.5, -0.5, -0.5),
        new Vector3(0.5, -0.5, -0.5),
        new Vector3(-0.5, 0.5, -0.5),
        new Vector3(0.5, 0.5, -0.5),
    };
    int[][] Polygons = new int[][]
    {   
        new int[]{1, 3, 7}, 
        new int[]{1, 7, 5}, 
        new int[]{0, 4, 6}, 
        new int[]{0, 6, 2},
        new int[]{0, 1, 4}, 
        new int[]{1, 5, 4},
        new int[]{2, 6, 3}, 
        new int[]{3, 6, 7}, 
        new int[]{0, 3, 1}, 
        new int[]{0, 2, 3}, 
        new int[]{4, 5, 7}, 
        new int[]{4, 7, 6}, 
    };

    Cube3D(Vector3 _Pos, Vector3 _Rot, float _Scale, color _Color)
    {
        Color = _Color;

        Add_Pos(_Pos);
        Add_Rot(_Rot);
        Set_Scale(_Scale);
    }

    void Draw()
    {
        for (int i = 0; i < Polygons.length; i++) 
        {
            final int[] Polygon = Polygons[i];

            final Vector3[] Verts3D_Polygon = new Vector3[]{Verts3D[Polygon[0]], Verts3D[Polygon[1]], Verts3D[Polygon[2]]};
            
            final Vector3 Vec1 = Verts3D_Polygon[1].Add(Verts3D_Polygon[0].Minus());
            final Vector3 Vec2 = Verts3D_Polygon[2].Add(Verts3D_Polygon[0].Minus());

            final Vector3 Normal_Polygon = Vec1.Cross(Vec2);

            final float Dot = Verts3D_Polygon[0].Dot(Normal_Polygon);  

            if(Dot <= 0)
            {
                continue;
            }

            final Vector2[] Verts2D_Polygon = Get_Verts2D(Verts3D_Polygon);

            fill(Color);
            noStroke();
            triangle(Verts2D_Polygon[0].X, Verts2D_Polygon[0].Y, Verts2D_Polygon[1].X, Verts2D_Polygon[1].Y, Verts2D_Polygon[2].X, Verts2D_Polygon[2].Y);
        }
    }

    void Add_Pos(Vector3 _Pos) 
    {
        for (int i = 0; i < Verts3D.length; i++) 
        {
            final Vector3 CurrentVert3D = Verts3D[i].Copy();

            final Vector3 NewVert3D = CurrentVert3D.Copy().Add(_Pos);

            Verts3D[i] = NewVert3D;
        }

        Pos = Pos.Add(_Pos);
    }
    void Add_Rot(Vector3 _Rot) 
    {
        if(_Rot.X != 0)
        {
            final float Radian = radians(_Rot.X);
            final float Sin = sin(Radian);
            final float Cos = cos(Radian);

            for (int i = 0; i < Verts3D.length; i++) 
            {
                final Vector3 CurrentVert3D = Verts3D[i].Copy();

                Vector3 NewVert3D = new Vector3(0, 0, 0);
                NewVert3D.X = CurrentVert3D.X;
                NewVert3D.Y = Pos.Y + (CurrentVert3D.Y - Pos.Y) * Cos - (CurrentVert3D.Z - Pos.Z) * Sin;
                NewVert3D.Z = Pos.Z + (CurrentVert3D.Y - Pos.Y) * Sin + (CurrentVert3D.Z - Pos.Z) * Cos;

                Verts3D[i] = NewVert3D;
            }
        }

        if(_Rot.Y != 0)
        {
            final float Radian = radians(_Rot.Y);
            final float Sin = sin(Radian);
            final float Cos = cos(Radian);

            for (int i = 0; i < Verts3D.length; i++) 
            {
                final Vector3 CurrentVert3D = Verts3D[i].Copy();

                Vector3 NewVert3D = new Vector3(0, 0, 0);
                NewVert3D.X = Pos.X + (CurrentVert3D.Z - Pos.Z) * Sin + (CurrentVert3D.X - Pos.X) * Cos;
                NewVert3D.Y = CurrentVert3D.Y;
                NewVert3D.Z = Pos.Z + (CurrentVert3D.Z - Pos.Z) * Cos - (CurrentVert3D.X - Pos.X) * Sin;

                Verts3D[i] = NewVert3D;
            }
        }

        if(_Rot.Z != 0)
        {
            final float Radian = radians(_Rot.Z);
            final float Sin = sin(Radian);
            final float Cos = cos(Radian);

            for (int i = 0; i < Verts3D.length; i++) 
            {
                final Vector3 CurrentVert3D = Verts3D[i].Copy();

                Vector3 NewVert3D = new Vector3(0, 0, 0);
                NewVert3D.X = Pos.X + (CurrentVert3D.Y - Pos.Y) * Sin + (CurrentVert3D.X - Pos.X) * Cos;
                NewVert3D.Y = Pos.Y + (CurrentVert3D.Y - Pos.Y) * Cos - (CurrentVert3D.X - Pos.X) * Sin;
                NewVert3D.Z = CurrentVert3D.Z;

                Verts3D[i] = NewVert3D;
            }
        }

        Rot = Rot.Add(_Rot);
    }

    void Set_Scale(float _Scale) 
    {
        for (int i = 0; i < Verts3D.length; i++) 
        {
            final Vector3 CurrentVert3D = Verts3D[i].Copy();

            final Vector3 NewVert3D = CurrentVert3D.Copy().Add(Pos.Minus()).Mult(_Scale / Scale).Add(Pos);

            Verts3D[i] = NewVert3D;
        }

        Scale = _Scale;
    }
}

[ 関連記事 ]

edunity.hatenablog.com