LiSPSMDemoXNA Shadow Mapping を原型として LiSPSM の機能を乗せ、それらを切り替えて確認できるようにしてあります。ただし、ライトとしては方向性光源のみを実装し、点光源には対応していません。
https://github.com/willcraftia/TestXna/tree/20130429/LiSPSMDemo
ZIP でのダウンロードは以下から (関係ない物も含まれてしまいますが)
https://github.com/willcraftia/TestXna/tree/20130429
なお、ビルドに必要な XNA コンテンツは Git 管理外としているため、別途、XNA 公式サイトより XNA Shadow Mapping をダウンロードし、XNA コンテンツを LiSPSMDemo へコピーしてプロパティを設定する必要があります。
XBOX LIVE indie games - シャドウ シリーズ 1: 基本シャドウ マッピングLiSPSM 公式サイトにある C++ コード (オリジナル コード) をベースにしていますが、オリジナル コードのままでは問題が幾らかあるため、Ogre の LiSPSM 実装を加えて参考にしています。なお、Ogre では LiSPSMShadowCameraSetup が LiSPSM の実装部分であり、その原型はオリジナル コードです。
http://xbox.create.msdn.com/ja-JP/education/catalog/sample/shadow_mapping_1
Light Space Perspective Shadow Mapsまた、日本語での LiSPSM の解説については Project ASURA を参考にしています。ここでは LiSPSM の仕組みについては述べないため、詳しく知りたい方は Project ASURA の解説を参照すると良いでしょう。
http://www.cg.tuwien.ac.at/research/vr/lispsm/
Ogre
http://www.ogre3d.org/
Project ASURA - Light Space Perspective Shadow Mapsなお、VSM (Variance Shadow Maps) も合わせて乗せています。
http://asura.iaigiri.com/OpenGL/gl59.html
Variance Shadow Maps以下、シャドウ マップを VSM とし、LiSPSMLightCamera、FocusedLightCamera、BasicCamera による各ライト カメラでの比較画像です。いずれも、XNA Shadow Mapping で用いられるシャドウ マップ サイズ 2048x2048 です。
http://www.punkuser.net/vsm/
LiSPSM + VSM |
Focused + VSM |
Basic + VSM |
カメラとライトが平行になる状況における補正
カメラとライトが平行に近づくと LiSPSM は大きく品質が劣化しますが、LiSPSMDemo ではそのような場合に n 値に補正を掛け、品質を向上させています。これは、Ogre で実装されている仕組みを参考に、オリジナルの n 算出式の結果に対して適用しています。なお、Ogre では n 算出式が完全自動ではなく、プロパティによる調整を前提に作られているようです (描画するシーンに応じてプロパティを適切に調整する必要があると思います)。以下、補正 ON と OFF での比較画像です。差異を顕著にするため、VSM ではなく Basic でシャドウ マップを生成しています。
LiSPSM + Basic + 補正 ON |
LiSPSM + Basic + 補正 OFF |
凸体 B の押し出しに関する問題
方向性光源を用いる場合、凸体 B を構成する際には、表示カメラの視錐台をシーン領域でクリップした後、B の各頂点からライト方向へレイを飛ばし、幾らか B の範囲をライトのある方向へ押し出して領域を拡張する必要があります。これを行わない場合、投影オブジェクトがカメラの外に出るような状況において、その分だけ影が描画されない問題が発生します。この問題は、例えば、このサンプルにおいては、デュード モデルの影に非常に接近する場合に起こりえます。オリジナル コードでは、そのようなレイとシーン領域との交点を B へ追加しますが、どうやらレイの始点となる各頂点がシーン領域の縁に存在し、結果として始点が交点となってしまい、交点の意味が無いという状態になってしまいました。もしかすると、凸体 B のクリッピングに誤りがあるのかもしれません。
これに対し、Ogre では、そのようなレイにそって一定の距離 (ライトの遠平面距離) にある点を追加して解決しています。そこで、LiSPSMDemo においても同様の概念で凸体 B を押し出しています。
ただ、実際にはどうなんでしょう?
表示カメラの視錐台をシーン領域でクリップする処理は、シーン領域の一部が視錐台によりクリップされる事も含んでいます。つまり、視錐台の外にある投影オブジェクトは凸体 B の外に出てしまうので、描画範囲から除外されてしまいます。そこで、このような投影オブジェクトを描画範囲に含めるため、凸体 B をライトのある方向へ少し押し出し、最終的なクリッピング領域を広げているのだと思います。ただ、これ自体は、LiSPSM に限らず、一般的にシャドウ マッピングにおいて考えなければならないクリッピング領域の問題であろうかと思います。
最小限必要となる凸体 B の構築を考えた場合、投影オブジェクトで構成される領域を別途管理し、凸体 B へこれを含めるなどの処理を行うべきなのかもしれません。実際、Ogre では投影オブジェクト領域と非投影オブジェクト領域を別途管理し、それらを考慮した領域の結合などを行なっているようです。
ですが、ある範囲に対して投影しうるオブジェクトであるか否かの判定自体が面倒でもあるので、厳密な判定が不要であるならば、一定距離で範囲を広げてしまえば良い気もします。
その他思うこと
Basic でシャドウ マップを作ると、セルフ シャドウが汚いなぁと。VSM でシャドウ マップを作ると、セルフ シャドウは綺麗になるものの、VSM ではモデルと影の関係が変になるんだよなぁと。LiSPSM + Basic におけるセルフ シャドウ |
LiSPSM + VSM におけるセルフ シャドウ |
LiSPSM + Basic におけるモデルの足元 |
LiSPSM + VSM におけるモデルの足元 |
0 件のコメント:
コメントを投稿