1. NDC空间:渲染流水线的“标准间”
如果你刚开始接触图形学或者Unity的Shader编程,看到“NDC空间”这个词可能会有点懵。别担心,我第一次看到的时候也觉得它像某种神秘的内部黑话。其实,你可以把它想象成一个标准化的“中转站”,或者一个所有图形硬件都认识的“通用语言”。
想象一下,你是一个导演,要拍一部电影。你的演员(模型顶点)来自世界各地,身高体型各异(模型空间)。为了让他们能在同一个舞台上表演,你需要先让他们站到舞台的指定标记位置(世界空间),然后调整好面对摄像机的角度和距离(观察空间)。接着,摄像机会根据镜头(投影矩阵)把他们拍进取景框里(齐次裁剪空间)。但这时候,画面还是扭曲的,带有透视效果的。NDC空间就是接下来最关键的一步:把取景框里这个扭曲的、带深度的画面,“熨平”成一个标准化的、长宽高都在-1到1之间的立方体空间。这个立方体,就是归一化的设备坐标空间(Normalized Device Coordinates)。
为什么非要这个“标准间”呢?因为下游的“工人”——也就是你的显卡硬件和光栅化阶段——只认识这个标准格式。无论你之前用的是透视投影还是正交投影,无论你的窗口是方的还是宽的,到了NDC这里,一切都统一了。X轴从左到右是-1到1,Y轴从下到上是-1到1,Z轴(深度)从近裁剪面到远裁剪面,在OpenGL里是-1到1,在DirectX里是0到1。这个标准化过程,就是由透视除法完成的,它是从齐次裁剪空间到NDC空间的唯一桥梁。
在Unity的渲染流水线里,这个过程通常是“黑盒”的,由底层自动完成。我们写的顶点着色器,通常只负责把顶点位置变换到齐次裁剪空间(输出SV_POSITION语义,也就是常说的positionCS),然后举手说:“我的任务完成了!” 后面的透视除法和屏幕映射,GPU会默默帮我们做好。但如果你想写出更高效、更自定义的着色器,尤其是涉及到后期处理、屏幕特效或者一些高级的渲染技巧时,理解这个“黑盒”里发生了什么,就至关重要了。它能帮你避免很多诡异的bug,比如深度值不对、屏幕坐标偏移,或者某些效果在透视相机下正常而在正交相机下失效。
2. 透视除法:从“扭曲”到“标准”的关键一步
好了,现在我们聚焦于从齐次裁剪空间到NDC空间的那个魔法步骤:透视除法。这个名字听起来很高深,但它的操作简单到令人发指:把齐次裁剪空间坐标的x, y, z三个分量,统统除以它的w分量。
用代码表示就是:
float4 clipPos = mul(UNITY_MATRIX_VP, float4(positionOS, 1.0)); // 顶点着色器输出,齐次裁剪空间坐标
float3 ndcPos = clipPos.xyz / clipPos.w; // 透视除法,得到NDC坐标
为什么除以w就能实现“标准化”和“透视校正”呢?这得从投影矩阵说起。在透视投影中,投影矩阵的一个核心作用,就是把视锥体(一个平头截体)变换成一个立方体。在这个过程中,它巧妙地把深度信息(即顶点离摄像机的距离)编码到了w分量里。对于透视投影,这个w值通常就等于变换前观察空间下的z值(取反),它代表了顶点的深度。
当你用x, y, z除以这个w时,你实际上是在进行透视校正插值的准备工作。离摄像机远的点(w值大),它的x, y坐标会被压缩


1万+

被折叠的 条评论
为什么被折叠?



