最終更新: mikk_ni3_92 2009年07月23日(木) 19:15:24履歴
現在地: メニュー >> 実践編05 >> 実践編05::シャドウマッピング >> 実践編05::シャドウマッピングの原理
次:実践編05::シャドウマッピング(全体の流れ)
日向 → 何も光をさえぎるものがない。 → 光のあたっている部分は、『光源に視点を置いた時に見える』という事。
これは、可視性、すなわち「Zバッファ」と似ている。
つまり、
『光源の位置から描画して、デプステストを通過したもの(描画されるもの)は日向である』
1パス目は光源からの描画。そして、デプステクスチャにする。
この時、
【擬似プログラム:1パス目】
2パス目は視点からの描画。
ここでポイントとなるのは、『シーン全体を暗めの光源で描画する』という事。
(すべてが日陰の状態での描画をする感じで)
これが、後で影となる。
【擬似プログラム:2パス目】
3パス目は比較処理が行われる部分。
ここでは、明るい光源でシーン全体を描画する。
そして、影になるピクセルはα値を0、それ以外は1とすることで
影になっているピクセルを破棄する。
その結果として、日向部分が描画される。
つまり、2パス目で日陰を描画し、3パス目で日向部分を上書き描画するのである。
【擬似プログラム:3パス目】
よくある図だが、
結局はカメラ視点の座標を光源からの映像に変換するテクスチャ行列Tを求めるのがポイント。
シャドウマップ=光源の視点からのスナップショットのようなもので、
EYE_LINEARでのテクスチャ座標生成を使って、テクスチャ投影をする。
そして、テクスチャ行列を使って作ったテクスチャ座標とシャドウマップを対応付ける。
上図の赤い線のような変換は、以下の式で書ける。
ここで、注意したいのは、クリップ空間は「-1」〜「1」の範囲になっているので、
それを「0」〜「1」の範囲に変換する事で、テクスチャ座標と合わせる。
そこで「バイアス行列」を乗算し、テクスチャ座標の自動生成を使う事で、以下のような式でテクスチャ行列をえられる。
このテクスチャ行列Tに対し、
次:実践編05::シャドウマッピング(全体の流れ)
次:実践編05::シャドウマッピング(全体の流れ)
日向 → 何も光をさえぎるものがない。 → 光のあたっている部分は、『光源に視点を置いた時に見える』という事。
これは、可視性、すなわち「Zバッファ」と似ている。
つまり、
『光源の位置から描画して、デプステストを通過したもの(描画されるもの)は日向である』
1パス目は光源からの描画。そして、デプステクスチャにする。
この時、
- 「カリング」を行って、ポリゴンの裏面だけを描画する。
- シーン全体がウィンドウ内に入るようにする。
【擬似プログラム:1パス目】
void FirstPass() { //--- 光源からの視点、ビューポートを設定しておく ---// glCullFace(GL_FRONT); //裏面だけを描画する glShadeModel(GL_FLAT); glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);//色は何も書き込まない DrawScene(); glBindTexture(GL_TEXTURE_2D,TextureId); glCopyTexSubImage2D(GL_TEXTURE_2D,0,0,0,0,0,ShadowMapSize.first,ShadowMapSize.second);//テクスチャにする glCullFace(GL_BACK); //デフォルトに戻す glShadeModel(GL_SMOOTH); glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE); }
2パス目は視点からの描画。
ここでポイントとなるのは、『シーン全体を暗めの光源で描画する』という事。
(すべてが日陰の状態での描画をする感じで)
これが、後で影となる。
【擬似プログラム:2パス目】
//色の設定 enum{BLACK,WHITE,GRAY}; float colors[3][4]= { {0,0,0,0}, {1,1,1,1}, {0.2,0.2,0.2,0.2} }; float lightPos[]={3,4,5,1.0}; void SecondPass() { //--- カメラ位置からの視点、ビューポートを設定しておく ---// glClear(GL_DEPTH_BUFFER_BIT); //暗い光源を設定 glLightfv(GL_LIGHT1,GL_POSITION,lightPos); glLightfv(GL_LIGHT1,GL_AMBIENT,&colors[GRAY][0]); glLightfv(GL_LIGHT1,GL_DIFFUSE,&colors[GRAY][0]); glLightfv(GL_LIGHT1,GL_SPECULAR,&colors[BLACK][0]);//スペキュラは黒で glEnable(GL_LIGHT1); glEnable(GL_LIGHTING); DrawScene();//シーンを描画 }
3パス目は比較処理が行われる部分。
ここでは、明るい光源でシーン全体を描画する。
そして、影になるピクセルはα値を0、それ以外は1とすることで
影になっているピクセルを破棄する。
その結果として、日向部分が描画される。
つまり、2パス目で日陰を描画し、3パス目で日向部分を上書き描画するのである。
【擬似プログラム:3パス目】
void ThirdPass() { //-- 明るい光源を用意、テクスチャの自動生成などの処理---// //比較処理とαテスト 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_INTENSITY); glAlphaFunc(GL_GEQUAL,0.999f); glEnable(GL_ALPHA_TEST); DrawScene(); ... ... }
よくある図だが、
結局はカメラ視点の座標を光源からの映像に変換するテクスチャ行列Tを求めるのがポイント。
シャドウマップ=光源の視点からのスナップショットのようなもので、
EYE_LINEARでのテクスチャ座標生成を使って、テクスチャ投影をする。
そして、テクスチャ行列を使って作ったテクスチャ座標とシャドウマップを対応付ける。
上図の赤い線のような変換は、以下の式で書ける。
T | テクスチャ行列 |
Pl | 光源のプロジェクション行列 |
Vl | 光源のビュー行列 |
Vc | カメラのビュー行列 |
ここで、注意したいのは、クリップ空間は「-1」〜「1」の範囲になっているので、
それを「0」〜「1」の範囲に変換する事で、テクスチャ座標と合わせる。
そこで「バイアス行列」を乗算し、テクスチャ座標の自動生成を使う事で、以下のような式でテクスチャ行列をえられる。
T | テクスチャ行列 |
B | バイアス行列 |
Lp | 光源のプロジェクション行列 |
Lv | 光源のモデルビュー行列 |
このテクスチャ行列Tに対し、
glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_EYE_LINEAR); glTexGenfv(GL_S,GL_EYE_PLANE, s座標に該当する(x,y,z,w)); glEnable(GL_TEXTURE_GEN_S);などを用いる事で、変換用の行列ができる
次:実践編05::シャドウマッピング(全体の流れ)