首页 > 代码库 > 关于Unity动态物体无法向使用使用custom shader和lightmap的物体投射阴影

关于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 Input103                 {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) : COLOR126                 {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             ENDCG137  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的效果差别很大,
完全是得不偿失的。
 
 
 
 
 
 
 
 
 



来自为知笔记(Wiz)



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