关于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的效果差别很大,

完全是得不偿失的。

来自为知笔记(Wiz)

时间: 2024-07-31 14:31:17

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

[Unity][Heap sort]用Unity动态演示堆排序的过程

[Unity][Heap sort]用Unity动态演示堆排序的过程 How Heap Sort Works 最近做了一个用Unity3D动态演示堆排序过程的程序. I've made this heap sort demo to show how heap sort works recently. 效果图(Demo) 一图抵千言. A picture paints a thousand words. 您可以在此查看完整的动态GIF效果图.博客园里放不下这么大的GIF图. 链接:http://p

Unity游戏开发的数学与物理 2 ( 通过键盘控制物体的运动 )

通过键盘控制物体的运动 实现需注意: 获取键盘相应的方法 边界检测 合力方向的速度处理 勾股定理 using UnityEngine; using System.Collections; //通过键盘控制物体的运动 public class KeyControlMotionTest : MonoBehaviour { //物体的X位置 float posX = 0; //物体的Y位置 float posY = 0; //物体在x方向上的速度 float speedX = 1; //物体在y方向上

【Unity Shaders】使用CgInclude让你的Shader模块化——Unity内置的CgInclude文件

本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源(当然你也可以从官网下载). ========================================== 分割线 ========================================== 写在前面 啦啦啦,又开了新的一章...为什么会讲CgInclude呢?什么又是Cg呢?呜,按我的理解

Unity动态对象优化

对于静态对象,Unity可以使用通过勾选Static,然后让Unity自身进行优化Draw Calls,但是对于动态对象,Unity在这方面没有处理,这就需要我们自己去实现,实现的原理就是首先去遍历每个对象的SkinnderMeshRenderer,然后将其所有的动态对象组合成一个大的对象并且将骨骼动画赋值给他,这样,我们就实现了动态对象的优化,代码如下: public static void CombineToMesh(GameObject _go)     {         Skinned

Unity动态改变src的解决方法

在c#程序(winform,wpf)中可以嵌入unity控件,从而实现三维场景.通过设置unity控件的src属性来设置场景,然而src必须是绝对路径,而且只能在设计器进行设置,不能在代码中动态修改,这在需要运行时动态切换场景的时就悲剧了.当然网上有很多关于Unity 如何动态改变src的方法,其方法是正确的,最大的问题莫过于没有说明代码该放在什么地方,干着急. 下面假设unity控件的文件Unity3dControl.cs,那么打开Unity3dControl.designer.cs,找到函数

Unity动态更换图片

博主写的是五秒倒计时后开始游戏,用图片显示倒计时数字,由于初学Unity所以方法可能不太好,但不失为一种解决方法. using UnityEngine; using System.Collections; using UnityEngine.UI;//别忘加了 public class GameController : MonoBehaviour { public Sprite five; public Sprite four; public Sprite three; public Sprit

unity 动态更新模型透明度

RaycastHit[] hits; Vector3 normal = transform.position - target.position; hits = Physics.RaycastAll(target.position, normal, float.PositiveInfinity, mMask); if (hits.Length>0) { GameObject p = hits[0].collider.gameObject; if (p != null) { Debug.LogEr

Unity动态创建FBX模型配置文件的存放路径

创建前目录结构: 创建后的目录结构: using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.IO; using System.Text; public class BuildTool { [MenuItem("BuildTool/RefreshCloth/RefreshSelectClothConfig")] stati

关于unity里pbr技术和材质 unity5默认shader和传统的对比

刚开始也不知道什么是pbr (Physically Based Rendering)后来才发现这是一种新的渲染方式 与之对应的是材质是pbs(Physically Based Shader) unity中的pbs有两种,一种是金属度的,一种是反射的, 具体前者可以做金属泥土之类,后者用于其他非金属的,但是这不绝对,前者也能做布料木头之类 最终使用还是要看艺术效果 (unity中金属度pbr材质) (unity中反射流程pbr材质) PBR做法 albedo map 无光颜色贴图normal ma