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

Jo *_*tes 8 opengl glsl deferred-rendering deferred-shading

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

在我的几何传递顶点着色器中,我使用以下方法计算gl_Position:

gl_Position = wvpMatrix * vec4(vertexLocation, 1.0f);
Run Code Online (Sandbox Code Playgroud)

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

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;
}
Run Code Online (Sandbox Code Playgroud)

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

我不禁想到我的clipSpaceLocation.z和clipSpaceLocation.w是问题的根源,但我已经尝试了我能想到的每个变化来计算它们,上面的代码得到了最正确的结果.

任何想法或建议?

Jo *_*tes 7

我只需要做一个微小的修复.这条线:

clipSpaceLocation.z = texture(depthSampler, texcoord).r;
Run Code Online (Sandbox Code Playgroud)

应该读:

clipSpaceLocation.z = texture(depthSampler, texcoord).r * 2.0f - 1.0f;
Run Code Online (Sandbox Code Playgroud)

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

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