模擬實時光照下的陰影

在3d遊戲中,實時光照是一個特別大的消耗,不僅是因爲對於顏色的計算,還有消耗在繪製實時陰影,對於手機遊戲無疑是一個很大的開銷,但是吧,沒有實時光照的影子,就顯得很呆板,這裏就說明一下3d遊戲中繪製陰影的原理。


太陽光可以看做是一個平行光,平行光經過物體,投影到某個平面中,於是在該平面形成了陰影。

現在,我們假設需要投影到一個平面上,該平面的方程爲ax+by+cz+d=0,其中(a,b,c)是該平面的法向量,假設該平面上存在一個點p(x2,y2,z2),那麼d=-(a*x2+b*y2+c*z2),現在假設太陽光的方向向量爲_LightVec,由上圖可以看出

{

ax+by+cz-(a*x2+b*y2+c*z2)=0           1

}

{

    x1=x + k*LightVec.x             2

    y1=y+ k*LightVec.y             3

    z1=z+ k*LightVec.z              4

}

(x1,y1,z1)和(x2,y2,z2)同樣是平面上的點,故可以將234代入1式中,得到:

k=a(x2-x)+b(y2-y)+c(z2-z)/(a*LightVec.x + b*LightVec.y +c*LightVec.z )

我是假設了平面法線向量(1, 0, 0)平面上存在點(0.3, 0, 0),所以可以算出k=(0.3-x)/LightVec.x;

代入上面得到

{

    x1=0.3

    y1=k*y + _LightVec.y;

    z1=k*z + _LightVec.z;

}

下面是完整shader代碼:

Shader "Expand/RealTimeShadow" {
	Properties {
		_Color ("Main Color", Color) = (1,1,1,1)
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_LightVec ("Light Position", Vector) = (1, 0, 0, 0)	//平行光向量
		_Hight("Hight", Range (0.0, 2)) = 0.32
	}
	SubShader {
		Tags {"Queue"="Geometry"}
		LOD 200
		//影子
		Pass {
			CGINCLUDE
			#include "UnityCG.cginc"
			 
			struct appdata {
				float4 vertex : POSITION;
				float3 normal : NORMAL;
			};
			struct v2f {
				float4 pos : POSITION;
			};
			ENDCG
			
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			float4 _LightVec;
			float _Hight;
			 v2f vert(appdata v) {
				v2f o;
				//假設投影的平面上有一個點(0.32, 0, 0)爲1x+0y+0z-(1*0.32+b*0+c*0)=0; 平行光向量;
				float3 vec3 = _LightVec;
				float k = (_Hight-v.vertex.x)/vec3.x;
				v.vertex.y = k*vec3.y + v.vertex.y;
				v.vertex.z = k*vec3.z + v.vertex.z;
				v.vertex.x = _Hight;
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				return o;
			}
			half4 frag(v2f i) : COLOR {
				return 0;
			}
			ENDCG
		}
	} 
}

可以自定義光照方向,離地高度,最後的效果是



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章