6

対数深度アルゴリズムを使用しているため、 someFunc(clipspace.z) が深度バッファーに書き込まれ、暗黙的なパースペクティブdivideはありません

私はRTT /ポストプロセッシングを行っているので、後でフラグメントシェーダーで、ndc.xy(フラグメント座標から)とclipspace.z(深度バッファーに保存された値のsomeFuncInv()から)を指定して、eyespace.xyzを再計算したい.

私にはclipspace.wがなく、保存された値はclipspace.z/clipspace.wではないことに注意してください(固定関数の深さを使用する場合と同様)-したがって、...の行に沿ったもの

float clip_z = ...; /* [-1 .. +1] */
vec2 ndc = vec2(FragCoord.xy / viewport * 2.0 - 1.0);
vec4 clipspace = InvProjMatrix * vec4(ndc, clip_z, 1.0));
clipspace /= clipspace.w;

...ここでは機能しません。

では、射影行列または逆行列を指定して、clipspace.xyz から clipspace.w を計算する方法はありますか?

4

1 に答える 1

11
clipspace.xy = FragCoord.xy / viewport * 2.0 - 1.0;

これは命名法に関して間違っています。「クリップ スペース」は、頂点シェーダー (または最後の頂点処理ステージが何であれ) が出力するスペースです。クリップ スペースとウィンドウ スペースの間には、正規化されたデバイス座標 (NDC) スペースがあります。NDC 空間は、クリップ空間の W 座標で割ったクリップ空間です。

vec3 ndcspace = clipspace.xyz / clipspace.w;

したがって、最初のステップは、ウィンドウ空間座標を取得し、NDC 空間座標を取得することです。これは簡単です:

vec3 ndcspace = vec3(FragCoord.xy / viewport * 2.0 - 1.0, depth);

ここで、値が適切な NDC 空間の深さであると仮定します。depth深度テクスチャから値をフェッチし、レンダリングされた深度範囲の近/遠値を使用して [-1, 1] 範囲にマップすると想定しています。そうでない場合は、そうする必要があります。

では、 が得られたのでndcspace、どうやって を計算するのclipspaceでしょうか? まあ、それは明らかです:

vec4 clipspace = vec4(ndcspace * clipspace.w, clipspace.w);

明らかで... ないので役に立ちませんclipspace.w。では、どうやってそれを得るのですか?

これを取得するにclipspaceは、最初に がどのように計算されたかを見る必要があります。

vec4 clipspace = Proj * cameraspace;

これは、 の 4 行目でそれを内積clipspace.wすることによって が計算されることを意味します。cameraspaceProj

まあ、それはあまり役に立ちません。の 4 行目を実際に見てみると、さらに役に立ちますProj。確かに、任意の射影行列を使用できます。典型的な射影行列を使用していない場合、この計算はより困難になります (不可能になる可能性があります)。

典型的な射影行列を使用したの 4 行目はProj、実際には次のとおりです。

[0, 0, -1, 0]

これは、clipspace.wが本当にただの であることを意味し-cameraspace.zます。それは私たちにどのように役立ちますか?

これを覚えておくと役立ちます:

ndcspace.z = clipspace.z / clipspace.w;
ndcspace.z = clipspace.z / -cameraspace.z;

それはいいことですが、未知のものを別のものと交換するだけです。まだ 2 つの未知数 (clipspace.zcameraspace.z) を含む方程式があります。しかし、私たちは別のことを知っています:射影行列の3clipspace.z行目の内積から来ています。従来の射影行列の 3 行目は次のようになります。cameraspace

[0, 0, T1, T2]

ここで、T1 と T2 はゼロ以外の数値です。当分の間、これらの数値が何であるかは無視します。したがって、clipspace.zは本当に ですT1 * cameraspace.z + T2 * cameraspace.w。が 1.0 であることがわかっている場合cameraspace.w(通常はそうです)、それを削除できます。

ndcspace.z = (T1 * cameraspace.z + T2) / -cameraspace.z;

ですから、まだ問題があります。実際、私たちはしません。なんで?この真正方程式には未知数が 1 つしかないからです。覚えておいてください:私たちはすでに知っていndcspace.zます. したがって、ndcspace.z を使用して を計算できますcameraspace.z

ndcspace.z = -T1 + (-T2 / cameraspace.z);
ndcspace.z + T1 = -T2 / cameraspace.z;
cameraspace.z = -T2 / (ndcspace.z + T1);

T1投影マトリックス (シーンが最初にレンダリングされたもの) からすぐにT2出てきます。そして、私たちはすでに持っていますndcspace.z。したがって、計算できcameraspace.zます。そして、次のことがわかっています。

clispace.w = -cameraspace.z;

したがって、これを行うことができます:

vec4 clipspace = vec4(ndcspace * clipspace.w, clipspace.w);

clipspace.w明らかに、リテラル コードではなくfloat for が必要になりますが、私の言いたいことはわかります。を取得したらclipspace、カメラ スペースを取得するには、逆投影行列を掛けます。

vec4 cameraspace = InvProj * clipspace;
于 2013-01-25T21:24:46.097 に答える