影行列
OpenGLにて影を表示する方法はいくつかあるようですが、シンプルな方法としては、影行列(Shadow Matrix)を用いて表示する方法があると思います。
この方法は、現実世界のようにライトを当てて明暗を作るのではなくて、擬似的にグラウンドに影らしきものを表示させるます。
ようは、ライトが当たっている物体を表示させるのとは別に、影ができるであろう位置に影っぽい形の影らしい色のグラウンド平面に変形させた物体を表示させることで、あたかも影があるように見せる方法のほうです。
この方法は、現実世界のようにライトを当てて明暗を作るのではなくて、擬似的にグラウンドに影らしきものを表示させるます。
ようは、ライトが当たっている物体を表示させるのとは別に、影ができるであろう位置に影っぽい形の影らしい色のグラウンド平面に変形させた物体を表示させることで、あたかも影があるように見せる方法のほうです。


- 記述(影をつける)
void display()
{
// ・・・
// box
{
float pos[3] = {0.0, 0.0, 2.0};
float sizes[3] = {1.0, 2.0, 0.5 };
glPushMatrix();
glTranslatef(pos[0], pos[1], pos[2]);
glEnable(GL_LIGHTING);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, red);
drawBox( sizes );
glPopMatrix();
#if 1 // shadow
setShadowDrawingMode();
setShadowTransform(pos[0], pos[1], pos[2]);
drawBox( sizes );
glPopMatrix();
#endif
}
// sphere
{
glPushMatrix();
glEnable(GL_LIGHTING);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, green);
glTranslatef(1.0, 3.0, 1.0);
glCallList(theSphere);
glPopMatrix();
#if 1 // shadow
setShadowDrawingMode();
setShadowTransform(1.0,3.0,1.0);
glCallList(theSphere);
glPopMatrix();
#endif
}
// ・・・
}
drawSphere関数で球体を表示させるような場合、影を表示させるときはもう一度drawSphere関数を呼ぶことになります。(処理的に倍)
影に見えるように計算して表示させているので、ソフトウェア・シャドウィングの部類になると思います。
影表示用関数
次の関数が重要になります。
void setShadowDrawingMode()
{
const float shadow_intensity = 0.65;
glDisable (GL_LIGHTING);
glDisable (GL_TEXTURE_2D);
glColor3f (
ground_color[0]*shadow_intensity,
ground_color[1]*shadow_intensity,
ground_color[2]*shadow_intensity );
}
void setShadowTransform(float x, float y, float z)
{
GLfloat matrix[16];
for (int i=0; i<16; i++) matrix[i] = 0;
matrix[0]=1;
matrix[5]=1;
matrix[8]=(x-light_pos[0])/(light_pos[2]);
matrix[9]=(y-light_pos[1])/(light_pos[2]);
matrix[15]=1;
glPushMatrix();
glMultMatrixf (matrix);
glTranslatef(x, y, z);
}
setShadowDrawingModeでは、影の色の設定をしています。
地面の色に対して1未満の係数をかけることで、少し暗い(影っぽい)色を作っています。
地面の色に対して1未満の係数をかけることで、少し暗い(影っぽい)色を作っています。
setShadowTransformでは、グラウンドに対して影に見えるようにマトリックス変換をかけています。
なぜこのような計算式になるかはよくわかりませんが、とにかくこの行列で変換することができます。
なぜこのような計算式になるかはよくわかりませんが、とにかくこの行列で変換することができます。
まとめ
今回の場合は、グラウンドはz=0固定で、ライトの位置と物体の位置を基に影を表示させています。
したがって、物体と物体が接近しても物体の上に影が落とすことはできません。
グラウンド以外にも影をつけるのは、ちょっと複雑になりそうです。
したがって、物体と物体が接近しても物体の上に影が落とすことはできません。
グラウンド以外にも影をつけるのは、ちょっと複雑になりそうです。
あと、グラウンドはテクスチャを張っていない状態なので、テクスチャを張ると色の設定のところが若干変える必要があるようです。
なんにしても、影があることでだいぶ地面との接近がわかりやすくなったと思います。
参考
- http://www.shader.jp/xoops/html/masafumi/directx9/3dtips/d3d14.htm
- http://wiki.livedoor.jp/mikk_ni3_92/d/%BC%C2%C1%A9%CA%D405::%B1ƹ%D4%CE%F3
- http://www.ia.hiof.no/~borres/cgraph/explain/shadow/p-shadow.html