[SOLVED] Multiple calls to "moveWithCollisions" in one frame breaks on the second call

It seems that the moveWithCollisions method works with the position of the mesh at the start of the frame, rather than at the time of the call to it. Calling moveWithCollisions twice in one frame causes the second call to handle collisions as if the first call had not happened. I wonder if there’s anything that can be done between calls to moveWithCollisions to avoid this issue.

This issue is demonstrated by this playground.

Run the playground and note the starting position of the spheres. Hit the “space” key once and it’ll move all the three spheres. The first (red) moves as expected, the other two (magenta & yellow) do not.

The first (red) sphere starts straight above its own ground mesh (which is also red). Its moveWithCollisions method is called to move it straight down through its ground mesh. This causes it to collide with the ground mesh and it stops when (and where) this occurs.

The second (magenta) sphere starts straight above its own ground mesh (also magenta). In this case, moveWithCollisions is called to moved it across to where there is no ground mesh beneath it. moveWithCollisions is then called a second time to move it straight down through the y-position of its ground mesh (like the first, red one). What is expected is that it would travel the full length down, since there is no ground to block movement. What is observed instead is that it reacts as if it is still over its ground, since that’s where it was at the start of the frame. It moves down until it is blocked by it’s ground and then it stops.

The third (yellow) sphere starts in a place where there is no ground mesh beneath it. moveWithCollisions is called to move right over its own ground mesh. Then moveWithCollisions is called again to move it down past its own ground mesh. What is expected is that the sphere would collide with its ground mesh during its second call to moveWithCollisions, since it is moving through it at that time. What is observed instead is that it moves straight through its ground mesh with no collisions stopping it. This is because at the start of the frame it was NOT over its ground at all, so the second call to moveWithCollisions thinks it is still not over its ground mesh, even though the first call moved it into that position.

This issue is especially important now that moveWithCollisions can be called with different parameters for different effects, so combining all movement into one call to moveWithCollisions is not always feasable. I wonder if there’s anything I can do to update a mesh’s final position between the first and second calls to moveWithCollisions.

1 Like

Taking a look!

Hi @violgamba, moveWithCollisions calculates collisions based off of the node’s absolutePosition which is based off of the worldMatrix, which is computed once per frame of the render loop. This is by design because re-computing the world matrix is an expensive operation so we cannot update the engine’s hotpath to force recompute if moveWithCollision is called more than once within a single render frame.

If you want to force recomputation of the worldMatrix, you can add a call to sphere2.computeWorldMatrix(true)-passing in the boolean param to force recomputation of the matrix. Please note that this is an expensive operation- in your case the scene is quite simple so it will be fast, but use with caution!

See this playground snippet with the above suggestion
Multiple moveWithCollisions in one frame breaks collision | Babylon.js Playground

I will also update the documentation to make note of this nuance of moveWithCollision - may use your playground as an example! Thank you!

3 Likes

Awesome! Thank you, @georgie, for responding so quickly. This is a great explanation for what I’m seeing, and the fix works fine!

To be clear, when you say that computeWorldMatrix() becomes expensive in complex scenes, it comes down to how deep the object is in the scene hierarchy, right? Like, how many parents contribute to its world matrix? So, I might have a complex scene, but if the object is a direct, or near, descendant of the scene root, then computeWorldMatrix() shouldn’t be too bad?

EDIT: Never mind, I’m asking this as a separate question.

Great thanks! Updated docs here!

Clarify behavior of movewithcollisions when called more than once within a single frame by georginahalpern · Pull Request #1353 · BabylonJS/Documentation

And linking your other post in case others are curious :slight_smile:
[RESOLVED] computeWorldMatrix(true) - source of its computational cost - Questions - Babylon.js