资讯动态

Unity光照系统实战:烘焙、探针与移动端性能优化

发布时间:2026/10/27 20:18:37 来源:尧图企业网站定制
1. 光照系统在项目里到底承担什么职责1.1 从“看得见”到“看得对”之间那道坎很多人第一次接触 Unity 光照系统都以为它只是给场景加一盏灯把物体照亮。等真正把项目做到中期就会发现光照系统管的远不止亮度——它决定了场景的空间层次、材质质感是否成立、玩家能不能一眼找到该走的路甚至还决定了这个项目最后能不能跑在目标机型上。同一套模型和材质光照参数差一档出来的效果可以是从“廉价 Demo”到“商业级画面”的差距这个落差我在不止一个场景里见过。把话说明白一点Unity 光照系统是这套引擎里负责“光如何产生、如何传播、如何被记录、如何被复现”的一整套机制。它包含光源组件本身、全局光照Global Illumination简称 GI的烘焙管线、光照贴图与探针体系、反射探针、阴影计算、环境光与天空盒以及和后处理联动的曝光与色调映射。它解决的核心问题是在有限的实时算力下怎么让画面看起来像是真实世界的光在作用而不是一堆平涂的色块。适合谁看这篇如果你已经能把一个场景搭起来、知道材质和 Shader 大概怎么回事但烘焙出来的图总是脏、总是漏光、总是发灰或者一动起来帧率就掉到没法看那这篇东西对你应该有用。完全没碰过 Unity 的新手也能看前面几节我会把概念捋顺后面几节是实打实的参数和排查记录。1.2 光照在项目里其实是个“复合工种”我习惯把光照工作拆成四层来看这四层经常被混在一起谈结果就是出问题时不知道该查哪儿。第一层是视觉层主光方向、色温、明暗对比、氛围基调。这层是美术判断决定了场景是清晨还是黄昏是阴森还是温暖。第二层是信息层光照要承担游戏性引导。哪里是出口、哪个按钮能按、哪条路是死路很多时候靠亮度差和颜色差在潜意识里告诉玩家。这一层经常被忽略结果就是玩家在场景里迷路。第三层是技术层光怎么算、算多少、算在哪。实时光还是烘焙光阴影用什么分辨率贴图多大探针多密。这层直接决定性能。第四层是管线层内置管线、URP、HDRP 三套东西的光照能力差异极大同一套参数在 URP 里能跑搬到内置管线里可能根本没有对应选项。开工前不确认管线后面全是返工。注意很多教程不告诉你它用的是哪条管线你照着抄参数发现找不到选项不是你操作错了是管线不对。看到“Light Layers”“Screen Space Global Illumination”这类词先确认管线再说。2. 光照系统的核心构成与选型考量2.1 五种光源类型各自适合干什么活Unity 的光源组件看着简单实际上每种类型的适用场景差别很大。选错类型后面再怎么调参数都是白费劲。光源类型计算方式能否实时阴影典型用途性能成本Directional方向光无限远平行光无衰减能且是唯一适合开实时阴影的太阳、月光、主环境光低但阴影贴图有成本Point点光向四周发射按距离衰减能但要渲染 6 面立方体贴图灯泡、火把、发光道具中等实时阴影很贵Spot聚光锥形范围内外角衰减能单张阴影贴图手电、射灯、舞台灯中等Area面光矩形/圆形面光源不支持实时阴影窗口光、灯箱、柔光仅烘焙实时无成本自发光材质物体表面发光需配合 GI 才影响环境屏幕、灯带、发光标识视 GI 方案而定我一直强调一个观点Area Light 是被严重低估的光源类型。室内场景里从窗口透进来的光用方向光模拟会很硬用聚光模拟会有明显的锥形边界只有面光能得到那种柔和、有方向性又不刺眼的效果。代价是它只能烘焙所以如果你的场景需要昼夜变化窗口光就得另想办法。点光源的实时阴影要特别小心。它本质上是把场景渲染六次到一张立方体贴图里如果场景里有十个带阴影的点光源等于多了六十次渲染。移动端基本可以放弃这个念头除非是那种只有一盏灯的密闭小房间。2.2 Realtime、Baked、Mixed三种模式背后的算盘光源组件上那个 Mode 下拉框是整套光照系统里最需要想清楚的一个选择。它的本质是在回答这笔计算账单是运行时付还是打包前付掉。Realtime 实时模式光源在运行时每帧参与计算能照亮动态物体能投射实时阴影但不产生间接光。也就是说光照不到的地方就是纯黑需要靠环境光或者别的光源补。它适合主方向光、需要跟随角色的光源、以及所有会动的东西。缺点是纯实时光照的场景容易发灰、发死因为没有光在墙面之间互相弹射积累的那种柔和感。Baked 烘焙模式光源只参与烘焙运行时不产生任何开销也不能照到动态物体除非用探针。它产生完整的直接光和间接光是画面质感的主要来源。缺点是光源本身不能移动、不能改变强度场景里的静态物体也不能动。Mixed 混合模式直接光实时、间接光烘焙兼顾两者。这是绝大多数项目的实际选择但 Mixed 下面还有三个子模式选错照样出问题Baked Indirect烘焙间接光直接光和阴影全实时间接光烘焙。动态物体能正常接收实时阴影画面灵活。适合需要动态物体多、光照变化不剧烈的场景。Shadowmask阴影遮罩多烘焙一张 Shadowmask 贴图把远处物体的阴影预烘进去近处仍然实时。这样可以在较小阴影距离下获得很长的阴影可见距离。代价是额外一张贴图内存以及配置复杂度上升。Subtractive减法直接光和阴影全部烘焙实时只用一个方向光补充颜色。这是移动端老方案画面质量一般动态物体和静态环境的融合感较差我基本不用了。一个常见误判把主方向光设成 Baked结果发现角色走过去身上没有阴影以为阴影坏了。其实是因为烘焙光压根不照动态物体。动态角色要靠 Light Probe 接收烘焙的环境光靠一盏 Realtime 或 Mixed 的主光接收实时阴影。2.3 光照贴图、探针、反射探针三套系统各管一摊Unity 的光照数据不是存在一个地方而是分成三套很多人在这里绕不清。光照贴图Lightmap管的是一块静态表面的光照信息包括直接光、间接光、阴影。它贴在这个物体的第二套 UV 上所以模型必须在导入时勾选 Generate Lightmap UVs否则烘焙会报错或者结果全黑。这是新手第一道坎我见过太多次因为模型没生成光照 UV折腾一下午以为光照系统坏了。光照探针Light Probe管的是动态物体收到的环境光照。原理是把场景里若干采样点的光照信息存成球谐系数Spherical Harmonics运行时对动态物体所在位置的相邻探针做插值。所以动态角色走进一个阴暗角落身体会自动变暗走过去又会变亮。这个系统完全是给会动的物体服务的静态物体用不上。反射探针Reflection Probe管的是环境反射。它从某个位置拍六张图组成一张立方体贴图材质上的金属和高光部分就靠它反射。动态物体如果带金属材质在静态场景里移动反射内容不会跟着变除非用 Realtime 反射探针——那个开销非常大一般只给水面、镜子这类特殊物体用。这三套东西的分工可以用一句话记住贴图管静态表面光探针管动态物体反射探针管金属反射。画面里哪部分不对就去查对应的那一套。3. 实操从零搭一套可靠的光照方案3.1 开工前的场景准备与静态标记这里我从最前面开始说因为光照出问题八成是准备工作没做全。第一步是确定管线。URP 和内置管线的光照设置项在同一个 Lighting 窗口里但能力差异很大URP 支持光照层、支持额外的烘焙光照阴影级联的配置项位置也不一样。HDRP 则是另一套物理单位体系流明、勒克斯参数思路完全不同。管线不统一后面所有参数讨论都没意义。第二步是标记静态。凡是不会移动的物体都要在 Inspector 里勾上 Contribute GI并把 Static 标记里的 Batching Static、Occluder Static 之类按需勾上。这一步的意义在于让烘焙器知道该把哪些物体纳入计算。如果漏标那个物体在烘焙结果里就是个“黑洞”会在墙上留下一块不该有的暗斑。第三步是检查模型的第二套 UV。选中模型资源在导入设置里有 Generate Lightmap UVs 选项勾上点 Apply。这个操作的内部逻辑是把模型的 UV 展开成互不重叠的图集供烘焙器写入光照信息。重叠的 UV 会导致两个面共享同一块光照数据出现奇怪的走向。UV 重叠严重的模型比如大量重复的小零件合并成一个要手动处理或者干脆拆开。第四步是规划光照贴图的分辨率预算。这个后面单独讲但最好现在就心里有数因为它决定了整个场景的图集分配。实操心得我习惯在场景里建一个空的 GameObject 作为“光照配置”容器把 Lighting Settings 资产、反射探针、以及环境光的配置说明都挂在那儿团队里任何人打开场景都能找到唯一的入口。大型场景多人协作时这个习惯能省掉大量“光照设置被谁改了”的扯皮。3.2 光照贴图尺寸与参数的计算过程光照贴图的尺寸不是随便填的它有一个可以算出来的下限。我拿一个具体场景举例。假设有一个 10 米见方的房间墙面加地板加天花板总面积大概 450 平方米。光照贴图分辨率Lightmap Resolution设成每单位 10 个像素那么每平方米是 100 个像素450 平方米就是 45000 像素。这是理论最小值实际还要算上UV 打包效率通常只有 60% 到 75%图块之间的 Padding 间隔背光面、Helper 面也需要占位置按 70% 效率算实际需要 45000 / 0.7 ≈ 64000 像素。一张 512×512 是 262144 像素理论上能放得下四个这样的房间但实际因为 UV 形状不规则通常一个房间就要占掉半张 512 的图。所以我一般给这种规模的场景先分 1024留足余量。内存账也要一起算。Unity 的光照贴图默认用 RGBA Half 格式也就是每像素 8 字节1024×1024 单张 1024 × 1024 × 8 8 MB如果开了 Directional Mode方向性光照贴图是两张直接翻倍到 16 MB换成 2048×2048单张就是 32 MB再翻倍就 64 MB这就是为什么移动端对这个数字极度敏感。手机上一个场景的光照贴图总占用控制在 8 MB 到 16 MB 是合理区间超过 24 MB 就要开始考虑压缩或者拆场景了。Directional Mode 要不要开它让烘焙的光照带上方向信息法线贴图在烘焙光下也能产生正确的明暗变化画面立体感会明显好一截。代价是双倍内存。我的判断标准是PC 和主机开移动端只在关键场景比如只有一两个室内的关卡开开放世界那种大场景一律关掉。光照贴图参数里还有几个值值得调Direct Samples / Indirect Samples采样次数直接决定烘焙时间和噪点。默认 32 和 500 左右。室内场景如果间接光噪点明显把 Indirect Samples 提到 1000 到 2000烘焙时间可能翻两三倍但换来的是不用后期模糊也能干净。Environment Samples环境光采样默认 256。天空盒有细节比如云的时候要适当提高否则环境光会显得平均而平淡。Bounces光线弹射次数。默认 2。室内间接光死黑就加到 3 或 4超过 4 收益非常小而且烘焙时间暴涨。Filtering降噪模式。Gaussian 快但会糊掉细节Advanced 慢但能保留接触阴影的硬度。我一般先用 Gaussian 迭代参数最终出图切 Advanced。Ambient Occlusion在烘焙里再叠一层 AO。这个值我通常开得比较克制0.5 到 1.0 之间因为 AO 叠太多会让墙角黑得很假而且和实时 SSAO 叠加后会过度。3.3 光照探针的布置密度与插值逻辑光照探针这块最容易犯两个错一是漏布二是乱布。漏布的表现是动态角色走进某个区域身上光照突然变成纯黑或者纯白。原因是角色所在位置不在任何探针组成的凸包内插值失败Unity 会退回到环境光的值。所以原则很简单动态物体能到达的所有位置都必须被探针包住。乱布的表现是明明布了探针角色走过去光照变化还是很生硬。原因是探针间距太大插值跨度过宽。探针插值本质是对周围几个探针做加权平均技术上用的是四面体化后的重心插值间距越大平均的范围越大光照变化就越平。我的经验值室内走廊每 3 到 5 米一组门口、转角、光源正下方要加密到 2 米左右因为这些位置光照变化最剧烈。大面积的空旷区域可以稀一点5 到 8 米一组但边缘必须贴边布。探针总数量不用太担心几百个在 PC 上开销可以忽略移动端上千个才会有感。还有两个细节探针不要穿墙。如果探针布在墙里插值时会把墙另一侧的亮光带过来角色靠近墙时会莫名变亮。所以探针要贴着墙内侧布不要嵌进墙体。Light Probe Group 有几个自动辅助功能比如在选中物体周围自动生成探针用来快速铺量可以但结果要人工整理自动生成的探针经常穿墙。反射探针的布置逻辑不同。它不是插值而是按影响范围生效同一个位置只能有一个反射探针生效重叠时按 Importance 和距离决定。所以每个独立的封闭空间房间、走廊、洞穴至少要有一个。探针位置放在空间中心或视线主要停留的位置不要贴墙。分辨率 128 基本够用重要场景可以上 256。Cubemap 128 的内存是 128×128×6×8 字节 ≈ 786 KB256 是它的四倍约 3 MB。方形房间一定要开 Box Projection然后调好 Box Size否则反射会明显偏金属表面看起来像贴了一张不匹配的照片。3.4 曝光、色调映射与后处理的联动光照调完最后一步是后处理这一步经常被当成“锦上添花”实际上它是把光照数据翻译成最终画面的必经环节参数不对会把前面所有工作废掉。曝光Exposure是所有后处理里最该先定的。它的作用是把场景的亮度范围映射到显示器能显示的范围。如果曝光过高阴影全被拉亮前期好不容易调出来的明暗对比全没了曝光过低高光全糊死光源周围一片死白。我的做法是先关掉所有后处理把主光的强度和场景基础亮度调到一个中性值再打开曝光让中灰区域落在视觉舒适的区间最后才调对比度和饱和。色调映射Tonemapping决定高光怎么衰减。ACES 是通用选择高光过渡自然色彩略偏。Neutral 保留原色更多适合风格化项目。内置管线没有内置的 Tonemapping要靠后处理插件URP 和 HDRP 自带。选哪个没有绝对对错但一个项目里必须统一不能不同场景两种色调映射玩家切场景会明显感觉到画面“跳”。Bloom用来做光源的辉光让亮部向外扩散。它的阈值Threshold设得太低整个画面都会发雾设得太高只有最亮的点才有光晕。经验值是从场景最亮的光源亮度往下试找到只有光源本身发光、墙面不发光的临界点。强度Intensity我一般控制在很低的水平宁可欠一点因为 Bloom 过量是新手画面最常见的廉价感来源。环境光Ambient单独说一句因为它不属于后处理但经常被混进去调。Lighting 窗口里的 Environment Lighting 决定了没有光照到的区域的基础亮度。用 Skybox 作为环境光来源能得到最自然的结果但如果天空盒太亮室内会整体发灰。这时候可以把环境光改成 Gradient 或者手动指定一个 Cubemap甚至直接调 Environment Intensity 压下去。室内场景我经常把环境光强度压到 0.3 到 0.5让烘焙的间接光成为主要的补光来源画面会干净很多。4. 性能与平台适配的权衡4.1 移动端的光照预算怎么算移动端做光照核心思路是“把一切能提前算的都在打包前算掉”。我给一个自己常用的预算表项目建议上限说明光照贴图总内存8–16 MB1024 单张约 8 MB控制在一到两张Directional Mode建议关闭直接省一半贴图内存实时光源数量主光 1 盏 少量无阴影点光每盏额外实时光都会增加逐像素计算实时阴影光源仅主方向光点光实时阴影是 6 次渲染移动端放弃阴影距离20–40 米超过这个距离玩家基本感知不到阴影贴图分辨率1024–2048配合级联使用光照探针数量数百以内上千会有明显的插值开销反射探针128 分辨率烘焙实时反射探针不要碰后处理仅 Tonemapping 轻度 BloomSSAO、SSR 一律不上这张表不是死规矩但它覆盖了绝大多数中小型移动项目的实际区间。真正需要根据项目调的主要是光照贴图数量和阴影距离这两项因为它们和场景规模直接挂钩。有一个容易被忽略的点光照贴图是常驻内存的。它不像普通贴图可以按需加载场景加载完成后整张图就在显存里。所以大场景拆分时不能让单个场景的光照贴图总量失控宁可拆成更多的子场景。4.2 阴影贴图分辨率与级联的换算阴影质量不够很多时候不是因为分辨率设低了而是因为阴影距离设得太长把有限的像素摊薄了。这里有个可以算的公式阴影贴图的有效密度 阴影贴图分辨率 ÷ 阴影覆盖距离。假设阴影距离设 50 米阴影贴图用 2048那么密度是 2048 / 50 ≈ 41 像素每米。一个身高 1.7 米的角色投在地面的阴影大约 70 像素宽边缘会有明显的阶梯感。如果想让阴影密度达到 100 像素每米50 米的覆盖范围就需要 5000 像素的贴图超过了多数平台的单张上限一般 4096。这时候有两个选择把阴影距离缩到 40 米4096/40 ≈ 102刚好或者用级联把近处单独拆分出来。级联Cascade的原理是把视锥按距离切成若干段近段用高密度远段用低密度各自一张贴图。URP 里可以设 1、2、4 级。设 4 级的话假设总距离 50 米近段大约覆盖 5 米用 2048 的贴图密度能到 400 像素每米阴影边缘锐利得能看清手指远段密度低但玩家也不会盯着看细节。代价是 draw call 增加。每个级联都要把投射阴影的物体渲染一遍4 级就是 4 遍。场景里阴影投射物体多的时候这个开销很可观。所以移动端常用 2 级PC 用 4 级。还有一个省事的优化把 Shadow Resolution 从 Very High 降到 High视觉差异在多数场景里几乎看不出来但显存和采样开销会明显下降。我在一个室外场景里做过对比High 和 Very High 在 1080p 下肉眼差异极小帧率却高了几个点。4.3 用脚本管理光照配置的实用写法项目做到后期光照参数会有多套配置白天、夜晚、室内、过场手动在 Inspector 里改容易出错。我习惯用 Lighting Settings 资产配合脚本切换这样配置可版本管理也不会被误改。using UnityEngine; using UnityEngine.Rendering; public class LightingProfileSwitcher : MonoBehaviour { public LightingSettings dayProfile; public LightingSettings nightProfile; public Light sunLight; public void ApplyDay() { Lightmapping.lightingSettings dayProfile; sunLight.color new Color(1.0f, 0.96f, 0.88f); sunLight.intensity 1.4f; sunLight.shadowStrength 0.9f; } public void ApplyNight() { Lightmapping.lightingSettings nightProfile; sunLight.color new Color(0.55f, 0.68f, 1.0f); sunLight.intensity 0.35f; sunLight.shadowStrength 0.6f; } }这段代码在运行时会切换光照设置资产但要注意它只影响后续的烘焙不会在运行时重新计算光照贴图。真正的运行时切换其实是切换已经烘焙好的场景或者切换光照贴图索引逻辑要复杂一些。所以这段脚本的实际用途是在编辑器里快速对比两套烘焙参数以及给美术一个统一入口去调整方向光的颜色强度搭配。别把它当成运行时昼夜系统的实现那需要另一套方案一般是两套烘焙结果做混合或者干脆用实时光。提示Lighting Settings 资产一定要纳入版本管理别用场景内嵌的设置。内嵌设置会在场景合并时产生大量冲突而且不同人打开场景看到的光照参数可能不一致排查起来非常痛苦。5. 常见问题与排查技巧实录5.1 典型故障速查表这套表是我从实际项目里攒下来的遇到问题按表查能省不少时间。现象最可能的原因排查动作烘焙后场景全黑模型没有生成光照 UV或 Contribute GI 没勾检查模型导入设置的 Generate Lightmap UVs检查物体静态标记墙面上有不规则暗斑模型 UV 重叠或存在反面的 Helper 面查看 UV 布局删除不可见的内表面墙角有明显的漏光几何体之间有缝隙光照贴图分辨率太低检查墙体是否严丝合缝把 Resolution 从 10 提到 20 试试动态角色走进阴影里还亮着光照探针没覆盖该区域补探针确保角色路径完全在探针凸包内动态角色身上光照突变探针间距过大或探针穿墙加密探针清理墙内探针金属表面反射不对反射探针位置错、没开 Box Projection调整探针位置到空间中心方形房间开启 Box Projection烘焙时间长得离谱Indirect Samples 或 Bounces 设太高先把 Bounces 降到 2Samples 降到 500 试跑光照贴图内存爆掉Directional Mode 开着或贴图尺寸 2048关掉 Directional Mode把尺寸降到 1024阴影边缘全是锯齿阴影距离太长贴图密度被摊薄缩短阴影距离或增加级联数画面整体发灰环境光太强压过了烘焙的间接光降低 Environment Intensity让烘焙结果主导室内比室外还亮环境光用了过亮的天空盒换成 Gradient 或手动 Cubemap压低强度5.2 几个真踩过的坑坑一烘焙了一半就中断结果比没烘焙还难看。Unity 的 Progressive Lightmapper 支持边烘焙边看结果但中途打断的话场景里的光照贴图处于部分完成状态可能出现一块亮一块暗。这时候不要急着改参数重烘先确认是不是没跑完。我的习惯是烘焙前先按一下 Clear Baked Data从头开始不要在半成品上继续。坑二改了模型但没重新烘焙光照数据还是旧的。Unity 会在模型修改后自动标记需要重烘但如果模型替换方式是直接拖新文件覆盖有时候标记会失效。表现是新模型上出现了旧模型的光照阴影看着像鬼影。解决办法是选中物体手动 Mark Scene as Dirty或者干脆清空重烘。坑三光照探针组复制粘贴后位置全乱。Light Probe Group 的探针是存在组件里的相对位置数据复制粘贴整个 GameObject 通常没问题但如果用某些批量工具处理探针的相对坐标会被重置。批量布置探针后一定要进 Scene 视图肉眼扫一遍。坑四多场景叠加烘焙Additive时光照贴图对不上。用多场景加载做关卡拼接时每个场景独立烘焙加载后如果两个场景有空间重叠光照贴图的采样会打架表现为接缝处莫名变亮或变暗。解决方案是把跨场景的接缝区域纳入同一个烘焙范围或者用遮挡物把接缝藏起来。这个坑我踩过一次排查了两天才定位到是烘焙范围的问题。坑五把所有光源都设成 Mixed 之后帧率莫名其妙掉了。Mixed 光源的直接光是实时计算的如果场景里有十几盏 Mixed 的点光或聚光等于十几盏实时光同时在算。所以 Mixed 不是“更安全的默认值”它一样有实时开销。真正零成本的是 Baked只是它要求物体不动。实操心得调试光照时把 Scene 视图切到 Baked Lightmap 可视化模式可以直接看到光照贴图的实际采样情况UV 拉伸、密度不足、接缝问题一眼就能看出来。这个模式比反复烘焙对比效率高得多我几乎每次调光照都会先打开它扫一遍。5.3 让光照数据保持可维护的几个习惯最后分享几条我在团队协作里坚持的做法跟技术细节无关但省下的时间比调参数多得多。一是光照参数的修改必须留记录。光照设置改动对画面的影响很大但改了什么、为什么改往往没人记得。我的做法是在 Lighting Settings 资产的命名里带上版本和日期重要改动在提交信息里写清楚改的是哪一项、观察到什么变化。听起来很笨但出问题时能救命。二是建立场景的光照检查清单。每次场景提交前过一遍静态标记是否完整、探针是否覆盖全路径、光照贴图尺寸是否超标、反射探针是否每个空间都有、环境光强度是否在合理区间。清单化之后低级错误的出现频率会下降一个数量级。三是不要一次调太多参数。光照系统各参数之间耦合很强同时改三个参数你没法判断是哪个起了作用。我习惯一次只动一个先粗调找到大致方向再细调逼近目标值。烘焙一次十几分钟这个节奏很重要。四是保留一版“保底”配置。项目后期经常需要临时出一个能跑得动的版本给外部看这时候如果光照参数正在调整中画面会很尴尬。留一版烘焙完整、参数保守的配置随时能切回去这个习惯让我躲过好几次“临时演示”的坑。光照系统这东西说到底是在有限预算下做取舍。参数记得再熟不如理解清楚“这笔计算账单是谁在付”这一个原则。想明白这个剩下的大部分选择都会变得清晰。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑