導入された機能に両面ステンシル機能があります。(これだけに限らず、もっと多彩な変化が可能です。表と裏でステンシルのレンダリングステートに違う設定ができるのが両面ステンシルです)。これを使えば、シャドウボリュームによる影の描画パスの回数を1回減らすことができます。ために追加された気がしてしょうがありませんが...今回は、前にやったボリューム影を両面ステンシルで行っただけでなく、元のモデルと同じ形の影を落とす方法に改良しました。(両面ステンシル影:DirectX9)まぁ、いつものように適当にファイルが入っています。出力されるフレームワークのファイルは紹介を省かせていただきます。アプリケーションのソースあと、実行ファイル、表示用モデル及び、プロジェクトファイルが入っています。今回のモデルは、コーネル箱の外枠モデルと、大きさ1の箱を用意しました。今回の方法は、シャドウボリュームを作る専用のメッシュを作成します。基本的にDirectXで扱うポリゴンは3角形ポリゴンです。その3角形を切り開いて、稜線(頂点と頂点を結ぶ辺)に4角形ポリゴンを挟み込みます。いっても、実際には、3角形ポリゴンを2枚埋め込むことになります。(この時点で共有された頂点はなくなるので、全ての頂点がどこかの3角形に所属しています)。頂点の位置も、「切り開いた」といっても、位置はずらさないで、もとのモデルと同じ頂点座標を使います。したがって、シャドウボリュームのメッシュは、元のメッシュと見た目上同じに見えます。稜線に埋め込んだ四角形ポリゴンは、普段は大きさが0の縮退をして姿を現しません。このポリゴンの量ですが、ちょっと多いです。元のメッシュのポリゴン1つにつき3つの稜線があります。稜線は2つのポリゴンにまたがっているので、1つのポリゴンに付き3/2の四角形ポリゴンが追加されることになります。4角形ポリゴンを3角形に割るとちょうど、1つのポリゴンに付き3つの3角形ポリゴンが追加されることになります。稜線に埋め込まれるのは、元のポリゴン数の3倍のポリゴンです。元のメッシュも必要なので、シャドウボリュームのメッシュは元のメッシュの4倍のポリゴン数になります。多いか少ないかは微妙なとこですね。プログラムですが、ちょっとややこしいので少しづつ見ていきましょう。最初に、元のメッシュのFVFを変換して、いらない情報を削りとります。次に、メッシュの面の数から、シャドウボリュームのメッシュの面数や頂点数を算出して、メモリを確保します。SHADOW_VOLUME_VERTEX[3*m_dwNumFaces];そしたら、元のメッシュをロックして、情報を所得します。所得する情報は、面ごとの頂点の位置データです。位置データから面の法線ベクトルを計算します。シャドウボリュームのメッシュの元のメッシュと同じ部分を作成しておきます。}後は、稜線に埋め込むデータです。元のメッシュの各面を総当りして共通する辺があるか検索します。共通する辺は同じ位置にある頂点が2つあれば辺が重なることを利用して計算します。今回の方法では、厚さ0の張り合わさったメッシュは適応できないので、気をつけてください。稜線が見つかったら、そのインデックスから頂点の位置や法線を求めます。ここで、ポリゴンの表を決めるためにポリゴンの周り順が左回りになるように調整します。m_dwNumFaces);後は、ロックを解いたり、メモリを開放します。}■シェーダさて、シェーダです。ピクセルシェーダは必要ありません(固定機能が使われます)。ラスタライザに渡すデータも何も要らないので、位置情報だけを頂点シェーダの出力とします。裏を向いていたら、定数だけライトから反対に引き伸ばします。内側にずらしています。ワールド行列に少し縮小スケールをかけておいてもいいかもしれません(元のメッシュを大きくする手もありますが)。今回の計算はローカル座標系で行っているので、ライトの位置をローカル座標に変換しておく必要があります。}このシェーダでレンダリングされるシャドウボリュームは、下のようになります。真っ白な部分が、シェーダでレンダリングされたシャドウボリュームです。必要なのが能力チェックです。今回は、いつものシェーダのほかに、両面ステンシルが使えるかどうかのチェックと、ステンシルバッファが使えるかどうかチェックします。フレームワークを使うのではなくて、サンプルのものを使いました。}■レンダリングでは、描画の部分を見てみましょう。ステンシルシャドウの最初はいつもどおりの描画です。画面クリアした後に、普通にモデルを表示します。次にシャドウボリュームの描画です。ステンシル系の設定が倍になりました。有効にすれば、両面ステンシルがつかるようになります。いつも2パス目で書くシャドウボリュームの設定をこちらに描きます。);そして、実際のレンダリングは、シェーダやシェーダの変数を設定してレンダリングすれば大丈夫です。}最後にステンシルテストしながら全画面に暗い半透明を描画します。ステンシルバッファの値が0でないところが影になるので、そのようなテストで書き込みます。);最後に元に戻して終了です。今回の結果は、影の位置が一致しますね(もちろん、こちらは面光源を使っていないのでぼやけませんが)。コーネル箱は本当にただの箱なので、メリハリをつけるのが大変ですね。影については、ちゃんとしたのができたので、個人的には気に入っています。ステンシルシャドウのくっきりする欠点はどうしようも無いですね。ステンシルソフトシャドウは、どうすればできるのだろうか・・・もどるimagire@gmail.com。