現在の【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#!