1. 程式人生 > >Planar Shadow

Planar Shadow

返回 brush tro plan 顏色 sample RM matrix AI

Unity上平面陰影的計算與實現

//如何求頂點投影到平面上的點(陰影點)
//當平面上取不相等的任意兩個點組成一個向量,與平面的法線總是垂直的,向量垂直點乘為0,因此可以通過一個點和一個法線來定義,
//plane方程如下:(P - P0)·N = 0 N=normal,P0表示平面上的一個點,P表示平面上的任意點,當P = P0時 0·N = 0
//射線方程 P = o + t * D,(o為射線起點,t為標量,表示射線原點到和平面交點的距離)聯立兩個方程式可求交點。方程如下:

//          ( O + D·t - P0 )·N = 0
//       => ( O - P0 )·N + D·N·t = 0
//       => t = ( P0 - O)·N / D·N  ( 其中D·N ≠0 ,向量點積滿足分配律)
// p0表示平面上一點中心點(0,0,0) o:頂點世界坐標  N:平面的法向量(0,1,0)D:直射光方向
//註意兩點:
//當 D·N = 0 時,表示射線與平面垂直,則射線與平面平行。
//解出 t < 0 時,表示 射線沿著平面相反的半平面發射,也是不相交的(當然如果是直線就沒關系啦)

Shader "Pluto/PlanarShadow"
{
	Properties
	{
		_ShadowColor ("Shadow Color",Color) = (0.25,0.25,0.25,0.25)
		_Center("Center", Vector) = (0,0.001,0,0)
        _Normal("Normal", Vector) = (0,1,0,0)
		_MainTex ("Texture", 2D) = "white" {}
	}
	SubShader
	{
		Tags { "RenderType"="Opaque" "LightMode"="ForwardBase" }
		LOD 100

		//渲染模型
		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"

			struct appdata
			{
				float4 vertex : POSITION; //模型空間中的頂點坐標
				float2 uv : TEXCOORD0;
			};

			struct v2f
			{
				float2 uv : TEXCOORD0;
				float4 vertex : SV_POSITION;  //裁剪空間中的頂點坐標
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex); //將頂點從模型空間轉換到裁剪空間中,更高效
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				// sample the texture
				fixed4 col = tex2D(_MainTex, i.uv);
				return col;
			}
			ENDCG
		}

		//渲染平面陰影Pass
		Pass
		{
			ZWrite On
			ZTest LEqual
			Blend SrcAlpha OneMinusSrcAlpha

			Stencil{
				Ref 0
				Comp Equal
				Pass IncrWrap
				ZFail Keep
			}

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag	
			#include "UnityCG.cginc"
			
			struct appdata
			{
				float4 vertex : POSITION;
			};

			struct v2f
			{
				float4 vertex : SV_POSITION;
			};

			float4 _ShadowColor;  	//陰影顏色
			float4 _Center;     	//平面上一點中心點
			float4 _Normal;    		//平面法線

			v2f vert (appdata v)
			{
				v2f o;
				float4 wPos = mul(unity_ObjectToWorld ,v.vertex);  //頂點世界坐標
				float4 lightDir = normalize(_WorldSpaceLightPos0);  //直射光的方向
				float dist = dot(_Center.xyz - wPos.xyz, _Normal.xyz) / dot(lightDir, _Normal.xyz);
				wPos = wPos + lightDir * dist;
				o.vertex = mul( UNITY_MATRIX_VP,wPos);  			//轉換到裁剪空間坐標
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				return _ShadowColor;  //直接返回影子顏色
			}

			ENDCG
		}
	}
}

  

技術分享圖片

參考:https://www.jianshu.com/p/c8438bf6af0f

----碼字不易,歡迎轉載,但保留版權,請於明顯處標明出處:http://www.cnblogs.com/beeasy/

Planar Shadow