ステンシルシャドウボリューム技法
結局のところ、セルフシャドウ表現までを含んだ正確な影を出すためには、どうしても光源からの光を何がどう遮蔽しているか、という情報を求めなければならない。つまり、そのシーンの、光から見た遮蔽構造を求めなければならないのだ。
比較的、互換性が高く、汎用性が高い技法として最近でも採用例が多いのが「ステンシルシャドウボリューム技法」(Stencil Shadow Volume)だ。この技法は2004年を代表する3D PCゲームとなった「DOOM3」(id software,2004)が採用したことでも話題になった。
この技法では、シーンをまずレンダリング、そのシーンの視点からの見た深度情報をZバッファに生成する。ちなみに、シーンの深度情報は影生成のためだけに……ということだけではなく、後段のレンダリングや、様々なポストエフェクトに活用するため、先にシーンの深度情報だけをレンダリングしてしまうテクニックが利用される場合が多くなってきている。
続いて、光源から見て、そのシーンの3Dモデルの輪郭となる頂点を光の進行方向……すなわち光線ベクトル方向に引き伸ばす。この引き伸ばして出来た領域が「影となる領域」であり、これが技法名にもなっている「シャドウボリューム」となる。
続いて、このシャドウボリュームをレンダリングして影を求めるわけだが、このレンダリングは少々技巧的で、表示用のフレームバッファではなく、「ステンシルバッファ」(Stencil Buffer)という多目的に活用される算術処理用のフレームバッファに対して行うのだ(ステンシルバッファはあらかじめ"0"に初期化しておく)。
このシャドウボリュームのレンダリングは2ステップにて行うのがこの特徴だ。
第1のステップでは、視点から見て、このシャドウボリュームの前面(表面)となるポリゴン(始点方向に面を向けている影領域)のみをステンシルバッファに"+1"演算でレンダリングする。
光源が複数ある場合や3Dオブジェクトが重なり合っているときは、この影領域の前面となる箇所は"+1"が重複されてレンダリングされることになり、ステンシル値は大きくなることもある。
第2ステップでは、今度は、このシャドウボリュームの、視点から見て後面(裏面)となるポリゴンを、同じように先ほどのステンシルバッファにレンダリングするのだが、今度は"-1"演算で行う。
なにも遮蔽物がない影領域では、第1ステップで表面をレンダリングした箇所の"+1"された回数分だけ、今度は"-1"されることになるので、ステンシル値は"±0"に戻る。ステンシル値がゼロとなった部分は、つまり影領域ではない……ということになるのだ。
しかし、何らかの遮蔽物があると、この影領域の裏面ポリゴンが描かれない……つまり"-1"されないことになり、そのステンシルバッファの内容は"0"にならず"1"以上の値を残したままになってしまう。なお、遮蔽物があるかないかの判断は、事前にレンダリングしておいたZバッファの内容(シーンの深度情報)を吟味して行う。
ステンシルバッファのピクセルのうち"0"にならなかった部分のピクセルは、「影となるピクセルである」ということを表すことになる。
影領域の前面と裏面を描き終わったステンシルバッファは、そのフレームのどのピクセルが影か否かを表しているので、最終的なレンダリングフェーズでは、このステンシルバッファの内容を参照して、影であれば影の色を付けていけばいい。ステンシルバッファは、特定の値で描画をマスク処理することも可能なので、ベタっと影色を塗ってもちゃんと影となるべきところにだけ"影色"を付けることが出来る。"影色"とは真っ黒にしてもよいし、そのシーンを普通にレンダリングして求まったピクセル色に、適当な透明度で暗い色をミックスして暗色を出すようにしてもいい。このあたりの表現はアーティスティックなセンスに左右される部分になる。
この技法では、結果的に、光源ごとに生成されたシャドウボリュームが、その光源からの光の遮蔽構造をステンシルバッファに記録するようなことになるため、セルフシャドウ表現も正しく考慮され、3Dモデルが相互に影を落とし合う相互投射影表現についても正しく描き出される。(続く)
(トライゼット西川善司)