Getting World Position from Depth Buffer Value

…衆ロ難τιáo~ 提交于 2021-02-04 10:27:08

问题


I've been working on a deferred renderer to do lighting with, and it works quite well, albeit using a position buffer in my G-buffer. Lighting is done in world space.

I have tried to implement an algorithm to recreate the world space positions from the depth buffer, and the texture coordinates, albeit with no luck.

My vertex shader is nothing particularly special, but this is the part of my fragment shader in which I (attempt to) calculate the world space position:

// 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;
}

I still have my position buffer, and I sample it to compare it against the calculate position later, so everything should be black:

vec3 actualPosition = texture(gPosition, TexCoord).rgb;
vec3 difference = abs(FragWorldPos - actualPosition);
FragColour = vec4(difference, 0.0);

However, what I get is nowhere near the expected result, and of course, lighting doesn't work:

(Try to ignore the blur around the boxes, I was messing around with something else at the time.)

What could cause these issues, and how could I get the position reconstruction from depth working successfully? Thanks.


回答1:


You are on the right track, but you have not applied the transformations in the correct order.

A quick recap of what you need to accomplish here might help:

  1. Given Texture Coordinates [0,1] and depth [0,1], calculate clip-space position

    • Do not linearize the depth buffer
    • Output: w = 1.0 and x,y,z = [-w,w]
  2. Transform from clip-space to view-space (reverse projection)

    • Use inverse projection matrix
    • Perform perspective divide
  3. Transform from view-space to world-space (reverse viewing transform)

    • Use inverse view matrix

The following changes should accomplish that:

// 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;
}

I would consider changing the name of CalcViewZ (...) though, that is very much misleading. Consider calling it something more appropriate like CalcLinearZ (...).



来源:https://stackoverflow.com/questions/32227283/getting-world-position-from-depth-buffer-value

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!