代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void SetupPostOutline(CommandBuffer cmd, ref RenderingData renderingData, Material material)
{
material.SetFloat(ShaderIDs._Scale, _Scale);
material.SetColor(ShaderIDs._Color, _Color);
material.SetFloat(ShaderIDs._DepthThreshold, _DepthThreshold);
material.SetFloat(ShaderIDs._DepthNormalThreshold, _DepthNormalThreshold);
material.SetFloat(ShaderIDs._DepthNormalThresholdScale, _DepthNormalThresholdScale);
material.SetFloat(ShaderIDs._NormalThreshold, _NormalThreshold);

// 获取投影矩阵的逆矩阵 == clip ->> P
// 以确保在 GPU 上处理纹理和深度坐标时获得正确的结果。直接使用 renderingData.cameraData.camera.projectionMatrix 可能会导致错误的投影和纹理坐标计算。
Matrix4x4 clipToView = GL.GetGPUProjectionMatrix(renderingData.cameraData.camera.projectionMatrix, true).inverse;

material.SetMatrix(ShaderIDs._ClipToView, clipToView);
cmd.SetGlobalTexture("_MainTex", source);
cmd.Blit(source, source, material);
}

解析

  1. GL.GetGPUProjectionMatrix 计算的是用于在 GPU 上执行映射的投影矩阵,Unity 使用它来处理纹理和深度坐标之间的转换。实际上,当使用 OpenGL 或 Vulkan 作为图形 API 时,Y值需要翻转,投影矩阵的 E 系数需要调整。GL.GetGPUProjectionMatrix 便是为了解决这个问题而产生的。

  2. renderingData.cameraData.camera.projectionMatrix 获取的是相机的投影矩阵,仅仅用于生成 3D 游戏物体在 2D 屏幕上的投影。在此情况下,只考虑了摄像机的投影参数,没有将 GPU 处理纹理和深度坐标所需的修正考虑在内。

因此,在这段代码中需要使用 GL.GetGPUProjectionMatrix(renderingData.cameraData.camera.projectionMatrix, true).inverse 作为 clipToView 矩阵,以确保在 GPU 上处理纹理和深度坐标时获得正确的结果。直接使用 renderingData.cameraData.camera.projectionMatrix 可能会导致错误的投影和纹理坐标计算。