SAMPLE
シャドウマップ
DESC
影を落とすはライトから投影したデプステクスチャを利用する。
そのため影を落としたい範囲にフラスタムがはいるようにする。
#define W 1024
#define H 1024
void App::onInit()
{
// シャドウマップ用のテクスチャオブジェクトを生成
glGenTextures( 1, &idShd );
glBindTexture( GL_TEXTURE_2D, idShd );
// シャドウマップ用のテクスチャオブジェクトを生成。
// 後でデプスバッファの値を格納するため ピクセルデータは設定しないでおく
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, W, H, 0,
GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL );
// 拡大縮小、リピート設定
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
// フラグメントの tc.R( Z )成分と シャドウマップテクスチャの値を比較する
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE );
// 比較関数の指定( より小さい == より暗い == より手前 )
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL );
// 比較の結果を輝度値として適用する
glTexParameteri( GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE );
}
ライトの位置からシャドウマップを投影するため、
投影マップと同じようにテクスチャ座標を動的に計算する。
今度はカメラではなくライトの位置から投影するのでライトの場所にカメラを置く。
void App::onDraw()
{
float n = 500;
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.5f, 0.5f, 0.5f);
glScalef(0.5f, 0.5f, 0.5f);
gluPerspective(60.0, (float)W/H, 1.0, 2000.0);
gluLookAt( n, n, n, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); // ライトの位置
// 合成された変換行列を取得する。
float m[16];
glGetFloatv(GL_MODELVIEW_MATRIX, m);
{
float vs[] = { m[0], m[4], m[8], m[12] };
float vt[] = { m[1], m[5], m[9], m[13] };
float vr[] = { m[2], m[6], m[10], m[14] };
float vq[] = { m[3], m[7], m[11], m[15] };
// 合成した変換行列をオブジェクトの頂点に掛ければ画面を覆うようにUVが自動計算される。
glTexGenfv( GL_S, GL_OBJECT_PLANE, vs );
glTexGenfv( GL_T, GL_OBJECT_PLANE, vt );
glTexGenfv( GL_R, GL_OBJECT_PLANE, vr );
glTexGenfv( GL_Q, GL_OBJECT_PLANE, vq );
}
// UVの自動生成を有効化する。
glEnable( GL_TEXTURE_GEN_S );
glEnable( GL_TEXTURE_GEN_T );
glEnable( GL_TEXTURE_GEN_R );
glEnable( GL_TEXTURE_GEN_Q );
// 自動生成の計算式にオブジェクト空間の頂点座標を使う。
glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
glTexGeni( GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
}
// デプステクスチャを作成するためライトの位置にカメラを置いてレンダリング。
// 前面を描いてしまうと、奥行きの判定の時に光のあたる面にも影が落ちてしまう。
// そこで裏面のみを描画する。
glEnable( GL_CULL_FACE );
glCullFace( GL_FRONT );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// ライトの位置にカメラを置く。
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective(60.0, (float)W/H, 1.0, 2000.0);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
gluLookAt( n, n, n, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
drawCube();
// レンダリングされたデプスバッファの値をデプステクスチャへセットする。
glBindTexture( GL_TEXTURE_2D, idShd );
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, W, H );
// 描画面を前面に戻して、2パス目の描画をする。
glEnable( GL_CULL_FACE );
glCullFace( GL_BACK );
// 画面をクリアする。
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// 適当な位置にカメラを置いて物体を描画する。
{
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
gluLookAt( -n, n, -n, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
// 影を落とすために、シャドウマップをバインドする。
// テクスチャ座標は自動計算される設定になっている。
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, idShd );
drawCube();
drawPlane();
}
}