Unity上平面陰影的計算與實現程序員
1 //如何求頂點投影到平面上的點(陰影點) 2 //當平面上取不相等的任意兩個點組成一個向量,與平面的法線老是垂直的,向量垂直點乘爲0,所以能夠經過一個點和一個法線來定義, 3 //plane方程以下:(P - P0)·N = 0 N=normal,P0表示平面上的一個點,P表示平面上的任意點,當P = P0時 0·N = 0 4 //射線方程 P = o + t * D,(o爲射線起點,t爲標量,表示射線原點到和平面交點的距離)聯立兩個方程式可求交點。方程以下: 5 6 // ( O + D·t - P0 )·N = 0 7 // => ( O - P0 )·N + D·N·t = 0 8 // => t = ( P0 - O)·N / D·N ( 其中D·N ≠0 ,向量點積知足分配律) 9 // p0表示平面上一點中心點(0,0,0) o:頂點世界座標 N:平面的法向量(0,1,0)D:直射光方向 10 //注意兩點: 11 //當 D·N = 0 時,表示射線與平面垂直,則射線與平面平行。 12 //解出 t < 0 時,表示 射線沿着平面相反的半平面發射,也是不相交的(固然若是是直線就不要緊啦) 13 14 Shader "Pluto/PlanarShadow" 15 { 16 Properties 17 { 18 _ShadowColor ("Shadow Color",Color) = (0.25,0.25,0.25,0.25) 19 _Center("Center", Vector) = (0,0.001,0,0) 20 _Normal("Normal", Vector) = (0,1,0,0) 21 _MainTex ("Texture", 2D) = "white" {} 22 } 23 SubShader 24 { 25 Tags { "RenderType"="Opaque" "LightMode"="ForwardBase" } 26 LOD 100 27 28 //渲染模型 29 Pass 30 { 31 CGPROGRAM 32 #pragma vertex vert 33 #pragma fragment frag 34 35 #include "UnityCG.cginc" 36 37 struct appdata 38 { 39 float4 vertex : POSITION; //模型空間中的頂點座標 40 float2 uv : TEXCOORD0; 41 }; 42 43 struct v2f 44 { 45 float2 uv : TEXCOORD0; 46 float4 vertex : SV_POSITION; //裁剪空間中的頂點座標 47 }; 48 49 sampler2D _MainTex; 50 float4 _MainTex_ST; 51 52 v2f vert (appdata v) 53 { 54 v2f o; 55 o.vertex = UnityObjectToClipPos(v.vertex); //將頂點從模型空間轉換到裁剪空間中,更高效 56 o.uv = TRANSFORM_TEX(v.uv, _MainTex); 57 return o; 58 } 59 60 fixed4 frag (v2f i) : SV_Target 61 { 62 // sample the texture 63 fixed4 col = tex2D(_MainTex, i.uv); 64 return col; 65 } 66 ENDCG 67 } 68 69 //渲染平面陰影Pass 70 Pass 71 { 72 ZWrite On 73 ZTest LEqual 74 Blend SrcAlpha OneMinusSrcAlpha 75 76 // 模板測試的判斷依據 77 // if((referenceValue & readMask) ComparisonFunction (stencilBufferValue & readMask)) 78 // 經過像素 79 // else 80 // 拋棄像素 81 82 // 在這個公式中,主要分ComparisonFunction的左邊部分和右邊部分 83 // referenceValue是有Ref來定義的,這個是由程序員來定義的,readMask是模板值讀取掩碼,它和referenceValue進行按位與(&)操做做爲公式左邊的結果,默認值爲255,即按位與(&)的結果就是referenceValue自己。 84 // stencilBufferValue是對應位置當前模板緩衝區的值,一樣與readMask作按位掩碼與操做,結果作爲右邊的部分。 85 86 //解決double blending,保證一個點只被渲染一次 87 Stencil{ 88 Ref 0 //設定參考值0,stencilbuffer裏面的值會跟它進行比較,stencilBuffer值默認爲0 89 Comp Equal //比較方式爲"相等" 90 Pass IncrWrap //當模版測試和深度測試都經過的時候,當前模板緩衝中的是值+1 91 ZFail Keep //當模板測試經過而且深度測試失敗,保存當前模板緩存中的內容不變 92 } 93 94 CGPROGRAM 95 #pragma vertex vert 96 #pragma fragment frag 97 #include "UnityCG.cginc" 98 99 struct appdata 100 { 101 float4 vertex : POSITION; 102 }; 103 104 struct v2f 105 { 106 float4 vertex : SV_POSITION; 107 }; 108 109 float4 _ShadowColor; //陰影顏色 110 float4 _Center; //平面上一點中心點 111 float4 _Normal; //平面法線 112 113 v2f vert (appdata v) 114 { 115 v2f o; 116 float4 wPos = mul(unity_ObjectToWorld ,v.vertex); //頂點世界座標 117 float4 lightDir = normalize(_WorldSpaceLightPos0); //直射光的方向 118 float dist = dot(_Center.xyz - wPos.xyz, _Normal.xyz) / dot(lightDir, _Normal.xyz); 119 wPos = wPos + lightDir * dist; 120 o.vertex = mul( UNITY_MATRIX_VP,wPos); //轉換到裁剪空間座標 121 return o; 122 } 123 124 fixed4 frag (v2f i) : SV_Target 125 { 126 return _ShadowColor; //直接返回影子顏色 127 } 128 129 ENDCG 130 } 131 } 132 }
參考:https://www.jianshu.com/p/c8438bf6af0f緩存
http://nanjingjiangbiao-t.iteye.com/blog/1795310app
https://blog.csdn.net/onafioo/article/details/53943264測試
----碼字不易,歡迎轉載,但保留版權,請於明顯處標明出處:http://www.cnblogs.com/beeasy/spa