从深度缓冲区和任意视图投影矩阵重建世界坐标

时间:2014-03-12 18:35:33

标签: opengl glsl deferred-rendering deferred-shading

我试图从延迟渲染器中的深度值重建3D世界坐标,但我有一点时间。我在网上找到的大多数例子都假设了标准的透视转换,但我不想做出这样的假设。

在我的几何传递顶点着色器中,我使用:

计算gl_Position
gl_Position = wvpMatrix * vec4(vertexLocation, 1.0f);

在我的照明传递片段着色器中,我尝试使用以下方法获取世界坐标:

vec3 decodeLocation()
{
  vec4 clipSpaceLocation;
  clipSpaceLocation.xy = texcoord * 2.0f - 1.0f;
  clipSpaceLocation.z = texture(depthSampler, texcoord).r;
  clipSpaceLocation.w = 1.0f;
  vec4 homogenousLocation = viewProjectionInverseMatrix * clipSpaceLocation;
  return homogenousLocation.xyz / homogenousLocation.w;
}

我以为我做对了,事实上,相机附近的物体似乎正确点亮了。但是我最近意识到,当我向远处移动时,物体会被照亮,好像他们离相机更远,而不是实际。我已经玩过我的灯光通行证,并确认我的世界坐标是唯一被误算的东西。

我无法帮助,但我认为我的clipSpaceLocation.z和clipSpaceLocation.w是问题的根源,但我已经尝试过我能想到的每个变体来计算它们,上面的代码会导致最正确的结果。

有任何想法或建议吗?

3 个答案:

答案 0 :(得分:6)

我只需要做一个微小的修复。这一行:

clipSpaceLocation.z = texture(depthSampler, texcoord).r;

应为:

clipSpaceLocation.z = texture(depthSampler, texcoord).r * 2.0f - 1.0f;

我理解它的方式,投影矩阵的设计使它们将近和远的平面映射到[-1,1],而不是像我一直假设的那样[0,1]。然后OpenGL将它们归一化到范围[0,1](a.k.a。“窗口空间”),所以我需要执行该规范化的反转。

这都是假设glDepthRange(0,1),默认情况下,没有理由改变它。

答案 1 :(得分:1)

您的一般方法是正确的,您只是没有正确反转窗口空间转换。窗口空间z(你可能进入你的深度纹理)是[0,1](默认情况下,更通用的是glDepthRange()),但NDC空间z是[-1,1]。因此,您可以将与x和y映射类似的行更改为

clipSpaceLocation.z = texture(depthSampler, texcoord).r * 2.0 - 1.0;

答案 2 :(得分:1)

请参阅我对gamedev.stackexchange的回答,以便更有效地重建世界和查看空间位置:

https://gamedev.stackexchange.com/a/111885/24009