透明度混合:这种方法可以得到真正的半透明效果。它会使用当前片元的透明度作为混合因子,与已经存储在颜色缓冲中的颜色值进行混合,得到新的颜色。但是透明度混合需要关闭深度写入。
这使得我们要非常小心物体的渲染顺序。
为了进行混合,我们需要使用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"="Transparent":Unity中透明度测试使用的渲染队列是名为AlphaTest的队列
10 "IgnoreProjectors"="True":意味着这个Shader不会受到投影器的影响
11 RenderType标签可以让Unity把这个Shader归入到提前定义的组(这里就是Transparent组)
12 */
13 Tags{"Queue"="Transparent""IgnoreProjectors"="True""RenderType"="Transparent"}
14 Pass
15 {
16 Tags{"LightMode"="ForwardBase"}
17 ZWrite Off//关闭深度写入
18 Blend SrcAlpha OneMinusSrcAlpha
19 CGPROGRAM
20 #pragma vertex vert
21 #pragma fragment frag
22 #include"Lighting.cginc"
23
24 fixed4 _Color;
25 sampler2D _MainTex;
26 float4 _MainTex_ST;
27 fixed _AlphaScale;
28
29 struct a2v
30 {
31 float4 vertex:POSITION;
32 float3 normal:NORMAL;
33 float4 texcoord:TEXCOORD0;
34 };
35 struct v2f
36 {
37 float4 pos:SV_POSITION;
38 float3 worldNormal:TEXCOORD0;
39 float3 worldPos:TEXCOORD1;
40 float2 uv:TEXCOORD2;
41 };
42 v2f vert(a2v v)
43 {
44 v2f o;
45 o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
46 o.worldNormal=UnityObjectToWorldNormal(v.normal);
47 o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;
48 o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
49 return o;
50 }
51
52 fixed4 frag(v2f i):SV_Target
53 {
54 fixed3 worldNormal=normalize(i.worldNormal);
55 fixed3 worldLightDir=normalize(UnityWorldSpaceLightDir(i.worldPos));
56 fixed4 texColor=tex2D(_MainTex,i.uv);
57 fixed3 albedo=texColor.rgb*_Color.rgb;
58 fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz*albedo;
59 fixed3 diffuse=_LightColor0.rgb*albedo*max(0,dot(worldNormal,worldLightDir));
60 return fixed4(ambient+diffuse,texColor.a*_AlphaScale);//颜色乘以透明程度
61 }
62
63 ENDCG
64 }
65 }
66 FallBack "Transparent/Cutout/VertexLit"
67 }
透明度混合(关闭深度写入)
我们可以调节材质面板上的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"="Transparent":Unity中透明度测试使用的渲染队列是名为AlphaTest的队列
10 "IgnoreProjectors"="True":意味着这个Shader不会受到投影器的影响
11 RenderType标签可以让Unity把这个Shader归入到提前定义的组(这里就是Transparent组)
12 */
13 Tags{"Queue"="Transparent""IgnoreProjectors"="True""RenderType"="Transparent"}
14 Pass
15 {
16 Tags{"LightMode"="ForwardBase"}
17 Cull Front
18 ZWrite On//开启深度写入
19 ColorMask 0//当ColorMask设为0时,意味着该pass不写任何颜色通道,即不会输出任何颜色。这正是我们需要的-该Pass只需要写入深度缓冲即可
20
21 }
22 Pass
23 {
24 Tags{"LightMode"="ForwardBase"}
25 Cull Back
26 ZWrite Off//关闭深度写入
27 Blend SrcAlpha OneMinusSrcAlpha
28
29 CGPROGRAM
30 #pragma vertex vert
31 #pragma fragment frag
32 #include"Lighting.cginc"
33
34 fixed4 _Color;
35 sampler2D _MainTex;
36 float4 _MainTex_ST;
37 fixed _AlphaScale;
38
39 struct a2v
40 {
41 float4 vertex:POSITION;
42 float3 normal:NORMAL;
43 float4 texcoord:TEXCOORD0;
44 };
45 struct v2f
46 {
47 float4 pos:SV_POSITION;
48 float3 worldNormal:TEXCOORD0;
49 float3 worldPos:TEXCOORD1;
50 float2 uv:TEXCOORD2;
51 };
52 v2f vert(a2v v)
53 {
54 v2f o;
55 o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
56 o.worldNormal=UnityObjectToWorldNormal(v.normal);
57 o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;
58 o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
59 return o;
60 }
61
62 fixed4 frag(v2f i):SV_Target
63 {
64 fixed3 worldNormal=normalize(i.worldNormal);
65 fixed3 worldLightDir=normalize(UnityWorldSpaceLightDir(i.worldPos));
66 fixed4 texColor=tex2D(_MainTex,i.uv);
67 fixed3 albedo=texColor.rgb*_Color.rgb;
68 fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz*albedo;
69 fixed3 diffuse=_LightColor0.rgb*albedo*max(0,dot(worldNormal,worldLightDir));
70 return fixed4(ambient+diffuse,texColor.a*_AlphaScale);//颜色乘以透明程度
71 }
72
73 ENDCG
74 }
75 }
76 FallBack "Transparent/Cutout/VertexLit"
77 }
透明度混合(开启深度写入)
双面渲染的透明效果建立在关闭深度写入的状态下。
1 Shader "Custom/AlphaBlend With Both Side" {
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 Tags{"Queue"="Transparent""IgnoreProjectors"="True""RenderType"="Transparent"}
9 Pass
10 {
11 Tags{"LightMode"="ForwardBase"}
12 Cull Front
13 //和之前一样的代码
14 }
15 Pass
16 {
17 Tags{"LightMode"="ForwardBase"}
18 Cull Back
19 //和之前一样的代码
20 }
21 }
22 FallBack "Transparent/Cutout/VertexLit"
23 }
24
伪代码
1 Shader "Custom/AlphaBlend With Both Side" {
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"="Transparent":Unity中透明度测试使用的渲染队列是名为AlphaTest的队列
10 "IgnoreProjectors"="True":意味着这个Shader不会受到投影器的影响
11 RenderType标签可以让Unity把这个Shader归入到提前定义的组(这里就是Transparent组)
12 */
13 Tags{"Queue"="Transparent""IgnoreProjectors"="True""RenderType"="Transparent"}
14 Pass
15 {
16 Tags{"LightMode"="ForwardBase"}
17 Cull Front
18 ZWrite Off//关闭深度写入
19 Blend SrcAlpha OneMinusSrcAlpha
20 CGPROGRAM
21 #pragma vertex vert
22 #pragma fragment frag
23 #include"Lighting.cginc"
24
25 fixed4 _Color;
26 sampler2D _MainTex;
27 float4 _MainTex_ST;
28 fixed _AlphaScale;
29
30 struct a2v
31 {
32 float4 vertex:POSITION;
33 float3 normal:NORMAL;
34 float4 texcoord:TEXCOORD0;
35 };
36 struct v2f
37 {
38 float4 pos:SV_POSITION;
39 float3 worldNormal:TEXCOORD0;
40 float3 worldPos:TEXCOORD1;
41 float2 uv:TEXCOORD2;
42 };
43 v2f vert(a2v v)
44 {
45 v2f o;
46 o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
47 o.worldNormal=UnityObjectToWorldNormal(v.normal);
48 o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;
49 o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
50 return o;
51 }
52
53 fixed4 frag(v2f i):SV_Target
54 {
55 fixed3 worldNormal=normalize(i.worldNormal);
56 fixed3 worldLightDir=normalize(UnityWorldSpaceLightDir(i.worldPos));
57 fixed4 texColor=tex2D(_MainTex,i.uv);
58 fixed3 albedo=texColor.rgb*_Color.rgb;
59 fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz*albedo;
60 fixed3 diffuse=_LightColor0.rgb*albedo*max(0,dot(worldNormal,worldLightDir));
61 return fixed4(ambient+diffuse,texColor.a*_AlphaScale);//颜色乘以透明程度
62 }
63 ENDCG
64 }
65 Pass
66 {
67 Tags{"LightMode"="ForwardBase"}
68 Cull Back
69 ZWrite Off//关闭深度写入
70 Blend SrcAlpha OneMinusSrcAlpha
71 CGPROGRAM
72 #pragma vertex vert
73 #pragma fragment frag
74 #include"Lighting.cginc"
75
76 fixed4 _Color;
77 sampler2D _MainTex;
78 float4 _MainTex_ST;
79 fixed _AlphaScale;
80
81 struct a2v
82 {
83 float4 vertex:POSITION;
84 float3 normal:NORMAL;
85 float4 texcoord:TEXCOORD0;
86 };
87 struct v2f
88 {
89 float4 pos:SV_POSITION;
90 float3 worldNormal:TEXCOORD0;
91 float3 worldPos:TEXCOORD1;
92 float2 uv:TEXCOORD2;
93 };
94 v2f vert(a2v v)
95 {
96 v2f o;
97 o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
98 o.worldNormal=UnityObjectToWorldNormal(v.normal);
99 o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;
100 o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
101 return o;
102 }
103
104 fixed4 frag(v2f i):SV_Target
105 {
106 fixed3 worldNormal=normalize(i.worldNormal);
107 fixed3 worldLightDir=normalize(UnityWorldSpaceLightDir(i.worldPos));
108 fixed4 texColor=tex2D(_MainTex,i.uv);
109 fixed3 albedo=texColor.rgb*_Color.rgb;
110 fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz*albedo;
111 fixed3 diffuse=_LightColor0.rgb*albedo*max(0,dot(worldNormal,worldLightDir));
112 return fixed4(ambient+diffuse,texColor.a*_AlphaScale);//颜色乘以透明程度
113 }
114
115 ENDCG
116 }
117 }
118 FallBack "Transparent/Cutout/VertexLit"
119 }
完整代码(建立在上面关闭深度写入的透明度混合代码基础上)
效果: