Push objects out of the way instead of sending them flying?

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
uber
Posts: 3
Joined: Sat Sep 17, 2016 1:26 am

Push objects out of the way instead of sending them flying?

Post by uber »

When an object collides with another object, I want it to just get pushed out of the way instead of having the first object's velocity affect it. Eg, regardless if the object collides at a speed of .5 or 500, I want the second object to simply get pushed out of the way of the first and have no residual velocity.

I thought of just zeroing out those objects' velocities, but then I'd still like other physics to act on them normally - just not with the specific collision between these two types of objects. How can I make that happen? :)
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Push objects out of the way instead of sending them flyi

Post by Norbo »

The first step would be to disable the default collision resolution by making the collision rule between the entities NoSolver. With that rule, contacts will still be generated, but the velocity solver won't do anything with them.

Then, on each timestep, it would be your responsibility to figure out how to separate the objects. There are a lot of ways to do this- I would tend to recommend sticking to the simple velocity-level ones if it works well enough. So, one possibility:
Enumerate all contacts associated with the entity by cycling through the entity.CollisionInformation.Pairs.Contacts lists. At each one, apply a corrective impulse- perhaps just contactNormal * contactPenetrationDepth * someTuningConstant. This is somewhat similar to Baumgarte stabilization used in the true contact constraints, just slightly less stable due to being outside of the solver loop. It introduces energy to the simulation, but it wouldn't include the full energy of the object moving at 100 m/s. Since it works at the velocity level, it will tend to play nice with the rest of physics.

You could also move the position directly, though then the object may be pushed into an invalid position, causing it to fall out of the level or something. Counteracting this is doable but can get complicated.
uber
Posts: 3
Joined: Sat Sep 17, 2016 1:26 am

Re: Push objects out of the way instead of sending them flyi

Post by uber »

Awesome, manually setting positions works well! Now for the special bonus round question...

Currently I'm doing this:

Code: Select all

foreach (var p in e.CollisionInformation.Pairs)
{
    foreach (var c in p.Contacts)
    {
         Vector3 force = c.Contact.Normal * c.Contact.PenetrationDepth;
         e.Position += force;
    }
}
I would like to use a different normal that I generate myself, so how can I calculate the penetration depth of an object from a different normal?

Conceptually, imagine a box that collides with spheres in front of it - instead of them being pushed along in front of it, as happens now, I would like them to be pushed outside the sides of it.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Push objects out of the way instead of sending them flyi

Post by Norbo »

A 'correct' solution would involve running the MPRToolbox.LocalSurfaceCast in the desired normal direction, similar to how the MPRToolbox.RefinePenetration function works. That's kind of complicated and not super duper cheap, so I'd recommend just approximating it.

One simple option would be to project the offset onto the plane whose normal is the moving object's movement direction. That way it would only ever move perpendicularly to the movement direction. In pseudocode, it would look something like:

Code: Select all

var offset = normal * penetrationDepth
var projectedOffset = offset - dot(offset , movementDirection) * movementDirection
where 'movementDirection' is normalized.

The resulting offset will always be smaller than the 'true' penetration offset along any given direction (assuming the collision detection system correctly detected the minimum depth). It may remain in collision for more than one frame, since it isn't resolving the 'true' penetration every frame, but it may work just fine. There is a chance that an object that is perfectly aligned along the movement direction doesn't get moved at all. If that becomes a problem, you could detect it and introduce an arbitrary bias along some perpendicular direction.
uber
Posts: 3
Joined: Sat Sep 17, 2016 1:26 am

Re: Push objects out of the way instead of sending them flyi

Post by uber »

The 'correct' solution works perfectly - it's fast enough for my purposes, and exactly the response I'm looking for!

As soon as I switch to a MobileMesh object instead of one of the built in Boxes or Spheres, I run into a problem - the CollisionInformation.Shape contained in the mesh doesn't appear to be castable to a ConvexShape that LocalSurfaceCast requires. If I manually create my own ConvexHullShape using the same vertices used to create the MobileMesh, then the collision detection is all wrong. What is the correct way to call LocalSurfaceCast on a MobileMesh?
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Push objects out of the way instead of sending them flyi

Post by Norbo »

MPR can only operate on convex objects. So, for mobile meshes, the MPR routine would need to run on a per-colliding-triangle basis. That could be done by diving into the TriangleMeshContactManifold used by the MobileMesh(..)PairHandler and iterating over the activePairTesters to find the already determined potential colliders, or using something like the MobileMeshContactManifold.FindOverlappingTriangles to select potential colliders and then using a proxy TriangleShape for each triangle in the mesh that needs to be tested.

Things get more complicated if the MobileMesh is Solid. That engages the MobileMeshContactManifold.ProcessCandidates logic, which can produce contacts that are not associated with any triangle at all. That would need a separate codepath to handle.

(Or, if it works well enough, just use an approximation :))
Post Reply