Planar Shadow

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

相關文章
相關標籤/搜索