这小节首先复习一下渲染管线,渲染管线的流程如下:
渲染管线分为应用程序阶段,几何阶段,光栅化阶段。其中光栅化阶段首先是图元装配是根据索引组成图元,并完成裁剪,然后进行光栅化,光栅化实际上是将图元对应屏幕坐标。Pixel Operation是计算每个像素的值,Pixel Operation主要包含以下操作:
1),深度检测
2),像素颜色计算
3),Blending
深度检测 ,也就是这节课要学习的内容
(1)什么是深度?
深度其实就是该像素点在3d世界中距离摄像机的距离。离摄像机越远,则深度值(Z值)越大。
(2)什么是深度缓存?
深度缓存中存储着准备要绘制在屏幕上的像素点的深度值。如果启用了深度缓冲区,在绘制每个像素之前,OpenGL会把该像素的深度值和深度缓存的深度值进行比较。如果新像素深度值<深度缓存深度值,则新像素值会取代原先的;反之,新像素值被遮挡,其颜色值和深度将被丢弃。
(3)什么是深度测试?
在深度测试中,默认情况是将要绘制的新像素的z值与深度缓冲区中对应位置的z值进行比较,如果比深度缓存中的值小,那么用新像素的颜色值更新深度缓存中对应像素的颜色值。
(4)为什么需要深度?
在不使用深度测试的时候,如果我们先绘制一个距离较近的物体,再绘制距离较远的物体,则距离远的物体因为后绘制,会把距离近的物体覆盖掉,这样的效果并不是我们所希望的。而有了深度缓冲以后,绘制物体的顺序就不那么重要了,都能按照远近(Z值)正常显示,这很关键。
接一下了解下Unity提供关于深度测试的两个命令
[ZWrite]
深度写入
是否此物体的像素深度会被记录(默认记录),
ZWrite On 深度记录(默认On)
ZWrite Off 不记录此深度,通常用于半透明物体
[ZTest]
深度测试
ZTest Less |Greater | LEqual | GEqual | Equal | NotEqual | Always
默认是 LEqual。 即当深度小于或者等于 深度最小值时,渲染物体,即渲染最近的物体。
接下来看一个例子,打开lesson8文件夹的1.scene.这个场景有两个物体,一个绿色物体,一个红色物体,绿色物体到摄像机的距离比红色物体到摄像机的距离短。如下图所示:
Green物体所用的shader代码如下
Red物体所用的Shader代码如下:
运行程序,效果如下:
为什么渲染的效果是绿色,可以分析下,这两个shader都使用了深度测试的默认命令ZWrite on和 ZTest LEqual,这两个物体的渲染顺序没法知道,这里有两种情况:
1.假设绿色的物体先进行渲染。在渲染绿色物体时,像素的深度值小于深度缓冲里的值,因此测试通过,由于zwriteon ,会将绿色物体像素的深度值写入到深度缓冲区,像素颜色值也会写入到帧缓冲区,然后渲染红色物体,由于红色物体较绿色物体距离摄像机远,所以红色物体的像素深度值大于深度缓冲区里的值。由于这里使用的是ZTestLequal,所以深度测试失败。因此红色物体不会在往帧缓冲区写入像素值。因此,最终为绿色。
2.假设红色的物体先进行渲染。在渲染红色物体时,像素的深度值小于深度缓冲里的值,因此测试通过,由于zwriteon ,会将红色物体像素的深度值写入到深度缓冲区,像素颜色值也会写入到帧缓冲区,然后渲染绿色物体,由于红色物体较绿色物体距离摄像机远,所以色色物体的像素深度值小于于深度缓冲区里的值。由于这里使用的是ZTestLequal,所以深度测试成功。因此绿色物体会往帧缓冲区写入像素值。因此,最终为绿色。
如果要是屏幕显示红色如何处理:
可以在shader加入ZTestGEqual命令运行程序
发现屏幕两个物体都没显示,如下图:
是什么原因引起的呢?是因为初始时深度缓冲值为最大值,当渲染绿色物体和红色物体时使用命令ZTestGEqual都会失败,
因此两个物体都没显示。那如何处理这个问题呢?
1. 可以修改深度缓冲区的初始值为最小值
2. 可以先渲染绿色物体,然后渲染红色物体(使用Queue Tag),使用ZTestalways
代码如下:
运行效果如下:
Unity 开发交流QQ群:528152133