Shader "MyUnlit/AlphaBlendDiffuse" { Properties { _Color("Color Tint(貼圖染色)",Color)=(1,1,1,1) _MainTex ("Texture(主貼圖)", 2D) = "white" {} //bump爲unity內置的法線紋理,當未配置任何法線紋理時,bump對應模型自帶的法線信息 _NormalMap("Normal Map(法線貼圖)",2D)="bump"{} _BumpScale("Bump Scale(凹凸程度)",float) = 1.0 _Cutoff("Alpha(總體透明度)",range(0,1)) = 0.5 } SubShader { //透明度混合須要定義的標籤 Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" } //1.Base Pass背面(順序,透明物體先渲染背面再渲染正面) Pass { //提示此Pass爲前向渲染中的Base Pass,計算環境光,自發光,平行光中的陰影,不計算其餘疊加光照效果 Tags{ "LightMode" = "ForwardBase" } //透明度混合須要關閉深度寫入 ZWrite Off //開啓混合操做並設置混合類型,此處類型爲透明度混合 Blend SrcAlpha OneMinusSrcAlpha //透明物體要考慮雙面渲染,第一個Pass只渲染背面,剔除正面 Cull Front CGPROGRAM #pragma vertex vert #pragma fragment frag //Base Pass指令,用於獲得對應的光照變量 #pragma multi_compile_fwdbase #include "UnityCG.cginc" //包含接收陰影的宏 #include "AutoLight.cginc" #include "Lighting.cginc" fixed4 _Color; sampler2D _MainTex; //用於控制對應紋理的縮放和偏移,格式固定爲xx_ST float4 _MainTex_ST; sampler2D _NormalMap; float4 _NormalMap_ST; float _BumpScale; fixed _Cutoff;//[0,1]範圍內用fixed struct appdata { float4 vertex : POSITION; float3 normal:NORMAL; float4 tangent:TANGENT;//與法線不一樣,w須要用於控制朝向 float2 uv : TEXCOORD0; }; struct v2f { //節約空間,xy份量存主貼圖uv;zw存法線貼圖的 float4 uv : TEXCOORD0; float4 pos : SV_POSITION;//變量名爲pos,有關陰影計算的宏中使用了此變量 //寄存器中無法存矩陣,因此分別存矩陣的每一行 float4 TtoW0 : TEXCOORD1; float4 TtoW1 : TEXCOORD2; float4 TtoW2 : TEXCOORD3; SHADOW_COORDS(4)//此陰影紋理座標存儲在TEXCOORD4中 }; //此處採用在世界空間中計算法線 v2f vert (appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); //用兩個份量分別存儲貼圖的縮放和偏移 o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex); o.uv.zw = TRANSFORM_TEX(v.uv, _NormalMap); float3 worldPos= mul(unity_ObjectToWorld, v.vertex).xyz; fixed3 worldNormal = UnityObjectToWorldNormal(v.normal); fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz); //叉積計算第三個標準正交基軸向,w指示朝向的正負 fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w; //節約空間,順便將世界空間中的頂點位置存在w份量中 o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x); o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y); o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z); //計算陰影紋理座標 TRANSFER_SHADOW(o); return o; } fixed4 frag (v2f i) : SV_Target { //還原世界座標 float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w); //還原出矩陣,用於將紋理從頂點空間(切線空間)變爲世界空間,統一計算 float3x3 TtoW= float3x3(i.TtoW0.xyz, i.TtoW1.xyz, i.TtoW2.xyz); //獲得世界空間中的光源方向和視線方向 fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos)); fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos)); //從zw份量中採樣出法線並進行凹凸程度的縮放,但此時法線依然處於頂點空間(切線空間) fixed3 tanNormal = UnpackNormalWithScale(tex2D(_NormalMap, i.uv.zw), _BumpScale); //經過以前構造的變換矩陣將法線從頂點空間變換到世界空間 fixed3 worldNormal = mul(TtoW, tanNormal); //採樣主紋理並染色,獲得反射率 fixed4 col = tex2D(_MainTex, i.uv); fixed3 albedo = col.rgb*_Color.rgb; //計算環境光 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; //計算漫反射 fixed3 diffuse = _LightColor0.rgb*albedo*saturate(dot(lightDir, worldNormal)); //計算光照和陰影衰減值,結果爲第一個參數 UNITY_LIGHT_ATTENUATION(atten, i, worldPos); //返回計算結果 return fixed4(ambient + diffuse * atten, col.a * _Cutoff); } ENDCG } //2.Base Pass正面 Pass { Tags{ "LightMode" = "ForwardBase" } ZWrite Off Blend SrcAlpha OneMinusSrcAlpha //透明物體要考慮雙面渲染,此Pass只渲染正面,剔除背面 Cull Back CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fwdbase #include "UnityCG.cginc" #include "AutoLight.cginc" #include "Lighting.cginc" fixed4 _Color; sampler2D _MainTex; float4 _MainTex_ST; sampler2D _NormalMap; float4 _NormalMap_ST; float _BumpScale; fixed _Cutoff; struct appdata { float4 vertex : POSITION; float3 normal:NORMAL; float4 tangent:TANGENT; float2 uv : TEXCOORD0; }; struct v2f { float4 uv : TEXCOORD0; float4 pos : SV_POSITION; float4 TtoW0 : TEXCOORD1; float4 TtoW1 : TEXCOORD2; float4 TtoW2 : TEXCOORD3; SHADOW_COORDS(4) }; v2f vert(appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex); o.uv.zw = TRANSFORM_TEX(v.uv, _NormalMap); float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; fixed3 worldNormal = UnityObjectToWorldNormal(v.normal); fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz); fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w; o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x); o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y); o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z); TRANSFER_SHADOW(o); return o; } fixed4 frag(v2f i) : SV_Target { float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w); float3x3 TtoW = float3x3(i.TtoW0.xyz, i.TtoW1.xyz, i.TtoW2.xyz); fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos)); fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos)); fixed3 tanNormal = UnpackNormalWithScale(tex2D(_NormalMap, i.uv.zw), _BumpScale); fixed3 worldNormal = mul(TtoW, tanNormal); fixed4 col = tex2D(_MainTex, i.uv); fixed3 albedo = col.rgb*_Color.rgb; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; fixed3 diffuse = _LightColor0.rgb*albedo*saturate(dot(lightDir, worldNormal)); UNITY_LIGHT_ATTENUATION(atten, i, worldPos); return fixed4(ambient + diffuse * atten, col.a * _Cutoff); } ENDCG } //3.Add Pass正常渲染 Pass { //提示此Pass爲前向渲染中的Add Pass,計算其餘疊加光照效果,每一個光源計算一次 Tags{ "LightMode" = "ForwardAdd" } ZWrite Off Blend SrcAlpha One Cull Back CGPROGRAM #pragma vertex vert #pragma fragment frag //Add Pass指令,用於獲得對應的光照變量 //#pragma multi_compile_fwdadd //陰影狀況下使用: #pragma multi_compile_fwdadd_fullshadows #include "UnityCG.cginc" #include "AutoLight.cginc" #include "Lighting.cginc" fixed4 _Color; sampler2D _MainTex; float4 _MainTex_ST; sampler2D _NormalMap; float4 _NormalMap_ST; float _BumpScale; fixed _Cutoff; struct appdata { float4 vertex : POSITION; float3 normal:NORMAL; float4 tangent:TANGENT; float2 uv : TEXCOORD0; }; struct v2f { float4 uv : TEXCOORD0; float4 pos : SV_POSITION; float4 TtoW0 : TEXCOORD1; float4 TtoW1 : TEXCOORD2; float4 TtoW2 : TEXCOORD3; SHADOW_COORDS(4) }; v2f vert(appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex); o.uv.zw = TRANSFORM_TEX(v.uv, _NormalMap); float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; fixed3 worldNormal = UnityObjectToWorldNormal(v.normal); fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz); fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w; o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x); o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y); o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z); TRANSFER_SHADOW(o); return o; } fixed4 frag(v2f i) : SV_Target { float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w); float3x3 TtoW = float3x3(i.TtoW0.xyz, i.TtoW1.xyz, i.TtoW2.xyz); fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos)); fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos)); fixed3 tanNormal = UnpackNormalWithScale(tex2D(_NormalMap, i.uv.zw), _BumpScale); fixed3 worldNormal = mul(TtoW, tanNormal); fixed4 col = tex2D(_MainTex, i.uv); fixed3 albedo = col.rgb*_Color.rgb; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; fixed3 diffuse = _LightColor0.rgb*albedo*saturate(dot(lightDir, worldNormal)); UNITY_LIGHT_ATTENUATION(atten, i, worldPos); return fixed4(ambient + diffuse * atten, col.a * _Cutoff); } ENDCG } } //無陰影 //FallBack "Transparent/VertexLit" //強制產生陰影 FallBack "VertexLit" }
對於至今爲止Shader學習內容的一個總結,算是一個比較綜合通用的shader了,由於是漫反射因此暫時沒有計算高光部分,以後再出一個帶高光版本的。算法
備註都有比較詳細的說明,基本思路是利用多個Pass分別進行正反面的渲染,再結合前向渲染的分光照渲染來實現。app
最後擺出效果圖w~學習