Jump to content

Rigid Physics General Discussion

Atomic Walrus

Recommended Posts

Over on the Discord there's been some work on the stock physics code going on, and I thought it could be helpful to share some of my notes on Rigid and RigidShape/Vehicle and how to get the most out of the stock systems. This is known information in one form or another, but since the physics have always been glitchy it isn't frequently discussed or compiled.

Contact vs Collision & contactTol

Collision events are handled in one of two ways depending on the velocity:
1) Very slow collisions are treated as "contacts," and use a solver specifically designed to handle stable resting contact (it involves springs that separate objects that are overlapping). This solver produces more reasonable results*** when objects are slow, but is not intended to handle proper impacts where force is reflected (bounce from restitution).
2) Normal-speed collisions are solved using conservation of momentum, which is better at simulating the outcome of impact events, but not great at simulating resting or sliding contact.

The cutoff velocity between these two is controlled by the contactTol datablock value. Contacts with a converging velocity less than contactTol, in m/s, are handled with the contact constraint. Above that speed they are solved as full collisions.

The stock value is 0.1 m/s, which means "contacts" only occur when the object is nearly stationary -- or when it's sliding along a surface, since the velocity in question is specifically "speed into the surface being contacted," not overall speed in any direction.

*** "But isn't the contact solver notorious for being broken and letting objects sink into surfaces?"
True. However this has been (hopefully) fixed by some work going on over in the Discord that should appear in the dev head <eventually?>.
For those who want to mess with this patch immediately (YMMV, no money back, etc.):

// Go to RigidShape.cpp or Vehicle.cpp, depending on whether you're using 4.x or 3.x respectively, 
// to the function "resolveContacts," and change the two instances of:
// to:
(mRigid.getZeroImpulse(r,...) / dt)
// This is a unit conversion from Impulse (mass * instant delta velocity) to Force (mass * deltaV over time)
// It needs to be done to fit the units of the other terms in the spring model. 
// The output of the whole spring calculation is converted to impulse (force * dt) later on

//And then for reasons I don't want to get into much today --
//  this is a reference velocity for damping, it needs to be appropriate to the dimensions of the object and should be autogenerated 
// -- change this term:
(vn / mDataBlock->contactTol)
// to:
(vn / 2.0f)


Collision Buffer Space & collisionTol

The detection system uses a buffer space of collisionTol (m) to basically "project" its collision geometry out around it. For a collision to be engaged with it needs to be both within that projected test buffer region and have a converging velocity (or be so slow that it's considered a "contact", see part 1).

In practice this means that the collision model of an object behaves like it is slightly extruded beyond the hull geometry. Since collision hulls must be convex, this is not hard to imagine visually (ascii art time):

_ _ _ _ 
_____   |  
     |  | ______
     |  /  _____
1= > | /| /    <== 2
     | \| \_____
     |  \ ______
     |  |

Above, neither reacts to the other. 
Their buffers overlap, but to collide one buffer needs to contact the other's actual collision hull.

Below, both objects will detect and respond to the collision.
Note that the actual collision hulls are not overlapping with each other.
If they were, we would have already "missed" the collision (see practical limits below for more on that)
_ _ _ _ 
_____   |  
     | _|____
     /  |____
1=> /| /|    <== 2
    \| \|____
     |  |
((Too technical: Note that the direction of the "expansion"/"extrusion" of the collision hull is not from the center outwards.
(It appeasr that way in the drawings for simplicity).
The projection technically occurs in the contact normal direction on a per-interaction basis, but that's fairly confusing to think about.))

You can see this in-game by increasing collisionTol and then looking at the gaps between objects and the surfaces they are resting on. Note that from an art perspective, you can resolve this gap by making the collision hull slightly smaller than the visual model (same thickness as the collisionTol you expect to use).

Objects handle high-speed collisions and stacking scenarios better with higher collisionTol, but if the value is too large for the size of the object you'll have trouble making it work visually, and the results may start to get floaty and unrealistic.

When in doubt, add a bit more collisionTol and hide the buffer space with the model.

Default value is 0.1m, 10 cm. That's plenty for basic prop objects and probably even slower vehicles, but I'd suggest 0.25m or even 0.5m on a vehicle if the model is on the larger side.

Integration Rate: Resolution vs. Performance

The stock sim tickrate of 32hz is usually fine for the average shooter or other moderately-paced action game, but it's too slow for physics simulations of interacting rigid-body objects when you don't have fancy technology like rollback, group interaction solvers, continuous collision detection, etc.

For this reason the physics tick is divided up into sub-frames that are "integrated" into the final deltas for the object's simulation tick. If a normal sim tick is 32ms, and the "integration" value for a RigidShape datablock is 4, the object will run four 32/4 = 8ms physics frames and then integrate the results to simulate the object for the full 32ms of the tick.

This increases the temporal resolution of the physics of the object, giving you better results at high speeds with fewer collision misses, in exchange for multiplying the processing time spent on physics calculations.

Set this for the expected speeds the object will encounter. I've found that reasonable values are in the range of ~3-16, with the high end being reserved for extra-fast vehicles like jets. 2 can be unpredictable and bouncy and is not recommended. Objects may not go to sleep properly or may fall through surfaces at moderate speeds if integration is set to 1.


Practical Limits: Speed, Complex Interactions, Collision Misses

It's still not going to be a box-stacking simulator. Even with fixes and tuning this won't replace something like PhysX for a VR game where you want to make physics puzzles that don't behave like they're from Trespasser (1998), or maybe Source multiplayer prop physics at best, where stuff kind of stacks but it's laggy and wobbly compared to singleplayer. You won't even be able to reliably place a pile of crates to drive through like a cheesy action movie, unless you place them all "at rest" and only wake them up as the car drives through them.

What this does allow is mostly reliable use of Vehicle objects without constantly worrying about them falling into space or getting flung into the atmosphere if they're parked too close together.

The trick to making your vehicles safe to crash is making sure you're never missing a significant portion of your collision geometry's chance to catch a collision. If the geometry is a box you don't have much to work with, so missing any particular collision event is worse than on a complex mesh. The more verts and edges in the model, the more collision events it generates (at the cost of more CPU usage doing collision testing, potentially way more).

Returning to the ASCII art in a 1D scenario now, it's possible to figure out the integration rate and/or collisionTol you need for a given velocity to never miss a collision:

integration = 4
tickrate = 32ms (roughly)
subframe = 8ms
velocity = 200m/s
collisionTol = 0.25m
T=0s   |   T=1s   
dX=0m  |  dX=1.6m

           -- 0.25m (collisionTol)
   ===> >  | |
      -------- 1.25m (dist to wall)

           |=|=> >
              -- 0.35m (missed collision by)
To make this scenario impossible, contactTol needs to be > dX. Given that integration is the performance-limiting setting,
fix integration @ 8
subframe = 4ms = 0.004s
velocity = 200m/s
Find collisionTol:

collisionTol > 200m/s * 0.004s
collisionTol > 0.8m

Or alternatively, for a fixed collisionTol of 0.6m, find the optimal integration for 200m/s max vel:
0.6m > 200m/s * 0.032 / integration
integration ticks > 200m/s * 0.032 s/tick / 0.6m
integration > 10.67 (integration should be at least 11).

A long-winded way of saying collisionTol should be >= maxVel * TickSec / integration so that you never miss a collision event.

For the standard test objects and default settings, integration = 4 and collisionTol = 0.1, so the max speed where 100% of collisions are detected is:
0.1 m >= V m/s * 0.008s -> V <= 0.1m/0.008s -> 12.5m/s, or around 25mph.

To be clear this is generally overkill; Most vehicles will not have perfect box collision hulls, nor would most interactions involve a single vert vs a plane like above even with cube hulls and flat surfaces. This comes up in worse case scenarios, like dropping a cube onto a perfectly flat surface when everything is axis-aligned. You either catch those corner verts hitting the floor, or you miss the entire collision because the vertical edges are perfectly perpendicular to the surface in this contrived case and will fail to interact with the plane. This is contrived, but not that uncommon due to how editors spawn objects, so it's still worth knowing the exactly limits.

When a cube lands on a plane hitting corner-first, which is 99.9% of the time once objects are moving from their editor-placed staring poses, you can actually miss that initial corner vert vs plane interaction and still catch the overall bulk interaction since the cube's edges will also trigger collision events.

In practice you can often undershoot this optimal tuning for performance reasons and still be fine, so feel free to undershoot on both of these and increase them as needed.

Edited by Atomic Walrus
Link to comment
Share on other sites

  • 1 month later...
  • 2 weeks later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...