9

我正在尝试从我的延迟渲染器中的深度值重建 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 是问题的根源,但我已经尝试了所有我能想到的变体来计算它们,上面的代码得到了最正确的结果。

有什么想法或建议吗?

4

3 回答 3

7

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

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

应该读:

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

根据我的理解,投影矩阵的设计是为了将近平面和远平面映射到 [-1,1],而不是像我一直假设的那样 [0,1]。然后 OpenGL 将它们标准化为范围 [0,1](也称为“窗口空间”),因此我需要执行该标准化的逆操作。

这一切都假设 glDepthRange(0, 1),它是默认的,几乎没有理由改变它。

于 2014-03-12T20:30:37.647 回答
1

您的一般方法是正确的,您只是没有正确反转窗口空间变换。窗口空间 z(您可能会加入深度纹理)是 [0,1](默认情况下,更一般的应该是glDepthRange()),但 NDC 空间 z 是 [-1,1]。因此,您可以将类似于 x 和 y 映射的那条线更改为

clipSpaceLocation.z = texture(depthSampler, texcoord).r * 2.0 - 1.0;
于 2014-03-12T20:16:04.970 回答
1

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

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

于 2015-11-30T05:11:32.680 回答