# Calculating Velocity/Rotation from manually driven Texture Positions in Niagara?

**URL:** <https://forums.unrealengine.com/t/calculating-velocity-rotation-from-manually-driven-texture-positions-in-niagara/2733622>\
**Category:** FX\
**Tags:** unreal-engine, question\
**Created:** [July 5, 2026, 2:12am UTC](https://forums.unrealengine.com/t/calculating-velocity-rotation-from-manually-driven-texture-positions-in-niagara/2733622 "2026-07-05T02:12:16Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![blindminds](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/blindminds/32/1213160_2.png) [@blindminds](https://forums.unrealengine.com/u/blindminds)\
**Post date:** [July 5, 2026, 2:12am UTC](https://forums.unrealengine.com/t/calculating-velocity-rotation-from-manually-driven-texture-positions-in-niagara/2733622/1 "2026-07-05T02:12:17Z")

</div>

I’m working on a highly optimized custom ECS / Data-Oriented flocking framework in C++ capable of running 150,000+ boids. To render this, I am calculating all the math in C++ memory arenas and pushing the data to Niagara via a DMA Texture Bridge (`UpdateTextureRegions`).

**The Setup:** In Niagara, I use a `Sample Texture` module (reading UVs via `ExecutionIndex`) to grab the exact 3D world coordinate for each boid, and then I use a `Set Parameters` module to directly set `Particles.Position = SampledPosition`. This effectively teleports the particles every frame. The translation works flawlessly and runs incredibly fast.

**The Problem:** I am trying to get the meshes to orient to their direction of travel. Because I am manually teleporting them and bypassing `Solve Forces and Velocity`, Niagara doesn’t automatically generate a velocity vector for them.

**What I’ve Tried:** I tried to calculate the velocity manually by creating a frame-delay line using a custom `Particles.OldPos` vector. The logic was:

1. Cache the old position (`Particles.OldPos = Particles.Position`).
2. Sample the new texture position (`Particles.Position = SampledTexture`).
3. Calculate the flight path (`Facing Direction = Position - OldPos`).

**The Result:** The boids spawn and seem to rotate initially, but then they become permanently locked in that rotation. Depending on where I place the `OldPos` module in the stack, they either lock facing radially outward from the center of the map, or directly inwards. They do not actively update their rotation as they fly around.

**My Question:** Is there a specific way this needs to be ordered in the Niagara stack, or a specific namespace (`Previous`) that must be used? My theory is that the Niagara HLSL compiler might be aggressively reordering the modules or optimizing out the `OldPos` variable into a same-frame alias of `Position`, causing the delta math to break or evaluate to `(0,0,0)`.

Does anyone know the proper, standard way to calculate finite difference (`Position - PreviousPosition`) for manually teleported particles in Niagara? I know the foolproof solution is to just generate a second Velocity Texture in C++ and pass it in, but I am trying to keep things as hyper-optimized as possible and avoid the extra PCIe/VRAM overhead if Niagara is capable of just calculating the math natively on the GPU.

Thanks in advance!

_"I found a previous thread suggesting to store the Last Position and Current Position to calculate Velocity (link), but when I try to implement this using `Set Parameter` modules, the Niagara compiler seems to alias the variables. The math evaluates to exactly (0,0,0), causing the Orientation module to lock to its default fallback rotation. -_ [How can I manually calculate Particle Velocity in Niagara - #2 by BRS\_GerDAngelo](https://forums.unrealengine.com/t/how-can-i-manually-calculate-particle-velocity-in-niagara/2379291/2)

---

<div class="post-metadata">

**Author:** ![ShadowBr0kerz](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/shadowbr0kerz/32/1201558_2.png) [@ShadowBr0kerz](https://forums.unrealengine.com/u/ShadowBr0kerz)\
**Post date:** [September 11, 2026, 6:41pm UTC](https://forums.unrealengine.com/t/calculating-velocity-rotation-from-manually-driven-texture-positions-in-niagara/2733622/2 "2026-09-11T18:41:23Z")

</div>

since you teleport the particles, Niagara never integrates anything, so Particles.Velocity stays dead. compute velocity yourself and feed it to orientation — with your architecture the clean answer is to never compute it in Niagara at all:

1. do the difference in C++. you already hold the position arenas for frame N and N-1. before uploading, compute v = (posN - posN-1) \* invDt per boid and write it into a second DMA texture channel (or pack it into the region layout). in Niagara the same Sample Texture setup reads channel 0 for position and channel 1 for velocity. no frame-delay state machine inside the emitter, no ordering hazards, deterministic, and it costs nothing on the GPU side — one more texture fetch per particle. this also fixes the why of your OldPos attempt failing: inside the particle update stack, OldPos written in the same pass as the teleport usually gets sampled before/after in a way that collapses the diff to zero or garbage, and stacking a one-frame delay next to Set Parameters that overwrite Position is an ordering trap. the C++ diff sidesteps all of it.
2. orientation: same logic — build the quaternion in C++ where you own the math. velocity direction + your bank/pitch rules → quat → upload as a third/fourth channel → set Particles.MeshOrientation from it after the sample. engine-side “align to velocity” nodes will fight teleported particles since they derive rotation from integrated velocity that never exists.
3. if you insist on engine-side anyway: the pattern that works is copying Position to OldPos in the Emitter Update stage (runs before particle update), then in particle update doing the diff with Engine.DeltaTime — but you must keep your Set Parameters teleport after the velocity module in the stack, and the sample of OldPos happens on the frame-delayed copy. it works but it is fragile and you are maintaining ordering that breaks on every emitter refactor.  
given 150k+ boids and an ECS host, option 1 + 2 is the right call: treat Niagara purely as a renderer of uploaded state, which is what it has become in your setup anyway.

---

<div class="post-metadata">

**Author:** ![blindminds](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/blindminds/32/1213160_2.png) [@blindminds](https://forums.unrealengine.com/u/blindminds)\
**Post date:** [October 6, 2026, 1:23am UTC](https://forums.unrealengine.com/t/calculating-velocity-rotation-from-manually-driven-texture-positions-in-niagara/2733622/3 "2026-10-06T01:23:07Z")

</div>

thank you for this, I dont know when I wil have time to come back to this project, but this is most excellent and much appreciated and looking forward to trying this.

I amy even still try the niagra setp you mention, but I dont think I thought of putting the data in 2 channels each, which solves the PCIe Bus problem.
