Quick answer: PhysX’s broadphase AABB tree updates during simulate(). Same-frame raycasts after a teleport see the old tree. Call flushQueryUpdates (or simulate(0)) before the query, or schedule moves before the simulate step.

Code moves a PxActor to a new transform, then immediately raycasts — the raycast hits the old position. The scene query accelerator hasn’t learned about the move yet.

Two Worlds: Sim and Query

PhysX maintains a query structure (AABB tree) separately from simulation. setGlobalPose updates the actor but not the query tree until the next simulate/flush.

Flush Query Updates

actor->setGlobalPose(newPose);
scene->flushQueryUpdates();   // rebuild query tree now
scene->raycast(...);              // hits the new position

Cheap if you only moved a few actors. For bulk moves, defer all queries until after the next simulate step.

Order: Move → Simulate → Query

The natural pattern: gather all moves for the frame, call simulate, then run queries. That gives you a consistent view without explicit flushes.

Kinematic Targets

For kinematic actors, use setKinematicTarget instead of setGlobalPose — it’s designed for movement integrated by simulate and avoids query inconsistencies.

Verifying

Teleport an actor, immediately query — you see it at the new position. No phantom hits at the old location. Bulk-move scenarios stay consistent without scattered flushes.

“PhysX query tree updates on simulate or explicit flush. Without it, raycasts see yesterday’s positions.”

Restructure code so moves happen before simulate, queries after — flushQueryUpdates is a tactical fix, not a strategy.