我一直在研究延迟渲染器来进行照明,它工作得很好,尽管在我的 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;
}
我还有我的位置缓冲区,我对其进行采样以便稍后将其与计算位置进行比较,所以一切都应该是黑色的:
vec3 actualPosition = texture(gPosition, TexCoord).rgb;
vec3 difference = abs(FragWorldPos - actualPosition);
FragColour = vec4(difference, 0.0);
然而,我得到的结果与预期的结果相去甚远,当然,照明也不起作用:
(尽量忽略方框周围的模糊,当时我在忙别的事情。)
是什么导致了这些问题,我怎样才能成功地从深度重建位置?谢谢。
最佳答案
您走在正确的轨道上,但您没有以正确的顺序应用转换。
在这里快速回顾一下您需要完成的工作可能会有所帮助:
给定纹理坐标 [0,1] 和深度 [0,1],计算裁剪空间位置
- 不要线性化深度缓冲区
- 输出:
w
= 1.0 和x,y,z
= [-w, w]
从裁剪空间转换到 View 空间(反向投影)
- 使用逆投影矩阵
- 执行透视划分
从 View 空间转换到世界空间(反向 View 转换)
- 使用逆 View 矩阵
以下更改应该可以实现:
// 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;
}
虽然我会考虑更改 CalcViewZ (...)
的名称,但这是非常具有误导性的。考虑将其命名为更合适的名称,例如 CalcLinearZ (...)
。
关于c++ - 从深度缓冲区值获取世界位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32227283/