6

我目前正在使用以下 GLSL 代码在后处理景深着色器中读取深度纹理:

vec4 depthSample = texture2D(sDepthTexture, tcScreen);
float depth = depthSample.x * 255.0 / 256.0 +
              depthSample.y * 255.0 / 65536.0 +
              depthSample.z * 255.0 / 16777216.0;

然后根据近、远平面距离将深度值转换为视空间距离:

float zDistance = (zNear * zFar) / (zFar - depth * (zFar - zNear));

这一切似乎都运行得很好,但是我很想知道如何仅基于当前投影矩阵进行上述计算,而不需要单独的zNearzFar值。

我最初的尝试涉及乘以(vec4(tcscreen.x, tcScreen.y, depth, 1.0) * 2.0 - 1.0)投影矩阵的倒数,将结果除以w,然后将结果z值作为距离,但这似乎不起作用。这里的正确方法是什么?

此外,当使用斜截头截体剪裁将近平面移动到选定的剪裁平面上时,现在每个像素的近平面距离是否可能不同?如果是这样,那么这是否意味着任何计算与深度纹理的距离的着色器都需要了解这种情况,而不是假设一个恒定的近平面距离?

谢谢!

4

2 回答 2

4

事实证明,我忘记取反最终的 Z 值以获得在近平面前面的正距离(OpenGL 相机向下看 -Z)。为了将来参考,获取近平面前面距离的 GLSL 代码是:

float depth = /* sampled from depth texture as in the original question */ ;

vec4 screenPos = vec4(tcScreen.x, tcScreen.y, depth, 1.0) * 2.0 - 1.0;
vec4 viewPosition = projectionMatrixInverse * screenPos;

float z = -(viewPosition.z / viewPosition.w);

如果您想要一个世界空间位置(就像 SuperPro 使用的那样),那么可以通过组合视图和投影矩阵然后使用该矩阵的逆矩阵而不是仅使用投影矩阵逆矩阵来找到它。

由于只需要 的 Z 和 W 分量,viewPosition因此上述用于计算的 GLSLviewPosition可以稍微简化。两个点积就足够了,而不是完整的矩阵乘法,并且不需要将完整的逆投影矩阵馈送到着色器中,因为只需要底部的两行:

vec2 viewPositionZW = vec2(
    dot(projectionMatrixInverseRow2, screenPos),
    dot(projectionMatrixInverseRow3, screenPos)
);

float z = -(viewPositionZW.x / viewPositionZW.y);

这样做的性能比使用近距和远距要差一些,大概是因为额外的点积,我得到了约 5% 的减少。近距和远距数学也可以通过输入(zNear * zFar)和输入来优化(zFar - zNear),但我没有看到这样做有任何可衡量的改进。

有趣的是,当您将上述内容与使用斜截头截体剪裁的投影矩阵相结合时,我无法从中得到任何明智的结果,但是当使用具有相同投影矩阵的近距和远距方程时,我确实得到了合理的输出,尽管使用似乎是深度值的一些失真(尽管这可能只是由于斜截头体裁剪中固有的深度精度损失)。如果有人能阐明这里在数学上到底发生了什么,我将不胜感激,尽管也许这应该是一个不同的问题。

于 2009-07-21T00:56:29.530 回答
2

我在闪电着色器中使用以下代码来计算闪电方向。Wold 位置也是通过将屏幕位置乘以投影矩阵的倒数来计算的。

不幸的是HLSL:

float depth = tex2D(DepthMapSampler, PSIn.TexCoord).r;

float4 screenPos;
screenPos.x = PSIn.TexCoord.x*2.0f-1.0f;
screenPos.y = -(PSIn.TexCoord.y*2.0f-1.0f);
screenPos.z = depth;
screenPos.w = 1.0f; 

float4 worldPos = mul(screenPos, xViewProjectionInv);
worldPos /= worldPos.w;

工作正常,所以我认为 Worldposition 是正确的!

于 2009-07-20T19:29:36.687 回答