透明度混合

Posted 露夕逝

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了透明度混合相关的知识,希望对你有一定的参考价值。

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

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

为了进行混合,我们需要使用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 }
完整代码(建立在上面关闭深度写入的透明度混合代码基础上)

 效果:

以上是关于透明度混合的主要内容,如果未能解决你的问题,请参考以下文章

错误记录Flutter 混合开发获取 BinaryMessenger 报错 ( FlutterActivityAndFragmentDelegate.getFlutterEngine() )(代码片段

OpenGL ES/iPhone 的透明度/混合问题

具有透明度的模型

渲染管道像素阶段“Alpha混合”

渲染管道像素阶段“Alpha混合”

用于背景透明度的 Sass mixin 回到 IE8