2.5 · Physics (Jolt)
Three-dimensional rigid-body physics, exposed through a thin PhysicsAPI abstraction so the engine can swap backends without rewriting every call site.
Overview
Jolt is the only registered 3D backend today, but every call site interacts with it through the
PhysicsAPI family of interfaces. That gives the engine room to add a second backend without rewriting
gameplay, recording, or editor code.
Key types
| Type | Header | Role |
|---|---|---|
PhysicsAPI | PhysicsAPI.h | Backend interface. Currently only JoltAPI. |
PhysicsScene / JoltScene | PhysicsScene.h / JoltScene.h | The simulation world. One instance per Hazel Scene. |
PhysicsBody / JoltBody | PhysicsBody.h / JoltBody.h | Rigid body. The Jolt impl wraps a JPH::BodyID. |
PhysicsShape | PhysicsShapes.h | Shape hierarchy — see below. |
PhysicsSystem | PhysicsSystem.h | Static facade for init / shutdown / mesh cooking / scene factory. |
PhysicsLayer, PhysicsLayerManager | PhysicsLayer.h | Collision filtering — which layers collide with which. |
SceneQueries | SceneQueries.h | RayCastInfo, BoxCastInfo, SphereCastInfo, CapsuleCastInfo, overlap variants, SceneQueryHit. |
Shape hierarchy
Phased stepping
JoltScene doesn't own its tick — it registers callbacks with the Scene's TimeManager, one
per phase. That keeps the order of operations identical to MuJoCo and observable from outside the physics module.
| Phase | Jolt callback | What it does |
|---|---|---|
| Acquisition | UpdateAcquisition | Read entity TransformComponent values into Jolt bodies. |
| Control | UpdateControl | Apply forces / torques set by scripts during the previous tick. |
| Physics | UpdatePhysics | Calls JPH::PhysicsSystem::Update(dt) — the actual integration step. |
| Validation | UpdateValidation | Drain contact events from the contact listener, fire script callbacks. |
| Export | UpdateExport | Write the integrated body transforms back to entity TransformComponents. |
Default settings
Tunables live in PhysicsSettings (serialized as part of SceneSettings):
Gravity
Default {0, -9.81, 0} (Y-up, m/s²). Override per scene through SetGravity.
Max bodies
Default 5700. Sets the size of the Jolt body pool; raising it costs memory up front.
Solver iterations
Position and velocity iteration counts — the usual stability-vs-cost knob.
Layers & queries
PhysicsLayerManager owns the layer table; bodies declare which layer they belong to and which layers
they collide with. Scene queries (SceneQueries.h) accept the same layer mask, so picking, casting, and
simulation share one filter source.
| Query | Use |
|---|---|
RayCastInfo | Pick a single body along a ray (mouse-pick, line-of-sight, lidar). |
BoxCastInfo / SphereCastInfo / CapsuleCastInfo | Sweep a shape — character motion, projectile prediction. |
| Overlap variants | Instantaneous overlap test — trigger volumes, AOE queries. |
SceneQueryHit | Hit record returned by all of the above. |
Pitfalls
TriangleMeshShape cannot be attached to a dynamic body. For moving concave geometry, use
ConvexMeshShape (cook once) or a CompoundShape of primitives.
Setting TransformComponent after the Physics phase is a one-frame teleport that the simulator
overwrites. Use Acquisition for writes from scripts, Export for reads.
Physics may depend on Scene (read), Core, and Math. It must not depend on Renderer, Editor, or
ScriptEngine. Scripts call into physics through ScriptGlue, never the other way around.
Extending
- New shape type: add to
ShapeTypeenum, derivePhysicsShape, and implement the Jolt-specific path inJoltShapes.h. - New backend: implement
PhysicsAPI,PhysicsScene, andPhysicsBodyfor the target library. Register it throughPhysicsSystem. - New query: extend
SceneQueries.h, then implementPhysicsScene::CastShape/OverlapShapein the active backend.
For the 2D counterpart, see Physics (Box2D). For robotics-grade simulation, see Physics (MuJoCo).