做Unity渲染这几年,我有个特别深的体会:很多人对渐进式烘焙(Progressive Lightmapper)的理解就停留在"比老方案快"这个层面,真到项目里一换,CPU模式跑得慢、GPU模式又总是报错,回头又搬回旧方案。其实这套烘焙器从诞生起就不是单纯"提速"的东西,CPU和GPU两条路径在工作方式上有本质差别,选错或者配置错,效果天差地别。
这篇文章我就从自己的迁移经历和几个实际项目里的烘焙数据出发,聊聊渐进式烘焙里CPU和GPU的区别、切换时怎么调参数、出了异常怎么定位,以及最后我总结的选型结论。不管你是刚接触烘焙的新手,还是想优化现有烘焙流程的老手,都能在这里找到可以直接拿去用的经验。
1. 中途预览与旧方案的差距:从Enlighten到渐进式烘焙的迁移理由
1.1 旧方案最让人崩溃的三个场景
我最早用Enlighten做烘焙时,最崩溃的还不是等待本身,而是"等待之后发现结果不对,还得重来"。很多时候我们只改动了一面墙的颜色,就要把整个场景重新烘焙一遍,然后去倒杯水、刷个手机,回来一看,光照已经偏移了,或者是某个角落出现大面积漏光,只能再调,再等。
第二个崩溃场景是预览不直观。旧方案在烘焙过程中你基本看不到中间状态,只有跑完才能知道结果。一旦美术同事说"这个风格不对,整体亮一点",那就等于从头再来。调试周期被拉得非常长,尤其在场景规模大的时候,一天根本试不了几个版本。
第三个场景是内存开销。Enlighten需要单独的预计算数据和系统计算阶段,它会把场景里的大量几何信息、簇信息、光照子系统数据全部吃进去,场景稍微大一点,内存占用就肉眼可见地涨。遇到那种几千个静态物体的关卡,烘焙一次风扇狂转,各种不稳定。
1.2 渐进式烘焙的工作节奏变化
渐进式烘焙和旧方案最大的不同,是它把烘焙变成了一个"从模糊到清晰"的收敛过程。你按下烘焙之后,贴图从一开始就是可见的,满屏噪点,随着采样数增加,噪点逐渐消失,画面一步步收敛到最终效果。这个概念有点像是给照片降噪,而不是等一整张图渲染完再显示。
这个特性对工作流的改善是革命性的。举个例子,有一次我在做某恐怖游戏项目的地下场景,灯光偏冷偏暗,美术说想让走廊尽头的点光源更“实”一点。以前这种调整,至少占用半个小时到一个小时。现在打开预览,一边提高采样一边观察,等噪点降到可接受范围,确认局部光影方向对了,再决定要不要继续增加采样。整个过程十分钟内结束。
渐进式烘焙的具体操作也可以说一说了:在Lighting窗口里,Scene标签下选择Progressive CPU或Progressive GPU;点击Bake按钮后,编辑器会开始采样并实时刷新预览。如果你想只看某一小部分,可以框选局部区域设置Focus,只对那块地方提高精细度,烘焙时间会显著降低。这个功能对调试特定房间、特定道具的光照特别有效率。
2. GPU与CPU两套计算路径,究竟差在哪儿
2.1 CPU路径:多核并行的稳健派
CPU模式走的是多线程+SIMD指令集加速。Unity把烘焙任务按照纹素(texel)切分成小块,分发到各个逻辑处理器上并行计算。它不依赖显卡,也不依赖CUDA,只要机器足够新、核心数足够多,效率就会不错。
CPU路径在做全局光照时,使用的是基于路径追踪的算法。每个纹素会发射多条光线,在场景中反复弹射、采样光源,最后把结果累积起来。跟GPU模式相比,CPU版本用的是自己内置的优化调度器,对每个纹素的内存访问更加保守,所以面对超大场景时不容易“一口气吃撑”。我在同一台机器上测试过一个将近百万三角形的大场景,CPU模式虽然耗时较长,但内存平稳,从启动到结束没有任何崩溃。
CPU版本还有一个优势,就是降噪。它集成的是Intel的Open Image Denoise,这个降噪器在处理大块低频噪点时非常稳,对阴影柔化、平滑过渡的细节保留较好。只要采样数不是低得离谱,CPU模式烘焙出来的图在暗部过渡上通常更细腻。
2.2 GPU路径:CUDA和即时预览的激进派
GPU模式依赖NVIDIA显卡的CUDA计算能力,基本思路是把需要烘焙的几何数据、纹理数据和光源数据都上传到显存,然后由GPU并行处理成千上万个光线路径。配合NVIDIA自己的OptiX降噪库,GPU模式可以在很低的采样数下就给出相对干净的中间预览,因此它特别适合“前期反复调灯光风格”的阶段。
我之前在一台双显卡台式机上测过一个中等场景,大概200多个静态物体,烘焙256分辨率的Lightmap。GPU模式首次跑完只需要80秒,CPU模式则用了将近6分钟,差距确实明显。预览时放大看,GPU模式在最初几十个采样内噪点较猛,但一旦跑过一定采样阈值,配合Denoiser,画面立刻变得可看。
GPU模式还适合光源数量多的场景。因为显卡并行度高,不同光源对同一个纹素的贡献可以快速叠加,不像CPU那样需要频繁进行多线程间的数据同步。我有个做展厅类项目的朋友,场景里一百多盏筒灯,以前CPU烘焙时要等一个多小时,切到GPU后直接压缩到十几分钟。
2.3 为什么GPU不一定每次都赢
听起来GPU模式好像全面占优,但实际项目中我翻过两次车。第一次是大场景,整个开放世界Demo的街区部分,顶点数到了几千万级别,GPU模式载入几何数据时直接把显存顶爆,烘焙进程报错退出。而CPU模式不仅没崩溃,还能一边慢慢烘焙一边正常操作编辑器。第二次是笔记本电脑,核显机型的GPU模式根本没有设备可用,强制切换到独立显卡后又碰上了驱动兼容问题。
还有一个很容易忽视的点:GPU烘焙的采样调度是粗粒度的,遇到某些高光材质或者复杂的折射反射,反而会因为一次采样结果里包含大量噪点而拖慢收敛速度。在低采样数下,带OIDN降噪的CPU模式反而能更快得到一个“观感上可用”的效果。所以我的判断标准不是“哪个名字更高级”,而是场景规模和美术验证阶段的实际需求。
| 对比项 | CPU(Progressive CPU) | GPU(Progressive GPU) |
|---|---|---|
| 硬件依赖 | 多核处理器,任何可用显卡即可 | NVIDIA显卡,要求CUDA支持、显存充足 |
| 大场景承载力 | 较高,内存调度稳健 | 受显存限制,顶点数多容易失败 |
| 预览收敛速度 | 低采样数下OIDN降噪表现好 | 高并行,采样效率高 |
| 光源密集场景 | 多线程同步开销明显 | 并行优势突出 |
| 崩溃风险 | 低 | 驱动、显存、多GPU切换等导致的报错较多 |
| 适合阶段 | 最终质量出图、超大场景 | 快速风格调优、中等规模场景 |
3. 项目实操:从CPU切到GPU烘焙时的参数调整与硬性检查
3.1 开始前的图形设备和驱动检查
如果你刚准备把项目从CPU模式切到GPU模式,先别急着点Bake,花十分钟把下面的硬性条件确认一遍。第一,必须是NVIDIA显卡,而且架构不能太老,一般来说GeForce GTX 900系列以后的卡都算可用,越新越好。第二,确认驱动更新到支持当前Unity版本对应的CUDA版本,否则很容易在启动烘焙时直接报Failed to initialize device。第三,如果你有双显卡,尤其是笔记本用户,一定要在系统设置里把Unity指定为使用独立显卡运行,不然所谓“GPU烘焙”可能跑在核显上,性能还不如CPU。
还有一个我自己踩过的坑:部分显卡驱动开了“多GPU模式”或者“SLI”时,GPU烘焙反而会出问题。报错时核心提示里面经常看到GetDeviceCaps失败或者CUDA error。遇到这种情况,不是项目代码的问题,而是驱动层面的调度。把多GPU相关的加速选项关掉,或者只保留主卡参与烘焙,问题就消失了。
3.2 Lighting窗口里的参数怎么配
进了Lighting窗口,Scene标签下Lightmapper选择Progressive GPU。接下来这组参数是我做了几十次实验后觉得最适合大多数静态场景的起点:
直接采样:一般开到16到32就够。这个数值决定从光源正面直接照到表面的采样数量,太低了会出现生硬的噪点,太高了会明显拉长烘焙时间。 间接采样:32到128。它负责光线弹射之后落到表面的信息,数值越大,间接光越平滑,但烘焙时间呈线性上涨。我一般先用64看效果,不够再往上加。 反弹次数:1到2次是合理默认值。很多人为了图“全局光更强”直接调到4甚至更高,结果暗部出现很多亮斑和溢色,时间也翻倍。你如果觉得场景太暗,更应该检查灯光强度和环境光,而不是无脑加反弹。 Lightmap分辨率:通常按每单位纹素设置,我常用32到128。一个典型的10米×10米房间,分辨率32就能得到比较干净的间接光;如果是展示用的近景模型,可以单独给它128。 Padding:8到16之间。这个值越大,不同UV岛屿之间混色的概率越小,但显存和贴图空间开销越大。常见漏光问题很多就跟padding太小有关。
那你可能会问,为什么我用默认参数烘焙出来的图偏偏就花?因为Unity的默认设置是基于比较保守的综合性需求,不是针对你的场景。具体项目里光照强度、材质粗糙度、UV布局都会影响采样需求。我的习惯是每次先跑一个低分辨率的快速预览,看看光影关系是否成立,再提高参数出最终图。
3.3 一次真实烘焙过程的参数记录
拿我手头某解谜项目的室内场景来说,这个场景大概40米×40米,200多个静态物体,总三角面数五万出头,光源数量12个。角色活动范围集中在一栋两层建筑里。
我先用CPU模式跑了一版,全场景Lightmap分辨率设为64,间接采样128,反弹2次,总耗时约11分钟40秒,内存占用最高到了5.2GB。出来的图整体很干净,暗部几乎没有噪点。然后我切到GPU模式,同样的参数,显存占用接近3GB,总耗时约4分钟25秒。如果你只看这个结果,会以为GPU全面碾压,其实注意看阴影边缘,GPU版本在几个小物件的接触阴影上比CPU版本略显“洗过”的痕迹,缺失了一点硬边过渡。
后来我把间接采样降到64,两种模式的烘焙时间都缩短了,GPU模式缩短到3分钟左右,CPU模式缩短到8分钟出头,视觉差距也变得不太明显。这就引出一个重要经验:烘焙时间不是单调地取决于硬件,调参本身就能拉开巨大差距。为了省那两分钟去迷信GPU模式,不如先把采样控制在一个合理范围。
3.4 一个烘焙前的自检脚本
我后来在团队里推广过一个烘焙前自检脚本,核心作用是在点Bake之前扫描场景里所有MeshRenderer,检查它们是否缺少UV2(光照贴图UV)。这里插一小段核心逻辑,你可以加到自己的Editor工具菜单里:
using UnityEngine; using UnityEditor; using System.Collections.Generic; public static class LightmapBakerUtility { [MenuItem("Tools/Lightmap/Check Static UV2")] public static void CheckStaticUV2() { MeshRenderer[] renderers = Object.FindObjectsOfType<MeshRenderer>(); List<string> missingUV2 = new List<string>(); foreach (MeshRenderer r in renderers) { if (!r.gameObject.isStatic && !r.staticEditorFlags.HasFlag(StaticEditorFlags.ContributeGI)) continue; MeshFilter mf = r.GetComponent<MeshFilter>(); if (mf == null || mf.sharedMesh == null) continue; Mesh mesh = mf.sharedMesh; bool hasLightmapUV = mesh.uv2 != null && mesh.uv2.Length > 0; if (!hasLightmapUV) missingUV2.Add(r.gameObject.name); } if (missingUV2.Count == 0) Debug.Log("All static meshes have UV2."); else foreach (string name in missingUV2) Debug.LogWarning("Missing UV2: " + name); } }这个脚本不复杂,但它在很多项目里救过命。因为渐进式烘焙在遇到缺少UV2的物体时不会直接给你报错,而是让美工肉眼看到某块区域光照是糊的、拉丝的,定位成本非常高。有了这个检查,你可以在烘焙前一次性把所有问题物体揪出来。
4. 烘焙结果异常排查:从漏光、黑斑到"No compatible GPU found"
4.1 漏光与UV的关系
漏光是我见过最频繁的烘焙异常,表现是墙根、墙角、门缝处出现不该出现的亮条,好像光线从隔壁房间“渗”了过来。很多人都以为是灯光强度问题,加了很多遮挡物,结果毫无改善。实际上漏光九成以上跟UV布局有关。
你可以这样理解Lightmap UV:烘焙器会把每个物体的UV岛展开、铺在一个大平面上,然后独立计算颜色。如果两个UV岛靠得太近、Padding不够,采样时边缘的颜色就会互相“串门”。墙面背面的亮光,就顺着UV缝隙串到了正面,表现成漏光。解决方式分三步:第一,尽量让建模软件里展开的UV2没有重叠、没有拉得过大的变形;第二,把Lightmap Padding调到8以上;第三,检查模型比例,统一建模单位,不要有的物体1米对应1个纹素,有的物体1米对应10个纹素。
4.2 黑斑与采样、光源亮度的关系
黑斑和亮斑是另一个高频问题,尤其是那种特别小的、集中的噪点颗粒,大面积的降噪都救不回来。我遇到过一个很典型的案例:场景里一盏聚光灯的Intensity设置到了20万,倍率又给了个很夸张的数值,烘焙时一小块地面出现了星星点点的黑斑。扒开参数一看,主光源强度远超合理范围。
黑斑的本质是数值不稳定。路径追踪里,光线落到异常明亮的光源上,会反馈回一个极高的辐射值,反映到贴图上就是亮斑;而周围纹素没有采到那个峰值,就形成强烈对比,视觉上变“黑”。另外,间接采样不够时,暗部区域长时间得不到足够光线贡献,也会呈现“黑漆漆一片”的噪点。所以处理顺序是:先检查光源强度是否在合理范围;再把间接采样提高到128以上测试;最后才考虑是不是材质用了自发光和异常高光造成的fireflies。
4.3 GPU模式启动失败的处理
如果你在切到Progressive GPU后点击Bake,几秒钟后看到一条“Baking Request failed。 Please check your graphics device driver”,先不要重装Unity。这个错误在多数情况下跟三件事有关:
驱动不合适。去显卡厂商官网下最新驱动,不要在设备管理器里点“自动更新”。 显卡不满足CUDA要求。可以看下自己显卡的Compute Capability,太老的架构确实跑不了。 编辑器开启了DX12但显卡驱动状态异常。你可以把Project Settings里的Graphics API切回DX11,再尝试烘焙。因为GPU烘焙目前对DX11环境兼容度最好。 另外提醒一下,多显卡机器上如果其中一个显示器接在核显上,Unity默认可能会选择核显设备。这时你需要到Window > Rendering > Lighting,在GPU烘焙相关设置里指定可用的独立显卡,或者直接禁用核显参与Unity工作。
4.4 “烘焙一半改了东西”的增量处理
渐进式烘焙虽然支持中途预览,但它并不支持存档恢复,关机或者切场景后中间进程就没了。如果你只是改了一个房间的软装,没必要全场景重烘。我常用的做法是选中这个房间的所有静态物体,配合手动指定Lightmap参数,只烘焙选中物体所在区域。烘焙后你会发现,没选中的物体在编辑视图里显示为灰模,这是正常的,因为在Lighting面板里它的烘焙数据没有更新。
这个“局部烘焙”思路特别适合那种三四十个房间的大关卡。关卡的共享走廊和公共空间先定死,单独改哪个房间只要烘哪个房间。如果你强行全量烘焙,每一次改动都是半小时起步,而这半小时完全可以去调其他内容。局部烘焙的代价是可能会有接缝,所以走廊这种公共区域我一般不参与局部烘焙,保持整段一致。
5. 大场景、高复杂度项目中的烘焙取舍与我的选型结论
5.1 场景颗粒度和显存压力的折算
进入大场景之后,CPU和GPU的选型就不仅仅是速度问题了,而是一个内存规划问题。我当时在测那个开放世界Demo时,把一段街区拆成三次烘焙,每次约800万顶点、300多张贴图。GPU模式第一次尝试时,还没有点击Bake,光是把场景数据上传到显存就直接炸了。CPU模式虽然慢,但它是分批读取场景数据的,内存一直稳定在可控范围内。
如果你的场景规模跟这个量级接近,我建议不管CPU还是GPU,先做场景拆分。拆分不是把美术资产拆散,而是用多个Scene叠加,烘焙时按Manage Lightmap区域处理。这样GPU完全可以从容应对,单个子场景烘焙时间基本能控制在十分钟内。拆分原则按“功能区域”来,而不是按“房间数量”来,否则接缝管理会让你头大。
5.2 我现在的默认配置
经过这几个项目的折腾,我现在给自己定了一个相对固定的选型规则:小场景、中场景、风格探索阶段用GPU模式;超大规模场景、最终质量阶段用CPU模式。GPU模式主要图它反馈快,光线方向和明暗关系几分钟就能看清,适合反复试风格;CPU模式则作为出图前的最终保证,更稳。
具体参数上,我常用的是一套“三级配置”。最低档用于Layout验收:Lightmap分辨率32,直接采样8,间接采样16,反弹1次。中档用于光照风格讨论:分辨率64,直接采样16,间接采样64,反弹2次。高档用于最终出图:分辨率128,直接采样32,间接采样128到256,反弹2次。这套配置不是从哪个官方文档抄的,而是从几个项目里磨出来的平衡点,你直接拿去用也不会跑太偏。
5.3 如果你还在犹豫,我建议这么选
最后聊一点决策方法。每个项目烘焙效率差异极大,因为灯光数量、材质复杂度、模型面数三个变量会交叉影响。有人照搬网上的“推荐参数”,发现自己的机器反而更慢,就开始怀疑配置,其实问题往往出在某个光源用了实时Shadowmask,或者某个材质的高光项没有归零。
我建议你拿到新项目时,先花半天做一组对比测试:同一个场景,分别用CPU和GPU跑低采样预览,记录时间、显存、内存,顺便截图对比暗部细节。带着这些数据再去选型,比任何人告诉你的结论都靠谱。做完这组测试,你对项目里哪部分是瓶颈、哪种模式更快,就已经心里有数了。
我个人现在的体会是:烘焙效率的核心,从来不是CPU和GPU谁更强,而是你能不能在小步快跑的预览循环里,快速锁定最终要的光影方案。渐进式烘焙给了我们这种工作方式的可能,CPU和GPU只是达成目标的两条路。你真正需要掌握的,是如何在正确的时间走正确的路,以及在路上遇到坑时,知道怎么绕过去。