使用着色器在OpenGL中绘制深度值

21

我想在片段着色器中绘制深度缓冲区,我这样做:

顶点着色器:

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);

但是我打印出来的都是白色,我做错了什么?


1
我想看到更多的上下文;就它们本身而言,着色器指令对我来说看起来很好。你给顶点指定了什么颜色?我唯一能想到的是,着色器没有完全加载,而你正在运行默认的固定管线设置,这恰好绘制了写入原语。为了调试,在你的主程序中设置glColor3f(1,0,0);,在着色器中设置gl_FragColor = vec4(0, depth, 0, 1.0);,以便区分固定函数和着色器管线。 - datenwolf
我在gDebugger中进行了一些调试,我的代码是正确的,但原因是所有东西都是白色的,是因为深度值非常接近于1,0.999,0.98888。 gl_fragcolor将颜色设置为纹理中的256。 - hidayat
1
这在透视投影情况下是可以预料的,因为深度值的非线性分布。请参阅@Nicol Bolas 的回答。 - datenwolf
2
思考一下,这些值表明了近和远裁剪平面距离的次优选择。理想情况下,近和远裁剪平面应该“触及”场景,即近裁剪平面尽可能靠近,远裁剪平面尽可能接近。如果您的裁剪平面设置为这样,您应该能够看到至少一些深度值更接近于0。 - datenwolf
2个回答

28

您希望在哪个空间中绘制深度?如果您想要绘制窗口空间中的深度,可以这样做:

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); 

gl_FragColor = vec4(...) 还会将 alpha 值设置为深度值。虽然不太可能需要混合深度片段,但将深度放在 alpha 通道中有点不寻常。 - datenwolf
另外,确定眼空间深度范围内的深度是否更容易(在GPU上实现)?它进行线性插值,从而在片段阶段节省一些指令。 - datenwolf
@datenwolf,剪辑空间Z只是眼睛空间Z的线性变换。既然我们谈论的是渲染到可以查看的图像,将剪辑空间Z映射到[0,1]和将眼睛空间Z映射到[0,1]之间没有区别。 - Nicol Bolas
无论如何,我认为在顶点着色器中完成是一种优雅的解决方案。 - datenwolf

16

的确,片段的“深度”值可以从它在剪辑空间(也就是所有矩阵变换后)的z值中读取。这是正确的。

然而,你的问题在于分母为w的除法。w的除法被称为透视除法。是的,它对于透视投影正常工作是必要的。

但是,在这种情况下,分母为w将所有值“压缩”在一起(就像你所见),非常接近1.0。这有一个很好的原因:在透视投影中,w =(某个乘数)* z 。也就是说,您正在将z值(无论计算出来是多少)除以原始z的(某个因子)。难怪你总是得到接近1.0的值。你几乎是在将z除以自己。

作为一个非常简单的解决方法,请尝试仅将z除以远平面,并将其作为深度发送到片段着色器中。

顶点着色器

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接