3D ワールド内のすべてのオブジェクトには法線があり、オブジェクトが反射する必要のある光の量を OpenGL が判断するのに役立ちます。サーフェスの法線を指定するのを忘れている可能性があります。それらを指定しないと、OpenGL はワールド内のすべてのオブジェクトを同じように照らします。
3D でサーフェスの法線を取得するには、少なくとも 3 つの頂点が必要です。つまり、少なくとも三角形です。
サンプルのもの:
サーフェスの法線を計算するには、2 つのベクトルが必要です。3D 空間に 3 つの頂点があるため、これらのサンプル ポイントには三角形が含まれる可能性があります。
// Top triangle, three points in 3D space.
vertices = new float[] {
-1.0f, 1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
0.0f, 1.0f, -1.0f,
}
これら 3 つの点が与えられると、次のように 2 つのベクトルを定義できるようになります。
// Simple vector class, created by you.
Vector3f vector1 = new Vector3f();
Vector3f vector2 = new Vector3f();
vector1.x = vertices[0] - vertices[3];
vector1.y = vertices[1] - vertices[4];
vector1.z = vertices[2] - vertices[5];
vector2.x = vertices[3] - vertices[6];
vector2.y = vertices[4] - vertices[7];
vector2.z = vertices[5] - vertices[8];
ベクトルが 2 つある場合、最終的にCross Productを使用してサーフェスの法線を取得できます。手短に言えば、外積は、入力ベクトルに垂直な角度を含む新しいベクトルを結果として生じる演算です。これは私たちが必要とする正常です。
コードで外積を取得するには、それを計算する独自のメソッドを作成する必要があります。理論的には、次の式を使用して外積を計算します。
A X B = (Ay * Bz - Az * By, Az * Bx - Ax * Bz, Ax * By - Ay * Bx)
コード内 (上記のベクトルを使用):
public Vector3f crossProduct(Vector3f vector1, Vector3f vector2) {
Vector3f normalVector = new Vector3f();
// Cross product. The normalVector contains the normal for the
// surface, which is perpendicular both to vector1 and vector2.
normalVector.x = vector1.y * vector2.z - vector1.z * vector2.y;
normalVector.y = vector1.z * vector2.x - vector1.x * vector2.z;
normalVector.z = vector1.x * vector2.y - vector1.y * vector2.x;
return normalVector;
}
これ以上のコメントの前に; 配列で法線を指定し、必要に応じてそれらを OpenGL に入れることができますが、このトピックを掘り下げると、このトピックの理解がはるかに良くなり、コードがはるかに柔軟になります。
これで、ループできる法線ができました。ベクトル値を法線配列に割り当て (NeHe のポートと同様ですが、動的に)、使用する OpenGL をセットアップして、GL_NORMAL_ARRAY
OpenGL がオブジェクトに光を正しく反射するようにします。
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
// I'm assuming you know how to put it into a FloatBuffer.
gl.glNormalPointer(GL10.GL_FLOAT, 0, mNormalsBuffer);
// Draw your surface...
別の最後のコメント。他の頂点値 (5.0f、10.0f、またはそれ以上) を使用している場合は、パフォーマンスを向上させるために、メソッドから返されるベクトルを正規化することをお勧めします。crossProduct()
そうしないと、OpenGL は新しいベクトルを計算して単位ベクトルを取得する必要があり、パフォーマンスの問題になる可能性があります。
また、あなたnew float[] {-4f, 0.9f, 6f, 1f}
の forGL_POSITION
は完全に正しくありません。4 番目の値が に設定されている場合、最初の 3 つの値が何であれ1.0f
、ライトの位置が であることを意味します。0, 0, 0
ライトの位置のベクトルを指定するには、4 番目の値を に変更します0.0f
。