从深度缓冲值获取世界位置

Tri*_*ert 10 c++ opengl

我一直在使用延迟渲染器进行照明,虽然在我的G缓冲区中使用位置缓冲区,但它运行良好.照明是在世界空间完成的.

我试图实现一个算法,从深度缓冲区和纹理坐标重新创建世界空间位置,虽然没有运气.

我的顶点着色器没什么特别的,但这是我的片段着色器的一部分,我(试图)计算世界空间位置:

// Inverse projection matrix
uniform mat4 projMatrixInv;
// Inverse view matrix
uniform mat4 viewMatrixInv;

// texture position from vertex shader
in vec2 TexCoord;

... other uniforms ...

void main() {
    // Recalculate the fragment position from the depth buffer
    float Depth = texture(gDepth, TexCoord).x;
    vec3 FragWorldPos = WorldPosFromDepth(Depth);

    ... fun lighting code ...
}

// Linearizes a Z buffer value
float CalcLinearZ(float depth) {
    const float zFar = 100.0;
    const float zNear = 0.1;

    // bias it from [0, 1] to [-1, 1]
    float linear = zNear / (zFar - depth * (zFar - zNear)) * zFar;

    return (linear * 2.0) - 1.0;
}

// this is supposed to get the world position from the depth buffer
vec3 WorldPosFromDepth(float depth) {
    float ViewZ = CalcLinearZ(depth);

    // Get clip space
    vec4 clipSpacePosition = vec4(TexCoord * 2.0 - 1.0, ViewZ, 1);

    // Clip space -> View space
    vec4 viewSpacePosition = projMatrixInv * clipSpacePosition;

    // Perspective division
    viewSpacePosition /= viewSpacePosition.w;

    // View space -> World space
    vec4 worldSpacePosition = viewMatrixInv * viewSpacePosition;

    return worldSpacePosition.xyz;
}
Run Code Online (Sandbox Code Playgroud)

我仍然有我的位置缓冲区,我将其采样以便稍后将其与计算位置进行比较,所以一切都应该是黑色的:

vec3 actualPosition = texture(gPosition, TexCoord).rgb;
vec3 difference = abs(FragWorldPos - actualPosition);
FragColour = vec4(difference, 0.0);
Run Code Online (Sandbox Code Playgroud)

但是,我得到的远不及预期的结果,当然,照明不起作用:

问题的形象

(试着忽略盒子周围的模糊,当时我正在弄乱别的东西.)

什么可能导致这些问题,我怎样才能从深度工作成功获得位置重建?谢谢.

And*_*man 15

您处于正确的轨道上,但尚未按正确的顺序应用转换.

快速回顾一下您需要完成的任务可能会有所帮助:

  1. 鉴于纹理坐标[ 0,1 ]和深度[ 0,1 ],计算裁剪空间位置

    • 难道不是线性的深度缓冲
    • 输出:w= 1.0和x,y,z= [ -w,w ]
  2. 从剪辑空间转换到视图空间(反向投影)

    • 使用反投影矩阵
    • 执行视角分割
  3. 从视图空间转换到世界空间(反向视图转换)

    • 使用逆视图矩阵

以下更改应实现:

// this is supposed to get the world position from the depth buffer
vec3 WorldPosFromDepth(float depth) {
    float z = depth * 2.0 - 1.0;

    vec4 clipSpacePosition = vec4(TexCoord * 2.0 - 1.0, z, 1.0);
    vec4 viewSpacePosition = projMatrixInv * clipSpacePosition;

    // Perspective division
    viewSpacePosition /= viewSpacePosition.w;

    vec4 worldSpacePosition = viewMatrixInv * viewSpacePosition;

    return worldSpacePosition.xyz;
}
Run Code Online (Sandbox Code Playgroud)

我会考虑更改名称CalcViewZ (...),这是非常误导.考虑称之为更合适的东西CalcLinearZ (...).