[Unity3D][Shader]PANCgShader--第二章 透明面--02透明物体Alpha混合

混合(Blending)

可编程图形管线中提到fragment shader为每一个片元(除非被discard)计算RGBA颜色(以fragment输出参数COLOR的形式)。

然后片元会按照在cg 逐片元操作中提到的过程被进一步处理。

这其中,提到了Blending阶段,该阶段会把该片元输出的颜色(称之为source color)同帧缓存中的颜色(称之为destination color)进行处理。

Blending是一个固定管线功能阶段,你只能指定其支持的操作,而不能对其进行编程处理。

Unity3D中通过Blend {code for SrcFactor} {code for DstFactor}来指定,该表达式对应的数学运算法则为:

float4 result=
SrcFactor*fragment_output+DstFactor*pixel_color;

fragment_output为fragment shader阶段的输出参数,pixel_color是当前帧缓存中已经存在的颜色。最终的result就是blending的结果。

下表展示了SrcFactor和DstFactor常用的code(更多Unity ShaderLab支持的code参见ShaderLab: Blending):

code expressiong
One float4(1.0,1.0,1.0,1.0)
Zero float4(0.0,0.0,0.0,0.0)
SrcColor fragment_output
SrcAlpha fragment_output.aaaa
DstColor pixel_color
DstAlpha pixel_color.aaaa
OneMinusSrcColor float4(1.0,1.0,1.0,1.0)-fragment_output
OneMinusSrcAlpha float4(1.0,1.0,1.0,1.0)-fragment_output.aaaa
OneMinusDstColor float4(1.0,1.0,1.0,1.0)-pixel_color
OneMinusDstAlpha float4(1.0,1.0,1.0,1.0)-pixel_color.aaaa

注意这里提到的所有颜色相关的值,最终都会被限制在[0,1]这个区间内。

Alpha混合

在Unity中Alpha混合等式为Blend SrcAlpha OneMinusSrcAlpha。对应的数学表达式为:

float4 rsult=
fragment_output.aaaa*fragment_output+
(float4(1.0,1.0,1.0,1.0)-fragment_output.aaaa)*pixel_color;

该混合等式,有时候也被称之为覆盖操作,即fragment_output覆盖pixel_color。

预乘Alpha混合

对于fragment shader输出color已经处理了alpha值的,不再需要对其再次处理,可以使用混合等式Blend One OneMinusSrcAlpha。对应的数学表达式为:

float result=
flaot4(1.0,1.0,1.0,1.0)*fragment_output+
(float4(1.0,1.0,1.0,1.0)-fragment_output.aaaa)*pixel_color;

叠加混合(Additive Blending)

等式为:Blend One One
对应的数学表达式为:

float4 result=
float4(1.0,1.0,1.0,1.0)*fragment_output+
float4(1.0,1.0,1.0,1.0)*pixel_color;

该混合方式会把fragment shader的输出颜色值直接加在帧缓冲的颜色上。在粒子系统中会经常出现该混合方式。更多的讨论见Order-Independent Transparency

Shader代码

对于Alpha混合透明物体shader的实现,需要注意几个点:
1,SubShader的第一句需要增加Queue为Transparent的Tags。
Tags{"Queue"="Transparent"}
2,Pass中第一句要关闭深度缓冲ZWrite Off(注意ZWrite Off 指令也可以写在SubShader层级下,那么将会影响所有的Pass)
3,Pass中紧接着在CGPROGRAM前面,需要声明混合模式,比如:Blend SrcAlpha OneMinusSrcAlpha。

Shader "My/Transparency/SrcAlpha_OneMinusSrcAlpha"
{ 
	 
    SubShader
    {		
		Tags{"Queue"="Transparent"}	
        Pass
        {						
			ZWrite Off
			Blend SrcAlpha OneMinusSrcAlpha
		
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
						
			struct vertexInput{
				float4 vertex:POSITION;	 
			};

			struct vertexOutput{
				float4 pos:SV_POSITION;							
			    float4 posInObjSpace:TEXCOORD0;
			};

            vertexOutput vert (vertexInput input)
            {                			   
			   vertexOutput output;
			   output.pos=UnityObjectToClipPos(input.vertex);
			   output.posInObjSpace=input.vertex;			   
			   return output;
            }

            fixed4 frag (vertexOutput input) : COLOR
            {
				return float4(0.0,1.0,0.0,0.3);
            }			
            ENDCG
        }				 
    }
}
  • 深度缓冲会记录片元的距离,根据算法决定哪些片元会自动被discard。因为透明物体的存在,被透明物体遮挡的物体需要可见,因此需要关闭深度缓冲。
  • Tags{"Queue"="Transparent"}指定了使用该subshader的mesh在所有不透明(opaque)的mesh渲染完毕后再渲染。之所以要这样指定,部分原因是因为我们关闭了深度缓冲,这会导致一个透明物体被它后面的非透明物体遮挡。因此我们通过增加"Queue"="Transparent"的Tags来指定透明物体在非透明物体渲染完毕后再渲染(需要注意这种方式并不是经常奏效,更多参考:Order-Independent Transparency)
    Unity中预定义的Queue包含以下几个:
    Background,index为1000
    Geometry,默认值,index为2000
    AlphaTest,index为2450
    Transparent,index为3000
    Overlay,index为4000,最后渲染的物体可以使用该Queue,比如lens flares.
    更多关于Unity ShaderLab的Tags内容参考:ShaderLab: SubShader Tags
发布了198 篇原创文章 · 获赞 23 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/iningwei/article/details/100630923