關於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的效果差別很大,
完全是得不償失的。
 
 
 
 
 
 
 
 
 






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM