US3S3L7——双面渲染
双面渲染的透明效果的需求
对于现实世界的半透明物体,我们不仅可以透过它看到其他物体的样子,也可以看到这个物体自己的内部结构
但是我们之前实现的 透明度测试 和 透明度混合 相关Shader,都无法看到模型的内部结构
如下图,左边的立方体使用透明混合,右边的立方体使用透明测试,它们都无法看到模型内部的结构
而双面渲染的透明效果 Shader 就是来解决该问题的,
让我们不仅可以透过半透明物体看到其他物体的样子,还可以看到自己的内部结构
双面渲染的透明效果的基本原理
基本原理:默认情况下,Unity会自动剔除物体的背面,而只渲染物体的正面
双面渲染的基本原理就是利用我们之前学习过的 Cull 剔除指令来进行指定操作
-
Cull Back
—— 背面剔除
-
Cull Front
—— 正面剔除
-
Cull Off
—— 不剔除
不设置的话,默认为背面剔除
- 对于透明度测试 Shader,由于它无需混合,因此我们直接 关闭剔除 即可
- 对于透明度混合 Shader,由于它需要进行混合,需要使用两个
Pass
,一个用于渲染背面,一个用于渲染正面
两个 Pass
中除了剔除命令不同,其他代码和之前一致
实现双面渲染的透明效果Shader
透明度测试
- 复用之前实现的 透明度测试 相关Shader代码
- 在
Pass
中关闭剔除 Cull Off
实现的 Shader 代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| Shader "TeachShader/Lesson59_AlphaTest" { Properties { _MainTex("MainTex", 2D) = ""{} _MainColor("MainColor", Color) = (1, 1, 1, 1) _SpecularColor("SpecularColor", Color) = (1, 1, 1, 1) _SpecularNum("SpecularNum", Range(0, 20)) = 15 _Cutoff("Curoff", Range(0, 1)) = 0 } SubShader { Tags { "Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
Pass { Tags { "LightMode" = "ForwardBase" } Cull Off
CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #include "Lighting.cginc"
sampler2D _MainTex; float4 _MainTex_ST; fixed4 _MainColor; fixed4 _SpecularColor; float _SpecularNum; fixed _Cutoff;
struct v2f { float4 pos: SV_POSITION; float2 uv: TEXCOORD0; float3 wNormal: NORMAL; float3 wPos: TEXCOORD1; };
v2f vert (appdata_base v) { v2f data; data.pos = UnityObjectToClipPos(v.vertex); data.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; data.wNormal = UnityObjectToWorldNormal(v.normal); data.wPos = mul(unity_ObjectToWorld, v.vertex);
return data; }
fixed4 frag (v2f i) : SV_Target { fixed4 texColor = tex2D(_MainTex, i.uv); clip(texColor.a - _Cutoff);
fixed3 albedo = texColor.rgb * _MainColor.rgb; float3 lightDir = normalize(_WorldSpaceLightPos0.xyz); fixed3 lambertColor = _LightColor0.rgb * albedo.rgb * max(0, dot(i.wNormal, lightDir)); float3 viewDir = normalize(UnityWorldSpaceViewDir(i.wPos)); float3 halfA = normalize(viewDir + lightDir); fixed3 specularColor = _LightColor0.rgb * _SpecularColor.rgb * pow(max(0, dot(i.wNormal, halfA)), _SpecularNum);
fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo + lambertColor + specularColor;
return fixed4(color.rgb, 1); } ENDCG } } }
|
透明度混合
-
复用之前实现的 透明度混合 相关Shader代码
-
复制之前的 Pass
,变成两个一模一样的 Pass
-
在第一个 Pass
中剔除正面 Cull Front
,在第二个 Pass
中剔除背面 Cull Back
相当于一个片元先渲染背面再渲染正面
实现的 Shader 代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
| Shader "TeachShader/Lesson59_Transparent" { Properties { _MainTex("MainTex", 2D) = ""{} _MainColor("MainColor", Color) = (1, 1, 1, 1) _SpecularColor("SpecularColor", Color) = (1, 1, 1, 1) _SpecularNum("SpecularNum", Range(0, 20)) = 15 _AlphaScale("AlphaScale", Range(0, 1)) = 1 } SubShader { Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
Pass { Tags { "LightMode" = "ForwardBase" } ZWrite Off Blend SrcAlpha OneMinusSrcAlpha Cull Front
CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #include "Lighting.cginc"
sampler2D _MainTex; float4 _MainTex_ST; fixed4 _MainColor; fixed4 _SpecularColor; float _SpecularNum; fixed _AlphaScale;
struct v2f { float4 pos: SV_POSITION; float2 uv: TEXCOORD0; float3 wNormal: NORMAL; float3 wPos: TEXCOORD1; };
v2f vert (appdata_base v) { v2f data; data.pos = UnityObjectToClipPos(v.vertex); data.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; data.wNormal = UnityObjectToWorldNormal(v.normal); data.wPos = mul(unity_ObjectToWorld, v.vertex);
return data; }
fixed4 frag (v2f i) : SV_Target { fixed4 texColor = tex2D(_MainTex, i.uv); fixed3 albedo = texColor.rgb * _MainColor.rgb; float3 lightDir = normalize(_WorldSpaceLightPos0.xyz); fixed3 lambertColor = _LightColor0.rgb * albedo.rgb * max(0, dot(i.wNormal, lightDir)); float3 viewDir = normalize(UnityWorldSpaceViewDir(i.wPos)); float3 halfA = normalize(viewDir + lightDir); fixed3 specularColor = _LightColor0.rgb * _SpecularColor.rgb * pow(max(0, dot(i.wNormal, halfA)), _SpecularNum);
fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo + lambertColor + specularColor; return fixed4(color.rgb, texColor.a * _AlphaScale); } ENDCG }
Pass { Tags { "LightMode" = "ForwardBase" } ZWrite Off Blend SrcAlpha OneMinusSrcAlpha Cull Back
CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #include "Lighting.cginc"
sampler2D _MainTex; float4 _MainTex_ST; fixed4 _MainColor; fixed4 _SpecularColor; float _SpecularNum; fixed _AlphaScale;
struct v2f { float4 pos: SV_POSITION; float2 uv: TEXCOORD0; float3 wNormal: NORMAL; float3 wPos: TEXCOORD1; };
v2f vert (appdata_base v) { v2f data; data.pos = UnityObjectToClipPos(v.vertex); data.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; data.wNormal = UnityObjectToWorldNormal(v.normal); data.wPos = mul(unity_ObjectToWorld, v.vertex);
return data; }
fixed4 frag (v2f i) : SV_Target { fixed4 texColor = tex2D(_MainTex, i.uv); fixed3 albedo = texColor.rgb * _MainColor.rgb; float3 lightDir = normalize(_WorldSpaceLightPos0.xyz); fixed3 lambertColor = _LightColor0.rgb * albedo.rgb * max(0, dot(i.wNormal, lightDir)); float3 viewDir = normalize(UnityWorldSpaceViewDir(i.wPos)); float3 halfA = normalize(viewDir + lightDir); fixed3 specularColor = _LightColor0.rgb * _SpecularColor.rgb * pow(max(0, dot(i.wNormal, halfA)), _SpecularNum);
fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo + lambertColor + specularColor; return fixed4(color.rgb, texColor.a * _AlphaScale); } ENDCG } } }
|
显示效果如下(下方是不使用双面渲染的混合和透明测试,上方是使用双面渲染的混合和透明测试):