6

我正在使用对数深度算法,这导致 someFunc(clipspace.z) 被写入深度缓冲区并且没有隐式透视除法

我正在做 RTT / 后处理,所以稍后在片段着色器中我想重新计算 eyespace.xyz,给定 ndc.xy(来自片段坐标)和 clipspace.z(来自存储在深度缓冲区中的值的 someFuncInv()) .

请注意,我没有clipspace.w,并且我存储的值不是clipspace.z/clipspace.w(就像使用固定函数深度时一样)-所以类似于...

float clip_z = ...; /* [-1 .. +1] */
vec2 ndc = vec2(FragCoord.xy / viewport * 2.0 - 1.0);
vec4 clipspace = InvProjMatrix * vec4(ndc, clip_z, 1.0));
clipspace /= clipspace.w;

...在这里不起作用。

那么有没有办法从clipspace.xyz中计算clipspace.w,给定投影矩阵还是它的逆矩阵?

4

1 回答 1

11
clipspace.xy = FragCoord.xy / viewport * 2.0 - 1.0;

这在命名上是错误的。“剪辑空间”是顶点着色器(或任何最后一个顶点处理阶段)输出的空间。剪辑空间和窗口空间之间是标准化设备坐标 (NDC) 空间。NDC 空间是剪辑空间除以剪辑空间 W 坐标:

vec3 ndcspace = clipspace.xyz / clipspace.w;

所以第一步就是取我们的窗口空间坐标,得到NDC空间坐标。这很容易:

vec3 ndcspace = vec3(FragCoord.xy / viewport * 2.0 - 1.0, depth);

现在,我将假设您的depth值是正确的 NDC 空间深度。我假设您从深度纹理中获取值,然后使用它渲染的深度范围近/远值将其映射到 [-1, 1] 范围。如果你没有,你应该。

那么,既然我们有了ndcspace,我们如何计算clipspace?嗯,这很明显:

vec4 clipspace = vec4(ndcspace * clipspace.w, clipspace.w);

很明显而且......没有帮助,因为我们没有clipspace.w. 那么我们如何得到它呢?

为了得到这个,我们需要看看clipspace第一次是如何计算的:

vec4 clipspace = Proj * cameraspace;

这意味着它clipspace.w是通过对 的第四行取cameraspace并点积来计算的Proj

嗯,这不是很有帮助。如果我们实际查看第四行,它会更有帮助Proj。当然,您可以使用任何投影矩阵,如果您不使用典型的投影矩阵,则此计算会变得更加困难(可能是不可能的)。

的第四行Proj,使用典型的投影矩阵,实际上就是这样:

[0, 0, -1, 0]

这意味着clipspace.w真的只是-cameraspace.z。这对我们有什么帮助?

记住这一点会有所帮助:

ndcspace.z = clipspace.z / clipspace.w;
ndcspace.z = clipspace.z / -cameraspace.z;

嗯,这很好,但它只是用一个未知数换另一个未知数;我们仍然有一个包含两个未知数 (clipspace.zcameraspace.z) 的方程。但是,我们确实知道其他事情:clipspace.z来自投影矩阵cameraspace第三行的点积。传统投影矩阵的第三行是这样的:

[0, 0, T1, T2]

其中 T1 和 T2 是非零数。我们暂时忽略这些数字。所以,clipspace.z真的只是T1 * cameraspace.z + T2 * cameraspace.w。如果我们知道cameraspace.w是 1.0(通常是这样),那么我们可以删除它:

ndcspace.z = (T1 * cameraspace.z + T2) / -cameraspace.z;

所以,我们还是有问题。事实上,我们没有。为什么?因为在这个euqation中只有一个未知数。记住:我们已经知道了ndcspace.z。因此,我们可以使用 ndcspace.z 来计算cameraspace.z

ndcspace.z = -T1 + (-T2 / cameraspace.z);
ndcspace.z + T1 = -T2 / cameraspace.z;
cameraspace.z = -T2 / (ndcspace.z + T1);

T1T2直接从我们的投影矩阵(场景最初渲染的那个)中出来。我们已经有了ndcspace.z。所以我们可以计算cameraspace.z。我们知道:

clispace.w = -cameraspace.z;

因此,我们可以这样做:

vec4 clipspace = vec4(ndcspace * clipspace.w, clipspace.w);

显然你需要一个浮点数clipspace.w而不是文字代码,但你明白我的意思。一旦你有clipspace, 得到相机空间,你乘以逆投影矩阵:

vec4 cameraspace = InvProj * clipspace;
于 2013-01-25T21:24:46.097 回答