关于Unity动态物体无法向使用使用custom shader和lightmap的物体投射阴影

  最近在做unity shader forge和marmoset的优化,TA那边遇到了一个阴影显示的问题,具体如下:

  在Forward Rendering状态下,静态场景使用了是shader forge生成的blendlayer类的shader,使用lightmap烘培贴图后,动态角色走到静态物体附近时,方向光在角色上的投影,无法投射到使用shader forge材质的物体上,但其他材质和使用marmoset的材质可以正常接收。查询了一些网站解决方案后,最终确定是custom shader 写法的问题,shader forge生成的shader属于自己实现vs和ps的功能,和写surface shader不同,除了着色用的shader pass("LightMode" = "ForwardBase")外需要Cast shadow用的第2个pass {"LightMode" = "ForwardAdd"}。
 
下面是一个参考方案的代码
  1.   1 "Test" {
      2     SubShader {
      3         Tags { "RenderType" = "Opaque"}
      4 
      5         // This pass acts the same as the surface shader first pass.
      6         // Calculates per-pixel the most important directional light with shadows,
      7         // then per-vertex the next 4 most important lights,
      8         // then per-vertex spherical harmionics the rest of the lights,
      9         // and the ambient light value.
     10  
     11         Pass {
     12             Tags {"LightMode" = "ForwardBase"}
     13             CGPROGRAM
     14 
     15                 #pragma multi_compile_fwdbase
     16                 #pragma vertex vert
     17                 #pragma fragment frag
     18                 #pragma fragmentoption ARB_precision_hint_fastest
     19                 #include "UnityCG.cginc"
     20                 #include "AutoLight.cginc"
     21  
     22                 struct Input
     23                 {
     24                     float4 pos : SV_POSITION;
     25                     float3 vlight : COLOR;
     26                     float3 lightDir : TEXCOORD1;
     27                     float3 vNormal : TEXCOORD2;
     28                     LIGHTING_COORDS(3,4)
     29                 };
     30  
     31                 Input vert(appdata_full v)
     32                 {
     33                     Input o;
     34                     o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
     35                     // Calc normal and light dir.
     36                     o.lightDir = normalize(ObjSpaceLightDir(v.vertex));
     37                     o.vNormal = normalize(v.normal).xyz;
     38  
     39                     // Calc spherical harmonics and vertex lights. Ripped from compiled surface shader
     40                     float3 worldPos = mul(_Object2World, v.vertex).xyz;
     41                     float3 worldNormal = mul((float3x3)_Object2World, SCALED_NORMAL);
     42                     o.vlight = float3(0);
     43                     #ifdef LIGHTMAP_OFF
     44  
     45                         float3 shlight = ShadeSH9(float4(worldNormal, 1.0));
     46                         o.vlight = shlight;
     47                         #ifdef VERTEXLIGHT_ON
     48                             o.vlight += Shade4PointLights (
     49  
     50                                 unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
     51  
     52                                 unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
     53  
     54                                 unity_4LightAtten0, worldPos, worldNormal
     55  
     56                                 );
     57  
     58                         #endif // VERTEXLIGHT_ON
     59                     #endif // LIGHTMAP_OFF
     60                     TRANSFER_VERTEX_TO_FRAGMENT(o);
     61                     return o;
     62                 }
     63  
     64                 float4 _LightColor0; // Contains the light color for this pass.
     65 
     66                 half4 frag(Input IN) : COLOR
     67                 {
     68                     IN.lightDir = normalize ( IN.lightDir );
     69                     IN.vNormal = normalize ( IN.vNormal );
     70  
     71                     float atten = LIGHT_ATTENUATION(IN);
     72                     float3 color;
     73                     float NdotL = saturate( dot (IN.vNormal, IN.lightDir ));
     74                     color = UNITY_LIGHTMODEL_AMBIENT.rgb * 2;
     75  
     76                     color += IN.vlight;
     77  
     78                     color += _LightColor0.rgb * NdotL * ( atten * 2);
     79                     return half4(color, 1.0f);
     80                  }
     81  
     82             ENDCG
     83         }
     84  
     85         // Take this pass out if you don't want extra per-pixel lights.
     86         // Just set the other lights' Render Mode to "Not Important",
     87         // and they will be calculated as Spherical Harmonics or Vertex Lights in the above pass instead.
     88  
     89         Pass {
     90  
     91             Tags {"LightMode" = "ForwardAdd"}
     92  
     93             CGPROGRAM
     94 
     95                 #pragma multi_compile_fwdadd
     96                 #pragma vertex vert
     97                 #pragma fragment frag
     98                 #pragma fragmentoption ARB_precision_hint_fastest
     99                 #include "UnityCG.cginc"
    100                  #include "AutoLight.cginc"
    101 
    102                 struct Input
    103                 {
    104                     float4 pos : SV_POSITION;
    105                     float3 lightDir : TEXCOORD1;
    106                     float3 vNormal : TEXCOORD2;
    107                 }; 
    108  
    109                 Input vert(appdata_full v)
    110                  { 
    111                     Input o;
    112                     o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    113  
    114                     // Calc normal and light dir.
    115                     o.lightDir = normalize(ObjSpaceLightDir(v.vertex));
    116                     o.vNormal = normalize(v.normal).xyz;
    117  
    118                     // Don't need any ambient or vertex lights in here as this is just an additive pass for each extra light.
    119                     // Shadows won't work here, either.
    120                     return o;
    121                 }
    122   
    123                 float4 _LightColor0; // Contains the light color for this pass.
    124 
    125                 half4 frag(Input IN) : COLOR
    126                 {
    127                     IN.lightDir = normalize ( IN.lightDir );
    128                     IN.vNormal = normalize ( IN.vNormal );
    129                  
    130                     float3 color;
    131                     float NdotL = saturate( dot (IN.vNormal, IN.lightDir ));
    132                     color = _LightColor0.rgb * NdotL;
    133                     return half4(color, 1.0f); 
    134                 }
    135 
    136             ENDCG
    137  
    138         }
    139     }
    140  
    141     FallBack "Diffuse"
    142  
    143 }
 
而使用surface shader时候,只需要在声明surface时,设置制定的option(fullforwardshadows)就可以了
  1. #pragma surface MarmosetSurfMarmosetDirect vertex:MarmosetVert fullforwardshadows
回过头来说shader forge插件,场景左侧使用sf生成的shader,use lightmap后,实时阴影果断看不到了
 
左边木板为surface shader,右边为VS+PS Shader,阴影无法投射到石头上
 
将shader forge设置为multi-light,他会自动生成ForwardAdd的pass,这样阴影就显示出来了。但照明效果也完全变了样子
 
这个问题,在shader forge的论坛上也有提过,作者也说修改过这个bug了,但实际上最新的0.36还是没有完全解决
 
如果设置ForwardAdd后还没有投影,可以把light的lightmapping 设置为realtimeOnly。或者是再复制一个投影的主光源。

 
结论,Shader forge还是慎用吧,而且shader node也远没有比sky shop这类 uber shader要节省,为了投影,导致使用lightmap和real time的效果差别很大,
完全是得不偿失的。
 
 
 
 
 
 
 
 
 





原文地址:https://www.cnblogs.com/TracePlus/p/4023913.html