本系列文章由Aimar_Johnny编写,欢迎转载,转载请标明出处,谢谢。
https://blog.csdn.net/lzhq1982/article/details/82710020
从这节开始说透明,透明有两种表达方式,一种是透明度测试(Alpha Test),一种是透明度混合(Alpha Blending)。前者只有透明和不透明两种效果,不存在半透,后者有半透效果。
在说透明前,要重点说明渲染顺序,对于不透明(opaque)物体,我们不需要考虑它的渲染顺序,因为深度缓冲区(depth buffer)已经帮我们处理好了,它会根据片元深度值和深度缓冲中的值作比较(开启深度测试情况下),当其值距摄像机更远时,则不会渲染,否则会覆盖掉颜色缓冲中的像素,并把深度值更新到深度缓冲中(开启深度写入情况下)。
但透明就不能这么做了,下面说明透明度测试和透明度混合的原理。
透明度测试:
当片元的透明度小于我们设定的阈值时,它就会被舍弃,则不会参与绘制,否则会被当做不透明处理,进行深度测试,深度写入等。所以透明度测试是不需要关掉深度写入的。除了会舍弃片元,其实和不透明物体渲染差不多。
透明度混合:
这种方法可以得到真正的半透效果。它会使用当前片元的透明度作为混合因子,与颜色缓冲中的颜色进行混合,得到新的颜色。这里需要注意,透明度混合需要关闭深度写入。但没有关闭深度测试,所以当混合渲染一个片元时,它还是会比较它的深度和深度缓冲中的深度,如果它的深度值离摄像机更远,则不再进行混合操作。所以当透明物体在不透明物体后面时,透明物体就不会混合了。所以对于透明度混合来说,深度缓冲只是可读的。
为什么透明度混合要关闭深度写入呢?如果不关闭深度写入,一个半透明表面背后的表面本来是可以透过它被看到的,但由于深度测试时该半透明表面离摄像机更近,导致后面的表面会被剔除,那就无法透过半透明表面看到后面物体了。但是这样也同时破坏了深度缓冲的工作机制,所以渲染顺序就非常重要了。
看下图:
根据上图我们看看不同的渲染顺序会有什么结果:
1、先渲染B,再渲染A,由于不透明物体开启了深度测试和写入,所以B会先写入颜色缓冲和深度缓冲。然后渲染A,深度测试发现A离摄像机更近,则用A的透明度来和颜色缓冲中的B的颜色混合,得到正确结果。
2、先渲染A,再渲染B,A是半透,则先写入颜色缓冲,但不会写入深度缓冲。再渲染B,由于深度缓冲没有值,则B直接写入深度缓冲,进而直接写入颜色缓冲,则覆盖了A,这个效果不是我们想要的。
所以我们应该在不透明物体渲染完之后再渲染半透物体。
那么如果都是半透物体,渲染顺序还重要吗?答案是肯定的。
1、先渲染B,再渲染A,则B先写入颜色缓冲,然后A会和颜色缓冲中的B进行混合,得到正确结果。
2、先渲染A,再渲染B,则A先写入颜色缓冲,随后B会和A进行混合,这样混合结果就反过来了,得到错误结果。
基于以上说明,渲染引擎一般会先对物体进行排序,再渲染。常用方法是:
1、先渲染不透明物体,并开启它们的深度测试和写入。
2、把半透明物体按它们离摄像机远近排序,然后按照从后往前的顺序渲染,开启深度测试,关闭深度写入。
下面我们看看unity的渲染顺序:
Unity提供了自己的渲染队列(render queue),可以用SubShader的Queue标签来决定模型属于哪个渲染队列。内部用一系列整数索引来表示每个渲染队列,索引号越小越早被渲染。如下表:
因此,如果用透明度测试实现透明效果,可以设置如下标签:
SubShader{
Tags { "Queue" = "AlphaTest" }
Pass {
...
}
}
同样,透明度混合如下:
SubShader{
Tags { "Queue" = "Transparent" }
Pass {
...
}
}
后面章节详细介绍透明度测试和透明度混合。