Missing Collision when using SetMatrix

Report any bugs here and we'll post fixes

Moderators: Sascha Willems, Thomas

Missing Collision when using SetMatrix

Postby Esharc » Wed Sep 03, 2025 4:31 am

Good morning Julio,

I noticed that when we adjust the world matrix of a body using SetMatrix and SetMatrixUpdateScene it seems that the contact points do not update, and collisions with other bodies do not register.

I have tweaked ndBasicRigidBody.cpp to show what I mean. The left and right arrow keys on the keyboard will move the one body left or right a bit using those two functions. If you hide the visual mesh and turn on the wire frame collision and show contact points you will see what I mean.

I have attached the file with the changes that I made.
ndBasicRigidBody.7z
(3.36 KiB) Downloaded 7 times
Esharc
 
Posts: 130
Joined: Tue Jan 10, 2017 5:23 am
Location: South Africa

Re: Missing Collision when using SetMatrix

Postby Julio Jerez » Wed Sep 03, 2025 11:26 am

I have the repro and I can see the issue.
I can see there is a real bug in that teleporting is not waking up the other bodies that it touches at the destination.
It is an intermittent problem that happens when the body it touches is covered by the same aabb of the scene tree.
Essentially that function should wakeup the body unconditionally. So that's a real bug that needs fixing.

For the effect, I’ll try to fix it, though it may be tricky in the sense that, that kind of teleporting may not be the best way to move a body
I explain it bellow.

For version 4, I made the decision to fully embrace first- and second-order Newtonian mechanics.
This means a body’s state is determined strictly by its velocity and net acceleration.

For example, in this function:
    bool ndScene::ValidateContactCache(ndContact* const contact, const ndVector& timestep) const
The code doesn’t check for changes in position. Instead, it checks if the set of contacts has zero velocity and acceleration once transformed into the collision’s local space.

I worked around this by calling invalidate cache instead of just resetting the contact distance, but this introduces a few shortcomings:

Since the update happens during the model update phase, the contacts are already calculated. If a body is teleported, it will still collide with contacts that don’t reflect its new position, because they are generated before teleport.

This may breaks the dynamics, leading to unpredictable behavior.
The body ends up moving based on penetration values from the previous frame.
Large teleport steps are especially problematic, for example,
if a body is moved far away and collides with something at its new position,
it won’t register a collision that frame.
But since the cache was invalidated, new contacts will be calculated in the next frame, which could result in deep penetrations.

to see this behavior, run the demo, and move the camera so that you can see the body sideway.
you will see that when you move the box, it goes into deep penetration, and this is the only thing that makes it recovers. but that is just luck. Other situations may be very undesirable.

are you moving your bodies by teleporting?
if so, may I suggest using
    void ndBodyDynamic::ApplyImpulsePair(const ndVector& linearImpulseIn, const ndVector& angularImpulseIn, ndFloat32 timestep)

basically, you calculate an impulse by dividing the delta position by the time step and multiply by the body mass and you call that function.

that function accumulate that impulse in the body, without moving it.
then, the solver calculate the correct velocity to realize movement.

it will not work for large teleports, but if you are using teleport to animate background objects, then that's a good way.

the moral is that you should use the right function for the right effect.
if you are doing runtime object placement, that is, moving a body to a position and let is settle.
them SetMatrixUpdateScene is the function to use.
It will move the body and calculate new contacts that will position the bodies and neighbor, base on resolving inter penetration.

if you are doing runtime body animations based of some velocity, that means some continue motion,
For that, ApplyImpulsePair is a better function.

check out demo: ..\ndSandbox\demos\ndBagroundLowLodVehicle.cpp

Sync to get the work around fix.
Julio Jerez
Moderator
Moderator
 
Posts: 12425
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Missing Collision when using SetMatrix

Postby Julio Jerez » Wed Sep 03, 2025 12:01 pm

if you decide to use the impulse, I made that change, so that you can see the difference
you can just try both methods, and see which want you prefer.

Code: Select all
   void IncrementRootPosition(const ndVector& vPosIncrement, ndFloat32 timestep)
   {
      if (m_rootNode && m_rootNode->m_body)
      {
         ndMatrix mBodyMatrix (m_rootNode->m_body->GetMatrix());

#if 1
         timestep = 0;
         mBodyMatrix.m_posit += vPosIncrement;
         m_rootNode->m_body->GetAsBodyKinematic()->SetMatrixUpdateScene(mBodyMatrix);
#else
         ndVector veloc(m_rootNode->m_body->GetVelocity());
         ndVector newVeloc(vPosIncrement.Scale(1.0f / timestep));
         ndVector deltaVeloc(newVeloc - veloc);
         ndVector impulse(deltaVeloc.Scale(1.0f / m_rootNode->m_body->GetInvMass()));
         m_rootNode->m_body->GetAsBodyKinematic()->ApplyImpulsePair(impulse, ndVector::m_zero, timestep);   
#endif
      }
   }
Julio Jerez
Moderator
Moderator
 
Posts: 12425
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Missing Collision when using SetMatrix

Postby Esharc » Thu Sep 04, 2025 3:54 am

Thank you for that nice explanation of the problem Julio.

What we plan to do is have VR controllers pick up a body and move the object around. For example picking up a hammer and using it on another object.

We have always had basic moving of objects in the world using the mouse pointer and the SetMatrixUpdateScene.

I like your solution using the ApplyImpulsePair, and would rather do that that use a work around that will cause your engine to behave the way you did not intend it to behave. We were also considering using the kinematic joint for picking objects up and moving them.
Esharc
 
Posts: 130
Joined: Tue Jan 10, 2017 5:23 am
Location: South Africa

Re: Missing Collision when using SetMatrix

Postby Julio Jerez » Thu Sep 04, 2025 8:28 am

Ahh I see.
In that case. I strongly recommend using the kinematic joints.
It is a solution along the line on the impulse but is far more powerful.

The impulse is good for making stuff like animating single bodies.

You can try incrementally.
First try to upgrade all your logic to use impulse.
I am sure that in many places this is sufficient.

Also set matrix has its uses when teleporting large distance.

Then after that, you can try the kinematic joints for the more difficult cases, like picking object from the scene.
Where getting distance from screen offer another layer of difficulty that that joint can handle better.

When it comes to object that are attached to other objects
The calculation becomes harder, for that, the kinematic joints takes care of the complexity.
It also handle the calculation of the impulse when picking object at a point. Which is more difficult than just applying impulse at the origin.
Julio Jerez
Moderator
Moderator
 
Posts: 12425
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Missing Collision when using SetMatrix

Postby Esharc » Thu Sep 04, 2025 10:03 am

Thanks Julio.

I have added applying impulses for moving small distances, and still use set matrix for large distances and initial placement of bodies in the scene.

During my testing I noticed that the kinematic joint will be a much easier implementation to handle picking things up with the VR controllers.

Thank you again for your valuable input
Esharc
 
Posts: 130
Joined: Tue Jan 10, 2017 5:23 am
Location: South Africa


Return to Bugs and Fixes

Who is online

Users browsing this forum: No registered users and 1 guest