現在の【OpenGL】シリーズいかがでしょうか?

プログラミングや専門知識がなくとも、「あー、こうやって画面の中で3D表示するのかぁ」という感じが伝わってくれれば御の字です。

 

所で、皆さんとCやC++でGLUTを使ってOpenGLを勉強している間に、私はOpenTKの話題を取り上げる下準備をしていますが、「これが同じOpenGL仕様に基づくライブラリーなのか?」と感じるほど、GLUTとOpenTKでは洗練度や発展度合いが違います。C#はC++の発展形(要するに"C++++"の意味です)と言われますが、多くのオブジェクトがクラス化、構造体化、プロパティ化して、よく使う関数などもメソッドとして実装されています。OpenGLなどはその活躍の場として適当なんでしょう。

 

以下は今日経験した話です。(3つとも同じように動くことを確認しました。)

 

1.面の法線の計算(1)

照光に対するプリミティブの法線を得るべく、GLUTで使った関数をベースにfloat型の変数を使って次のようにC#用に書き換えました。

 

        //面の法線の計算(1)
        float[] GetNormal(double[] vertex1, double[] vertex2, double[] vertex3)    //引数は隣接する3頂点の座標
        {
            float[] Normal = new float[3];    //戻り値用変数
            double ax, ay, az, bx, by, bz, nx, ny, nz, len; 

            //3 - 2間のベクトル(ax, ay, az)
            ax = vertex3[0] - vertex2[0];    //x
            ay = vertex3[1] - vertex2[1];    //y
            az = vertex3[2] - vertex2[2];    //z
            //1 - 2間のベクトル(bx, by, bz)
            bx = vertex1[0] - vertex2[0];    //x
            by = vertex1[1] - vertex2[1];    //y
            bz = vertex1[2] - vertex2[2];    //z
            //a、bベクトルの外積を計算
            nx = ay * bz    - az * by;
            ny = az * bx - ax * bz;
            nz = ax * by - ay * bx;
            //法線を正規化
            len = Math.Sqrt(Math.Pow(nx, 2.0) + Math.Pow(ny, 2.0) + Math.Pow(nz, 2.0));
            Normal[0] = (float)(nx / len);
            Normal[1] = (float)(ny / len);
            Normal[2] = (float)(nz / len);
            return Normal;
        }
 

2.面の法線の計算(2)

ところが、Vertex3という使いやすい(というか、OpenTKでは必須の)構造体(注)があり、こっちを使うべきじゃないか、と書き直しました。

柱:C++と異なり、C#ではクラスと構造体は一見ほとんど同じように見えます。違いはこちら。ユーザーの方が書かれた、これとか、これも参考になるでしょう。

 

        //面の法線の計算(2)
        Vector3 GetNormal(Vector3 vertex1, Vector3 vertex2, Vector3 vertex3)    //引数は隣接する3頂点の座標
        {
            Vector3 Normal = new Vector3();        //戻り値用変数
            double ax, ay, az, bx, by, bz, nx, ny, nz, len; 

            //3 - 2間のベクトル(ax, ay, az)
            ax = vertex3.X - vertex2.X;    //x
            ay = vertex3.Y - vertex2.Y;    //y
            az = vertex3.Z - vertex2.Z;    //z
            //1 - 2間のベクトル(bx, by, bz)
            bx = vertex1.X - vertex2.X;    //x
            by = vertex1.Y - vertex2.Y;    //y
            bz = vertex1.Z - vertex2.Z;    //z
            //a、bベクトルの外積を計算
            nx = ay * bz    - az * by;
            ny = az * bx - ax * bz;
            nz = ax * by - ay * bx;
            //法線を正規化
            len = Math.Sqrt(Math.Pow(nx, 2.0) + Math.Pow(ny, 2.0) + Math.Pow(nz, 2.0));
            Normal.X = (float)(nx / len);
            Normal.Y = (float)(ny / len);
            Normal.Z = (float)(nz / len);
            return Normal;
        }
 

3.面の法線の計算(3)

当たり前と言えば当たり前ですが、このVector3は当然計算に堪えるようにオブジェクト化されており、必要なメソッドも持っていました。

 

        //面の法線の計算(3)
        Vector3 GetNormal(Vector3 vec1, Vector3 vec2, Vector3 vec3)    //引数は平面上の3頂点ベクトル
        {
            return Vector3.Normalize(Vector3.Cross(vec2 - vec1, vec3 - vec1));
        }
        //Cross - 2 つのベクターのクロス積(日本では外積と呼ぶが必ずしも正確ではない)を計算します。戻り値 Vector3(https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%82%B9%E7%A9%8D)
        //Normalized - 指定したベクトルと方向が同じで、長さが 1 であるベクトルを返します。戻り値 Vector3(https://learn.microsoft.com/ja-jp/dotnet/api/system.numerics.vector3.normalize?view=net-8.0)

 

変数を使って25行書いたコードがコメントを入れて4行になってしまいました。

 

恐るべし、C#!