透明度混合:这种方法可以得到真正的半透明效果。它会使用当前片元的透明度作为混合因子,与已经存储在颜色缓冲中的颜色值进行混合,得到新的颜色。但是透明度混合需要关闭深度写入。
这使得我们要非常小心物体的渲染顺序。
为了进行混合,我们需要使用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 }
效果: