web-dev-qa-db-ja.com

シェーダーを使用してopenglで深度値を描画します

フラグメントシェーダーで深度バッファーを描画したいのですが、これを行います。

頂点シェーダー:

varying vec4 position_;

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
position_ = gl_ModelViewProjectionMatrix * gl_Vertex;

フラグメントシェーダー:

float depth = ((position_.z / position_.w) + 1.0) * 0.5;

gl_FragColor = vec4(depth, depth, depth, 1.0);

しかし、私が印刷するのは白だけです、私は何が間違っているのですか?

19
hidayat

どの空間に奥行きを描きたいですか?ウィンドウスペースの深さを描画する場合は、次のように実行できます。

gl_FragColor = vec4(gl_FragCoord.z);

ただし、ほとんどの数値は1.0に非常に近いため、これは特に有用ではありません。非常に近いオブジェクトのみが表示されます。これは、標準の透視投影を使用した深度バッファーの深度値の分​​布の性質です。

または、言い換えれば、それがあなたが白くなっている理由です。

これらの値を線形空間で使用する場合は、次のような操作を行う必要があります。

float ndcDepth = ndcPos.z =
    (2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far) /
    (gl_DepthRange.far - gl_DepthRange.near);
float clipDepth = ndcDepth / gl_FragCoord.w;
gl_FragColor = vec4((clipDepth * 0.5) + 0.5); 
22
Nicol Bolas

実際、フラグメントの「深さ」値は、クリップ空間のz値から読み取ることができます(つまり、すべての行列変換後)。それだけは正しいです。

ただし、問題はwによる除算にあります。 wによる除算は、パースペクティブ除算と呼ばれます。はい、透視投影が正しく機能する必要があります。

ただし。この場合、wで除算すると、(これまで見てきたように)すべての値が1.0に非常に近くなります。これには正当な理由があります: 透視投影w= (some multiplier) *z。つまり、z値(計算されたものは何でも)を元のz(の何らかの係数)で除算します。常に1.0に近い値が得られるのも不思議ではありません。あなたはほとんどzをそれ自体で分割しています。

これに対する非常に簡単な修正として、zをfarPlaneで除算し、それをdepthとしてフラグメントシェーダーに送信してみてください。

頂点シェーダー

varying float DEPTH ;

uniform float FARPLANE ;  // send this in as a uniform to the shader

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
DEPTH = gl_Position.z / FARPLANE ; // do not divide by w

フラグメントシェーダー:

varying float DEPTH ;
// far things appear white, near things black
gl_Color.rgb=vec3(DEPTH,DEPTH,DEPTH) ;

その結果、悪くはなく、非常に直線的に見えるフェードになります。

enter image description here

12
bobobobo