1. if 分支的本质
-
GPU 在执行像素着色时,会把多个像素线程打包成一个批次并行执行(PC 端常叫 warp,移动端常叫 wavefront 或者“执行束”)。
-
一个批次内的所有线程必须执行相同的指令。
如果 if 条件在同一个批次里不一致,就会产生 分支发散(divergence),导致 GPU 分别执行两个分支并合并结果 → 性能下降。
2. 什么时候 if 很便宜
-
条件是 uniform(运行时常量)
来自材质属性、C#SetFloat、MaterialPropertyBlock等,每个物体绘制时该值一致。 -
批次内像素的条件一致
即使不是 uniform,只要这个批次里的像素条件值相同,就不会发散。 -
分支内是重逻辑
如果条件大部分为 false,可以避免大量无用计算,if 反而更省性能。 -
移动端也一样
Mali、Adreno、PowerVR 等移动 GPU 也是 SIMD/SIMT 架构,原理一致。
3. 什么时候 if 会变慢
-
条件来自 per-pixel 数据(如贴图、屏幕空间计算结果),warp 内的像素条件可能不同。
-
分支两边都很轻,发散造成的执行两遍比直接算两边再 lerp 还慢。
-
分支嵌套复杂,引发额外的寄存器压力和指令调度开销。
4. 常见的三种条件来源
| 条件来源 | warp 内一致性 | 性能表现 | 典型场景 |
|---|---|---|---|
编译期常量(#if 宏) |
永远一致 | 最快 | 平台差异、功能开关 |
| uniform 常量(材质属性、C# 传值) | 每物体一致 | 高效 | 材质开关、效果启用/禁用 |
| per-pixel 动态值(贴图、varying) | 可能不一致 | 易发散 | mask 控制、屏幕空间条件 |
5. 优化策略
-
条件尽量 uniform 化
能在 CPU 端提前判断的逻辑,不要放到每像素去判断。 -
效果分材质
需要开启的效果直接用不同材质,而不是一个材质里用贴图 mask 去分支。 -
重逻辑用 if,轻逻辑用 lerp
-
重逻辑:避免不必要计算,用分支跳过。
-
轻逻辑:直接两边算再 lerp,免得发散。
-
-
分支层级浅化
避免深层 if 嵌套带来的寄存器和调度开销。
6. 误区与澄清
-
❌ 误区 1:「GPU if 分支很耗性能,要避免」
✔ 真相:耗性能的是 分支发散,不是 if 本身。条件一致时 if 很便宜。 -
❌ 误区 2:「材质面板的属性不是常量」
✔ 真相:对 GPU 一个 draw call 来说,它就是 uniform 常量。 -
❌ 误区 3:「PC 和移动端差别很大」
✔ 真相:SIMD/SIMT 分支执行原理一致,区别在硬件规模和调度策略。
7. 简短结论
如果条件在一个 warp 内一致,if 分支几乎没有额外开销,反而能节省重逻辑计算;
如果条件在 warp 内不一致,就会引发分支发散,性能下降,轻逻辑建议用 lerp 替代。








暂无评论内容