从深度缓冲区值获取世界位置 [英] Getting World Position from Depth Buffer Value
问题描述
我一直在研究延期渲染器以进行照明,尽管在我的G缓冲区中使用了位置缓冲区,但效果很好.照明是在世界空间中完成的.
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.
推荐答案
您处在正确的轨道上,但尚未按正确的顺序应用转换.
You are on the right track, but you have not applied the transformations in the correct order.
-
给出纹理坐标[ 0 , 1 ]和深度[ 0 , 1 ],计算剪辑空间位置
Given Texture Coordinates [0,1] and depth [0,1], calculate clip-space position
- 不要 不 线性化深度缓冲区
- 输出:
w
= 1.0 和x,y,z
= [ -w ,w ]
- Do not linearize the depth buffer
- Output:
w
= 1.0 andx,y,z
= [-w,w]
从剪辑空间转换为视图空间(反向投影)
Transform from clip-space to view-space (reverse projection)
- 使用反投影矩阵
- 进行透视划分
从视图空间到世界空间的转换(反向视图转换)
Transform from view-space to world-space (reverse viewing transform)
- 使用逆视图矩阵
通过以下更改可以实现:
// 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(...)
.
I would consider changing the name of CalcViewZ (...)
though, that is very much misleading. Consider calling it something more appropriate like CalcLinearZ (...)
.
这篇关于从深度缓冲区值获取世界位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!