CPU 还是 GPU 模拟:一次选对
"这个发射器用 CPU 还是 GPU?"是特效评审会上最高频的问题。选错并不会立刻报错,而是在项目后期以帧率崩塌的形式出现。先把原理讲清楚,再给决策表。
两种模拟位置的含义
粒子模拟的每帧计算(力的积分、碰撞、生命周期的推进)有两种执行位置:
- CPU 模拟:在 CPU 线程上算。粒子数据留在主存,可以随便和游戏逻辑交互(蓝图、C++ 直接读写每个粒子的数据),支持任意模块。
- GPU 模拟:把粒子数据放在显存,用 Compute Shader 成批算。速度快一个量级(数万粒子也能几毫秒搞定),但数据不出显存,游戏逻辑读不到每个粒子的状态,且部分模块(依赖逐粒子外部数据的功能)不被支持。
决策表
| 你的需求 | 选择 | 理由 |
|---|---|---|
| 特效要和逻辑交互(每个粒子带伤害、粒子要跟随某个 Actor 的每个骨骼点) | CPU | GPU 数据读不回主存 |
| 需要游戏中的逐粒子命中判断 | CPU | 同上 |
| 大量"纯表现"粒子(环境氛围尘、暴雨、爆炸碎片) | GPU | 量大,GPU 批处理优势 |
| 用了 Niagara Fluids(流体模拟) | 按模板要求 | 流体插件自己管理位置 |
| 需要数据接口读骨骼 / 距离场模拟(GPU 侧) | GPU | DI 本身就是 GPU 侧设计 |
| 移动端项目 | 先 CPU,后按预算转 GPU 或砍量 | 移动端 GPU 模拟支持有限,见性能章 |
一个容易被忽略的代价:数据回读
CPU 模拟的粒子数据可以被逻辑直接读取,这听起来方便,但它是双向的:每次你在蓝图里 ForEach 遍历粒子,或者每帧把粒子位置同步给碰撞检测,都在消耗主线程。见过最夸张的案例:一个 CPU 特效每帧把 3000 个粒子位置拷贝给物理查询,主线程多耗 4ms。"能用 CPU 读"不等于"应该每帧读"。
混合策略:一个 System 里两种都有
实际项目里常见的是混合:一个爆炸特效,核心的冲击波和伤害判定用 CPU Emitter(粒子少、要交互),周围的火星和烟用 GPU Emitter(纯表现、量多)。System 时间轴一次性编排两者,玩家看不出区别,帧率却轻松很多。
切换的成本
在 Emitter 编辑器里切换 CPU/GPU 是一个下拉框的事,但不是零成本:切换后部分模块会变灰(GPU 不支持),需要替换或删除。所以建议第一版就用对的模拟目标,而不是先做 CPU 再想着"以后优化转 GPU"——那时候往往要重写大半逻辑。
