【ShaderLab学习】AlphaTest & AlphaBlend理解[2]

Alpha Blend

透明混合使用当前片元的透明度作为混合因子,与已存储在颜色缓冲中的颜色值进行混合,得到新的颜色。需要注意的是,透明度混合需要关闭深度写入,这时候要注意物体的渲染顺序。

  • 源颜色(当前片元颜色)source colorS或者SrcColor表示
  • 目标颜色(颜色缓冲中的颜色)destination colorD或者DstColor表示

官方文档:

https://docs.unity3d.com/Manual/SL-Blend.html

语义:

首先,需要正确设置渲染队列:

Tags { "Queue"="Transparent" }

其次,需要关闭ZWrite

ZWrite Off

然后,可以指定混合函数,如:

Blend SrcAlpha OneMinusSrcAlpha
语义 描述
Blend Off 关闭混合
Blend SrcFactor DstFactor 开启混合,并设置混合因子。源颜色(片元颜色)乘以SrcFactor。而目标颜色(颜色缓存中的颜色)乘以DstFactor,将两者相加后存入颜色缓存。
Blend SrcFactor DstFactor,SrcFactorA DstFactorA 和上面一样,只是使用不同的混合因子来混合透明通道
BlendOp BlendOperation 不是把源颜色和目标颜色简单相加后混合,而是使用BlendOperation对它们进行其他操作

Blend operations 常用混合操作

Add 将源和目标添加在一起。
Sub 从源中减去目标。
RevSub 从目标中减去源。
Min 使用较小的源和目标。
Max 使用较大的源和目标。

Blend factors 混合因子

以下所有属性在Blend命令中都适用于SrcFactor&DstFactor。 源指的是计算的颜色,目标是已经在屏幕上的颜色。
如果BlendOp使用逻辑运算,则忽略混合因子。

One 1 - 使用它让源或目标颜色完全通过
Zero The 0 - 使用此值删除源或目标值
SrcColor 源的Color(RGB)值
SrcAlpha 源的Alpha(a)值
DstColor 目标的Color(RGB)值
DstAlpha 目标的Alpha(a)值
OneMinusSrcColo 1 - source color.
OneMinusSrcAlpha 1 - source alpha.
OneMinusDstColor 1 - destination color.
OneMinusDstAlpha 1 - destination alpha.

最常见的混合类型:

Blend SrcAlpha OneMinusSrcAlpha // Traditional transparency 最常用的透明度混合
Blend One OneMinusSrcAlpha // Premultiplied transparency 预乘透明度
Blend One One // Additive 叠加的
Blend OneMinusDstColor One // Soft Additive 软叠加 
Blend DstColor Zero // Multiplicative
Blend DstColor SrcColor // 2x Multiplicative 两倍相乘 (2X Multiply) 
BlendOp Min //变暗
BlendOp Max //变亮

测试

Shader代码如下:

Shader "Custom/l2xin/T_AlphaBlend"
{
    Properties 
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
    }
    
    SubShader
    {
        Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
        
        Pass
        {
            Tags { "LightMode"="ForwardBase" }
            
            //Alpha Blend
            Blend SrcAlpha OneMinusSrcAlpha
            
            CGPROGRAM

            
            #pragma vertex vert
            #pragma fragment frag
            
            #include "Lighting.cginc"
            
            sampler2D _MainTex;
            float4 _MainTex_ST;         
            
            struct a2v{
                float4 vertex : POSITION;
                float4 texcoord: TEXCOORD0;
            };
            
            struct v2f{
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
            };
            
            v2f vert(a2v v){
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                return o;
            }
            
            fixed4 frag(v2f i) :SV_Target{
                fixed4 texColor = tex2D(_MainTex, i.uv);
                return texColor;
            }
        
            ENDCG
        }
    }
    FallBack "Diffuse"
}

Blend SrcAlpha OneMinusSrcAlpha(最常用的半透明效果)

【ShaderLab学习】AlphaTest & AlphaBlend理解[2]_第1张图片

更多展示效果

转自:风宇冲Unity3D教程学院 http://blog.sina.com.cn/s/blog_471132920101d8z5.html

在树叶使用的Shader中添加Blend代码

  • Blend zero one:仅显示背景的RGB部分,无Alpha透明通道处理。
    【ShaderLab学习】AlphaTest & AlphaBlend理解[2]_第2张图片

  • Blend one zero: 仅显示贴图的RGB部分,无Alpha透明通道处理。 A通道为0即本应该透明的地方也渲染出来了。
    【ShaderLab学习】AlphaTest & AlphaBlend理解[2]_第3张图片

  • Blend one one:贴图和背景叠加,无Alpha透明通道处理。仅仅是颜色rgb数值的叠加更趋近于白色即(1,1,1)了。
    【ShaderLab学习】AlphaTest & AlphaBlend理解[2]_第4张图片

  • Blend SrcAlpha zero:仅仅显示贴图,贴图含Alpha透明通道处理。但是贴图中的透明部分,即下图黑色部分没有颜色来显示,因为源颜色乘以alpha值0,为0;而混合目标的颜色乘以zero 0,也是0。所以透明部分显示的颜色为(0,0,0)
    【ShaderLab学习】AlphaTest & AlphaBlend理解[2]_第5张图片

  • Blend SrcAlpha OneMinusSrcAlpha:
    最终颜色 = 源颜色 * 源透明值 + 目标颜色*(1 - 源透明值)
    最常用的透明混合方式。贴图alpha值高的部分,显示得实,而混合的背景很淡。而alpha值高的部分,贴图显示得淡,而背景现实得实。
    【ShaderLab学习】AlphaTest & AlphaBlend理解[2]_第6张图片

后记-AlphaTest和AlphaBlend性能

Unity的官方文档中,提到了它们的性能问题——https://docs.unity3d.com/Manual/SL-ShaderPerformance.html

Fixed function AlphaTest or it’s programmable equivalent, clip(), has different performance characteristics on different platforms:

  • Generally it’s a small advantage to use it to cull out totally transparent pixels on most platforms.
  • However, on PowerVR GPUs found in iOS and some Android devices, alpha testing is expensive. Do not try to use it as “performance optimization” there, it will be 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是会被真正渲染的。也就说我们之前说的在FS之前做的“Depth Test”。但是,由于Alpha Test在fragment shader里使用了clip函数改变了fragment是否被渲染的结果,因此,GPUs就无法使用上述的优化策略了。也就是说,只要在完成了所有的fragment shader处理后,GPUs才知道哪些fragments会被真正渲染到屏幕上,这样,原先那些可以减少overdraw的优化就都无效了。

这一段摘自乐乐女神的博客:https://blog.csdn.net/candycat1992/article/details/41599167 。我也没有理解到位,总之结论是尽可能使用Alpha Blending就对了。。


参考

  • 蛮牛https://docs.unity3d.com/Manual/SL-Blend.html
  • 风宇冲http://blog.sina.com.cn/s/blog_471132920101d8z5.html
  • 冯乐乐https://blog.csdn.net/candycat1992/article/details/41599167

你可能感兴趣的:(Shaderlab,shaderlab,AlphaBlend)