Unity3D的内置宏 DYNAMICLIGHTMAP_ON
Table of Contents
请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com
在Unity中,DYNAMICLIGHTMAP_ON
是一个与 动态光照贴图(Dynamic Lightmaps) 相关的内置变体关键字(Shader Variant Keyword)。它的核心作用是 控制着色器是否处理动态光照贴图数据,主要用于实现动态物体的间接光照混合效果。
核心含义
-
动态光照贴图标识
- 当该宏被激活时(
#if defined(DYNAMICLIGHTMAP_ON)
),表示当前渲染的物体 启用了动态光照贴图,需要在着色器中采样动态光照贴图数据。 - 若未激活,则物体仅使用静态光照贴图或实时光照。
- 当该宏被激活时(
-
技术目的
- 允许动态物体(如可移动的物件)与烘焙的静态场景光照进行间接光交互。
- 结合 Enlighten 或 Progressive Lightmapper 系统,实现动态物体的间接光实时更新。
触发条件
该宏在以下情况下自动激活:
-
物体设置
- 物体的 Mesh Renderer 组件中勾选 Lightmap Static 为 Contribute GI,同时设置 Lightmap Parameters 为支持动态更新。
-
光照系统配置
- 项目中启用了 Realtime Global Illumination(实时全局光照)。
- 使用 Baked Indirect 或 Shadowmask 混合光照模式。
-
Shader编译指令
- 在Shader中通过
#pragma multi_compile
或#pragma shader_feature
声明动态光照贴图支持:#pragma multi_compile __ DYNAMICLIGHTMAP_ON
- 在Shader中通过
技术实现机制
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:动态光照贴图不更新
- 表现:物体移动后间接光无变化。
- 检查步骤:
- 确认 Window > Rendering > Lighting Settings 中启用了 Realtime Global Illumination。
- 确保物体的 Mesh Renderer 勾选了 Contribute GI。
- 检查动态光照贴图是否完成烘焙(观察Unity编辑器右下角进度条)。
问题2:Shader报错未定义unity_DynamicLightmap
- 解决方案:
- 包含Unity内置的全局光照库:
#include "UnityGlobalIllumination.cginc"
- 确保正确声明动态光照贴图变体:
#pragma multi_compile __ DYNAMICLIGHTMAP_ON
- 包含Unity内置的全局光照库:
问题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等)。