「毎日Unity」の技術ブログ

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

混合色の作成方法

混合色の作成方法を自分用にメモ。

[ 方法 ]

不透明オブジェクトAと不透明オブジェクトBの混合色

混合色 = (色A + 色B) / 2

不透明オブジェクトAと半透明オブジェクトBの混合色

混合色 = (1 - 透明度B) * 色A + 透明度B * 色B

半透明オブジェクトAと半透明オブジェクトBの混合色

混合色 = (透明度A * 色A + 透明度B * 色B) / (透明度A + 透明度B)

【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

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

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

[ 実行結果 ]

[ プログラム ]

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

final int FrameRate = 60;

float AngleX_Cube = 0;
float AngleY_Cube = 0;
float Width_Cube = 100;

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

void setup()
{
    frameRate(FrameRate);
}

void draw() 
{
    background(255);

    float PosX = Width_Window / 2;
    float PosY = Height_Window / 2;

    translate(PosX, PosY);

    float[][] Verts = new float[8][3];

    for (int i = 0; i < 8; i++) 
    {
        float PosX_Vert = (i & 1) == 0 ? -Width_Cube / 2 : Width_Cube / 2;
        float PosY_Vert = (i & 2) == 0 ? -Width_Cube / 2 : Width_Cube / 2;
        float PosZ_Vert = (i & 4) == 0 ? -Width_Cube / 2 : Width_Cube / 2;

        float PosX_Vert_ = PosX_Vert * cos(AngleY_Cube) - PosZ_Vert * sin(AngleY_Cube);
        float PosZ_Vert_ = PosX_Vert * sin(AngleY_Cube) + PosZ_Vert * cos(AngleY_Cube);
        PosX_Vert = PosX_Vert_;
        PosZ_Vert = PosZ_Vert_;

        float PosY_Vert_ = PosY_Vert * cos(AngleX_Cube) - PosZ_Vert * sin(AngleX_Cube);
        PosZ_Vert = PosY_Vert * sin(AngleX_Cube) + PosZ_Vert * cos(AngleX_Cube);
        PosY_Vert = PosY_Vert_;

        Verts[i][0] = PosX_Vert;
        Verts[i][1] = PosY_Vert;
        Verts[i][2] = PosZ_Vert;
    }

    for (int i = 0; i < 4; i++) 
    {
        final int Index = (i + 1) % 2 + i / 2 * 2;

        line(Verts[i][0], Verts[i][1], Verts[Index][0], Verts[Index][1]);
        line(Verts[i + 4][0], Verts[i + 4][1], Verts[Index + 4][0], Verts[Index + 4][1]);
        line(Verts[i][0], Verts[i][1], Verts[i + 4][0], Verts[i + 4][1]);
    }

    line(Verts[0][0], Verts[0][1], Verts[1][0], Verts[1][1]);
    line(Verts[3][0], Verts[3][1], Verts[2][0], Verts[2][1]);
    line(Verts[7][0], Verts[7][1], Verts[6][0], Verts[6][1]);
    line(Verts[4][0], Verts[4][1], Verts[5][0], Verts[5][1]);

    AngleX_Cube += radians(1);
    AngleY_Cube += radians(1);
}

[ 感想 ]

ChatGPTに吐かせたコードを改良して立方体の描画をしようしたのですが、吐かせたコードの内容が理解できなくて失敗しました。なぜビット演算子を使う必要があるのかがわからない。

[ 関連記事 ]

edunity.hatenablog.com

【Processing】スクリーンショットのやり方

スクリーンショットのやり方を自分用にメモ。

[ やり方 ]

「save()」でスクリーンショットを保存できます。画像はpdeファイルと同階層に保存されます。

[ 使用例 ]

以下はウィンドウを左クリックすると「ScreenShot」という名前のスクリーンショットが保存されるコードです。

void setup()
{

}

void draw()
{

}

void mouseClicked(MouseEvent MouseEvent)
{
    if(MouseEvent.getButton() == LEFT)
    {
        save("ScreenShot.png");
    }
}

【Processing】オーディオの再生方法

オーディオの再生方法を自分用にメモ。

[ 再生方法 ]

再生したい音楽ファイルはpdeファイルと同階層にあるdataフォルダ内に入れておきます。

import ddf.minim.*;

Minim Minim_;

AudioSnippet Audio;

void setup()
{
    Minim_ = new Minim(this);

    Audio = Minim_.loadSnippet("Audio.mp3");
}

void draw()
{

}

void keyPressed() 
{
    if(key == 'a')
    {
        Audio.play(0);// 再生
    }
    else if(key == 'b')
    {
        Audio.loop();// ループ再生
    }
    else if(key == 'c')
    {
        Audio.pause();// 一時停止
    }
    else if(key == 'd')
    {
        Audio.setGain(Audio.getGain() + 1);// 音量上げる
    }
    else if(key == 'e')
    {
        Audio.setGain(Audio.getGain() - 1);// 音量下げる
    }
}

【Processing】複数キー同時入力の取得方法

複数キー同時取得の対応方法を自分用にメモ。

[ 対応方法 ]

import java.util.HashMap;
import java.util.Map;

//入力を取得したいキーをあらかじめ登録しておきます。
final HashMap<Character, Boolean> InputMap = new HashMap<Character, Boolean>()
{{
   put('w', false);
   put('a', false);
   put('s', false);
   put('d', false);
   put(' ', false);
   put(ENTER, false);
   put(TAB, false);
}};

void setup()
{

}

void draw()
{
    // for (Map.Entry<Character, Boolean> Entry : InputMap.entrySet()) 
    // {
    //     if(Entry.getValue())
    //     {
    //         println(Entry.getKey() + "キーが押されています。");
    //     }
    // }

    if(InputMap.get('w'))
    {
        //ここはwキーとdキーが押された時に呼ばれます。
    }

    if(InputMap.get('a') && InputMap.get('d'))
    {
        //ここはaキーとdキーが同時に押された時に呼ばれます。
    }
}

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

【Unity】ビルドしたファイルを実行するとNull参照エラーが発生する時の解決方法

【Unity】ビルドしたファイルを実行するとNull参照エラーが発生する時の解決方法をメモ。

[ エラー ]

エディタでは問題なく動作するのに、ビルドしたファイルを実行すると「NullReferenceException: Object reference not set to an instance of an object」エラーが発生する。

[ 原因 ]

Resources.Loadで読み込みが完了していないGameObjectをInstantiateしようとしたことが原因です。Resources.Loadで読み込みたいファイルのサイズが大きすぎると読み込みに失敗してしまう場合があるみたいです。

[ 解決方法 ]

非同期処理でファイル読み込みが完了するまでInstantiateを実行しないようにします。

[ 参考文献 ]

forum.unity.com