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图形API(macOS),GPU模式要看显卡是否支持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 = 32,Indirect Samples = 128,Bounces = 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分辨率的Lightmap(2048×2048 = 419万像素),每个像素按8字节算就是约32MB,加上中间缓冲,一张图就要大概100MB的显存。如果你的场景有20张这样的Lightmap,光Lightmap就是2GB,再加上场景贴图、材质、BackBuffer,8GB显存的老卡很容易爆。
如果你显存不够,不要直接调低分辨率,更好的做法是把场景拆成多个区域,分别烘焙。或者关闭“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 Lightmapper,Mode选择CPU,Direct Samples设为32,Indirect设为128,Bounces = 2,然后点击“Generate Lighting”。
烘焙开始后,注意看窗口下方的进度条。这里有很多人不知道的一个小技巧:进度条显示的是“当前迭代轮次 / 总轮次”,而总轮次是由“Samples”和“Texel数”共同决定的。如果Noise Threshold设置得太低,比如0.001,总轮次会变得非常大,烘焙时间可能翻十倍。我测试时默认Noise Threshold是0.05,CPU模式总共跑了大概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的垃圾数据。这个习惯养成之后,你会在后续维护版本时省掉很多麻烦。