首页 > 代码库 > 透明度混合

透明度混合

透明度混合:这种方法可以得到真正的半透明效果。它会使用当前片元的透明度作为混合因子,与已经存储在颜色缓冲中的颜色值进行混合,得到新的颜色。但是透明度混合需要关闭深度写入。

这使得我们要非常小心物体的渲染顺序。

为了进行混合,我们需要使用Unity提供的混合命令——Blend。

我们这里使用 Blend SrcAlpha OneMinusSrcAlpha

内部公式为:DstColor(new)=SrcAlpha*SrcColor+(1-SrcAlpha)*DstColor(old);

首先是关闭深度写入的代码:

技术分享
 1 Shader "Custom/AlphaBlend" {
 2     Properties {
 3         _Color ("Main Tint", Color) = (1,1,1,1)
 4         _MainTex ("Albedo (RGB)", 2D) = "white" {}
 5         _AlphaScale("Alpha Scale",Range(0,1))=1
 6     }
 7     SubShader {
 8     /*
 9     "Queue"="AlphaTest":Unity中透明度测试使用的渲染队列是名为AlphaTest的队列
10     "IgnoreProjectors"="True":意味着这个Shader不会受到投影器的影响
11 
12     通常使用了透明度测试的shader都应该在SubShader中设置这3个标签
13     */
14     Tags{"Queue"="Transparent""IgnoreProjectors"="True""RenderType"="TransparentCutout"}
15         Pass
16         {
17         Tags{"LightMode"="ForwardBase"}
18         Cull Off
19         ZWrite Off
20         Blend SrcAlpha OneMinusSrcAlpha
21         CGPROGRAM
22         #pragma vertex vert
23         #pragma fragment frag
24         #include"Lighting.cginc"
25 
26         fixed4 _Color;
27         sampler2D _MainTex;
28         float4 _MainTex_ST;
29         fixed _AlphaScale;
30 
31         struct a2v
32         {
33         float4 vertex:POSITION;
34         float3 normal:NORMAL;
35         float4 texcoord:TEXCOORD0;
36         };
37         struct v2f
38         {
39         float4 pos:SV_POSITION;
40         float3 worldNormal:TEXCOORD0;
41         float3 worldPos:TEXCOORD1;
42         float2 uv:TEXCOORD2;
43         };
44         v2f vert(a2v v)
45         {
46         v2f o;
47         o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
48         o.worldNormal=UnityObjectToWorldNormal(v.normal);
49         o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;
50         o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
51         return o;
52         }
53 
54         fixed4 frag(v2f i):SV_Target
55         {
56         fixed3 worldNormal=normalize(i.worldNormal);
57         fixed3 worldLightDir=normalize(UnityWorldSpaceLightDir(i.worldPos));
58         fixed4 texColor=tex2D(_MainTex,i.uv);
59         fixed3 albedo=texColor.rgb*_Color.rgb;
60         fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz*albedo;
61         fixed3 diffuse=_LightColor0.rgb*albedo*max(0,dot(worldNormal,worldLightDir));
62         return fixed4(ambient+diffuse,texColor.a*_AlphaScale);
63         }
64 
65         ENDCG
66         }
67     }
68     FallBack "Transparent/Cutout/VertexLit"
69 }
透明度混合(关闭深度写入)

我们可以调节材质面板上的Alpha Scale参数,以控制整体透明度。

技术分享

当然,关闭深度写入有时候会带来因为排序错误而产生的错误的透明效果(模型本身有复杂的遮挡关系)。

技术分享

所以我们可以采用开启深度写入进行透明度混合。原理是开启2个Pass来渲染模型。第一个Pass开启深度写入,但是不输出颜色,它的目的仅仅是为了把该模型的深度值写入深度缓冲中。第二个Pass进行透明度混合。(多使用一个Pass会对性能造成一定的影响)。在之前的代码中原有的Pass前面添加以下代码即可:

Pass
{
    ZWrite On
    ColorMask 0
}

完整代码:

技术分享
 1 Shader "Custom/AlphaBlend" {
 2     Properties {
 3         _Color ("Main Tint", Color) = (1,1,1,1)
 4         _MainTex ("Albedo (RGB)", 2D) = "white" {}
 5         _AlphaScale("Alpha Scale",Range(0,1))=1
 6     }
 7     SubShader {
 8     /*
 9     "Queue"="AlphaTest":Unity中透明度测试使用的渲染队列是名为AlphaTest的队列
10     "IgnoreProjectors"="True":意味着这个Shader不会受到投影器的影响
11 
12     通常使用了透明度测试的shader都应该在SubShader中设置这3个标签
13     */
14     Tags{"Queue"="Transparent""IgnoreProjectors"="True""RenderType"="TransparentCutout"}
15         Pass
16         {
17         ZWrite On
18         ColorMask 0
19         }
20         Pass
21         {
22         Tags{"LightMode"="ForwardBase"}
23         ZWrite Off
24         Blend  SrcAlpha OneMinusSrcAlpha
25         CGPROGRAM
26         #pragma vertex vert
27         #pragma fragment frag
28         #include"Lighting.cginc"
29 
30         fixed4 _Color;
31         sampler2D _MainTex;
32         float4 _MainTex_ST;
33         fixed _AlphaScale;
34 
35         struct a2v
36         {
37         float4 vertex:POSITION;
38         float3 normal:NORMAL;
39         float4 texcoord:TEXCOORD0;
40         };
41         struct v2f
42         {
43         float4 pos:SV_POSITION;
44         float3 worldNormal:TEXCOORD0;
45         float3 worldPos:TEXCOORD1;
46         float2 uv:TEXCOORD2;
47         };
48         v2f vert(a2v v)
49         {
50         v2f o;
51         o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
52         o.worldNormal=UnityObjectToWorldNormal(v.normal);
53         o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;
54         o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
55         return o;
56         }
57 
58         fixed4 frag(v2f i):SV_Target
59         {
60         fixed3 worldNormal=normalize(i.worldNormal);
61         fixed3 worldLightDir=normalize(UnityWorldSpaceLightDir(i.worldPos));
62         fixed4 texColor=tex2D(_MainTex,i.uv);
63         fixed3 albedo=texColor.rgb*_Color.rgb;
64         fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz*albedo;
65         fixed3 diffuse=_LightColor0.rgb*albedo*max(0,dot(worldNormal,worldLightDir));
66         return fixed4(ambient+diffuse,texColor.a*_AlphaScale);
67         }
68 
69         ENDCG
70         }
71     }
72     FallBack "Transparent/Cutout/VertexLit"
73 }
透明度混合(开启深度写入)

 

透明度混合