zoukankan      html  css  js  c++  java
  • 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/

  • 相关阅读:
    ES6新特性
    浏览器兼容问题
    跨域
    箭头函数与普通函数的区别
    单页面应用
    vue试题
    Git 常用命令
    【分享代码】一个笨办法获取容器的剩余内存
    【笔记】thanos receiver的router模式
    【分享】让prometheus支持PUSH模式,可以使用remote write协议推送数据
  • 原文地址:https://www.cnblogs.com/beeasy/p/8711115.html
Copyright © 2011-2022 走看看