UnityShader(十七)透明效果
前言:
在实时渲染中实现透明效果,通常会在渲染模型时控制它的透明通道(Alpha Channel)。当开启透明混合后,一个物体被渲染到屏幕上时每个片元除了颜色值和深度值外,还有一个透明值,1表示像素完全不透明,0表示完全透明。
Unity中通常有两种方法实现透明效果:
1.使用透明测试(Aplha Test),这种方法其实无法实现真正的半透明效果
2.透明度混合(Alpha Blending)
透明度测试
只要一个片元的透明度不满足条件,那么它对应的片元就会被舍弃。被舍弃的片元不会进行任何处理,也不会对颜色缓冲区有任何影响,否则就会按照普通的不透明物体的处理方式进行处理,即进行深度测试、深度写入等。
也就是书透明度测试不需要关闭深度写入,它和其它不透明物体最大的不同就是它会根据透明度来舍弃一些偏远。但是这种效果很极端,要么完全透明,要么完全不透明,也就不能够实现半透明的效果
透明度混合
这种方法可以实现真正的半透明效果。它会使用当前片元的透明度作为混合因子,与已经存储再颜色缓冲中的颜色值进行混合,得到新的颜色。
但是透明度混合需要关闭深度写入,这需要我们小心物体的渲染顺序。但需要注意的是,透明度混合只是关闭了深度写入,但不会关闭深度测试。
渲染顺序的重要性
对于游戏物体都是不透明物体来说,渲染顺序不是很重要,因为强大的深度测试会解决游戏物体的前后关系。
假设现在场景中有两个物体A和B,A为半透明物体,B为透明物体,且A在B的前面。
第一种情况:我们先渲染B,再渲染A。呢么由于不透明物体开启了深度测试和深度写入,而此时深度缓存中没有任何数据,那么B就会被写入颜色缓冲区和深度缓冲区。随后再渲染A,透明物体会进行深度测试但不会深度写入,所以在渲染出的图像中我们发现B会比A距离摄像机更近,我们会使用A的透明度来和颜色缓冲中的B的颜色进行混合,得到真正的半透明物体。
第二种情况:我们先渲染A,再渲染B。渲染A时深度缓冲区没有任何有效数据(因为透明物体是不需要深度写入的),因此A直接写入颜色缓冲中,但不会修改深度缓冲。等到渲染B时,B会进行深度测试直接通过,那么它的颜色就会被直接写入颜色缓冲中,结果就是B的颜色会直接覆盖颜色缓冲中A的颜色,从视觉上来看,B出现在A的前面,这是错误的。
同样,现在假设A和B都是半透明物体,且A在B前面。
第一种情况:先渲染B再渲染A。那么B会正常写入颜色缓冲,然后A会和颜色缓冲中B颜色进行混合,得到正确的半透明效果。
第二种情况:先渲染A再渲染B。那么A会正常写入颜色缓冲,然后B会和颜色缓冲中A颜色进行混合,这样结果就相反了过来,得到错误的结果(B看起来像是在A前面)
UnityShader的渲染顺序
Unity为了解决渲染顺序问题提供了渲染队列(render queue)的解决方案,我们可以使用SubShader的Queue标签来决定我们的模型将归于哪个渲染队列。Unity在内部使用一系列整数索引来表示每个渲染队列,且索引越小表示越先被渲染。