前言:
在unity中主要有两种透明效果的实现,透明度测试和透明度混合,透明度测试比较简单暴力,就是对片元的alpha通道的值进行测试,满足条件就留下该片元,不满足就抛弃该片元,所以在本章中主要讨论第二种---透明度混合。本书主要内容是对UnityShader入门精要的总结。
一、透明度混合与渲染顺序的联系
在渲染不透明物体时,不考虑渲染顺序是因为深度缓冲的存在,它通过深度测试和深度函数来确保物体的前后遮挡关系,而在渲染透明物体时,我们依然要使用深度测试,它将决定一个片元是否应该被留下,但是要关闭深度写入,先解释一下为什么要关闭深度写入,因为如果不关闭深度写入,那么如果一个透明物体比一个不透明物体里摄像机更近的话,那么这个不透明物体的片元就会被抛弃,我们就无法看到不透明的那种效果。回到渲染顺序的问题上,考虑以下这种情况,一个不透明物体A距离摄像机近,一个不透明物体B距离摄像机远,如果先渲染A再渲染B,这个时候A先被写入颜色缓冲,此时再写入B,由于A没有写入深度缓冲,这时B作为不透明物体会通过深度测试写入深度缓冲,那么此时颜色缓冲区的颜色就是B的,A的颜色就会被清空掉。而如果我们先渲染B再渲染A,B会先写入深度缓冲,A将会通过深度测试,但不会写入深度缓冲,深度值依然是B的深度值,但是它的颜色值会根据Blend命令与当前颜色缓冲区的值进行计算,然后写入颜色缓冲区。
渲染引擎一般都会先对物体进行排序,再渲染:
首先渲染所有不透明物体,开启深度测试和深度写入,然后渲染所有不透明物体,开启深度测试,但关闭深度写入。
在unity中解决渲染顺序的方法是渲染队列(render queue),用subshader的Queue标签来决定我们的模型将归于哪个渲染队列。
二、开启深度写入的半透明效果
当模型本身就有很复杂的遮挡关系的时候,例如一个复杂的莫比乌斯环,那么就会有各种各样的因为排序作物而产生的错误的半透明效果。解决方案:使用两个pass来渲染模型,第一个pass开启深度写入,但不输出颜色,这样就不会因为关闭了深度写入出现错误的效果,这一步实际上就是渲染一个不透明物体,但是不输出颜色,只有深度值,深度缓冲中的深度值将会变成该物体的深度值,而不输出颜色也就意味着,虽然深度测试通过了,也进行了深度写入,但是依然保留之前不透明物体片元的颜色,如果这里进行了颜色写入就一定会出错,那就和渲染一个透明物体没有区别了。第二个pass关闭深度写入,进行深度测试,这个时候,物体距离相机最近的片段都会通过深度测试,因为在深度缓冲中的深度值已经是该物体距离相机最近的片段的深度值了,两者是相等的,(按道理来说,即使关闭深度测试,效果也不会出错,因为第一步已经进行了深度测试和深度写入,第二个pass就可以把深度测试和深度写入关闭),但是由于第一个pass是关闭了颜色写入的,所以在颜色缓冲区的颜色还是渲染该物体之前的颜色缓冲区,第二个pass就是进行混合计算然后计算混合写入,这种解决方案有两个问题:第一,增加一个pass会对性能有影响,第二,在模型内部之间不会有任何真正的半透明效果,因为,这种方法的渲染实际上就是先对该物体进行一个片段的去留操作,距离相机较远的片元也就是被遮挡的片元要被抛弃,只留下距离相机最近的片元,内部片元会因此被抛弃,也就理所当然不会出现内部的半透明效果。
在第一个pass中使用一个新的渲染命令,ColorMask
这里需要使用 ColorMask 0;
三、unity中的blend命令
unity中的blend命令除了设置混合的状态,同时也开启了混合,而在其它图形API里,这两个操作是需要分别单独打开的。
Unity中设置混合因子的命令主要有两个
Blend SrcFactor DstFactor:开启混合,并设置了混合因子,源颜色乘以SrcFactor,目标乘以DstFactor,然后两者相加,这个命令默认是相加,当然也可以有别的计算方式,稍后会介绍
Blend SrcFactor DstFactor,SrcFactorA DstFactorA:这个命令与上一个不同的点就是多了一组因子,从字面意思就能看出这个和Alpha通道有关,这个命令用来为RGB通道和Alpha通道设置不同的混合因子。例如RGB需要混合相加,而透明度需要保留源颜色的透明度,那么就可以写成Blend SrcAlpha OneMinusSrcAlpha,One Zero;
混合操作:上面介绍源颜色和目标颜色的默认混合操作是相加的,它们还可以有很多其它操作,命令为BlendOp Operation
还有一个与Min命令对应的Max命令,类似用法。
常见的混合类型:这里模仿ps里的一些效果给出了一些示例
四、双面渲染
如果一个物体时透明的,那么我们不仅能看到它背后的物体,还应该能看到该物体内部的情况。而之前的情况都无法观察到物体内部和背面,那是因为渲染引擎为了提高效率默认情况下剔除了背面,如果想实现双面渲染就要使用Cull命令。
Cull Back:剔除背面,默认情况下,是该选项
Cull Front:剔除正面
Cull Off:不剔除
对于透明度测试实现双面渲染来说,只需要关闭剔除,关闭剔除以后就不会再剔除背面,这个时候背面就可以进入gpu渲染管线了,但是依然会有深度测试和深度写入,也就是如果离摄像机更近的片元如果通过了深度测试及其它测试,那么距离摄像机更远的背面依然是看不到的,但是如果离摄像机更近的片元没有通过深度测试和alpha测试被抛弃,且背面的面片通过了测试,此时就能看到背面,这就是透明度测试实现的双面渲染的效果,如果没有双面渲染,那么即使离摄像机更近的片元被抛弃,我们也不能看到背面的片元,因为在渲染管线的应用程序阶段,它就因为背面剔除操作而无法进入GPU渲染管线阶段。
对于透明度混合来说,需要使用两个pass,第一个剔除正面,渲染背面,第二个剔除背面,渲染正面,这样的话由于pass是逐个执行的(注意这里讨论的渲染路径都是forwardbase,以后遇到一些其它渲染路径可能就不是逐个执行了),所以背面总会在正面之前渲染。
来源:CSDN,作者:莫之
原文:https://blog.csdn.net/qq_36383623/article/details/86612755
版权声明:本文为博主原创文章,转载请附上博文链接!