从深度缓冲区获取真正的 z 值 [英] Getting the true z value from the depth buffer

查看:43
本文介绍了从深度缓冲区获取真正的 z 值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如预期的那样,从着色器中的深度缓冲区采样返回 0 到 1 之间的值.给定相机的近剪裁平面和远剪裁平面,如何计算此时的真实 z 值,即与相机的距离?

Sampling from a depth buffer in a shader returns values between 0 and 1, as expected. Given the near- and far- clip planes of the camera, how do I calculate the true z value at this point, i.e. the distance from the camera?

推荐答案

来自 http://web.archive.org/web/20130416194336/http://olivers.posterous.com/linear-depth-in-glsl-for-real

// == Post-process frag shader ===========================================
uniform sampler2D depthBuffTex;
uniform float zNear;
uniform float zFar;
varying vec2 vTexCoord;
void main(void)
{
    float z_b = texture2D(depthBuffTex, vTexCoord).x;
    float z_n = 2.0 * z_b - 1.0;
    float z_e = 2.0 * zNear * zFar / (zFar + zNear - z_n * (zFar - zNear));
}

[edit] 所以这是解释(有 2 个错误,见下面 Christian 的评论):

[edit] So here's the explanation (with 2 mistakes, see Christian's comment below) :

OpenGL 透视矩阵如下所示:

An OpenGL perspective matrix looks like this :

当你将这个矩阵乘以一个齐次点 [x,y,z,1] 时,它给你: [don't care, don't care, Az+B, -z] (A 和 B矩阵中的 2 个大分量).

When you multiply this matrix by an homogeneous point [x,y,z,1], it gives you: [don't care, don't care, Az+B, -z] (with A and B the 2 big components in the matrix).

OpenGl 接下来进行透视划分:它将这个向量除以它的 w 分量.这个操作不是在着色器中完成的(除了像阴影贴图这样的特殊情况),而是在硬件中;你无法控制它.w = -z,所以Z值变成-A/z -B.

OpenGl next does the perspective division: it divides this vector by its w component. This operation is not done in shaders (except special cases like shadowmapping) but in hardware; you can't control it. w = -z, so the Z value becomes -A/z -B.

我们现在处于标准化设备坐标中.Z 值介于 0 和 1 之间.出于某种愚蠢的原因,OpenGL 要求将其移动到 [-1,1] 范围内(就像 x 和 y 一样).应用了缩放和偏移.

We are now in Normalized Device Coordinates. The Z value is between 0 and 1. For some stupid reason, OpenGL requires that it should be moved to the [-1,1] range (just like x and y). A scaling and offset is applied.

这个最终值然后存储在缓冲区中.

This final value is then stored in the buffer.

上面的代码正好相反:

  • z_b 是存储在缓冲区中的原始值
  • z_n 将 z_b 从 [-1,1] 线性变换为 [0,1]
  • z_e 与 z_n=-A/z_e -B 的公式相同,但对 z_e 求解.它等价于 z_e = -A/(z_n+B).A 和 B 应该在 CPU 上计算并作为统一发送,顺便说一句.

相反的功能是:

varying float depth; // Linear depth, in world units
void main(void)
{
    float A = gl_ProjectionMatrix[2].z;
    float B = gl_ProjectionMatrix[3].z;
    gl_FragDepth  = 0.5*(-A*depth + B) / depth + 0.5;
}

这篇关于从深度缓冲区获取真正的 z 值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆