从clipspace.xyz和(inv)投影矩阵计算clipspace.w

时间:2013-01-25 14:15:28

标签: opengl glsl shader direct3d

我正在使用对数深度算法,导致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;

......在这里不起作用。

有没有一种方法可以在clippace.xyz中计算clipspace.w,给定投影矩阵或它是反向的?

1 个答案:

答案 0 :(得分: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;

所以,我们仍有问题。实际上,我们没有。为什么?因为在这个方面只有一个未知数。请记住:我们已经知道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;