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"——那时候往往要重写大半逻辑。