Unity Shader入门教程(二十):深度纹理和法线纹理
发表于2018-06-07
虽然在Unity里获取深度纹理和法线纹理的代码非常简单,但是大家还是需要去掌握他们的实现原理。
1、什么是深度纹理?
深度纹理实际就是一张渲染纹理,只不过它里面存储的像素值不是颜色值,而是一个高精度的深度值。由于被存储在一张纹理中,深度纹理的深度值范围是[0,1],而且通常是非线性分布的,那么,这些深度值是从哪里得到的呢?总体来说,这些深度值来自于顶点变换后得到的归一化的设备坐标(Normalized Device Coordinates,NDC)。一个模型要想要最终被绘制到屏幕上,需要把它的顶点从模型空间变换到齐次裁剪坐标系下,这是通过在顶点着色器中乘以MVP变换矩阵得到的。在变换的最后一步,我们需要使用一个投影矩阵来变换顶点,当我们使用的是透视投影类型的摄像机时,这个投影矩阵就是非线性的。
下图显示了之前给出的Unity中透视投影对顶点的变换过程,下图最左侧的图显示了投影变换前,即观察空间下视锥体的结果以及相应的顶点位置,中间的图显示了应用透视裁剪矩阵后的变换结果,即顶点着色器阶段输出的顶点变换结果,最右侧的图则是底层硬件进行了透视除法后得到的归一化的设备坐标。需要注意的是,这里的投影过程是建立在Unity对坐标系的假定上的,也就是说,我们针对的是观察空间为右手坐标系,使用列矩阵在矩阵右侧进行相乘,且变换到NDC后z分量范围将在[-1,1]之间的情况。而类似DirectX 这样的图形接口中,变换后z分量范围将在[0,1]之间。
下图显示了再使用正交摄像机时投影变换的过程。同样变换后会得到一个范围为[-1,1]的立方体。正交投影使用的变换矩阵是线性的。
深度纹理中像素值深度值对应了NDC中顶点坐标的z分量的值。由于NDC中z分量的范围在[-1,1],为了让这些值能够存储在一张图像中,做了下面的映射:
d = 0.5·zndc + 0.5
其中,d对应了深度纹理中像素值,zndc对应了NDC坐标中的z分量的值。
Unity中,当使用延迟渲染路径时,深度纹理所当然可以访问到,因为延迟渲染会把这些信息渲染到G-buffer中。
其它渲染模式,会使用着色器替换技术选择RenderType为Opaque的物体,判断其渲染队列是否小于等于2500(Background、Geometry、AlphaTest),如果满足条件就把它渲染到深度纹理和法线纹理中。
在Unity中,我们可以选择让一个摄像机生成一张深度纹理或是一张深度+法线纹理。
当选择前者,即只需要一张深度纹理,Unity会直接获取深度缓存或是按之前讲到的着色器替换技术,选取需要的不透明物体,并使用它投影时使用的Pass(LightMode被设置为ShadowCaster的Pass)来得到深度纹理。如果没有这样的Pass,那么这个物体就不会出现在深度纹理中。