In Niagara 5.7, can a particle persistently follow its source NDC entry across its lifetime — or is NDC genuinely only designed for spawn-time consumption?
Context
I have N moving positions (Mass entities, hundreds concurrent) that each need an associated VFX following them — e.g. an orbit halo, spawned once, particles live ~10 s, orbit center tracks the entity as it moves.
The standard pattern — one UNiagaraComponent per actor + local-space emitter — works fine but lags the game at scale. So I’m trying to consolidate into one shared UNiagaraComponent serving N instances via Niagara Data Channels.
Spawn half works: C++ writes per-entity entries to an NDC (Position, EntityID, ShouldSpawn), and Spawn Particles From Data Channel on the emitter fires K particles per active entry, capturing EntityID as a particle attribute at spawn.
Where I’m stuck: the per-frame Particle Update read. Each particle needs to look up the NDC entry where EntityID == MyEntityID, get its current Position, and recentre its orbit on it. Approaches I’ve ruled out:
- Read NDC by Index — O(1) but indices aren’t stable frame-to-frame (channel buffer rebuilt every tick).
- HLSL scratch scanning entries — works but fragile; an earlier prototype using this pattern didn’t land.
- FNiagaraID PersistentID pattern — particle-to-particle only, no NDC counterpart.
- Shipped NDC content modules (Water, Fluids, ClonerEffector) — all spatial-grid / collision style, none implement moving-source-follow.
What’s left is a custom UNiagaraDataInterface backed by TMap<int32, FVector> exposing O(1) Read(EntityID) (~300 LOC of UE C++). It works, but sidesteps NDC for the tracking half.
The actual question: Is there a built-in Niagara mechanism I’m missing, or is custom DI the intended path — and NDC isn’t actually designed for persistent per-particle source tracking?
[Attachment Removed]