6

現在、次の GLSL コードを使用して、後処理の被写界深度シェーダーの深度テクスチャから読み取っています。

vec4 depthSample = texture2D(sDepthTexture, tcScreen);
float depth = depthSample.x * 255.0 / 256.0 +
              depthSample.y * 255.0 / 65536.0 +
              depthSample.z * 255.0 / 16777216.0;

次に、深さの値を近距離と遠距離の平面距離に基づいてビュー空間距離に変換します。

float zDistance = (zNear * zFar) / (zFar - depth * (zFar - zNear));

これはすべてかなりうまくいくようですが、別zNearzFar値を必要とせずに現在の射影行列のみに基づいて上記の計算を行う方法を知りたいと思っています。

私の最初の試み(vec4(tcscreen.x, tcScreen.y, depth, 1.0) * 2.0 - 1.0)では、射影行列の逆数を掛け、結果を で割り、結果の値を距離としてw取りましたzが、うまくいかなかったようです。ここで正しいアプローチは何ですか?

また、斜めの錐台クリッピングを使用してニアプレーンを選択したクリッピングプレーンにシフトすると、ニアプレーンの距離がピクセルごとに異なる可能性がありますか? もしそうなら、深度テクスチャからの距離を計算するシェーダーはこのケースを認識する必要があり、平面に近い距離が一定であると仮定しないことを意味しますか?

ありがとう!

4

2 に答える 2

4

最終的な Z 値を否定して、ニア プレーンの前に正の距離を取得するのを忘れていたことがわかりました (OpenGL カメラは -Z を見下ろします)。今後の参考のために、近い平面の前の距離を取得するための GLSL コードは次のとおりです。

float depth = /* sampled from depth texture as in the original question */ ;

vec4 screenPos = vec4(tcScreen.x, tcScreen.y, depth, 1.0) * 2.0 - 1.0;
vec4 viewPosition = projectionMatrixInverse * screenPos;

float z = -(viewPosition.z / viewPosition.w);

代わりに (SuperPro が使用していたように) ワールド空間位置が必要な場合は、ビュー行列と射影行列を組み合わせてから、射影行列の逆行列を使用するだけでなく、その行列の逆行列を使用して見つけることができます。

の Z 成分と W 成分のみviewPositionが必要なため、計算用の上記の GLSL はviewPositionいくらか単純化できます。完全な行列乗算の代わりに 2 つの内積で十分です。下の 2 行のみが必要なため、完全な逆射影行列をシェーダーに入力する必要はありません。

vec2 viewPositionZW = vec2(
    dot(projectionMatrixInverseRow2, screenPos),
    dot(projectionMatrixInverseRow3, screenPos)
);

float z = -(viewPositionZW.x / viewPositionZW.y);

これのパフォーマンスは、近距離と遠距離を使用するよりも少し悪くなります。おそらく余分な内積が原因で、約 5% 削減されました。近距離と遠距離の計算は、定数としてフィード(zNear * zFar)(zFar - zNear)インによって最適化することもできますが、これを行っても測定可能な改善は見られませんでした.

興味深いことに、上記を斜錐台クリッピングを使用している射影行列と組み合わせると、そこから意味のあるものは何も得られませんが、同じ射影行列で近距離と遠距離の式を使用すると、妥当な出力が得られます。これは、深度値の歪みのように見えます (ただし、これは、斜めの錐台クリッピングに固有の深度精度の損失が原因である可能性があります)。ここで数学的に何が起こっているのかを誰かが明らかにすることができれば、私はそれを感謝しますが、それは別の質問にあるはずです.

于 2009-07-21T00:56:29.530 に答える
2

稲妻の方向を計算するために、稲妻シェーダーで次のコードを使用します。Wold 位置も、スクリーン位置に射影行列の逆数を掛けることによって計算されます。

残念ながら HLSL:

float depth = tex2D(DepthMapSampler, PSIn.TexCoord).r;

float4 screenPos;
screenPos.x = PSIn.TexCoord.x*2.0f-1.0f;
screenPos.y = -(PSIn.TexCoord.y*2.0f-1.0f);
screenPos.z = depth;
screenPos.w = 1.0f; 

float4 worldPos = mul(screenPos, xViewProjectionInv);
worldPos /= worldPos.w;

正常に動作するので、Worldposition は正しいと思います。

于 2009-07-20T19:29:36.687 に答える