Niagara Data Channel collision data duplicates event at world origin (0,0,0)

Hi!
I’m using Niagara Data CHannel to spawn shell casings from gunfire — the spawning itself works fine. At the shell collision location, I spawn sounds or effects, and that works too, but with some strange behaviour

The problem is that when a particle is spawned, it immediately sends collision data at the zero coordinate and triggers the code, even though not all conditions are met. For example, Particle Age should be> 0.5s

When the particle actually hits a surface, it sends the correct collision data, but right after that it also sends collision data for the zero coordinate, even though I can clearly see that the collision did not happen there

—————

I added FX at the collision location to demonstrate this issue

It might be related to [:check_box_with_check: Keep Previous Frame Data] or some other NDC settings, but I’ve tried every possible combination. The shell either wouldn’t spawn at all, would spawn only once, or would spawn continuously but wouldn’t send collision data

—————

Here is my NDC

—————

Here is Niagara

The NDC spawn and reader work as expected — the data is being sent and the particles spawn correctly. I set them up following Epic’s tutorial, so I’m not sure if it’s worth showing that part here. The problem starts when I try to pass particle collision data to Blueprint

—————

This is how I built NDC writer module

I’m writing data to pass into Blueprint and doing several checks to avoid sending everything all the time. For some reason, these checks don’t work on the very first frame when the particle is spawned

—————

This is how I read data from NDC in weapon blueprint

When the shells hit something, s/vfx is triggered. This is currently done via Event Tick for testing purposes

that zero-coordinate event on spawn is the collision event path feeding uninitialized data: on the particle’s first frames the collision buffer holds default/zero values for particles that have not collided yet, and anything consuming the channel sees that as a real event. Keep Previous Frame Data makes it worse because you then re-read last frame’s buffer, which also starts zeroed.

reliable fixes, in order:

  1. validate in the consumer. a genuine hit always carries a non-zero surface normal and a location on geometry. in the code that receives the NDC event, skip entries where the location is effectively zero or the normal is zero. crude, one comparison, bulletproof.
  2. do not transmit raw collision state — write your own event payload. use the collision event module to set explicit per-particle attributes (Particles.bHit, Particles.HitPos from the collision result) and only send to the data channel when bHit is true. you control exactly what enters the channel, so phantom events never exist in it.
  3. the age gate has to live on the sender. you checked Particle Age > 0.5s — but if that check sits in the consumer, the zero event has already been sent and consumed. put the gate on the particle side before the data is written to the channel.
  4. spawn order: if the shells and the NDC listener spawn in the same frame, the listener’s first read sees whatever the buffer was initialized with. delaying listener activation by a frame after spawn also removes the first-frame artifact.
    the combination of 1 + 2 is what most people settle on: never create a channel entry from raw collision buffer state, only from an explicitly validated hit. the zero events disappear completely and the real hits keep working.