1. 项目概述:为什么你的烘焙总是“翻车”?
如果你在Unity里做过灯光烘焙,大概率经历过这样的场景:场景摆好了,灯光打上了,满怀期待地点下“Generate Lighting”,然后看着进度条缓慢爬升,最后得到一个要么一片死黑、要么曝光过度、要么阴影诡异的结果。更让人头疼的是,你调整了几个参数,重新烘焙,又是漫长的等待,结果可能更糟。问题出在哪?很多时候,根源就在于对“Static”标记和灯光模式(Mixed与Baked)的理解不够透彻,设置上“乱勾一气”。
Unity的全局光照(GI)系统非常强大,但它的工作逻辑和我们直觉中的“实时打光”有很大不同。它本质上是一个预计算系统,需要你明确地告诉引擎:哪些东西是静止不动的(Static),哪些灯光需要参与这种预计算(Baked/Mixed)。错误地标记一个动态物体为Static,或者为动态灯光错误地选择了Baked模式,都会导致光照贴图计算错误、内存浪费,甚至运行时出现严重的视觉错误。这篇指南的目的,就是帮你彻底理清Static、Mixed灯光、Baked灯光这三者之间的关系,避开那些常见的“坑”,让你能高效、精准地控制场景光照,得到预期中的烘焙效果。无论你是正在为项目性能优化头疼的TA,还是试图让场景看起来更棒的场景美术,这些内容都至关重要。
2. 核心概念拆解:Static、Baked、Mixed到底指什么?
在深入实操之前,我们必须像认识新朋友一样,搞清楚这三个核心术语的“性格”和“职责”。理解它们,是避免所有混乱的第一步。
2.1 Static:不是“静止”,而是“可被预计算”
很多新手会把GameObject Inspector面板右上角的“Static”复选框简单地理解为“这个物体不会动”。这个理解对了一半,但更本质的理解是:标记为Static的物体,其几何信息(顶点、法线、UV等)可以被光照系统用于预计算。
注意:这里的“Static”与C#编程中的
static关键字完全无关。它纯粹是Unity编辑器针对场景物件的一个标记,用于光照、导航、遮挡剔除等系统的预计算。
当你勾选一个物体的Static时,你实际上是对多个系统做出了承诺:
- 对光照系统:我的网格和位置在运行时不会改变,你可以放心地把光照信息(亮度、颜色、阴影)“烘焙”到我的表面(即光照贴图)上。
- 对导航系统:我是障碍物或可走地面,AI可以基于我生成导航网格。
- 对遮挡剔除系统:我的形状可以用来判断能否挡住后面的物体。
为什么不能乱勾?
- 动态物体勾了Static:如果一个小怪被你标记为Static,但代码里让它移动了。那么,它身上烘焙的光照贴图不会跟着它移动,会导致它无论跑到哪里,都带着最初位置的光照和阴影,看起来极其诡异,像是个“鬼影”。
- 性能浪费:不必要的Static标记会增加光照贴图的计算量、存储量(更大的光照贴图纹理)和内存占用。一个复杂的、有大量细小零件的装饰物,如果完全不会受到动态光照影响,且自身也不移动,那么标记为Static是合适的。但如果它只是一个简单的背景板,或许有更优的处理方式。
实操心得:我的习惯是在项目初期就建立规范。通常,大型环境建筑、地面、山脉等绝对静止的物体才勾选Static。中小型道具根据情况决定:如果它永远待在同一个角落,且需要接受高质量的间接光,可以勾;如果它可能被玩家移动、拾取,或者场景中有动态光会影响到它,就一定不要勾。你可以利用图层(Layer)来批量管理Static物体,例如创建一个“StaticGeometry”层,专门放置这些物体。
2.2 Baked(烘焙)灯光:一劳永逸的“画师”
Baked模式的灯光,其所有光照贡献(直接光、间接光、阴影)都会被永久性地“画”到Static物体的光照贴图上。一旦烘焙完成,这颗灯光在运行时就不再进行任何实时光照计算。
工作原理:
- 引擎模拟光线从该灯光发出。
- 光线与场景中所有标记为Static的物体进行交互(反弹、吸收、投射阴影)。
- 将这些交互产生的明暗、颜色信息,计算并编码成纹理(即光照贴图),存储在磁盘上。
- 运行时,直接将这张纹理贴到对应的Static物体表面。灯光物体本身可以被禁用甚至删除,不影响视觉效果。
优点:
- 性能极佳:运行时零光照计算开销,非常适合低端设备或需要大量固定光源的复杂静态场景(如室内装修、复杂建筑)。
- 效果顶级:可以计算非常复杂的间接光反弹、柔和阴影、全局光照效果,因为计算是在编辑时进行的,不受运行时帧时间限制。
缺点与避坑点:
- 只影响Static物体:这是最大的限制。Baked灯光无法照亮任何非Static的物体(如玩家角色、移动的NPC)。如果你发现角色在烘焙好的场景里一片漆黑,首先检查灯光模式。
- 无法动态变化:灯光颜色、强度、位置在运行时不能改变。想象一个烘焙了阳光的场景,你无法做出昼夜循环。
- 光照贴图尺寸与内存:高质量烘焙需要大的光照贴图尺寸,这会增加构建体积和运行时内存。需要权衡。
典型应用场景:太阳光(如果不需要昼夜变化)、室内固定的壁灯、吊灯、橱窗灯等所有位置、参数固定,且只需要照亮静态环境的灯光。
2.3 Mixed(混合)灯光:动静结合的“魔术师”
Mixed模式是Unity GI系统的精髓,它试图在效果和性能之间取得平衡。一颗Mixed模式的灯光,其光照贡献会被拆分成两部分:
- 直接光(Direct Light):以实时方式计算。意味着它每帧都会计算,可以照亮所有物体(Static和Non-Static),并且其颜色、强度、位置可以实时改变。
- 间接光(Indirect Light):以烘焙方式计算。只有它照射到Static物体后产生的反弹光(间接光照)会被烘焙到光照贴图中。
工作原理(以Shadowmask模式为例,这是最常用的工作流):
- 烘焙阶段:Mixed灯光像Baked灯光一样,计算其对Static物体的间接光照,并将其烘焙到光照贴图中。同时,它还会为Static物体生成一张额外的“阴影遮罩(Shadowmask)”纹理,这张纹理记录了“这个Static表面的点,应该受到哪盏实时灯的阴影影响”。
- 运行阶段:
- 对Static物体:直接光实时计算并投射实时阴影(或使用Shadowmask),叠加已烘焙的间接光。这实现了静态物体也能有动态阴影,且间接光效果高质量。
- 对非Static物体:直接光实时计算并投射实时阴影,间接光则通过Light Probe(光照探针)来近似获取。
优点:
- 动态与静态的桥梁:既能用实时直接光影响动态物体,又能让静态物体拥有高质量的烘焙间接光和高效的动态阴影。
- 支持有限度的动态变化:灯光的直接光部分可以实时变化,适合需要开关、调光或轻微移动的灯光。
缺点与复杂性:
- 设置更复杂:需要理解Light Probe、Shadowmask等概念,配置不当容易出问题。
- 性能开销高于纯Baked:因为直接光是实时计算的。
典型应用场景:街道上的路灯(需要照亮行走的玩家,同时为建筑提供良好的间接光)、可以开关的室内灯、颜色会缓慢变化的氛围灯。
3. 灯光烘焙全流程实操与参数详解
理解了理论,我们进入实战环节。一次成功的烘焙,依赖于正确的物体标记、合理的灯光模式选择以及精细的参数调节。
3.1 第一步:场景准备与Static标记策略
在点击烘焙按钮之前,花几分钟整理你的场景。
- 分层与批量操作:如前所述,使用图层管理Static物体。选中所有大型静态环境模型,在Inspector右上角勾选“Static”。Unity会弹出对话框,通常我们只勾选“Contribute GI”和“Occluder Static”即可,这表示它参与全局光照计算和遮挡剔除。
- 检查模型UV:光照贴图需要第二套UV(UV1)。在导入模型设置中,确保“Generate Lightmap UVs”是勾选的。对于自定义模型,务必在3D软件中展好第二套UV,避免重叠、拉伸,否则烘焙会出现难看的接缝或花斑。
- 非Static物体的准备:对于玩家、敌人等动态物体,绝对不要勾Static。它们将通过Light Probe(光照探针)来获取环境间接光。你需要手动或自动在场景中布置光照探针组(Light Probe Group)。
3.2 第二步:灯光模式选择与参数配置
这是核心决策点。为场景中的每一盏灯做出明确选择。
决策流程图(简化):
- 灯光是否需要移动或改变属性(颜色/强度)?
- 是-> 选择Mixed模式。
- 否-> 进入下一问题。
- 灯光是否需要照亮非Static物体(如角色)?
- 是-> 选择Mixed模式。
- 否-> 选择Baked模式。
Mixed灯光的关键参数详解: 在灯光组件的“Light”部分,选择“Mixed”模式后,会出现“Baking”设置。
- Baking:这个下拉菜单是关键。
- Realtime:此选项已废弃且容易混淆。不要选。
- Baked:不要被名字迷惑!这里选Baked,意味着这颗Mixed灯光的间接光部分将被烘焙,这是正确的、最常用的设置。
- Mixed:一个遗留选项,行为复杂且不推荐在新项目中使用。
- Shadowmask:在Project Settings -> Quality中,设置“Shadowmask Mode”。推荐使用“Shadowmask”,它能在运行时为Static物体提供高质量的静态阴影混合。
Baked灯光的参数: 相对简单,主要关注“Intensity”(强度)和“Color”(颜色),因为烘焙后这些就无法改变了。确保它的“Baking”选项就是“Baked”。
3.3 第三步:光照贴图与光照探针设置
打开Window -> Rendering -> Lighting Settings。
Lightmapping Settings:
- Lightmapper:有“Progressive CPU”和“Progressive GPU”(如果硬件支持)可选。GPU通常更快。
- Indirect Resolution:这是最重要的质量参数之一。单位是“每单位纹素数”。值越高,光照贴图越清晰,间接光细节越丰富,但烘焙时间和内存占用呈平方增长。室内小场景可能用20-40,大型开放世界可能用2-5。先从10开始测试。
- Lightmap Resolution:同样重要,影响直接光照和阴影在光照贴图上的精度。通常设置为Indirect Resolution的2-4倍。
- Lightmap Size:单张光照贴图纹理的最大尺寸。2048或4096是常用值。Unity会自动将场景的光照信息打包到多张这个尺寸的图集中。
- Compression:开启以节省磁盘空间,但可能引入轻微瑕疵。
- Ambient Occlusion:环境光遮蔽设置,强烈建议开启,能极大地增强角落和接触面的体积感。
Light Probe设置:
- 在场景中创建“Light Probe Group”。像布置棋子一样,在动态物体可能活动的空间均匀布置探针点。关键区域(如明暗交界处)需要更密集。
- 在Lighting Settings的“Light Probes”部分,可以设置探针的生成参数。通常默认即可。
3.4 第四步:执行烘焙与结果检查
点击Lighting Settings窗口底部的“Generate Lighting”按钮。这是一个需要耐心的过程。
烘焙完成后,检查以下方面:
- 光照贴图预览:在Scene视图的“Shaded”模式下,选择“Global Illumination Preview”,可以查看生成的光照贴图。检查是否有明显的接缝、漏光或过暗区域。
- 静态物体:确保它们的光照看起来自然,阴影正确。
- 动态物体:在Game视图里,移动你的角色或动态物体,观察其身上的光照是否平滑变化,是否在进入暗处时正确变暗。如果动态物体在烘焙过的区域看起来“自发光”或与环境脱节,说明光照探针布置不足或密度不够。
- 性能统计:打开Stats面板,观察“Rendering”中的“Saved by batching”和“SetPass calls”。成功的烘焙应该能显著降低Draw Call。
4. 常见问题、疑难杂症与排查指南
即使按照流程操作,依然会遇到各种奇怪的问题。这里记录了我踩过的一些坑和解决方案。
4.1 问题一:烘焙后,静态物体一片漆黑或曝光过度
- 排查步骤:
- 检查灯光模式:确认照亮该区域的灯光不是“Realtime”模式。Realtime灯光不参与烘焙。
- 检查Static标记:确认该物体确实勾选了“Static”和“Contribute GI”。
- 检查灯光范围:Baked和Mixed灯光的“Indirect Multiplier”(间接光乘数)是否过低或为0?检查灯光Range是否够大,能否覆盖到物体。
- 检查光照贴图分辨率:“Indirect Resolution”可能太低,导致光照信息根本没有被采样到。尝试提高该值重新烘焙一小块区域测试。
- 检查UV:在模型的导入设置中,检查“Lightmap UVs”的预览,确保其没有严重重叠或拉伸。
4.2 问题二:动态物体在烘焙场景中不受光或光照不匹配
- 排查步骤:
- 首要检查:照亮该区域的灯光模式必须是Mixed。Baked灯光无法照亮动态物体。
- 检查光照探针:动态物体是否处于“Light Probe Group”的覆盖范围内?在Scene视图的“Global Illumination”模式下,可以看到光照探针的覆盖球体。确保动态物体的活动路径被探针包围。
- 探针密度:如果动态物体在移动时光照发生跳跃式变化,说明探针布置太稀疏。需要在关键路径上增加探针密度。
- 动态物体材质:确保其材质的Shader是支持“Light Probe”的。所有Standard Shader和URP/HDRP的Lit Shader都支持。
4.3 问题三:烘焙时间过长,或光照贴图尺寸巨大
- 优化策略:
- 减少不必要的Static:仔细审查场景,只将真正静态的大型物体标记为Static。大量的小型碎石、草叶可以考虑使用GPU Instancing或其他批处理技术,而不是标记为Static。
- 调整分辨率:理性降低“Lightmap Resolution”和“Indirect Resolution”。对于远处或不太重要的物体,可以通过Override设置单独降低其光照贴图分辨率。
- 分块烘焙:对于超大型场景,不要一次性烘焙整个世界。利用Unity的“Lighting Data Asset”和场景分块加载,只烘焙当前需要的区域。
- 使用GPU Lightmapper:如果显卡支持,切换到“Progressive GPU”,速度会有数量级的提升。
- 优化模型:减少Static物体的面数,简化网格。
4.4 问题四:阴影出现闪烁、断层或“粉刺”状瑕疵
- 排查步骤:
- Shadowmask距离设置:在Quality Settings中,有一个“Shadow Distance”和一个“Shadowmask Mode”下的“Distance Shadowmask”切换。当摄像机与物体的距离超过“Shadow Distance”时,Static物体会使用烘焙的阴影(可能模糊);在此距离内,会使用实时阴影。如果这个过渡距离设置不当,或者Shadowmask模式配置错误,会导致阴影在镜头移动时闪烁或突变。尝试调整“Shadow Distance”,或使用“Shadowmask”模式代替“Distance Shadowmask”。
- 灯光阴影参数:检查Mixed灯光的阴影设置,如“Shadow Strength”、“Resolution”。过低的Resolution会导致阴影锯齿严重。
- 光照贴图精度:灯光产生的、烘焙在Static物体上的阴影出现断层,通常是“Lightmap Resolution”过低导致的。提高该值。
4.5 问题五:场景烘焙后,材质变紫(粉色)或丢失
这是一个常见且令人崩溃的问题,尤其在使用了Addressables或脚本化构建管线后。
- 根本原因:Unity在烘焙光照时,会为需要烘焙的材质生成一个临时的“烘焙变体”(Baked Variant),这个变体引用了光照贴图等数据。如果构建或资源管理流程中,这个变体没有被正确打包或引用丢失,运行时就会显示为Shader错误(通常是粉色)。
- 解决方案:
- 检查材质球:确保场景中所有Static物体的材质球都是“常驻”资源,而不是在Addressables中被标记为远程加载且未包含在构建内。光照烘焙变体依赖于原材质球。
- Graphics Settings:检查Edit -> Project Settings -> Graphics中的“Shader Stripping”设置。对于使用了光照贴图的平台,不要过度剥离Shader变种。可以尝试关闭“Lightmap modes”的剥离。
- 构建后检查:在构建输出目录中,检查光照数据资产(如
LightingData.asset)和相关的*_lightmap.exr文件是否存在。如果使用Addressables,确保它们被打包到了正确的资源组并随场景加载。 - 脚本化构建管线:如果你使用了自定义的构建脚本,确保在
IBuildTask中正确处理了LightingDataAsset的依赖收集和打包。一个常见的遗漏点是没有将光照数据显式地添加到构建的资源列表中。
5. 进阶技巧与性能调优心得
掌握了基础流程和问题排查,下面分享一些能提升效率和质量的经验。
5.1 混合使用烘焙与实时灯光
一个高性能的高质量场景,往往是Baked、Mixed和Realtime灯光精心搭配的结果。
- 背景全局光照:使用一颗强度较低的Baked方向光(模拟天光)或Skybox来提供基础的、无变化的全局照明和间接光。这奠定了场景的基调。
- 主要静态光源:室内主灯、固定的壁灯等使用Baked模式,获得最好的效果和零运行时开销。
- 互动与动态光源:玩家手电筒、爆炸火光、可开关的灯使用Realtime模式。注意控制其数量和影响范围。
- 衔接与补充:走廊灯、窗户外的环境光补充使用Mixed模式,让动态角色能自然地融入静态环境。
5.2 光照贴图UV的优化技巧
光照贴图的质量和效率,一半取决于UV。
- 自动生成:对于简单模型,Unity的“Generate Lightmap UVs”足够好用。但务必检查“Pack Margin”参数,增加此值(如0.005到0.01)可以避免烘焙时纹理边缘渗色。
- 手动展UV:对于复杂或重要的模型(如主角大厅),手动在3D软件中展第二套UV是值得的。原则是:最大化利用UV空间,避免拉伸,为重要区域分配更多UV面积。例如,一个房间的内墙和地板应该获得比天花板更多的UV空间,因为它们是视觉焦点。
- UV重叠:绝对禁止。重叠的UV会导致光照信息相互覆盖,产生不可预测的、混乱的烘焙结果。
5.3 利用Light Probe Proxy Volume(LPPV)解决大物体问题
对于大型的非Static物体(如一辆公交车、一个巨型机器人),传统的单点Light Probe采样会失效,因为物体体积太大,其不同部位所处的光照环境不同。这时就需要LPPV。
- 工作原理:LPPV定义一个3D体积框,在这个框内密集生成虚拟的探针网格。大型动态物体会根据其每个像素在这个体积内的位置,进行三线性插值获取光照信息,从而实现整个物体表面的光照渐变。
- 使用方法:创建一个“Light Probe Proxy Volume”组件,将其附加到大型动态物体上,调整其大小覆盖物体,并确保该体积被场景的Light Probe Group包围。在物体的材质上,启用“Use Light Probe Proxy Volume”。
5.4 烘焙迭代策略:快速预览与最终烘焙
没有人能一次调对参数。高效的迭代是关键。
- 最低质量预览:将Lighting Settings中的“Indirect Resolution”和“Lightmap Resolution”降到极低(如2和4),关闭“Compression”和“Ambient Occlusion”。用GPU Lightmapper进行第一次烘焙,速度极快,用于检查灯光布局、Static标记是否正确,整体明暗关系是否合理。
- 区域烘焙:Unity允许你只烘焙选中的物体。选中一个有问题或代表性的区域(如一个房间),进行局部烘焙,快速验证参数调整效果。
- 渐进式烘焙:使用“Progressive”模式,你可以看到光照结果逐步收敛的过程。在达到可接受质量时就可以手动停止,无需等待最终收敛,非常适合调整阶段。
- 最终烘焙:当所有参数、布局确认无误后,再将分辨率调到目标值,开启所有高质量选项,进行完整的最终烘焙。这个过程可以去喝杯咖啡。
灯光烘焙是Unity场景美术和性能优化的基石,它要求我们在编辑期付出计算时间,来换取运行时的极致性能和视觉保真度。整个过程像是一场与引擎的精密对话,你需要通过Static标记、灯光模式、各种分辨率参数来清晰地表达你的意图。避免“乱勾Static”,本质上是建立一种清晰、规范的对象管理思维。而精通Mixed与Baked,则是掌握了平衡动态需求与静态美学的钥匙。希望这份指南能帮你理清思路,下次点击“Generate Lighting”时,心中充满的是掌控感而非忐忑。记住,最好的学习方式永远是:在理解原理的基础上,大胆尝试,耐心观察,细致调整。每一个“翻车”的场景,都是通往精通之路的宝贵路标。