Unity渐进式烘焙CPU与GPU模式详解:从原理到避坑
1. 从一次深夜卡死说起聊聊Unity渐进式烘焙到底值不值得用我第一次用Unity的Progressive Lightmapper渐进式光照烘焙是在一个室内场景项目上场景里塞了上百盏灯还有一堆动态物件要参与全局光照计算。当时项目组还在用旧版Enlighten即Unity 2019之前默认的实时GI方案每次调完光照参数按下Bake基本上就是泡杯咖啡、刷两条短视频再回来看看进度条——运气好十分钟运气不好直接Editor崩掉。后来切到渐进式烘焙CPU模式跑完整个场景只用了不到之前一半的时间而且最爽的是烘焙过程中可以随时改光源颜色、调强度改了它立马增量更新不用全量重来。这个体验说实话让我有点惊讶因为那时候我对“渐进式”三个字还停留在“会不会比Enlighten更吃内存”的顾虑里。后来我又在一台老机器上试了GPU烘焙模式本来想着显卡不怎么样可能会翻车结果NVidia的RTX系显卡在CUDA加速下完完全全把烘焙时间压到了一个可以接受的范围。今天这篇东西就专门聊聊渐进式烘焙里CPU和GPU这两条路怎么选、怎么配、怎么避坑。我尽量把从原理到实操的东西一次讲清楚不堆术语用大白话把关键点拆透。适合看这篇文章的人刚接触Unity光照烘焙的新手被“Enlighten到底该不该留”困扰的团队以及想用GPU烘焙但不知道怎么调参数、怎么排错的人。顺便说一句如果你还在用Unity 2018或者更老的版本渐进式烘焙其实是2019.1才正式转正的功能老版本没有建议先升级再继续往下读。2. 渐进式烘焙究竟是“渐进”在哪先搞懂它和Enlighten的本质区别2.1 旧方案的痛点全量重算改一处等于翻一锅先说Enlighten。它属于离线的预计算方案你按下Bake它会把场景里的几何体、光源、材质反射率全部收集起来生成辐射度数据然后再做一次全局光照的求解。问题在于只要场景里任何一个参与光照的物体位置变了、光照颜色改了、或者材质参数调整了整个预计算基本就要重新跑一遍。对小场景还好场景一复杂一次重新烘焙的时间会呈指数级增长迭代效率非常低。而且Enlighten的Lightmap分辨率是按空间密度来分配的它对场景结构敏感有时候同一个房间的不同墙面会突然出现很明显的接缝调试起来异常痛苦。2.2 渐进式烘焙的核心理念把“一次算完”改成“一次次逼近”Progressive Lightmapper的思路完全换了一个方向。它不再试图一次性求出全局光照的最终解而是把渲染方程拆成无数个采样点每个采样点逐次计算直接光照、间接光照、弹射光照每算完一轮就更新一遍Lightmap然后进入下一轮迭代。换句话说它是“边算边逼近”而不是“攒到最后一步才出图”。这种做法的好处是显而易见的你可以看到Lightmap从模糊到清晰的过程每轮迭代之间Lightmap的数据是有效的不是等全部算完才生成。更关键的是Unity在每次迭代结束之后会检查场景里的变化——如果你只是挪动了一个灯的位置它只需要对该灯影响的区域重新计算而不是整个场景重来。这就是“渐进”二字的真正价值把全量计算变成了一个可持续迭代的过程。2.3 CPU和GPU模式共享同一套算法逻辑只是算力载体不同这一点很多人容易误解。渐进式烘焙有两种模式CPU默认和GPU在Player Settings里开启后可选。它们跑的是同一套核心算法光照方程、采样策略、反弹次数、滤波方式完全一样。区别只在于谁来执行这些计算——CPU模式用处理器的所有核心GPU模式用显卡的CUDA核心。但正因为运行载体不同两者的参数设置、内存占用、支持的功能边界也出现了明显的差异。我在下表里列一下它们在你实际使用中最直观的区别对比维度CPU模式GPU模式计算单元多核CPU线程数可调NVIDIA显卡CUDA核心需开启内存占用受系统内存限制通常能扛更大场景受显存限制贴图堆叠和备份数据易爆显存取样速度单轮迭代速度较慢但稳定单轮迭代极快RTX系列优势明显场景复杂度更适合多物体、超大场景适合中小场景或烘焙场景切块后使用实时预览支持且CPU模式预览更顺滑支持但显存吃紧时预览会卡迭代更新支持灯光修改后局部更新支持但会重新上传相关数据有额外开销调试便利性可暂停单轮迭代检查具体样本暂停/恢复功能较弱但可以通过Device报错判断一句话总结CPU模式更像一个“稳重型老黄牛”GPU模式是“爆发型快马”选谁取决于你的场景和硬件。3. 动手之前先配好环境CPU和GPU模式的前置设置与关键参数3.1 Player Settings里那个容易被忽略的开关很多人以为在Lighting窗口里切换到Progressive GPU就算完事了其实有个前置开关必须先打开。进入Edit Project Settings Player找到Other Settings部分往下翻到“Configuration”你会看到一个选项叫“GPU Skinning”不对是“Lightmap Encoding”和“Auto Graphics API”也不是关键是那个“GPU Compute Support”选项。如果这个选项没有勾选就算你在Lighting窗口里选GPU Progressive它也会在烘焙时报错或者自动降级回CPU模式。一定要记住GPU Compute Support必须在Player Settings中开启同时确保你的显卡驱动和Unity版本兼容。以Unity 2021 LTS为例它默认支持DX11和DX12下的GPU烘焙但如果你用的是Metal图形APImacOSGPU模式要看显卡是否支持Metal的Compute Shader部分老卡是不支持的开了也跑不动。3.2 Lighting窗口里的必调参数Direct Samples / Indirect Samples / Bounces打开Window Rendering Lighting Settings选择Progressive Lightmapper之后你会看到三个关键的采样参数Direct Samples每个texel光照贴图像素上的直接光照采样数量默认是32。它决定了直接光照的噪点水平数值越高噪点越少但每轮迭代的计算量也越大。Indirect Samples间接光照的采样数量默认是128。这个参数直接决定间接光墙壁反弹、环境光遮蔽等的质量噪点最明显的通常是这个部分。Bounces光线弹射次数默认是2最大可以拉到8。每多一次弹射光线就能多反射一次但计算量呈线性增长超过4次之后视觉差异就非常细微不建议盲目拉高。我个人的推荐起步值是Direct Samples 32Indirect Samples 128Bounces 2。先把这三个值确定下来再根据场景大小调整最终质量。如果你跑完发现墙角噪点仍然严重优先加Indirect Samples而不是Direct Samples因为间接光的收敛速度比直接光慢得多。3.3 CPU模式的核心控制项Worker线程数和内存配额CPU模式在Lighting窗口里有一个“Workers”选项默认是0自动等于系统逻辑核心数。如果你在跑烘焙的同时还要用编辑器干别的活建议手动限制一下比如设成物理核心数的一半否则烘焙会把所有核心吃掉编辑器直接卡成幻灯片。另外在Preferences GI Cache里可以设置缓存路径和最大缓存大小默认是10GB。这个缓存是给中间数据用的CPU模式特别依赖它如果你经常切场景建议把缓存设大一点比如20GB不然每次换场景都要重新生成中间数据白白浪费时间。3.4 GPU模式的必要配置显存估算与CUDA设备选择GPU模式在Lighting设置里会出现一个“GPU Device”下拉框列出当前机器上所有支持CUDA的显卡。注意这个列表只包含NVIDIA显卡AMD和Intel核显是不被支持的因为Unity的GPU Lightmapper只调用CUDA和显卡的品牌支持无关就是硬性限制。显存占用怎么估算核心公式是Lightmap数据大小 ≈ 场景总面积单位texel × 每个texel的字节数默认格式下每个texel约8~16字节 中间样本缓冲通常是Lightmap数据的2~3倍 反弹光线数据视Bounces数量而定。举个例子一个2048分辨率的Lightmap2048×2048 419万像素每个像素按8字节算就是约32MB加上中间缓冲一张图就要大概100MB的显存。如果你的场景有20张这样的Lightmap光Lightmap就是2GB再加上场景贴图、材质、BackBuffer8GB显存的老卡很容易爆。如果你显存不够不要直接调低分辨率更好的做法是把场景拆成多个区域分别烘焙。或者关闭“Auto Generate”手动通过Lightmap Parameters控制每块区域的烘焙顺序和分辨率。GPU模式下还有一个隐藏坑如果你开启了HDR高动态范围贴图显存占用会进一步增加因为HDR的缓冲区比LDR大得多。实测下来在同等条件下HDR模式比LDR模式多占30%~40%的显存。避免爆显存最直接的办法是在完全空白场景里先测试烘焙一块小区域观察任务管理器或GPU-Z里的显存占用曲线大致估算后再决定整个场景的规模。4. 实操过程实录从准备场景到完成第一次烘焙完整走一遍4.1 准备一个适合做对比的小场景为了看清楚CPU和GPU的差异我建议你用一个相对可控的室内场景来测试。我自己的测试场景是一个5米×8米的走廊里面有桌椅、几个柜子、两扇窗户、一个吊灯和三个壁灯总三角形数大概10万目标Lightmap分辨率设为1024像素/单位最终会生成四张Lightmap。第一步是把所有参与烘焙的静态物体设置为Static在Inspector右上角勾选特别是光照贴图要参与GI的物体必须勾选Contribute GI否则它们只接收直接光不会有间接光反射。这一步经常被忽略很多人烘焙出来发现墙壁是黑的检查了一大圈才发现是忘了勾Static。第二步是在Lighting窗口把场景的Skybox和环境光调低。渐进式烘焙对天空光的采样尤其敏感如果Skybox亮度很高间接光的初次弹射会非常亮导致Lightmap整体过曝。我先默认Skybox关掉改用纯色环境光亮度设为0.3左右这样更容易观察烘焙过程中间接光的变化。4.2 CPU模式完整操作步骤与数据观察在Lighting窗口选择Progressive LightmapperMode选择CPUDirect Samples设为32Indirect设为128Bounces 2然后点击“Generate Lighting”。烘焙开始后注意看窗口下方的进度条。这里有很多人不知道的一个小技巧进度条显示的是“当前迭代轮次 / 总轮次”而总轮次是由“Samples”和“Texel数”共同决定的。如果Noise Threshold设置得太低比如0.001总轮次会变得非常大烘焙时间可能翻十倍。我测试时默认Noise Threshold是0.05CPU模式总共跑了大概1200轮耗时8分15秒。过程中你会在Scene视图看到一张模糊的Lightmap逐渐变清晰。此时可以随时移动灯光位置Unity会自动标记受影响区域并在下一轮迭代中重新计算该区域的光照。我把吊灯从走廊中段移到尽头系统只花了大约30秒就完成了局部更新这在Enlighten时代完全不敢想。CPU模式我遇到的一个明显问题是内存。当场景中的Lightmap达到4张1024分辨率时系统内存占用从启动时的8GB上升到13.8GB。如果你机器内存小于16GB建议在Lighting窗口把“Max Lightmap Size”调低到512或者把“Texel Confidence”的参数调低否则会卡到怀疑人生。4.3 GPU模式完整操作步骤与数据观察开启GPU模式前先确认Player Settings里的GPU Compute Support已经勾选。然后切到Lighting窗口把Mode改为GPU。此时你会发现Lightmap渲染速度肉眼可见地变快。我的测试机器是一块中端NVIDIA显卡显存8GB同样的走廊场景GPU模式只用了2分47秒就达到和CPU模式一样的噪点水平。但显存占用直接飙到了6.8GB逼近8GB上限。这意味着如果我继续加大分辨率或者增加Lightmap数量很大概率会Out Of Memory。GPU模式下有一个经常遇到的现象烘焙开始时Unity会先做一次“数据打包”把所有场景几何体、光源、材质参数组织成GPU可用的结构然后再上传到显卡。这一步在CPU模式下几乎无感但GPU模式下场景稍微复杂一点你会看到进度条卡在“Preparing Data”阶段长达几十秒这属于正常现象不是死机。等真正开始迭代后速度才会显现出来。GPU模式的另一个坑是某些材质使用了不支持GPU采样的着色器或者启用了某些第三方Shader的特性会在烘焙过程中弹出“Shader not supported in GPU Lightmapper”之类的报错。这种报错下Unity会直接停止GPU烘焙整个界面灰掉只能强行关掉重开场景。遇到这种情况最简单的办法是把对应材质换成一个内置标准材质先烘焙一遍确认GPU流程正常后再换回原来的材质。4.4 CPU和GPU同参数下的结果对比我同时用CPU和GPU两个模式把Direct/Indirect/Bounces都设为同样数值烘焙同一个场景得到的Lightmap结果在视觉上几乎无法区分采样边缘会有细微差别但综合噪点水平一致。这对很多纠结画质的同学是个好消息你不是非要上GPU才能获得好效果CPU模式的物理收敛同样靠谱只是速度慢。但要注意GPU和CPU产生的中间文件光照缓存在“版本之间”不互通。如果你用CPU烘焙到一半切到GPU继续Unity会重新从头开始采样所以不要频繁切换模式去“续跑”那样只会浪费时间。5. 常见问题速查与独家避坑技巧5.1 烘焙结果全是黑块或漏光应当怎么办漏光Light Leak和黑块是渐进式烘焙最常见的两大视觉问题。漏光通常是因为Lightmap分辨率不够或者场景中物体之间的间距过小导致texel采样跨越了物体边界。比如门缝、墙角、两个紧贴的家具之间特别容易出现漏光。解决办法有三个第一把Lightmap分辨率提高一档从512调到1024第二在Lightmapping设置里勾选“Anti-Aliasing”和“Use Embree”其实不用关键是要开启“Enable GPU Lightmapper”的“Atlas Padding”不是正确的是在Lightmap Parameters里把“Padding”增大到16或32它控制Lightmap图集中物体间的间隔间隔越大越不容易混边第三把场景中存在细缝的物理空隙用简单的几何体填满视觉上几乎看不出来但烘焙时能避免采样错误。黑块通常是在墙角或者物体边缘出现一整块深色则多半是因为采样数不足特别是Indirect Samples太低。你可以在Lighting窗口勾选“Show Resolution Overlay”把显示模式调成“Texel Density”看看黑块出现的区域是不是分辨率极低。如果是那说明该区域的UV展开有问题或者Lightmap分辨率不够。解决方法是单独调整该物体的Lightmap Parameters或使用Unity的“Lighmap UVs”自动展开并检查UV岛有没有重叠。记住UV重叠是渐进式烘焙的暗黑杀手哪怕只有一个三角形重叠它旁边的那片区域也会出现黑色陷阱。5.2 烘焙过程中报“Out of Memory”或“CUDA Error”怎么处理CPU模式下的“Out of Memory”通常是因为系统物理内存不足。先检查Lightmap大小和数量把“Max Lightmap Size”降低到512再不行把Direct/Indirect Samples各降一半看内存占用立刻降一截。如果场景实在太大最有效的办法是拆场景烘焙分区域多次烘焙最后用同一个Lighting场景合并光照数据脚本合并网上有很多这类工具但要注意版本兼容性。GPU模式报“CUDA Error”比出内存错误更常见。我遇到过的“CUDA error 702”通常是显卡驱动问题直接更新驱动到最新版本还有“CUDA error 719”是指显存不足右键显卡队列里关掉其他占显存的软件例如浏览器硬件加速或者干脆重启Unity。这里有个独门技巧打开Windows任务管理器在“性能”标签里查看CUDA专用显存占用如果Unity的烘焙还没开始就已经占了几百MB多半是历史残留先把Unity完全退出再重新打开释放显存后再尝试。5.3 为什么已经开了GPU模式但速度没提升这种情况我排查过很多次十有八九是“GPU设备选择”里根本没有识别到你的显卡或者显卡被其他应用占用。检查方式是打开Lighting窗口的“GPU Device”下拉框如果里面是空的说明Unity没有检测到可用设备。原因显卡驱动不是Game Ready版、NVIDIA控制面板里禁用了CUDA、或者你把Unity进程跑在了核显上。解决方法是强制Unity使用独立显卡在NVIDIA控制面板的“管理3D设置”中把Unity编辑器设为“高性能NVIDIA处理器”。另一种可能是场景太小、采样量太少GPU启动/数据打包的开销超过了实际迭代节省的时间。我实测在只有几十个三角形的空房间里CPU和GPU的速度差异几乎为零甚至CPU还更快一点因为不用等待数据打包。所以GPU模式适合用在场景规模达到一定程度时如果你场景很小别迷信GPU老老实实CPU反而更高效。5.4 不要太相信“Auto Generate”手动控制烘焙时机的优势“Auto Generate”默认是开启的也就是说你只要动了场景里的任何东西包括移动一个空物体Unity都会自动重新烘焙。这种设置在小场景下很友好但在大场景下会频繁触发巨大计算导致编辑器卡死。我强烈建议在正式做项目时关闭Auto Generate改为手动控制每次调好关键参数后再按下Generate Lighting。同时配合“Lightmap Parameters”可以为不同物体设置不同分辨率比如地面用2048远处的小饰物用512这样能大幅降低总烘焙时间和内存占用。6. 用渐进式烘焙做项目时我沉淀下来的几条经验如果你问我CPU和GPU到底选哪种我的回答是取决于你的开发阶段和机器配置。日常迭代、频繁调光用CPU模式就足够它不挑显卡中途改场景也顺手尤其是当周围同事的电脑显卡性能参差不齐时CPU模式能保证团队里最低配的机器也能正常烘焙。但如果你的场景已经相对稳定属于“只有局部微调”的阶段而且你手头有一块显存足够的中高端NVIDIA显卡GPU模式能帮你在几分钟内看到近似最终结果大幅缩短验证时间。我还想提醒一个关于Lightmap质量的核心认知渐进式烘焙的“渐进”并不是无限逼近真理的魔法它只是把噪声逐步降到你认为可接受的阈值。Noise Threshold设置得越低时间越长但视觉收益递减。我测试过把Noise Threshold从0.05降到0.001耗时从8分钟增加到45分钟画质的差异肉眼几乎看不出差别。所以不要追求“绝对干净”只要在暗部区域看不到明显噪点就足以应对大多数游戏场景了。最后说一个我在多个项目里反复踩过的坑烘焙完成后记得在Lighting窗口点击“Build”旁边的小箭头选择“Clear Baked Data”清理中间数据特别是GPU模式下它会在工程目录下生成大量临时文件。如果不清理随着反复烘焙工程体积会越来越大最后打包时可能多出几个GB的垃圾数据。这个习惯养成之后你会在后续维护版本时省掉很多麻烦。