在 Unity 中,SetPass Calls(SetPass 调用) 是渲染管线中核心的性能指标之一,本质是 GPU 切换渲染状态(着色器 Pass、材质、纹理、渲染目标等)的次数,直接反映渲染效率的高低。下面从核心概念、影响因素、优化方法等维度全面解析:

一、核心概念:SetPass Calls 是什么?

Unity 的渲染流程中,每个材质(Material) 关联的着色器(Shader) 会包含一个或多个 Pass(渲染通道)。当 GPU 渲染一批物体时:

  1. 若物体使用的材质/Pass 与上一批完全一致,GPU 可批量渲染,无需切换状态;
  2. 若材质/Pass 不同,GPU 必须停止当前渲染,切换到新的渲染状态(即触发一次 SetPass Call),再继续渲染。

简单来说:SetPass Calls 次数 = GPU 切换渲染状态的次数,次数越多,GPU 空等(状态切换)的时间越长,渲染性能越差(尤其移动端/低配设备)。

二、SetPass Calls 的计算逻辑

Unity 编辑器的 Stats 面板(Game 视图右上角打开)可实时查看 SetPass Calls 数值,其计算规则:

  • 每个独立的 Pass 切换触发 1 次调用;
  • 即使是同一材质,若渲染目标(如 RenderTexture)、深度测试、混合模式等状态变化,也会触发新的调用;
  • 批处理(静态/动态批处理)能合并相同状态的物体,减少调用次数。

示例:

  • 场景中有 100 个使用相同材质/相同 Pass 的立方体:开启静态批处理后,SetPass Calls = 1;
  • 场景中有 100 个立方体,50 个用材质 A,50 个用材质 B(同 Shader 不同 Pass):SetPass Calls = 2;
  • 若 100 个立方体用 100 种不同材质:SetPass Calls = 100(性能极差)。

三、影响 SetPass Calls 飙升的常见原因

  1. 材质/Shader 碎片化

    • 大量不同材质(即使仅纹理/颜色不同)、Shader 包含多个 Pass(如 ForwardAdd 用于实时光照);
    • 示例:每个物体单独改材质颜色,导致材质实例化(Material Instance),失去批处理条件。
  2. 批处理失效

    • 静态批处理:物体未标记为 Static、顶点数超过阈值(默认 300)、使用动态纹理(如 RenderTexture);
    • 动态批处理:物体顶点数超过阈值(移动端300,PC400)、使用非统一缩放(如 (2,1,1))、包含多子网格;
    • SRP Batcher 未开启(URP/HDRP 专属优化)。
  3. 渲染状态频繁切换

    • 混合模式(Blend)、深度测试(ZTest)、模板测试(Stencil)变化;
    • 渲染目标切换(如多次渲染到 RenderTexture);
    • 光照变化(如实时光照数量多,触发 ForwardAdd Pass)。
  4. UI 渲染(UGUI)

    • UGUI 每个“不同材质/图集”的 UI 元素会触发 SetPass 调用;
    • 示例:分散的小图集、每个 Text 用不同字体材质,导致 UI 的 SetPass Calls 暴增。

四、优化 SetPass Calls 的核心方法

1. 启用批处理(最核心)

批处理类型 适用场景 开启/优化方式
静态批处理 静止物体(建筑、道具) 标记物体为 Static;PlayerSettings 中开启 Static Batching;合并静态物体的网格
动态批处理 动态小物体(粒子、小怪) PlayerSettings 中开启 Dynamic Batching;控制物体顶点数(<300);统一缩放
SRP Batcher(URP/HDRP) 所有物体 开启 SRP Batcher(Project Settings → Graphics);Shader 按 SRP 规范编写

2. 减少材质/Shader 碎片化

  • 材质复用:避免为每个物体创建独立材质,共用材质实例(仅修改属性时用 MaterialPropertyBlock,而非实例化材质);
    // 推荐:用 MaterialPropertyBlock 修改属性,不实例化材质
    MaterialPropertyBlock mpb = new MaterialPropertyBlock();
    renderer.GetPropertyBlock(mpb);
    mpb.SetColor("_Color", Color.Red);
    renderer.SetPropertyBlock(mpb);
    
  • 合并 Shader Pass:减少 Shader 中的 Pass 数量(如用 SRP 合并非光照 Pass);
  • 使用图集(Atlas):将多个纹理合并为一张图集,减少材质切换(UI/3D 物体均适用)。

3. 优化渲染状态

  • 统一渲染状态:尽量让物体使用相同的混合模式、深度测试规则;
  • 减少实时光照:实时光照会触发 ForwardAdd Pass,优先用烘焙光照(Lightmap);
  • 合批渲染目标:减少频繁切换 RenderTexture,批量渲染到同一目标。

4. UGUI 专项优化

  • 合并 UI 图集:将所有 UI 图片合并到少量图集,避免每个图片一个材质;
  • 简化 Text 材质:共用字体材质,避免每个 Text 单独实例化材质;
  • 禁用不必要的 Canvas:Canvas 重建会触发额外的 SetPass 调用,非可见时禁用。

五、关键注意事项

  1. SetPass Calls 不是唯一指标:需结合 Triangles(三角面数)、Vertices(顶点数)、GPU Instancing 综合分析;
  2. SRP Batcher 优先级高于传统批处理:URP/HDRP 项目优先开启 SRP Batcher,其原理是按 Shader 分组渲染,而非按材质,能大幅减少 SetPass 调用;
  3. 移动端敏感:移动端 GPU 状态切换开销远高于 PC/主机,SetPass Calls 超过 200-300 可能出现掉帧,PC 可接受更高数值(但仍需控制)。

六、调试工具

  • Stats 面板:实时查看 SetPass Calls 数值;
  • Frame Debugger:逐帧分析渲染流程,定位触发 SetPass 调用的物体/材质;
  • Profiler(Render 模块):深入分析渲染耗时,找到 SetPass 调用的性能瓶颈。

总结

SetPass Calls 是衡量 Unity 渲染状态切换效率的核心指标,优化的核心思路是减少 GPU 状态切换次数:通过批处理、材质复用、图集合并、统一渲染状态等方式,将 SetPass Calls 控制在合理范围(移动端 < 200,PC < 500),可显著提升渲染性能。