以前ディファードレンダリングを試していたときの続きネタになります。あのときにはワールド座標の位置も G-buffer に書き出していました。デプスバッファも別にセットして出力していたので、このデプスバッファを活用出来れば実は G-buffer としての出力テクスチャが1つ削減出来ます。
説明
ワールド座標を復元するには、描画の際のビューマトリックスとプロジェクションマトリックスも必要になります。WorldViewProjection 行列の逆行列を用いてプロジェクション空間での値からワールド座標を復元します。
デプスバッファに描かれた値というのは、以下の図のようなプロジェクション空間の結果の Z 軸値となっています。
しかしながらテクスチャのフェッチでは基本的には左上(0,0)とし、右下(1,1)となった座標系で行います。
そのため、この二つの空間を変換する必要があります。X 軸方向で言えば、テクスチャ座標0から1を、プロジェクション空間 -1 から 1 へと変換します。
フェッチしたZ座標とそのときのUVの値をプロジェクション空間へ変換したx,y値を用いることで、プロジェクション空間の (x,y,z) が揃います。これにより先に準備しておいた ViewProjection の逆行列を乗算して、 w 値で割ることでワールド座標が復元できます。
DirectX のシェーダーにおいては、ベクトルと行列の演算が逆順にしてもコンパイルエラーにならないので注意が必要です。(自分もこの辺りでミスを犯していて苦労した記憶があります). また、w の除算は使う直前のピクセルシェーダー内で行いましょう。頂点シェーダーで w 除算した値を出しているんだけど~とやってると悩まされます。
うまく行かない場合にはこのあたりを確認してみるとよいでしょう。
シェーダーコードは以下のような感じで乗算しています。使用した算術ライブラリは DirectXMath です。
matrix mtxInvVP; float4 projectedPos; float4 wPos = mul( mtxInvVP, projectedPos );
結果
復元したワールド座標を用いてスペキュラの計算も入れてみました。
G-Buffer 出力フェーズで出したデプスバッファを活用することで、G-Buffer の1つのテクスチャを減らすことができました。
しかし、前回の読み込み専用デプスステンシルステートを活用している、という状態ではないので引き続きネタを探してみたいと思います。