現在地: メニュー >> 実践編05 >> 実践編05::シャドウマッピング >> 実践編05::シャドウマッピングの原理
次:実践編05::シャドウマッピング(全体の流れ)

シャドウマッピングの原理


日向 → 何も光をさえぎるものがない。 → 光のあたっている部分は、『光源に視点を置いた時に見える』という事。

これは、可視性、すなわち「Zバッファ」と似ている。

つまり、
『光源の位置から描画して、デプステストを通過したもの(描画されるもの)は日向である』

【手順】

  1. 光源の位置からの描画を行い、その時の全ピクセルのZバッファを記録
  2. カメラ位置からの描画を行う。この時に光源からの投影テクスチャとしてシャドウマップを投影
  3. テクスチャが投影された時のあるピクセルと光源からの距離を比較計算する。


※デプステクスチャの値をD、光源と注目点の距離をRとすると、
R = D 光源から描画した時にさえぎるものはない → 日向
R > D 何かさえぎるものがある → 影



▲光源から見た時、AのほうがBより奥にある


以下、順番に説明していきます

1パス目(光源からの描画)


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パス目は視点からの描画。
ここでポイントとなるのは、『シーン全体を暗めの光源で描画する』という事。
(すべてが日陰の状態での描画をする感じで)
これが、後で影となる。


【擬似プログラム: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パス目(テクスチャ投影と日向の描画)


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::シャドウマッピング(全体の流れ)

目次

― その他 ―

Wiki内検索

計測中...(07.10.8〜)

Save The World






▲よろしければ広告のクリックもお願いします


▲ランキングに参加しました

管理人/副管理人のみ編集できます