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/1795310
https://blog.csdn.net/onafioo/article/details/53943264
----码字不易,欢迎转载,但保留版权,请于明显处标明出处:http://www.cnblogs.com/beeasy/