Quick answer: Use CPU sim for emitters whose data the game thread reads. For GPU sim, use async readback via custom Data Interface; never read sync.
Insight session shows a 12 ms stall every frame on the game thread waiting for GPU readback. Niagara module is GPU-simulated and BP queries particle positions every Tick.
The Fix
Niagara Emitter properties:
Sim Target: CPUSim // for game-thread readable
// Or split into two emitters:
EffectVisual (GPU, 100k particles, no readback)
EffectGameplay (CPU, 64 particles, reads on game thread)
// In BP/C++:
GetNiagaraParticlePositions(EffectGameplay, OutPositions);
// CPU sim returns immediately, no GPU stall.
GPU is for visual scale; CPU is for gameplay-readable state. Don’t mix the two purposes in one emitter.
Verifying
Insight: game-thread waits gone. Visual emitter still GPU-fast. Gameplay reads land same frame.
“Right sim target. No stalls. Gameplay reads.”
Related Issues
For Niagara user param, see user param. For collision event, see collision event.
CPU for reads. GPU for visuals.