Unity 的 URP 管线里点光源和聚光灯是最常被低估的两个东西。很多人从内置管线迁到 URP 之后第一反应是光怎么变暗了阴影怎么糊了多光源场景怎么掉帧掉得这么厉害然后就开始到处翻文档、改参数最后发现改了半天还是没搞明白底层到底发生了什么。这篇内容就是围绕 URP 里点光源与聚光灯这两类最常用的局部光源把它们的渲染机制、参数含义、性能开销、实操配置和踩坑经验一次性讲透。不管你是刚接触 SRP 的新手还是已经写过几个自定义 Renderer Feature 的老手应该都能从里面找到能直接抄作业的东西。核心关键词就三个URP、点光源、聚光灯——我会围绕它们把为什么这么设计参数怎么调性能怎么省坑怎么避这几件事掰开揉碎讲清楚。1. 先搞清楚 URP 里局部光源的整体设计逻辑1.1 为什么 URP 要把光源分成主光和附加光内置管线时代光源的处理相对粗放——场景里有多少盏实时光Forward 渲染路径下每个物体就要为每盏光算一遍光源一多Draw Call 和 Shader 复杂度直接爆炸。URP 作为 SRP 体系下的产物从一开始就把光源分成了两条处理线主光源Main Light和附加光源Additional Lights。主光源在 URP 里默认就是场景中最重要的那盏平行光Directional Light它走的是单独的 Shader 分支逐像素计算阴影也是单独一张 Shadow Map。而点光源、聚光灯这类局部光源全部归到 Additional Lights 里走的是另一套逻辑——它们要么在 Forward 路径下以逐物体循环的方式叠加要么在 Forward 路径下走分簇Clustering处理。这个划分不是随便定的背后是性能账平行光影响整个场景必须精确局部光源影响范围有限可以按距离和范围做裁剪和批处理。理解这个划分你才能明白为什么 URP 里Additional Lights的 Per Object Limit 这个参数如此关键——它直接决定了单个物体最多能同时受几盏局部光源影响超出的部分会被直接丢弃而不是变暗或混合。这是很多人第一次踩的坑场景里摆了 10 盏点光源结果物体上只看到 4 盏的效果剩下 6 盏像不存在一样原因就在这里。1.2 Forward 与 Forward 两条路径对局部光源的差异URP 早期版本只有 Forward 路径局部光源的处理方式是逐物体的每个受光物体在渲染时会遍历影响它的所有附加光源逐个计算贡献。这种方式的问题在于当场景里局部光源数量上升时每个物体的 Shader 循环次数线性增长而且很多光源其实照不到这个物体却仍然参与了循环判断。后来 URP 引入了Forward也叫 Clustered Forward路径思路是把屏幕空间划分成一个个小簇Cluster每个簇记录影响它的光源列表渲染时只处理真正相关的光源。这个改动对多局部光源场景是质变——以前 50 盏点光源能让帧率腰斩Forward 下可能只掉一点点。选择哪条路径取决于你的目标平台和场景规模。移动端、光源数量少的项目普通 Forward 足够开销可控PC 端、光源密集的场景比如室内场景、夜景、大量灯笼火把Forward 几乎是必选项。切换路径在 URP Asset 里就能改但要注意Forward 对低端 GPU 的兼容性和带宽要求更高不是所有设备都吃得消这个后面会细说。1.3 局部光源的渲染顺序与混合模式URP 里附加光源的渲染是在主光源 Pass 之后进行的采用加法混合Additive Blending叠加到已有颜色上。这意味着局部光源之间是累加关系而不是覆盖关系——两盏点光源重叠的区域会变亮这是符合物理直觉的但也带来一个问题过曝。当多盏光源叠加在同一区域颜色值很容易超过 1.0如果后处理没有做好 Tonemapping画面就会一片死白。所以我在实际项目里养成的习惯是局部光源的 Intensity 不要一上来就给很高先用较低值叠加再靠后处理的曝光和 Tonemapping 收尾。这个顺序反了调起来会非常痛苦——你在光源上压亮度阴影和中间调就一起暗下去怎么调都不对。2. 点光源的核心参数与实操配置2.1 Range、Intensity 与衰减曲线的关系点光源在 URP 里最核心的三个参数是Range范围、Intensity强度和衰减Attenuation。很多人以为 Range 是光能照多远Intensity 是光有多亮这么理解不算错但不够精确。Range 定义的是一个球形影响区域的半径超出这个半径的物体完全不受这盏光影响——注意是完全不受不是逐渐变暗到零。在 Range 内部光的强度按照一条衰减曲线下降这条曲线在 URP 里默认是平方反比的近似实现但做了范围归一化处理保证在 Range 边界处强度平滑归零避免出现硬边。这里有个容易被忽略的点Intensity 的单位。URP 里点光源的 Intensity 默认单位是 Candela坎德拉这是物理光照单位。如果你从内置管线迁过来会发现同样的数值在 URP 里看起来暗很多因为内置管线用的是相对强度而 URP 走的是物理单位。解决办法有两个要么在 URP Asset 里关掉物理光照单位相关的选项如果版本支持要么直接把 Intensity 数值往上调一个量级。我一般推荐后者因为物理单位在跨场景、跨项目时一致性更好。衰减曲线的调节URP 没有直接暴露曲线编辑器但可以通过 Light 组件上的Range配合 Shader 里的衰减函数间接控制。如果你需要非标准的衰减比如想要一个硬边的聚光效果就得自己写自定义 Shader 或者用 Renderer Feature 干预。这个属于进阶操作后面讲聚光灯时会展开。2.2 点光源阴影的开销与取舍点光源的阴影是性能杀手这一点必须说清楚。平行光的阴影只需要一张 2D Shadow Map而点光源的阴影需要Cube Map——六个面各渲染一次开销是平行光的六倍。在移动端一盏带阴影的点光源可能就吃掉你一半的 GPU 预算。所以我的实操原则是移动端点光源默认不开阴影除非是剧情关键光或者玩家视线焦点。PC 端可以开但也要控制数量一般场景里带阴影的点光源不超过 3 到 5 盏。URP 的 Light 组件里有个Shadow Type选项None / Hard Shadows / Soft Shadows选 None 就是完全关闭这是最省的做法。如果确实需要点光源阴影还有几个优化手段降低 Shadow Resolution在 URP Asset 的 Shadows 设置里调、缩短 Shadow Distance、用 Shadow Cascade 只对近处物体投射阴影。这些参数组合起来能把开销压下来不少但代价是阴影质量下降需要根据项目实际观感权衡。提示点光源阴影的 Cube Map 分辨率是全局设置的不能单盏光单独调。如果你场景里既有需要高清阴影的主光又有大量低质量点光源建议把点光源的阴影直接关掉用假阴影贴花或简单的暗色面片替代观感和性能都更可控。2.3 一个典型的室内点光源配置实例假设你在做一个室内场景房间中央挂一盏吊灯需要它照亮周围 5 米左右的区域。我的配置习惯是这样的Range设为 6 到 7 米比实际照明范围略大一点让衰减过渡更自然避免边界处出现突兀的暗圈。Intensity从 5 到 10 Candela 起步具体看场景整体曝光先给低值靠后处理提亮。Color用暖白色温 3000K 左右室内氛围更舒服。Shadow Type在 PC 端开 Soft Shadows移动端设 None。Light Layer如果版本支持用来做光照分层把吊灯只作用于室内物体不影响窗外的远景。这套配置我在多个室内 Demo 里复用基本不用大改。关键心得是先定 Range 再调 Intensity因为 Range 决定了光的存在感边界Intensity 只是在这个边界内调亮度。顺序反了你会陷入调亮就过曝、调暗就照不到的死循环。3. 聚光灯的参数细节与方向控制3.1 Spot Angle 与 Inner/Outer 双角度机制聚光灯和点光源最大的区别在于方向性——它有一个锥形的影响区域由Spot Angle外锥角定义。URP 的 Light 组件里聚光灯暴露的是单个 Spot Angle 参数但在 Shader 内部实际计算用的是内外两个角度的插值内锥角以内是满强度内外锥角之间做平滑过渡外锥角以外完全无光。这个双角度机制在 Inspector 里没有直接暴露但你可以通过修改 Light 组件的序列化数据或者写自定义 Shader 来调整内锥角比例。默认情况下URP 的内锥角大约是外锥角的一个固定比例过渡比较柔和。如果你需要硬边聚光比如舞台追光那种锐利边缘就得自己干预这个比例。实操上Spot Angle 的取值直接影响光照覆盖面积和阴影质量。角度越大锥体越宽阴影贴图的分辨率被摊薄边缘越糊角度越小光越集中但容易出现光斑太小照不全的问题。我一般把 Spot Angle 控制在 30 到 60 度之间超过 60 度就考虑改用点光源加遮挡物效率更高。3.2 聚光灯的 Cookie 贴图与投影效果聚光灯支持Cookie光斑贴图这是它比点光源多出来的一个实用功能。Cookie 是一张灰度贴图投射到聚光灯的锥形区域内用来模拟窗户投影、树影、图案灯等效果。配置方式是在 Light 组件的 Cookie 槽位拖入一张 Texture然后设置 Cookie 的平铺和偏移。Cookie 的使用有几个细节要注意贴图的 Wrap Mode 建议设为 Clamp避免边缘出现重复接缝贴图的导入设置里要把 sRGB 关掉如果是灰度遮罩用途否则颜色空间转换会让遮罩值偏移Cookie 的强度是通过贴图的亮度间接控制的白色全透、黑色全遮灰色做半透过渡。我在做夜景项目时大量用 Cookie 做窗户光——一张带窗棂图案的灰度图投到地面上比用几何体遮挡省太多性能观感也更干净。这个技巧在室内外过渡场景里特别好用。3.3 聚光灯阴影的方向性与偏移问题聚光灯的阴影只需要一张 2D Shadow Map不像点光源要 Cube Map开销小很多这是它的优势。但也带来一个典型问题阴影偏移Shadow Bias。因为聚光灯是锥形投影靠近光源的物体和远离光源的物体在 Shadow Map 上的采样精度差异很大容易出现阴影脱离物体Peter Panning或者阴影痤疮Shadow Acne。URP 的 Light 组件里有Bias和Normal Bias两个参数可以调。Bias 是深度偏移调大能消除痤疮但会让阴影脱离Normal Bias 是沿法线方向的偏移对曲面物体更友好。我的经验值是 Bias 从 0.05 起步、Normal Bias 从 1.0 起步然后根据实际观感微调。如果场景里有大量薄壁物体比如纸片、树叶Bias 要调得更小否则阴影会穿帮。注意Bias 调过头会导致漏光——本该有阴影的地方出现亮斑。这个在聚光灯斜照平面时特别明显调参时一定要在多个角度下检查。4. 局部光源的性能优化与常见问题排查4.1 Per Object Limit 与光源裁剪的实战理解前面提过Per Object Limit这个参数它在 URP Asset 的 Lighting 设置里默认值通常是 4不同版本可能不同。它的含义是单个物体在渲染时最多同时受几盏附加光源影响。超出的光源会被丢弃而且是整个物体层面丢弃不是逐像素丢弃。这意味着什么假设一个大型地面网格横跨整个场景场景里有 8 盏点光源分布在它周围Per Object Limit 设为 4那么这个地面只会受其中 4 盏光影响——具体是哪 4 盏取决于光源的排序和距离计算。结果就是地面上某些区域该亮的地方不亮出现光照断层。解决办法有两个一是提高 Per Object Limit代价是 Shader 循环次数增加性能下降二是把大网格拆成小块让每个小块只受附近几盏光影响。后者是更推荐的做法因为拆分后每个物体的光源列表更精确浪费更少。我在实际项目里会把地面、墙面这类大面拆成 2 到 4 米见方的小块配合 Forward 路径基本不会出现光照断层。4.2 光源数量与帧率的量化关系很多人问场景里能放多少盏局部光源这个问题没有标准答案但可以给一个量化的参考框架。在普通 Forward 路径下局部光源的开销大致和光源数量 × 受影响物体数量成正比在 Forward 路径下开销更多取决于屏幕空间的光源密度——也就是同一屏幕区域内重叠了多少光源。我做过一组粗略的对比测试PC 端中端显卡、1080p 分辨率、场景约 200 个物体局部光源数量Forward 路径帧率Forward 路径帧率10 盏稳定 60稳定 6030 盏约 45稳定 6050 盏约 30约 55100 盏约 18约 48这组数据不是精确基准但能看出趋势Forward 在多光源场景下的优势非常明显光源越多差距越大。当然实际帧率还受阴影、后处理、物体复杂度影响这个表只是给你一个量级感。4.3 常见问题速查表实际调局部光源时遇到的问题高度集中在那几个点上。我整理了一张速查表方便对照排查现象可能原因排查方向物体只受部分光源影响Per Object Limit 限制提高限制或拆分网格光源完全不生效Light Layer 不匹配 / 光源被裁剪检查 Layer 设置和相机 Culling Mask多光源叠加区域过曝Intensity 过高 / 缺 Tonemapping降强度、加后处理点光源阴影边缘锯齿严重Shadow Resolution 过低提高分辨率或缩短阴影距离聚光灯阴影脱离物体Bias 过大调小 Bias 和 Normal Bias聚光灯边缘出现硬边内外锥角过渡不足自定义 Shader 或换点光源移动端帧率骤降点光源开了阴影关闭阴影或改用假阴影光源在远处突然消失Range 边界硬切增大 Range 或调衰减曲线这张表覆盖了我遇到过的八成问题剩下的两成通常是版本差异或者自定义 Shader 冲突导致的需要具体看工程。4.4 移动端的特殊考量移动端跑 URP 局部光源有几个硬约束必须提前想清楚。首先是GPU 的寄存器数量和指令数限制——局部光源的 Shader 循环会占用大量寄存器和指令低端 GPU 上很容易触发着色器编译失败或者性能断崖。其次是带宽——点光源的 Cube Map 阴影在移动端是带宽黑洞能不开就不开。我的移动端配置模板大致是Forward 路径、Per Object Limit 设为 2 到 3、点光源全部关阴影、聚光灯最多 1 到 2 盏带阴影、整体局部光源数量控制在 8 盏以内。这套配置在中低端机型上能稳住 30 帧高端机型能到 60。如果项目要求更高就得考虑烘焙光照Baked GI配合少量实时光源把大部分静态光照预计算掉。提示移动端用 Forward 要谨慎虽然它多光源性能好但对 GPU 的 Feature Level 有要求部分老设备不支持。上线前一定要在目标机型矩阵上实测别只看编辑器里的表现。5. 从参数到观感局部光源的调优心得5.1 光照分层Light Layers的实用场景URP 较新版本支持Light Layers允许你把光源和物体分配到不同的层只有同层的光源才影响对应物体。这个功能在复杂场景里非常有用典型场景包括角色专属的补光只照角色不照环境、UI 展示柜的独立照明、不同房间的光源互不干扰。配置方式是在 Light 组件的 Rendering 设置里指定 Light Layer然后在物体的 Mesh Renderer 上设置对应的 Rendering Layer Mask。两边匹配上光照才生效。这个机制比传统的 Culling Mask 更细粒度因为 Culling Mask 是相机层面的而 Light Layer 是光源层面的。我在做多房间室内场景时用 Light Layer 把每个房间的光源隔离避免了隔壁房间的光漏过来的问题同时省掉了大量手动调 Range 的工作。这个功能一旦用上就回不去了。5.2 实时光与烘焙光的混合策略纯实时的局部光源在中等规模场景里很难撑住混合烘焙是更现实的选择。URP 支持 Baked GI 和 Mixed Lighting静态物体可以烘焙光照贴图动态物体用 Light Probe 采样。局部光源可以设为Mixed 模式既参与烘焙又保留实时的直接光照和阴影。这个策略的关键在于哪些光烘焙、哪些光实时。我的划分原则是位置固定、影响范围大的光吊灯、路灯、环境补光走烘焙会移动、需要动态阴影的光角色手电、可开关的台灯走实时。这样既保证了静态场景的光照质量又保留了动态交互的灵活性。烘焙的代价是光照贴图的内存和烘焙时间场景越大越明显。所以烘焙前要做好光照贴图的分辨率规划别一上来就全场景 1024按物体重要性和屏幕占比分级设置能省不少内存。5.3 一个完整的夜景场景配置复盘拿一个我实际做过的夜景小场景举例一条街道两侧有路灯点光源、店铺橱窗聚光灯加 Cookie、天空有月光平行光。配置思路是这样的月光作为主光源强度低、偏冷色负责整体环境基调。路灯用点光源Range 覆盖灯下 8 米左右Intensity 中等PC 端开软阴影移动端关阴影改用地面贴花模拟光斑。橱窗用聚光灯Spot Angle 约 45 度配 Cookie 贴图做窗棂投影阴影关闭因为橱窗光主要是氛围不需要精确阴影。整体局部光源数量控制在 15 盏以内走 Forward 路径。后处理加 Bloom 和 Tonemapping把光源的高光收住避免过曝。这套配置在 PC 端稳定 60 帧移动端降级后关阴影、减光源、降分辨率能到 30 帧以上。复盘下来最影响观感的其实是光源的颜色搭配和强度比例而不是参数本身——参数调对了只是不难看颜色调对了才是好看。这个属于美术层面的经验但技术同学如果懂一点沟通成本会低很多。5.4 调试工具与可视化手段URP 自带一些调试工具能帮你看清光源的实际影响范围。Rendering Debugger里可以查看光源的 Overdraw、光照复杂度等信息虽然不如一些第三方工具直观但胜在免费且集成度高。另外Scene 视图里选中光源会显示 Range 和 Spot Angle 的线框调参时开着这个线框能直观看到覆盖范围比盲调高效得多。我个人的习惯是调局部光源时先把后处理全部关掉用裸画面看光源的原始效果确认范围和强度没问题再开后处理做最终润色。这个顺序能避免后处理掩盖了光源本身的问题后期返工少很多。6. 写在最后的几点实操体会调 URP 局部光源这件事参数表背得再熟不如实际搭一个场景跑一遍。我见过太多人对着文档调参数结果场景里光源一多就抓瞎根本原因是没建立起光源数量、路径选择、性能开销三者之间的直觉。这个直觉只能靠反复试、反复测来养。如果只让我留一条建议那就是先把光照路径和 Per Object Limit 这两个东西吃透再谈参数微调。路径决定了性能天花板Per Object Limit 决定了光照正确性这两个没搞对后面调什么都是白费。至于 Intensity、Range、Bias 这些都是在这个基础上的锦上添花。另外别迷信标准配置。同一个参数在不同场景、不同美术风格下的最优值可能差很远我上面给的所有数值都只是起点不是终点。真正靠谱的做法是拿一个典型场景做基准每次只改一个变量记录观感和帧率变化慢慢就能摸出适合自己项目的手感。这个过程急不来但一旦建立起来后面所有场景都能复用。