2013/05/06

XNA PSSM

SharpDX ベースの自作フレームワークで PSSM (Parallel-Split Shadow Maps) 関連のコードを整理したので、これを XNA 実装として公開しておきます。
PSSMDemo
https://github.com/willcraftia/TestXna/tree/20130506/PSSMDemo
ZIP DL はリポジトリから
https://github.com/willcraftia/TestXna/tree/20130506
自作フレームワークからの簡易移植であり、XNA としてコードを綺麗に整理していません。また、TestXna リポジトリには PSSMDemo プロジェクト以外も含まれ、リポジトリの ZIP ダウンロードには関係の無いプロジェクトも含まれます。

PSSMDemo は、先に公開した LiSPSMDemo 同様に、XNA Shadow Mapping サンプルを原型として実装してあります。今回もライトは方向性光源のみです。また、自作フレームワーク側で色々とリファクタリングを行ったので、クラス構造が LiSPSMDemo とは大きく異なります。

なお、ビルドに必要な XNA コンテンツは Git 管理外としているため、別途、XNA 公式サイトより XNA Shadow Mapping をダウンロードし、XNA コンテンツを LiSPSMDemo へコピーしてプロパティを設定する必要があります。
XBOX LIVE indie games - シャドウ シリーズ 1: 基本シャドウ マッピング
http://xbox.create.msdn.com/ja-JP/education/catalog/sample/shadow_mapping_1
PSSM ですが、日本語で纏められたサイトを見つける事ができませんでした。NVIDIA の GPU Gems を参考にしてください。
GPU Gems 3 - Chapter 10. Parallel-Split Shadow Maps on Programmable GPUs
http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html
MS の DirectX サンプルなどでは、カスケード シャドウ マップと紹介されています。
簡単に説明すると、カメラの視錐台を分割し、分割された視錐台それぞれについてシャドウ マップを生成し、影付きシーンを描画する際には、描画するオブジェクトの位置から適切なシャドウ マップを選択し、そこから深度を選択するという処理です。
分割された視錐台に対するシャドウ マップの生成では、XNA Shadow Mapping にあるような基礎的なロジックを用いても良いですし、LiSPSM を用いても良いです。
重要な点は、視錐台の分割により、一つのシャドウ マップで対象とするシーンの領域を小さくし、シャドウ マップの品質を向上させる点です。
以下、シャドウ マップを Basic (R 値に深度を書き込んだだけのもの) とし、ライト カメラに LiSPSMLightCameraBuilder (LiSPSM)、UniformLightCameraBuilder (USM)、BasicLightCameraBuilder (Basic ライト: XNA Shadow Mapping とほぼ同じロジック) を用いた比較画像です。いずれも、分割数 3、シャドウ マップ サイズ 2048x2048 (XNA Shadow Mapping と同サイズ) です。
分割3 + LiSPSM ライト + Basic マップ (2048x2048)
分割 3 + USM ライト + Basic マップ (2048x2048)
分割 3 + Basic ライト + Basic マップ (2048x2048)
このように、視錐台分割により、Basic ライトであっても、それなりに綺麗な影を生成できることが分かると思います。

分割数を少なくする程に、分割無しの品質に近づきますが、LiSPSM や USM は分割無しでもそれなりの品質であるため (元より分割無しでの品質向上アルゴリズム)、Basic ライトの場合にのみ大きな影響が表れます。
以下、Basic ライトについての、分割数を変更した場合の比較画像です。
分割 3 + Basic ライト + Basic マップ (2048x2048)
分割 2 + Basic ライト + Basic マップ (2048x2048)
分割 1 + Basic ライト + Basic マップ (2048x2048)
分割 1 は、XNA Shadow Mapping と概ね同等のシャドウ マップ生成です。

以下、Basic ライトについてシャドウ マップ サイズの変化による比較画像です。
分割 3 + Basic ライト + Basic マップ (2048x2048)
分割 3 + Basic ライト + Basic マップ (1024x1024)
分割 3 + Basic ライト + Basic マップ (512x512)
1024x1024 でも、それなりに綺麗かなと僕は感じます。512x512 は流石に厳しいですかね・・・。Basic ライトに加えて VSM を適用すると、更に綺麗な感じにはなりますが、ブラー適用の度合いにより色々と変化するので、比較画像は省略します。なお、VSM を用いる場合、分割数分だけブラーを適用する (負荷が増大する) ことにもなるので、適用すべきか否かについて十分な検討が必要であろうと思われます。例えば、2048x2048 のシャドウ マップに対して VSM のために 3 回のブラーを適用すると、ブラーのカーネル次第ですが、負荷も相当なものになります。

以下、おまけのような物ですが、サンプルでは影の色を C# コード上で変更できるようにしているため、(0, 0.5, 0) に設定した場合の例です。
影への色付け
影を緑色にしたい人は稀だとは思いますが、状況によって影の濃さは異なると思うので、黒をベースにその度合を変えて利用するなども良いかなと感じます。

まぁ、こんな所です。いつまでもシャドウ マッピングに拘っていてはいけないと感じていて、雑に XNA へ移植しています。おかしい点があれば、ご指摘して頂けると幸いです。

0 件のコメント:

コメントを投稿

libgdx いじり

Google が提供している Java 版の Tango Examples は Rajawali をベースにしているため、自分が仕事で開発する Tango アプリも Rajawali ベースとしていましたが、最近は libGDX への移行を進めています。一応、要点については移行が...