1. 项目概述:从静态烘焙到动态光影的十年跨越
如果你是从Unity 5.x甚至更早版本一路走来的开发者,提起LightMap,脑海里浮现的很可能是一段漫长而充满不确定性的等待——点击“烘焙”按钮,泡杯咖啡,祈祷不要出现漏光、接缝或者奇怪的色块。那个时代的全局光照(GI)技术,更像是一门“烘焙”的艺术,充满了手工调整和运气成分。然而,当项目升级到Unity 2022 LTS,你会发现光影世界已经发生了翻天覆地的变化。实时全局光照、混合光照、光照探针体积等技术的成熟,让“LightMap”这个词的含义,从一张静态的、预计算的光照贴图,演变为一套动态的、实时的光照解决方案体系。
这个演进过程并非一蹴而就,它伴随着渲染管线(Built-in RP, URP, HDRP)的分化、硬件性能的提升以及算法本身的革新。对于许多正在将老项目升级,或在新项目中尝试高级光照效果的团队来说,技术栈的断层感非常明显。在Unity 5.x中行之有效的设置,在2022版中可能完全失效,甚至导致性能灾难。更棘手的是,网络上充斥着不同版本、不同管线的碎片化信息,让开发者很容易掉进“坑”里。本文的目的,就是梳理从Unity 5.x到2022版这近十年间,LightMap相关核心技术的演进脉络,并聚焦于从“静态烘焙”到“支持实时更新”这一核心诉求,提供一份基于实战的、完整的避坑指南。无论你是想优化一个老项目,还是在新项目中构建一套稳健的动态光影系统,这里的内容都将为你节省大量试错时间。
2. 核心概念演进与技术选型解析
2.1 Unity 5.x时代的Enlighten与烘焙哲学
在Unity 5.x时期,全局光照的绝对主角是Enlighten预计算实时全局光照(Precomputed Realtime GI)。这套系统的设计哲学非常清晰:将复杂的间接光计算提前(烘焙)到LightMap和Light Probe中,运行时通过轻量的实时计算来更新直接光照变化对间接光的影响。它的工作流分为两步:预计算和实时更新。
- 预计算(烘焙):这是最耗时的一步。Enlighten会将场景的几何结构、材质反射率等信息,通过辐射度算法(Radiosity)预计算物体表面之间的光线反弹,生成光照贴图(Lightmap)和光照探针(Light Probe)数据。此时的Lightmap是静态的,存储了场景的“基础照明”信息。
- 实时更新:当场景中的实时光源(如Directional Light设置为Realtime)移动或改变强度时,Enlighten会利用预计算好的“传输路径”信息,快速近似地计算出这些变化对间接光照的影响,并动态更新光照探针和部分Lightmap(如果启用)。这实现了“实时全局光照”的视觉效果。
避坑点1:对“实时”的误解。很多开发者误以为Enlighten Realtime GI是完全实时的。实际上,它的“实时”建立在沉重的预计算基础上。预计算时间随场景复杂度呈指数级增长,且对场景结构有严格要求(需封闭、需UV2)。一旦场景改动,就需要重新预计算,这在大型项目迭代中是不可承受之痛。因此,在Unity 5.x后期,很多项目实际上只使用其Baked GI模式,即完全烘焙静态光照,放弃实时更新,以换取稳定的效果和烘焙时间。
2.2 Unity 2018-2020:Progressive GPU Lightmapper的崛起与管线分化
Unity 2018引入了基于GPU的Progressive Lightmapper(渐进式光照贴图器),这是一个革命性的变化。它采用路径追踪(Path Tracing)算法,能够生成噪点逐渐减少、视觉上无偏的、电影级质量的光照贴图。相比CPU版的Enlighten,Progressive(尤其是GPU模式)烘焙速度有数量级的提升,并且对场景的封闭性要求降低。
与此同时,可编程渲染管线(SRP)的推出带来了URP和HDRP。这直接导致了光照系统的分化:
- Built-in RP(内置渲染管线):继续支持Enlighten和Progressive Lightmapper,是旧项目兼容的基石。
- URP(通用渲染管线):在早期版本中,URP对Enlighten的支持不完整,主要推动使用Progressive Lightmapper进行完全烘焙(Baked Lighting)。其实时全局光照能力较弱,更多依赖光照探针和屏幕空间技术(如SSGI)。
- HDRP(高清渲染管线):作为高端管线,它很早就弃用了Enlighten,全面转向Progressive Lightmapper进行光照烘焙,并大力推广实时光线追踪(Ray Tracing)和屏幕空间全局光照(SSGI)作为其实时动态全局光照方案。
技术选型决策点:在这个阶段,选择哪种方案,首先取决于你选择的渲染管线。如果坚持Built-in RP,可以延续Enlighten的工作流;如果使用URP/HDRP,Progressive烘焙是更现代、更高效的选择。但需要注意的是,Progressive Lightmapper在当时主要定位是烘焙器,其“实时更新”能力并不如Enlighten那样是原生设计的一部分。
2.3 Unity 2021-2022:实时GI的现代化方案与最佳实践
来到Unity 2022 LTS,技术格局已经非常清晰。Enlighten技术已被官方标记为“Legacy”,不再推荐用于新项目。现代Unity的“LightMap技术栈”应该被理解为“静态光照烘焙” + “动态全局光照”的组合。
静态光照烘焙(基石):Progressive Lightmapper(GPU)已成为所有管线下高质量静态光照烘焙的绝对标准。它快速、高质量,用于处理所有静态(Static)物体和静态光源(Baked Light)的照明,生成最终的Lightmap Atlas。这是场景光照的基底,性能消耗为零(运行时仅采样贴图)。
动态全局光照(实时更新):这才是实现“实时更新”效果的核心。根据管线不同,主要有以下方案:
- Built-in RP / URP:
- 光照探针(Light Probes) + 反射探针(Reflection Probes):这是最经典、性能最好的动态物体全局光照方案。通过在被动态物体包围的空间中布置探针网络,动态物体在移动时混合邻近探针的数据,从而获得变化的间接光和反射。这是实现“实时更新”视觉效果的骨干技术。你需要精心布置探针密度,在走廊、转角处加密。
- 屏幕空间全局光照(SSGI):URP包中提供的后处理效果。它根据屏幕深度和法线信息,估算屏幕内像素的间接光反射。优点是无需预计算,完全实时,对动态场景友好。缺点是视野外、被遮挡的物体无法贡献间接光,且容易有屏幕空间算法的典型瑕疵(如边缘泄露)。
- HDRP:
- 实时光线追踪全局光照(Ray Traced GI):这是最高质量的实时方案,通过追踪光线模拟真实的物理反弹。效果极佳,但需要高端RTX显卡,性能开销巨大。
- 屏幕空间全局光照(SSGI):HDRP中的SSGI效果更佳,作为Ray Traced GI的降级或补充方案。
- 光照探针体积(Light Probe Volumes):HDRP中光照探针的升级版,将探针组织成3D体积网格,能为大型动态物体(如角色)提供更精确、渐变的间接光照,避免了传统探针混合的突兀感。
- Built-in RP / URP:
避坑点2:混淆“烘焙”与“实时”的目标。很多开发者追求“完全实时的光影更新”,这在不使用光线追踪的情况下是不现实的。现代最佳实践是:用Progressive Lightmapper烘焙好绝大部分静态环境的精美光照(作为基底),然后用光照探针/SSGI/Ray Tracing来处理动态物体和光源移动带来的光照变化。这样既保证了质量,又平衡了性能。
3. 从烘焙到实时更新的完整工作流与实操
3.1 场景准备与模型规范(跨版本通用)
无论技术如何演进,良好的场景和模型规范是高质量光照的基础。
模型导入设置:
- 生成光照贴图UV(Lightmap UV):在模型导入设置中,务必勾选“Generate Lightmap UVs”。这会让Unity为模型自动生成第二套UV(UV1),用于展开Lightmap,避免与主UV(UV0)重叠导致纹理错误。对于复杂模型,自动生成的UV可能有过大的拉伸或重叠,需要使用3D软件手动展好第二套UV。
- 注意:Unity 2022中,对于使用Progressive Lightmapper的模型,有时需要检查模型的“Scale in Lightmap”参数是否合理,过大或过小都会影响烘焙质量和Atlas利用率。
场景物体标记(Static vs Dynamic):
- 将所有永远不会移动、旋转、缩放的物体(如地形、建筑、大型道具)标记为Static。这包括在Inspector右上角勾选“Static”下拉菜单中的“Contribute GI”和“Occluder Static”等。Static物体才能被烘焙进Lightmap。
- 所有需要移动的物体(角色、车辆、可交互道具)绝对不能标记为Static。它们的光照将完全依赖于实时光源、光照探针和反射探针。
光源设置与模式选择:
- Mixed(混合)模式:这是实现“静态基底+动态更新”的关键光源类型。一个Mixed模式的Directional Light(方向光,常作为太阳/月亮)会将其直接光照部分实时渲染,同时将其间接光照部分烘焙到Lightmap中。当它移动(如昼夜循环)时,直接光实时变化,间接光(通过探针)也能近似更新。
- Realtime(实时)模式:光源完全动态,不参与烘焙,每帧计算。性能开销大,常用于手电筒、车灯等小范围特效光源。
- Baked(烘焙)模式:光源效果完全烘焙到Lightmap中,运行时无性能消耗。适用于静态的室内灯泡、霓虹灯等。
3.2 静态光照烘焙配置(以Progressive Lightmapper为例)
打开Window > Rendering > Lighting (Unity 2022中为Lighting Settings)。
- Lightmapper选择:在“Lighting Settings”中,选择Progressive GPU(首选)或Progressive CPU。GPU烘焙速度远快于CPU。
- 光照贴图分辨率与参数:
- Lightmap Resolution:单位是“每单位纹素(texels per unit)”。值越高,Lightmap越清晰,但贴图尺寸和烘焙时间也越长。室内细节场景可能需要30-50,大型户外场景10-20即可。可以通过物体的“Scale in Lightmap”属性(在Mesh Renderer组件中)微调单个物体在Lightmap中的占比。
- Lightmap Padding:烘焙图集中各图表之间的间隔,防止采样时边缘渗色。通常2-10像素,分辨率越高,Padding可以相对设小。
- Max Lightmap Size:最终生成的图集大小。2048或4096是常见选择。Unity会自动将多个物体的光照信息打包到一张或多张这个尺寸的图集中。
- 环境光设置:
- Environment Lighting> Source:设置为“Color”或“Gradient”来定义场景的基础环境光(天空颜色)。对于烘焙,更推荐使用Skybox Material,并确保该天空盒材质被分配到Lighting窗口的“Environment”栏中,这样烘焙出的环境反射才准确。
- Environment Reflections> Source:同样设置为Skybox,用于烘焙反射探针或物体的环境反射。
- 开始烘焙:点击“Generate Lighting”按钮。Progressive Lightmapper会以渐进方式显示预览,你可以随时暂停查看效果,满意后再等待其完成最终烘焙。
实操心得:烘焙前,务必在“Lighting Settings”的“Scene”标签页下,点击“Baked Lightmaps”旁边的“...”菜单,选择“Delete Baked Data”,清除旧的烘焙数据,避免残留数据干扰。
3.3 实现动态光照更新:光照探针网络部署
这是让动态物体融入已烘焙静态场景的灵魂步骤。
- 创建光照探针组:GameObject > Light > Light Probe Group。将其放置在场景中。
- 布置探针:
- 原则:在动态物体可能活动的所有空间均匀布置。想象一个3D网格。
- 关键区域加密:在门口、走廊、楼梯、转角等光照变化剧烈的区域,需要增加探针密度。在开阔且光照均匀的区域,可以稀疏布置。
- 避免放置:不要将探针放在物体内部、或贴墙放置。探针应该位于动态物体可以到达的“自由空间”中。
- 使用“Selected Positions”模式:在Light Probe Group组件中,可以框选多个探针进行复制、对齐等操作,提高布局效率。
- 烘焙探针:布置好后,再次点击“Generate Lighting”。这次烘焙不仅会更新Lightmap,也会计算每个光照探针位置的颜色和强度信息。烘焙完成后,动态物体(MeshRenderer)只要其“Use Light Probes”选项为开启状态(默认开启),在移动时就会自动混合邻近探针的数据,从而获得与当前位置匹配的间接光照。
避坑点3:探针数量与性能。探针数据是运行时加载到内存中的。一个拥有成百上千个探针的大型场景,其数据量不容小觑。务必使用遮挡剔除(Occlusion Culling)来确保不在视野内的探针数据不被加载。同时,在性能敏感的平台(如移动端),需要严格控制探针总数。
3.4 在URP/HDRP中启用屏幕空间全局光照(SSGI)
对于URP和HDRP,SSGI提供了一个无需预布置探针的实时更新方案。
URP:
- 安装URP包(如未安装)。
- 在Project Settings > Graphics中,将URP Asset分配给“Scriptable Render Pipeline Settings”。
- 在主相机或后处理体积(Volume)中,添加“Screen Space Global Illumination”后处理覆盖。
- 调整参数,如“Ray Step”、“Intensity”等。SSGI效果很依赖屏幕分辨率和场景深度精度,可能需要仔细调校。
HDRP:
- 在HDRP Asset中,确保“Frame Settings” > “Lighting”下的“Screen Space Global Illumination”已启用。
- 在场景中创建一个后处理体积(Volume),并将其设置为“Global”。
- 在该Volume的Override中,添加“Screen Space Global Illumination”并启用它,调整参数。
注意事项:SSGI是屏幕空间效果,这意味着它只能处理摄像机能看到的内容。对于封闭房间内的动态物体,如果光源在房间外,SSGI可能无法计算出正确的间接光。此时,光照探针仍然是更可靠的选择。通常建议将SSGI作为探针网络的视觉质量补充,而非完全替代。
4. 版本升级与项目迁移中的核心避坑指南
将Unity 5.x项目升级到2022版,光照部分是最容易出问题的环节之一。
4.1 从Enlighten迁移到Progressive Lightmapper
- 备份项目:这是第一步,也是最重要的一步。
- 更改Lightmapper:在Lighting Settings中,将Lightmapper从“Enlighten”切换到“Progressive (GPU)”。
- 检查所有光源模式:Enlighten时代的“Realtime”和“Baked”模式在Progressive下基本对应,但“Mixed”模式的行为可能有细微差别,特别是间接光的质量。需要重新审视Mixed光源的效果。
- 重新生成光照贴图UV:对于导入的模型,检查其导入设置。有时从旧项目升级后,模型的“Generate Lightmap UVs”设置可能丢失或需要重新生成以适配新的Lightmapper。选中所有关键模型,在Model Importer中重新应用此设置。
- 彻底清除旧数据并重新烘焙:
- 删除Library文件夹下的“Lightmap-”开头的缓存文件(操作前请关闭Unity)。
- 在Unity中,通过Lighting Settings窗口删除所有Baked和Realtime GI数据。
- 重新布置光照探针组(旧探针数据可能不兼容)。
- 执行一次完整的Progressive烘焙。这个过程可能比Enlighten预计算快很多,但首次需要等待。
4.2 渲染管线迁移带来的光照问题
如果你从Built-in RP迁移到URP/HDRP,问题会更复杂。
- 材质丢失/变粉红:这是最常见问题。所有使用内置Standard Shader或旧版自定义Shader的材质都会失效。解决方案是使用Unity的材质升级工具(Edit > Render Pipeline > Universal Render Pipeline / HD Render Pipeline > Upgrade Project Materials...)。但此工具并非万能,对于复杂的自定义Shader,需要手动重写或寻找URP/HDRP的等效Shader。
- 光照强度异常:URP/HDRP使用物理光照单位,而Built-in RP使用任意单位。升级后,所有光源的强度(Intensity)值可能看起来过高或过低。需要根据新的PBR标准重新调整。例如,一个明亮的日光Directional Light在HDRP中强度可能在60,000到100,000 lux之间,而在URP中可能只需要1-3。
- 光照贴图不显示:确保在URP/HDRP的管线资源(Pipeline Asset)中,相关的光照设置已启用。在URP中,检查URP Asset中的“Lighting”设置,确保“Baked Global Illumination”已开启。在HDRP中,检查HDRP Asset的“Lighting”部分。
- 阴影问题:URP/HDRP的阴影质量和距离是独立配置的。升级后可能需要重新调整主方向光的阴影距离(Shadow Distance)和分辨率,以及相机的远裁剪平面。
4.3 性能优化与常见问题排查
Lightmap Atlas过多或尺寸过大:
- 问题:运行时加载大量巨型Lightmap,导致内存激增和DrawCall上升。
- 排查:在Lighting Settings的“Lightmaps”标签页查看生成的图集数量和尺寸。检查是否有大量小物体被分配了过高的“Scale in Lightmap”值。
- 解决:降低全局的“Lightmap Resolution”;合理设置物体的“Scale in Lightmap”(不重要的小物件可以调低至0.1-0.5);尝试使用“Lightmap Parameters”来对不同类别的物体应用不同的烘焙设置。
光照接缝(Seams):
- 问题:在物体边缘或Lightmap图块边界出现明显的颜色或亮度断层。
- 原因:通常是光照贴图UV展开不当,导致相邻表面在Lightmap Atlas上被分得太开,或者Padding值太小导致边缘采样了邻居的颜色。
- 解决:检查问题模型的Lightmap UV(在模型导入设置预览);适当增加“Lightmap Padding”;对于复杂静态物体,考虑将其拆分为多个子物体分别烘焙,有时能获得更好的UV分布。
动态物体光照闪烁或突变:
- 问题:角色移动时,身上的间接光突然跳变。
- 原因:光照探针布置太稀疏,动态物体在两个探针间跳跃式混合。
- 解决:在动态物体的行走路径上加密光照探针。使用Light Probe Proxy Volume (LPPV)(HDRP中为Light Probe Volume)来处理大型动态物体(如公交车),它能提供更平滑的体积内插值,避免“像素级”的探针跳跃感。
烘焙时间过长:
- 排查:检查场景中是否有面数极高且标记为Static的物体;检查Lightmap Resolution是否设置过高;确认使用的是Progressive GPU而非CPU。
- 解决:对远处或细节不重要的静态物体,降低其“Scale in Lightmap”甚至取消其“Contribute GI”标记;使用遮挡剔除将不可见区域排除在烘焙计算之外;分层烘焙,先烘焙大块基础光照,再单独烘焙细节区域。
5. 实战案例:构建一个支持昼夜循环的动态场景
让我们通过一个具体案例,串联起上述所有知识点。目标:在一个拥有静态建筑和地形、动态角色和车辆的开放场景中,实现一个平滑的、光照效果正确的昼夜循环系统。
步骤1:场景基础设置
- 导入所有静态模型(建筑、道路、山体),确保它们已正确生成Lightmap UV,并标记为Static。
- 导入动态模型(角色、汽车),不标记为Static。
- 创建一个Directional Light作为太阳,将其模式设置为Mixed。这是实现昼夜循环的关键。
步骤2:布置静态光照与探针网络
- 根据场景规模,在Lighting Settings中设置合适的Lightmap Resolution(例如15)和Max Lightmap Size(4096)。
- 在场景中均匀布置一个基础的光照探针组(Light Probe Group),覆盖所有道路和角色活动区域。在建筑入口、树下阴影区加密探针。
- 在室内、隧道等封闭空间内部,单独布置高密度的探针组,以捕获准确的局部间接光。
- 点击“Generate Lighting”,使用Progressive GPU进行完整烘焙。此时,静态场景拥有了精美的光照,探针也记录了各位置的光照信息。
步骤3:实现昼夜循环脚本为Directional Light编写一个简单的旋转脚本,模拟太阳东升西落。关键是,在旋转过程中,光源的“Mode”始终保持为Mixed。
using UnityEngine; public class DayNightCycle : MonoBehaviour { public float dayDurationInSeconds = 120f; // 一天游戏时间对应的真实秒数 public float startRotationX = 0f; // 起始角度,例如0为清晨 void Update() { // 计算当前时间比例 float timeRatio = Time.time / dayDurationInSeconds; // 将时间比例映射到360度旋转(可根据需要调整旋转轴) float currentRotation = startRotationX + (timeRatio * 360f); // 应用旋转,这里绕X轴旋转模拟太阳轨迹 transform.rotation = Quaternion.Euler(currentRotation, -30f, 0f); // -30f可以模拟一定的纬度倾斜 // 可选:根据太阳高度角调整光强和颜色 Light sunLight = GetComponent<Light>(); float angle = currentRotation % 360; if (angle > 180) angle = 360 - angle; // 处理过顶后的角度 // 简单示例:太阳在地平线以下时强度为0,在头顶时最强 float intensityFactor = Mathf.Clamp01(angle / 90f); sunLight.intensity = Mathf.Lerp(0f, 1.2f, intensityFactor); // 根据管线调整基准强度 // 调整颜色:黄昏/黎明偏红黄,正午偏白 if (angle < 20f) { sunLight.color = Color.Lerp(Color.red, Color.white, angle / 20f); } else { sunLight.color = Color.white; } } }步骤4:验证动态光照更新
- 运行游戏。观察静态场景(建筑、地面)的光照。由于太阳是Mixed光,其直接光照部分会实时变化(阴影方向、亮度),而间接光照部分(建筑背光面的亮度)已经被烘焙到Lightmap中,不会实时变化。这是正确的,因为建筑是Static的。
- 控制动态角色在场景中移动。你会发现,角色身上的光照(特别是阴影下的部分)会随着位置和太阳角度的变化而平滑变化。这是因为角色在实时采样并混合周围光照探针的数据,而探针捕获的正是Mixed光源实时变化的直接光对周围环境的“第一次反弹”影响(虽然探针数据是烘焙时预计算的传输路径,但混合权重在实时更新)。同时,太阳的直接光也实时照射在角色身上。
- 如果角色进入一个布置了室内探针的房间,即使太阳在室外,角色也能获得室内正确的间接光照。
步骤5:增强效果与优化
- 反射更新:创建数个反射探针(Reflection Probe),设置为“Baked”或“Custom”,并在昼夜变化的关键角度(如正午、黄昏)手动烘焙,或者使用脚本在运行时动态混合,以更新场景中的反射效果(如窗户、水面)。
- 启用SSGI(URP/HDRP):在URP或HDRP中,为相机添加Screen Space Global Illumination效果。这将为动态物体和静态物体的屏幕像素增加额外的、实时的间接光反射细节,让阴影内部的色彩更加丰富、真实,尤其是对于快速变化的直接光(如移动的太阳)产生的次级反弹。
- 性能监控:在Profiler中监控“Rendering”和“Memory”模块。观察Draw Calls是否因Lightmap过多而上升,以及光照探针数据的内存占用。根据性能瓶颈,调整Lightmap分辨率、探针数量或SSGI的采样数。
通过这个案例,你可以清晰地看到现代Unity光照系统的分工协作:Progressive Lightmapper负责高质量的静态基底,Mixed光源和光照探针网络负责驱动动态物体光照的实时更新,SSGI等屏幕空间技术负责补充高质量的视觉细节。这套组合拳,正是从Unity 5.x到2022版,LightMap技术演进所指向的、兼顾质量与性能的现代化解决方案。