14

フラグメントシェーダーで深度を取得することに関する多くの情報を読みました。

そのような

http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=234519

gl_FragCoord.zしかし、線形かどうかはまだわかりません。

GLSL仕様では、その範囲はスクリーンスペースで[0,1]であり、線形かどうかは言及されていません。

レンダリングされたモデルを使用して Kinect の深度マップを一致させるため、線形性は非常に重要だと思います。

それが線形でない場合、ワールド空間で線形化する方法は?

4

4 に答える 4

36

gl_FragCoord.z が線形かどうかはまだわかりません。

が線形かどうかgl_FragCoord.zは、射影行列に依存します。正射投影gl_FragCoord.zは線形ですが、透視投影は線形ではありません。

一般に、深さ (gl_FragCoord.zおよびgl_FragDepth) は次のように計算されます ( GLSL gl_FragCoord.z の計算と gl_FragDepth の設定を参照)。

float ndc_depth = clip_space_pos.z / clip_space_pos.w;
float depth = (((farZ-nearZ) * ndc_depth) + nearZ + farZ) / 2.0;

射影行列は、シーンの 3D ポイントからビューポートの 2D ポイントへのマッピングを表します。目空間からクリップ空間に変換し、クリップ空間の座標をクリップ座標のw成分で除算することにより、正規化されたデバイス座標 (NDC) に変換します。

正投影

Orthographic Projection では、目空間の座標は正規化されたデバイス座標に線形にマッピングされます。

正投影

正投影行列:

r = right, l = left, b = bottom, t = top, n = near, f = far 

2/(r-l)         0               0               0
0               2/(t-b)         0               0
0               0               -2/(f-n)        0
-(r+l)/(r-l)    -(t+b)/(t-b)    -(f+n)/(f-n)    1

Orthographic Projection では、Z コンポーネントは次の線形関数によって計算されます。

z_ndc = z_eye * -2/(f-n) - (f+n)/(f-n)

正射Z関数

透視投影

透視投影では、投影行列は、ピンホール カメラから見た世界の 3D ポイントからビューポートの 2D ポイントへのマッピングを表します。
カメラ錐台 (切頭ピラミッド) の眼球座標は、立方体 (正規化されたデバイス座標) にマップされます。

透視投影

透視投影行列:

r = right, l = left, b = bottom, t = top, n = near, f = far

2*n/(r-l)      0              0               0
0              2*n/(t-b)      0               0
(r+l)/(r-l)    (t+b)/(t-b)    -(f+n)/(f-n)    -1    
0              0              -2*f*n/(f-n)    0

透視投影では、Z コンポーネントは有理関数によって計算されます。

z_ndc = ( -z_eye * (f+n)/(f-n) - 2*f*n/(f-n) ) / -z_eye

パースペクティブ Z 機能

深度バッファ

正規化されたデバイス座標は (-1,-1,-1) から (1,1,1) の範囲にあるため、Z 座標は深度バッファーの範囲 [0,1] にマップする必要があります。

depth = (z_ndc + 1) / 2 


それが線形でない場合、ワールド空間で線形化する方法は?

深度バッファーの深度を元の Z 座標に変換するには、投影 (正射投影または透視投影)、およびニア プレーンとファー プレーンを知る必要があります。

正投影

n = near, f = far

z_eye = depth * (f-n) + n;

透視投影

n = near, f = far

z_ndc = 2.0 * depth - 1.0;
z_eye = 2.0 * n * f / (f + n - z_ndc * (f - n));

透視投影行列がわかっている場合、これは次のように実行できます。

A = prj_mat[2][2]
B = prj_mat[3][2]
z_eye = B / (A + z_ndc)

への回答も参照してください

ビュースペースの深さの値とndc xyを指定してビュースペースの位置を回復する方法

于 2017-08-16T09:52:31.067 に答える
12

通常の透視投影行列を想定すると、透視分割 ( によるgl_Position.w) ステップが実行されると、深度は直線性を失い、直線的でgl_FragCoord.zはなくなります。より詳細な説明については、@Dreamer's answerをお読みください。

線形に戻すには、次の 2 つの手順を実行する必要があります。

1) 変数gl_FragCoord.zを [-1, 1] の範囲の正規化されたデバイス座標に変換します。

z = gl_FragCoord.z * 2.0 - 1.0 

2) 射影行列 (IP) の逆行列を適用します。(x と y に任意の値を使用できます)、最後のコンポーネントを正規化します。

unprojected = IP * vec4(0, 0, z, 1.0)
unprojected /= unprojected.w

znear と zfar の間の線形 z を持つビュー空間 (またはカメラ空間、名前を付けます) のポイントを取得します。

于 2013-05-16T21:06:50.340 に答える
3

線形 Z が必要かどうかを決定するのはあなた次第です。すべては射影行列に依存します。あなたはこれを読むかもしれません:

http://www.songho.ca/opengl/gl_projectionmatrix.html

これは、射影行列がどのように機能するかを非常によく説明しています。前景の精度を高め、背景の精度を低くするには、非線形 Z を使用する方がよい場合があります。遠方では深度アーティファクトが目立たなくなります...

于 2011-10-15T13:20:23.163 に答える