标签:android style blog http io ar color os 使用
关于alpha的问题一直是个比较容易摸不清头脑的事情,尤其是涉及到半透明问题的时候,总是不知道为什么A就遮挡了B,而B明明在A前面。这篇文章就总结一下我现在的认识~
Alpha Test和Alpha Blending是两种处理透明的方法。
Alpha Test采用一种很霸道极端的机制,只要一个像素的alpha不满足条件,那么它就会被fragment shader舍弃,“我才不要你类!”;否则,就会按正常方式写入到缓存中,并进行正常的深度检验等等,也就是说,Alpha Test是不需要关闭ZWrite的。Alpha Test产生的效果也很极端,要么完全透明,即看不到,要么完全不透明。
而Alpha Blending则是一种中庸的方式,它使用当前fragment的alpha作为混合因子,来混合之前写入到缓存中颜色值。但Alpha Blending麻烦的一点就是它需要关闭ZWrite,并且要十分小心物体的渲染顺序。如果不关闭ZWrite,那么在进行深度检测的时候,它背后的物体本来是可以透过它被我们看到的,但由于深度检测时大于它的深度就被剔除了,从而我们就看不到它后面的物体了。因此,我们需要保证物体的渲染顺序是从后往前,并且关闭该半透明对象的ZWrite。
在Unity的Surface Shader里实现上述两种技术是非常简单的,可以参见之前的文章——Alpha Test和Alpha Blending。简单总结一下就是,只要在#pragma里设置alphatest:_Cutoff或alpha指令即可。
但是,它们背后的原理是什么呢?这就要从它们生成的Vertex & Fragment Shader说起了。那么,请看下一节~
我们先来说比较简单的Alpha Test。
在Vertex & Fragment Shader里,要实现它非常简单。
一种方法是自己在shader中编写代码,只要使用类似下面的语句就可以了:
// alpha test clip (o.Alpha - _Cutoff);
另一种方法是使用固定管线的Alphatest指令。具体可见官方文档。使用Alphatest指令的方法选择更多,我们不仅仅是判断它小于_Cutoff时舍弃该fragment,还可以是判断它是否大于、是否大于等于,等等。但原理是和第一种方法一样,归根到底都是要靠discard函数来舍弃那么不符合条件的fragments。
Alpha Blending略微复杂一点,因为它涉及到了ZWrite的一些问题。它首先需要关闭ZWrite:
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
在使用Alpha Blending时,一定要格外小心由于它关闭了深度缓存而造成的种种问题。从Unity的这张图可以看出:
深度检验是在Vertex Shader后面就进行的,因此在Fragment Shader阶段,由于它关闭了深度缓存,所以像素的覆盖与否完全取决于渲染的先后顺序。
当然,有时我们可以混合使用这两种技术,例如第一个pass里使用Alpha Test渲染实体部分,第二pass里对上一个pass里被剔除的fragment使用Alpha Blending进行柔和渲染。
Unity的官方文档中,有两个地方提到了它们的性能问题——一个是编写Shaders时的性能提示,一个是优化图像性能。微微地感觉这两个页面有很多重复,未来某一天可能会合成一个页面。。。
它们是这么写的:
Fixed function AlphaTest or it’s programmable equivalent, clip()
, has different performance characteristics on different platforms:
以及
Keep in mind that alpha test (discard) operation will make your fragments slower.
总结一下,就是使用Alpha Test看似更简单,但其实在大多数平台上,相比与Alpha Blending,只有一点小小的性能提升。但是!!!在iOS和某些Android设备上,由于它们使用了PowerVR GPUs,因此Alpha Test的性能消耗反而会更大。因此,一个忠告就是,尽可能使用Alpha Blending,而不要使用Alpha Test。
我们会觉得很奇怪,没有关闭深度缓存,不需要计算混合颜色,仅仅调用来discard舍弃fragment不是非常简单的事吗?为什么在移动平台上反而效率更低呢?有句话叫,“简单粗暴”,可以用在这里。性能下降的原因就是它太粗暴了!(我乱说的你不要当真。。。)
好啦,言归正传~原因呢由于我经验有限,只能依靠强大的谷歌来找答案。我找到了这里、这里。总结一下,就是PowerVR GPUs使用了一种叫做“Deferred Tile-Based-Rendering”的技术。这种技术里有一个优化阶段,就是为了减少overdraw它会在调用fragment shader前判断哪些Tile是会被真正渲染的。但是,由于Alpha Test在fragment shader里使用了clip函数改变了fragment是否被渲染的结果,因此,GPUs就无法使用上述的优化策略了。也就是说,只要在完成了所有的fragment shader处理后,GPUs才知道哪些fragments会被真正渲染到屏幕上,这样,原先那些可以减少overdraw的优化就都无效了。
【Unity Shaders】Alpha Test和Alpha Blending
标签:android style blog http io ar color os 使用
原文地址:http://blog.csdn.net/candycat1992/article/details/41599167