Unity 通用透明物體漫反射Shader(雙面渲染&多光源&光照衰減&法線貼圖&凹凸透明度控制)

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~學習

不帶投影的結果帶投影的結果

相關文章
相關標籤/搜索