具有延迟渲染、位置转换的 OpenGL 阴影映射

OpenGL shadow mapping with deferred rendering, position transformation

我正在使用延迟渲染,我相应地在纹理中存储眼睛 space 位置:

顶点:

gl_Position = vec4(vertex_position, 1.0);

几何:

vertexOut.position = vec3(viewMatrix * modelMatrix * gl_in[i].gl_Position);

片段:

positionOut = vec3(vertexIn.position);

现在,在第二个通道(光照通道)中,我尝试使用从这个 vec4

计算出的 UV 坐标对我的阴影贴图进行采样
vec4 lightSpacePos = lightProjectionMatrix * lightViewMatrix * lightModelMatrix * vec4(position, 1.0);

使用的位置与从位置纹理存储和采样的位置相同。 在进行此计算之前,我是否需要使用逆相机视图矩阵转换位置?要将它带回世界 space 或者我应该如何进行?

通常阴影贴图是通过比较当前片段与光线的 window-space Z 坐标(这是深度纹理存储的)来完成的。这必须使用共同的参考方向来完成,因此涉及从光线的角度重新投影当前片段的位置。

您现在的视图-space 位置是相对于您的当前 相机的,不是特别有用。要有效地做到这一点,您需要 world-space 位置。如果你通过逆视图矩阵转换视图-space 位置,你可以得到它。

给定 world-space 位置,从光的角度转换为 clip-space:

// This will be in clip-space
vec4 lightSpacePos = lightProjectionMatrix * lightViewMatrix * vec4 (worldPos);

// Transform it into NDC-space by dividing by w
lightSpacePos /= lightSpacePos.w;

// Range is now [-1.0, 1.0], but you need [0.0, 1.0]
lightSpacePos = lightSpacePos * vec4 (0.5) + vec4 (0.5);

假设默认深度范围,lightSpacePos 现在可以使用了。 xy 包含要从阴影贴图中采样的纹理坐标,z 包含用于比较的深度。

如需更详尽的解释,请参阅 following answer


顺便说一下,您需要从 G-Buffer 中消除位置纹理以实现合理的性能。仅给定深度以及投影和视图矩阵,重建世界或视图-space 位置非常容易,所涉及的算法比额外的纹理获取快得多。以足够的精度存储额外的纹理来表示 3D 中的位置 space 将消耗每帧大量的内存带宽,这是完全没有必要的。

OpenGL Wiki 中的

This article 解释了如何执行此操作。你可以更进一步,回到 world-space,这比 view-space 更令人向往。您可能需要稍微调整深度缓冲区以获得足够的精度,但它仍然比单独存储位置更快。