-
-
Notifications
You must be signed in to change notification settings - Fork 0
COLLISION_PIPELINE
Collision in Gravitas is split into deterministic stages: broad phase, pair filtering, narrow phase, contact manifold generation, response, notifications, and cleanup. The same structure exists for 3D, 2D, and explicit mixed 2D/3D contacts, with each domain owning its own state and ordering rules.
This page is the readable entry point. Use the reference pages when you need the full implementation contract:
- 3D colliders route through
GravitasPhysicsServiceandGravitasCollisionService. - 2D colliders route through
GravitasPhysics2DServiceandGravitasCollision2DService. - Mixed contacts exist only in
PhysicsRuntimeMode.Mixedand route throughGravitasMixedCollisionService. - GridForge-backed voxel partitions produce deterministic candidate pairs.
- Candidate pairs pass hierarchy, same-agent, layer, local physical ignore, trigger, awake, and bounds filters before narrow phase.
- Narrow phase writes deterministic contact manifolds.
- Response solves contacts and joints in stable islands during
LateSimulate(). - Contact notifications and pair cleanup happen after response.
flowchart LR
Refresh["Refresh collider bounds"]
Partition["GridForge partitions"]
Candidates["Candidate pairs"]
Filters["Deterministic filters"]
Narrow["Shape narrow phase"]
Contacts["Contact manifolds"]
Response["Response islands"]
Notify["Notifications + cleanup"]
Refresh --> Partition --> Candidates --> Filters --> Narrow --> Contacts --> Response --> Notify
| Path | Body/collider types | Broad phase | Pair/response owner |
|---|---|---|---|
| 3D |
SolidBody, LSCollider
|
PhysicsPartition on GridForge voxels |
GravitasPhysicsService |
| 2D |
SolidBody2D, LSCollider2D
|
PhysicsPartition2D on the internal Y=0 storage plane |
GravitasPhysics2DService |
| Mixed 2D/3D | existing 3D and 2D types |
PhysicsMixedPartition using embedded 2D slabs |
GravitasMixedCollisionService |
2D uses X/Z host projection: world Vector3d.x maps to Vector2d.x and world
Vector3d.z maps to Vector2d.y. World Vector3d.y is height or mixed
embedding metadata, not a 2D collision axis.
PhysicsRuntimeMode.Both runs 2D and 3D side by side without cross-dimensional
contacts. PhysicsRuntimeMode.Mixed adds the dedicated mixed lifecycle.
Collision work is part of context.LateSimulate():
- Bodies integrate motion and CCD frame state.
- Dynamic collider bounds and partitions refresh.
- Active partitions emit candidate pairs in stable order.
- Pair filters reject invalid or non-physical interactions.
- Narrow phase evaluates exact shape-pair collision.
- Contact manifolds are written to pair-owned storage.
- Contact and joint rows are solved in deterministic islands.
- Grounding/support and sleep state update from post-response state.
- Contact events, pair maintenance, retained partition cleanup, and deactivation cleanup run.
Mixed contacts run after both dimension-local services have integrated and refreshed their own collider partitions, so mixed response observes post-integration 2D and 3D positions.
Broad-phase candidate pairs are filtered before exact shape work:
| Filter | Purpose |
|---|---|
| Context ownership | Reject colliders from another context. |
| Same-agent/hierarchy | Suppress host-owned sibling/parent-child collisions. |
| Runtime mode | Keep 2D, 3D, Both, and Mixed behavior explicit. |
| Mobility/awake state | Avoid response work for fully sleeping local partitions. |
| Layer matrix | Apply context-wide physical collision policy. |
| Collider-local ignored layers | Apply per-collider physical ignore masks. |
| Bounds | Reject separated broad colliders before narrow phase. |
| Duplicate partition routing | Ensure a pair shared by several voxels runs once. |
Public queries do not use collider-local ignored physical layer masks. Query include masks are caller-owned; see Query Services.
Narrow phase owns shape truth. Supported shape coverage includes:
| Domain | Shape families |
|---|---|
| 3D | sphere, capsule, cuboid, finite cylinder, finite cone, mesh, compound |
| 2D | circle, capsule, AABB, convex polygon, compound |
| Mixed | supported 3D shapes against embedded 2D circle/capsule/AABB/polygon/compound slabs |
Convex SAT paths use stable axis generation and pair-oriented normals. Cuboid versus capsule checks first solve exact segment-to-oriented-box distance for rounded features, then use ordered SAT only when the capsule core reaches the box; inclusive projections and directional exit depths preserve touching and containment semantics. Convex mesh versus capsule checks use the closest capsule-segment point to the mesh center for their exterior representative manifold and fall back to deterministic BVH traversal with stable contact-ID reduction when contact exists away from it. Closed-convex containment instead orients face planes from the scaled world-space center of mass and reduces the whole capsule over face and edge-cross axes to a matched support-feature exit manifold. Other mesh paths use the same deterministic BVH candidate ownership; candidate order follows the stable built tree rather than authored triangle indices. Concave mesh/mesh pairs canonicalize relation direction by stable collider ID and delegate each BVH-admitted triangle pair to FixedMathSharp's full-domain rigid-frame contact relation. Compound paths scan parts in stable declaration order and return the owner collider as the public identity.
Finite axes, oriented cuboids, and planar convex shapes retain center-relative
canonical geometry through narrow phase. Contact witnesses use
ContactAnchor or ContactAnchor2D: a representable origin, normalized frame
rotation, and representable local point. Solvers and replay hashes consume that
canonical frame directly, so a valid contact is not dropped or deformed merely
because its rotated offset or absolute world point crosses a Fixed64 scalar
face. Origin, Rotation, LocalPoint, and LocalDisplacement expose the
canonical components. The two local terms remain separate until exact
evaluation so a representable world witness is not lost to an overflowing
local intermediate.
Offset and legacy PointA/PointB views materialize derived coordinates and
throw when the requested view is not representable; domain-edge callers should
use TryGetOffset and the matching TryGetPoint* method.
Response keeps materialized 2D/3D lever vectors as the ordinary fast path and
reconstructs a Gravitas-owned ExactLever3D from contact anchors only when the
complete compact expression cannot be proven representable. Point velocity,
effective mass, warm-start completion, friction, and final body deltas then
remain exact through one final checked narrowing. Compound mass properties use
the Gravitas-owned ExactMassPoint3D, ExactMassPoint2D, and
ExactMassWeight types for the equivalent weighted-center and parallel-axis
contract; no saturated child center or weight is admitted as physical data.
These internal physics semantics consume FixedMathSharp's policy-neutral wide
arithmetic through the intentional friend-assembly boundary and never enter
Gravitas public signatures.
ExactContactResponseKernel is the sole owner of the exact normal,
accumulated-normal, Coulomb-line, and Coulomb-disk response policy.
ExactContactLever3D and ExactContactLever2D adapt body mobility and
dimension-specific state into that kernel; they do not duplicate its arithmetic
or expose the FixedMathSharp internal representation.
Embedded 2D mixed volumes also select planar boundary anchors semantically. Built-in circles, capsules, boxes, polygons, and compounds therefore do not require a public closest point or representable query-to-boundary distance to produce a contact witness. Exact compound candidate ranking preserves authored part order on ties.
For shape state, pair matrices, SAT invariants, mesh policy, and compound ownership details, read Collider Shape Reference.
CCD is opt-in per body or through context defaults. The runtime supports:
- static/kinematic blockers for fast dynamic bodies.
- dynamic-vs-dynamic candidate indexing and relative movement checks.
- host-driven kinematic active sources.
- rotational CCD where supported.
- service-level handoff queues for chained contacts.
- mixed handoffs when
PhysicsRuntimeMode.Mixedis active.
Sphere/cuboid time of impact uses the exact spherical dilation of the oriented cuboid. The local-space reducer distinguishes planar faces from rounded edges and corners, then reconstructs contact from the original authored world chord without normalized-direction loss.
The CCD reference explains exact reducer paths, conservative proxy boundaries, TOI ordering, and service counters: Continuous Collision Detection.
Non-trigger contacts are solved through deterministic manifold response. Bodyless trigger volumes skip physical response and emit trigger notifications only when exactly one collider in the pair is a trigger and the other collider is body-owned. Both colliders in a valid trigger pair receive enter, stay, and exit callbacks.
2D, 3D, and mixed pair callbacks use stable pair order: A/B for same-dimension
pairs and 3D/2D for mixed pairs. Exit admission is consumed before user
delegates run, so callback failure or reentrant teardown does not retry an
already admitted exit against the same pair lifetime. Both admitted sides are
attempted even if the first throws: one exception is re-thrown with its
original stack, while multiple failures are reported as an AggregateException
in pair order. Deferred exits retain the pair's notification guard until
cleanup finishes, preventing direct deactivation from reentering the same
separation.
3D and 2D response both:
- combine contact rows with enabled joint rows.
- build deterministic body islands.
- wake connected sleeping bodies when an island has an awake participant.
- apply warm-start impulses from pair-local caches.
- solve bounded iterations from
PhysicsSettings.DiscreteSolverIterations. - update sleep state after response.
Mixed response is constrained: 2D participants receive planar X/Z correction, planar velocity deltas, and scalar yaw angular deltas. Vertical Y impulse is constrained out of the 2D body model.
For contact manifolds, material response, warm-start caches, sleep/wake, and event timing, read Collision Response.
| Goal | Start with |
|---|---|
| Add or improve a shape pair | Collider Shape Reference, then shape-pair tests. |
| Change broad-phase partition behavior | Collision Broad Phase, then partition/candidate benchmarks. |
| Change tunneling behavior | Continuous Collision Detection, then CCD replay and stress tests. |
| Change friction/restitution/contact solve behavior | Collision Response, then response invariant tests and benchmarks. |
| Add host-facing query behavior | Query Services and Query Reference. |
- Preserve deterministic pair, partition, contact, and response ordering.
- Use
Fixed64,Vector2d,Vector3d, and fixed-point geometry in runtime collision code. - Keep 2D, 3D, and mixed collision paths explicit.
- Do not compare plain collider IDs across dimensions.
- Avoid LINQ and iterator allocations in collision hot paths.
- Pool only when lifetime and ownership are obvious and testable.
- Add focused tests for separated, touching, overlapping, degenerate, rotated, and high-speed cases when changing collision behavior.
- Add benchmarks for partitioning, pair distribution, narrow phase, CCD, or response loop changes.
| Area | Source |
|---|---|
| 3D collision service | src/Gravitas/Core/3D/GravitasCollisionService.cs |
| 3D physics/pairs/response |
src/Gravitas/Core/3D/GravitasPhysicsService.cs, src/Gravitas/Core/3D/GravitasPhysicsService.Pairs.cs, src/Gravitas/Core/3D/GravitasPhysicsService.Response.cs
|
| 2D collision service | src/Gravitas/Core/2D/GravitasCollision2DService.cs |
| 2D physics/pairs/response |
src/Gravitas/Core/2D/GravitasPhysics2DService.cs, src/Gravitas/Core/2D/GravitasPhysics2DService.Pairs.cs, src/Gravitas/Core/2D/GravitasPhysics2DService.Response.cs
|
| Mixed collision | src/Gravitas/Core/Mixed |
| Narrow phase | src/Gravitas/CollisionHandling/Detection |
| Contact data | src/Gravitas/CollisionHandling/Contacts |
| Response | src/Gravitas/CollisionHandling/Response |
| Collision tests |
tests/Gravitas.Tests/CollisionHandling, tests/Gravitas.Tests/Physics2D, tests/Gravitas.Tests/MixedDimensions
|