2013/03/28

ベクトルのパック値とレンダ ターゲットでハマる

XNA Particels 3D サンプルと Shadow Mapping サンプルを移植していて、色々とハマりました。

まず、Particels 3D では PackedVector の Short2 を頂点データの一部に利用し、シェーダでは float2 でこれを受け取りますが、同様にした所、どうにも float2 で受け取れませんでした。int2 ならば受け取れます。頂点要素のフォーマット指定に従って、パック値から(バイトの並びから)自動的に float へ展開するものと思っていたのですが、違うのですかね・・・。
パック化の目的は頂点サイズを減らす事にあると思うので、int2 で受け取れるならそれで良いかという事にしてしまいました・・・納得はしていませんが。

続いて、Shadow Mapping はバック バッファ以外のレンダ ターゲットを利用するので、レンダ ターゲット周りの動作確認に良いかと思って移植してみたのですが、光源からの深度を書き込んだレンダ ターゲットがシェーダに渡されない状態にハマっていました。Shadow Mapping サンプルでは左上隅にレンダ ターゲットに書き込まれた深度マップを表示するので、書き込みの成功をこれで確認できるのに、深度マップと合わせてモデルを描画する際に、何故か参照できない(全深度が 0 になっている)状態でした。

結論としては、レンダ ターゲットとして利用しているテクスチャは、レンダ ターゲットとして設定する際には RenderTargetView、シェーダへ渡す際には ShaderResourceView で包んで利用する事になりますが、この両方がアクティブな状態となっている場合、ShaderResourceView で渡している側には 0 埋めされたテクスチャが設定される事が原因でした。MSDN を良く読むと、ID3D11DeviceContext.PSSetShaderResources の Remarks 等に、これを示唆する事が書いてありました。
ShaderResourceView として利用した後に参照を外してやれば良いだけですが、参照の外し忘れで同じ問題にハマるのも怖いので自動解決する方法を模索しましたが、あまり良い方法が思い浮かばないなぁと。
追記:その後、よくよく調べてみると、RenderTargetView を DeviceContext へ設定する際に ShaderResourceView 等の読み取りビューが設定されたスロットが null でリセットされる事が原因でした。素直に書く場合、必要な時に ShaderResourceView を設定するため、仮に null であっても再設定されるコードになるはずですが、僕はラッパークラスで参照をキャッシュするなどしていたため、D3D 内では null であるにも関わらず、ラッパークラスでは null ではないという状態の不整合が発生していたようです。
これらの他に、ハードウェア オクルージョン カリングを使う必要があるので、XNA の OcclusionQuery に相当するクラスを作り、Lens Flare サンプルを移植して試していました。
そろそろ必要な機能が揃い、動作も安定してきましたが、インスタンシングに関する枠組みを作ってみてから、ブロック地形のコードを新たな枠組みの上に乗せてみようかなと思っています。

0 件のコメント:

コメントを投稿

libgdx いじり

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