■ 2005年02月28日 [OpenGL][テクスチャ] 第14回 環境テクスチャを光源に使う
環境は光源
以前,スフィアマッピングを使って Phong の陰影付けモデルにおける鏡面反射成分を表現する例を示しました.このようにスフィアマッピングやキューブマッピングのような環境マッピングは,物体表面への映り込みを再現する手法としてだけでなく,鏡面反射によるハイライトの生成や陰影付け自体にも利用できます.
その例として,映り込みに表面材質の影響を加味した方法 [Cabral] があります.また,この環境マップを因子分解して,その陰影付けを高速に実行する方法 [Ramamoorthi] や,これに影や相互反射による影響も考慮した方法 [Sloan] (PDF) なども提案されています.
一方,環境に用いるテクスチャの画像自体も,光源として利用するために従来の 8bit 程度の量子化ではなく,実数で表現することによってダイナミックレンジの非常に大きなものが利用される [Debevec] ようになっています.
したがって,これまでの「この位置に点光源を置いて」といったような照明の設定方法に加えて,環境のテクスチャを空間に分布している光源として取り扱うという考え方が,今後は一般的なものになっていくと予想されます.実際,最近のグラフィックスハードウェアでは,このような手法の実装を容易にするような拡張が行われています.
ところで陰影付けの復習
Phong の陰影付けモデルでは,鏡面反射成分の分布を光線の反射光ベクトルと視線ベクトル(あるいは視線の反射ベクトルと光線ベクトル)をもとに決定します.
その一方,OpenGL で採用されている方法(多分,Blinn のモデルに由来していると思うけど,実は経緯をよく知らない)では,視線ベクトルと光線ベクトルとの中間ベクトルと,物体表面の法線ベクトルをもとにして,これを決定します.
どちらも似たような効果が得られるのですが,これらの右側の図にあるように,実際にはハイライトの形(鏡面反射成分の分布)が微妙に違います.
ハイライトの形
同じように陰影を求めているのに,このように見掛けが違ってくるというのは妙な話ですね.どちらの形がいいかどうかという話をする前に,それぞれの物理的な意味を考えてみましょう.
一つ目の例は視線の反射ベクトルと光線ベクトルとの内積から鏡面反射光強度を求めています.これは見方を変えれば,視線の反射ベクトル方向に明度が同心円状に分布する物体があって,それが映り込んでいる状態と等価であるとみなせます.
これに対して二つ目の例は,光源の中心位置が映り込んでいる物体表面上の位置を中心に,鏡面反射光が分布しているとみなすことができます.ハイライトの形状が視線の方向に向かって延びている状況は,たとえば夕日が海に映えるようなシーンで目にすることができます(卒業生の篠原君が作ったサンプルムービー).個人的には,ゲームでウェットな路面へのヘッドライトの移り込みがこのように再現されていなかったりすると,「けっ」と思ってしまいます.
本当の光源は点ではない
上の二つはどちらが正しいというわけではありません.両方とも「光源が点である」という近似を採用しているために,計算方法の違いがハイライト形状の差として現れているに過ぎません.光源を点とみなしても,一応それらしい陰影は得られます.何より陰影計算を大幅に簡略化できるというメリットの方がありがたいのです.
しかし,現実の光源は光の放射面積をもつため,この近似が成立しないこともしばしば発生します.「リアルなんだけど 3DCG っぽい」などと感じることがあるとすれば,多分どこかでこの近似が破綻しているのでしょう.
環境テクスチャを光源として用いる手法は,光源を点とみなすよりずっと良い近似が得られます.そしてグラフィックスハードウェアの進化によって,この計算も非常に高速に行えるようになりました.
GL_REFLECTION_MAP と GL_NORMAL_MAP
キューブマッピングでは (s, t, r) の三つの軸についてテクスチャ座標を生成しますから,テクスチャ座標を反射方向ベクトルとして生成するのか中間ベクトルとして生成するのかを glTexGeni(…, GL_TEXTURE_GEN_MODE, …) で選べるようになっています.つまり,上の二つの方法のどちらにも対応できるわけですね.
本当は今回,スフィアマッピングで Phong シェーディングする話をキューブマップに置き換えて説明する予定だったんですが,ちょっと長くなったのと絵を描くのに疲れたので,実際のプログラムに関しては次回に回します.すみません.