Ric*_*ney 6 opengl math 3d shader
我目前正在使用以下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;
Run Code Online (Sandbox Code Playgroud)
然后根据近平面和远平面的距离将深度值转换为视图空间距离:
float zDistance = (zNear * zFar) / (zFar - depth * (zFar - zNear));
Run Code Online (Sandbox Code Playgroud)
这一切似乎都工作得很好,但是我很想知道如何仅基于当前的投影矩阵来进行上述计算,而无需使用单独的zNear和zFar值。
我最初的尝试涉及乘以(vec4(tcscreen.x, tcScreen.y, depth, 1.0) * 2.0 - 1.0)投影矩阵的逆,将结果除以w,然后将结果z值作为距离,但这似乎没有用。这里正确的方法是什么?
另外,当使用斜截头截头裁剪将近平面移到选定的裁剪平面上时,每个像素的近平面距离现在是否可能不同?如果是的话,这是否意味着任何计算与深度纹理的距离的着色器都需要了解这种情况,而不需要假定恒定的近平面距离?
谢谢!
事实证明,我忘记对最终的 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);
Run Code Online (Sandbox Code Playgroud)
如果您想要一个世界空间位置(就像 SuperPro 使用的那样),那么可以通过组合视图和投影矩阵然后使用该矩阵的逆矩阵而不是仅使用投影矩阵逆来找到它。
因为只需要 Z 和 W 分量,所以viewPosition上面的 GLSL 计算viewPosition可以稍微简化。两个点积就足够了,而不是完整的矩阵乘法,并且不需要将完整的逆投影矩阵输入着色器,因为只需要底部两行:
vec2 viewPositionZW = vec2(
dot(projectionMatrixInverseRow2, screenPos),
dot(projectionMatrixInverseRow3, screenPos)
);
float z = -(viewPositionZW.x / viewPositionZW.y);
Run Code Online (Sandbox Code Playgroud)
这样做的性能比使用近距离和远距离差一点,大概是因为额外的点积,我得到了约 5% 的减少。近距和远距数学也可以通过将(zNear * zFar)和(zFar - zNear)in 作为常数来优化,但我没有看到这样做有任何可测量的改进。
有趣的是,当您将上述内容与使用倾斜平截头体裁剪的投影矩阵相结合时,我无法从中得到任何有意义的东西,但是当使用具有相同投影矩阵的近距和远距方程时,我确实得到了合理的输出,尽管深度值似乎有些失真(尽管这可能只是由于倾斜截头体剪切中固有的深度精度损失所致)。如果有人可以阐明这里数学上到底发生了什么,我将不胜感激,尽管也许这应该是另一个问题。