Unity3D的内置宏 DYNAMICLIGHTMAP_ON

Table of Contents

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com

在Unity中,DYNAMICLIGHTMAP_ON 是一个与 动态光照贴图(Dynamic Lightmaps) 相关的内置变体关键字(Shader Variant Keyword)。它的核心作用是 控制着色器是否处理动态光照贴图数据,主要用于实现动态物体的间接光照混合效果。


核心含义

  1. 动态光照贴图标识

    • 当该宏被激活时(#if defined(DYNAMICLIGHTMAP_ON)),表示当前渲染的物体 启用了动态光照贴图,需要在着色器中采样动态光照贴图数据。
    • 若未激活,则物体仅使用静态光照贴图或实时光照。
  2. 技术目的

    • 允许动态物体(如可移动的物件)与烘焙的静态场景光照进行间接光交互。
    • 结合 EnlightenProgressive Lightmapper 系统,实现动态物体的间接光实时更新。

触发条件

该宏在以下情况下自动激活:

  1. 物体设置

    • 物体的 Mesh Renderer 组件中勾选 Lightmap StaticContribute GI,同时设置 Lightmap Parameters 为支持动态更新。
  2. 光照系统配置

    • 项目中启用了 Realtime Global Illumination(实时全局光照)。
    • 使用 Baked IndirectShadowmask 混合光照模式。
  3. Shader编译指令

    • 在Shader中通过 #pragma multi_compile#pragma shader_feature 声明动态光照贴图支持:
      #pragma multi_compile __ DYNAMICLIGHTMAP_ON
      

技术实现机制

1. 数据传递

动态光照贴图信息通过以下方式传递到着色器:

  • 顶点数据:动态光照贴图坐标通过 TEXCOORD2 传递。
  • Uniform变量:动态光照贴图纹理(unity_DynamicLightmap)和采样器(samplerunity_DynamicLightmap)。

2. 着色器代码示例

struct v2f {
    float2 uv : TEXCOORD0;
    #if defined(LIGHTMAP_ON)
        float2 lightmapUV : TEXCOORD1; // 静态光照贴图UV
    #endif
    #if defined(DYNAMICLIGHTMAP_ON)
        float2 dynamicLightmapUV : TEXCOORD2; // 动态光照贴图UV
    #endif
};

half3 GetLightmapColor(v2f i) {
    half3 staticGI = 0;
    half3 dynamicGI = 0;
    
    #if defined(LIGHTMAP_ON)
        staticGI = SampleLightmap(unity_Lightmap, samplerunity_Lightmap, i.lightmapUV);
    #endif
    #if defined(DYNAMICLIGHTMAP_ON)
        dynamicGI = SampleLightmap(unity_DynamicLightmap, samplerunity_DynamicLightmap, i.dynamicLightmapUV);
    #endif
    
    return staticGI + dynamicGI; // 混合静态和动态间接光
}

应用场景

1. 动态物体间接光更新

  • 示例:场景中的可移动箱子在移动后,其表面的间接光照(如环境反射光)能根据新位置的光照环境实时更新。
  • 实现:通过动态光照贴图重新烘焙该区域的间接光,着色器通过 DYNAMICLIGHTMAP_ON 采样更新后的数据。

2. 混合光照模式

  • Shadowmask / Distance Shadowmask 模式中,动态物体的间接光依赖动态光照贴图。
  • Baked Indirect 模式下,直接光实时计算,间接光通过动态贴图更新。

性能影响与优化

模式 内存占用 GPU计算开销 适用场景
DYNAMICLIGHTMAP_ON 较高 中等 需要动态间接光的移动物体
纯静态光照贴图 完全静态的场景物件
纯实时光照 最低 全动态场景或低端设备

优化建议

  • 限制动态光照贴图的分辨率(Lightmap Parameters > Resolution)。
  • 仅在必要物体上启用动态光照贴图(通过Layer筛选)。
  • 使用 Light Probes 替代简单动态物体的间接光计算。

常见问题与解决方案

问题1:动态光照贴图不更新

  • 表现:物体移动后间接光无变化。
  • 检查步骤
    1. 确认 Window > Rendering > Lighting Settings 中启用了 Realtime Global Illumination
    2. 确保物体的 Mesh Renderer 勾选了 Contribute GI
    3. 检查动态光照贴图是否完成烘焙(观察Unity编辑器右下角进度条)。

问题2:Shader报错未定义unity_DynamicLightmap

  • 解决方案
    • 包含Unity内置的全局光照库:
      #include "UnityGlobalIllumination.cginc"
      
    • 确保正确声明动态光照贴图变体:
      #pragma multi_compile __ DYNAMICLIGHTMAP_ON
      

问题3:动态光照贴图性能开销过大

  • 优化方案
    • 降低动态物体的光照贴图分辨率。
    • 使用 Light Probes + Light Probe Proxy Volume (LPPV) 替代动态光照贴图。
    • 在URP/HDRP中使用更高效的 Screen Space Global Illumination (SSGI)

与其他光照系统的关系

系统/功能 DYNAMICLIGHTMAP_ON 的协作方式
Light Probes 动态物体优先使用光照探针,未覆盖区域回退到动态光照贴图
Enlighten 依赖Enlighten生成动态光照贴图数据(旧版Unity)
Progressive GPU 使用GPU加速烘焙动态光照贴图(新版Lightmapper)
Shadowmask 动态光照贴图存储间接光,Shadowmask处理直接光阴影

代码实践:动态/静态光照混合

v2f vert(appdata_full v) {
    v2f o;
    // 传递静态光照贴图UV
    #if defined(LIGHTMAP_ON)
        o.lightmapUV = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
    #endif
    // 传递动态光照贴图UV
    #if defined(DYNAMICLIGHTMAP_ON)
        o.dynamicLightmapUV = v.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
    #endif
    return o;
}

half4 frag(v2f i) : SV_Target {
    // 采样直接光照
    half3 directLight = CalculateDirectLighting();
    
    // 采样间接光照(静态+动态)
    half3 indirectLight = 0;
    #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
        indirectLight = GetLightmapColor(i);
    #else
        indirectLight = SampleSH(i.normalWS); // 回退到球谐光照
    #endif
    
    return half4(directLight + indirectLight, 1);
}

总结

DYNAMICLIGHTMAP_ON 是Unity实现动态全局光照的关键机制之一,通过条件编译使着色器能够适配动态间接光需求。合理运用该特性,开发者可在保持实时交互性的同时,为动态物体提供高质量的间接光照效果。需注意性能平衡,建议结合项目需求选择光照方案(动态贴图/光照探针/SSGI等)。

kumakoko avatar
kumakoko
pure coder