Box3D provides geometric types and functions. These include:
- primitives: spheres, capsules, and convex hulls
- triangle meshes and height fields for static terrain
- convex hull construction from point clouds
- mass and bounding box computation
- local ray and shape casts
- contact manifolds
- shape distance (GJK)
- time of impact
- dynamic bounding volume tree
The collision interface is designed to be usable outside of rigid body simulation. For example, you can use the dynamic tree for other aspects of your game besides physics.
The main purpose of Box3D is rigid body simulation, so the collision module only contains features that are also useful in the physics engine.
Shape Primitives
Shape primitives describe collision geometry and may be used independently of physics simulation. At a minimum, you should understand how to create primitives that can later be attached to rigid bodies.
Box3D shape primitives support several operations:
- Test a point or proxy for overlap with the primitive
- Perform a ray cast against the primitive
- Compute the primitive's bounding box
- Compute the mass properties of the primitive
Spheres
Spheres have a center and radius. Spheres are solid.
A 3D vector.
Definition math_functions.h:41
b3Vec3 center
The local center.
Definition types.h:1888
float radius
The radius.
Definition types.h:1891
A solid sphere.
Definition types.h:1886
You can also initialize a sphere inline:
b3Sphere sphere = {{2.0f, 3.0f, 0.0f}, 0.5f};
Capsules
Capsules have two center points and a radius. The center points are the centers of two hemispheres connected by a cylinder.
float radius
The radius of the hemispheres.
Definition types.h:1913
b3Vec3 center1
Local center of the first hemisphere.
Definition types.h:1907
b3Vec3 center2
Local center of the second hemisphere.
Definition types.h:1910
A solid capsule can be viewed as two hemispheres connected by a rectangle.
Definition types.h:1905
Convex Hulls
Box3D convex hulls are solid convex polyhedra. The geometry lives in a heavy, immutable b3HullData object. The world shares identical hull data through a reference counted database, so many shapes built from the same data hold one copy. A shape is convex when all line segments connecting two interior points remain inside the shape.
The most common hull is a box. Use b3MakeBoxHull for an axis-aligned box and b3MakeCubeHull for a cube. The values are half-extents (half-widths):
b3BoxHull b3MakeBoxHull(float hx, float hy, float hz)
Make a box as a hull. Do not call b3DestroyHull on this.
b3BoxHull b3MakeCubeHull(float halfWidth)
Make a cube as a hull. Do not call b3DestroyHull on this.
Efficient box hull.
Definition types.h:2023
b3BoxHull stores everything inline — do not call b3DestroyHull on one. Its .Base member is the b3HullData that you pass to shape creation:
b3HullData base
The embedded hull. So the offsets index into the arrays that follow.
Definition types.h:2025
b3ShapeId b3CreateHullShape(b3BodyId bodyId, const b3ShapeDef *def, const b3HullData *hull)
Create a convex hull shape and attach it to a body.
For a box that is offset or rotated from the body origin:
b3BoxHull b3MakeTransformedBoxHull(float hx, float hy, float hz, b3Transform transform)
Make a transformed box as a hull.
For arbitrary convex geometry, provide a point cloud and let Box3D compute the hull:
if (data == NULL)
{
}
b3HullData * b3CreateHull(const b3Vec3 *points, int pointCount, int maxVertexCount)
Create a generic convex hull.
void b3DestroyHull(b3HullData *hull)
Destroy a hull.
A convex hull.
Definition types.h:1964
maxVertexCount limits the output complexity; pass the same value as pointCount to allow the full hull. b3CreateHull returns NULL on degenerate input (e.g. fewer than four non-coplanar points, or nearly-zero volume). Always check before using it.
Box3D also provides helpers to create cylindrical and conical hulls:
b3HullData * b3CreateCone(float height, float radius1, float radius2, int slices)
Create a tessellated cone as a hull.
b3HullData * b3CreateCylinder(float height, float radius, float yOffset, int sides)
Create a tessellated cylinder as a hull.
Hulls created with b3CreateCylinder, b3CreateCone, and b3CreateHull are heap-allocated and must be freed with b3DestroyHull. b3BoxHull values are stack/struct-allocated and must not be freed.
Triangle Meshes
Triangle meshes let you describe concave or open surfaces using a triangle soup. They are intended for static geometry: b3CreateMeshShape only creates contacts on static bodies.
The mesh is built from a b3MeshDef and cooked into a b3MeshData that contains an internal BVH for efficient collision queries:
bool identifyEdges
Compute triangle adjacency information using shared edges.
Definition types.h:2073
b3Vec3 * vertices
Triangle vertices.
Definition types.h:2046
int triangleCount
The triangle count. Must be 1 or more.
Definition types.h:2063
int32_t * indices
Triangle vertex indices. 3 for each triangle.
Definition types.h:2049
bool weldVertices
Optionally weld nearby vertices.
Definition types.h:2066
int vertexCount
The vertex count. Must be 3 or more.
Definition types.h:2060
b3MeshData * b3CreateMesh(const b3MeshDef *def, int *degenerateTriangleIndices, int degenerateCapacity)
Create a generic mesh.
This is a sorted triangle collision bounding volume hierarchy.
Definition types.h:2147
This is used to create a re-usable collision mesh.
Definition types.h:2044
Pass identifyEdges = true when triangles share edges so Box3D can suppress internal-edge collisions between adjacent triangles (the 3D equivalent of ghost collision handling on polygon chains).
The b3Mesh struct pairs a b3MeshData pointer with a scale vector:
const b3MeshData * data
Immutable pointer to the mesh data.
Definition types.h:2201
b3Vec3 scale
This scale may be non-uniform and have negative components.
Definition types.h:2205
This allows mesh data to be re-used with different scales.
Definition types.h:2199
Scale may be non-uniform and may have negative components, but no component may be zero.
Per-triangle surface materials are supported. Provide a b3SurfaceMaterial array in b3ShapeDef::materials and an index array in b3MeshDef::materialIndices:
Shape id references a shape instance. This should be treated as an opaque handle.
Definition id.h:53
uint8_t * materialIndices
Triangle material index.
Definition types.h:2054
b3SurfaceMaterial * materials
Surface material used on mesh shapes per triangle. Ignored for convex shapes. Ignored for compound sh...
Definition types.h:462
int materialCount
Surface material count.
Definition types.h:465
b3ShapeId b3CreateMeshShape(b3BodyId bodyId, const b3ShapeDef *def, const b3MeshData *mesh, b3Vec3 scale)
Create a mesh hull shape and attach it to a body.
b3ShapeDef b3DefaultShapeDef(void)
Use this to initialize your shape definition.
Used to create a shape.
Definition types.h:457
Material properties supported per triangle on meshes and height fields.
Definition types.h:399
Destroy the mesh data when no longer needed, after the shape referencing it has been destroyed:
void b3DestroyMesh(b3MeshData *mesh)
Destroy a mesh.
Box3D provides factory helpers for common mesh configurations: b3CreateGridMesh, b3CreateWaveMesh, b3CreateBoxMesh, and others.
Height Fields
Height fields describe terrain as a regular grid of sample heights. Like meshes, they are only valid on static bodies.
def.heights = heightSamples;
def.countX = 256;
def.countZ = 256;
def.scale = (
b3Vec3){1.0f, 1.0f, 1.0f};
def.globalMinimumHeight = -10.0f;
def.globalMaximumHeight = 50.0f;
b3HeightFieldData * b3CreateHeightField(const b3HeightFieldDef *data)
Create a generic height field.
A height field with compressed storage.
Definition types.h:2260
Data used to create a height field.
Definition types.h:2218
b3ShapeId b3CreateHeightFieldShape(b3BodyId bodyId, const b3ShapeDef *def, const b3HeightFieldData *heightField)
Create a height-field shape and attach it to a body.
scale controls cell spacing (x/z) and height scale (y). Setting a material index to B3_HEIGHT_FIELD_HOLE (0xFF) punches a hole in that grid cell, useful for cave entrances and tunnels.
When placing multiple height fields side by side, give all of them the same globalMinimumHeight and globalMaximumHeight so compressed heights quantize identically and the seams line up.
Destroy the height field after the shape referencing it has been destroyed:
void b3DestroyHeightField(b3HeightFieldData *heightField)
Destroy a height field.
Compound Shapes
A compound shape aggregates spheres, capsules, hulls, and meshes into a single static collision shape. Compounds are only allowed on static bodies. They are designed for offline baking and open-world streaming — see the dedicated compound page for the full API and usage pattern.
Geometric Queries
Shape Point Test
Box3D does not expose standalone b3PointInShape functions. Point overlap is expressed through the b3ShapeProxy abstraction that GJK uses. A degenerate proxy — a single point with zero radius — serves as a point test:
b3Vec3 queryPoint = {5.0f, 2.0f, 1.0f};
float radius
The external radius of the point cloud.
Definition types.h:1366
const b3Vec3 * points
The point cloud.
Definition types.h:1360
int count
The number of points. Do not exceed B3_MAX_SHAPE_CAST_POINTS.
Definition types.h:1363
bool b3OverlapHull(const b3HullData *shape, b3Transform shapeTransform, const b3ShapeProxy *proxy)
Overlap shape versus hull.
A shape proxy is used by the GJK algorithm. It can represent a convex shape.
Definition types.h:1358
The same pattern works with b3OverlapSphere, b3OverlapCapsule, b3OverlapMesh, and b3OverlapHeightField.
Ray Cast
Cast a ray at a shape to get the point of first intersection and the surface normal.
Caution: No hit will register if the ray starts inside a convex shape such as a sphere or hull. Convex shapes are treated as solid.
{
}
b3Vec3 origin
Start point of the ray cast.
Definition types.h:1310
bool hit
Did the cast hit?
Definition types.h:1427
float maxFraction
The maximum fraction of the translation to consider, typically 1.
Definition types.h:1317
b3Vec3 translation
Translation of the ray cast.
Definition types.h:1314
b3CastOutput b3RayCastHull(const b3HullData *shape, const b3RayCastInput *input)
Ray cast versus hull shape in local space.
Low level ray cast or shape-cast output data.
Definition types.h:1404
Per-shape ray cast functions: b3RayCastSphere, b3RayCastCapsule, b3RayCastHull, b3RayCastMesh, b3RayCastHeightField, b3RayCastCompound. All operate in the shape's local space. Use b3IsValidRay to validate input before calling.
To cast against the full simulation world, use b3World_CastRay or the convenience function b3World_CastRayClosest.
Shape Cast
A shape cast sweeps an abstract point cloud (a b3ShapeProxy) through space and finds where it first contacts another shape. A sphere is a single point with a non-zero radius; a capsule is two points with a radius; a box is eight points with zero radius.
b3Vec3 proxyPoints[] = {{-0.5f, -0.5f, -0.5f}, {0.5f, 0.5f, 0.5f}};
{
}
float maxFraction
The maximum fraction of the translation to consider, typically 1.
Definition types.h:1381
b3ShapeProxy proxy
A generic query shape.
Definition types.h:1375
b3Vec3 translation
The translation of the shape cast.
Definition types.h:1378
b3CastOutput b3ShapeCastHull(const b3HullData *shape, const b3ShapeCastInput *input)
Shape cast versus a hull. Initial overlap is treated as a miss.
Per-shape cast functions: b3ShapeCastSphere, b3ShapeCastCapsule, b3ShapeCastHull, b3ShapeCastMesh, b3ShapeCastHeightField, b3ShapeCastCompound.
For the most general form — sweeping one proxy against another — use b3ShapeCast with a b3ShapeCastPairInput. All shape cast functions call this internally.
Distance
b3ShapeDistance computes the closest points and separation distance between two shapes, each expressed as a b3ShapeProxy. It uses the GJK algorithm.
b3Transform b3InvMulWorldTransforms(b3WorldTransform A, b3WorldTransform B)
Relative transform of frame B in frame A. The narrow phase boundary.
Definition math_functions.h:725
b3ShapeProxy proxyB
The proxy for shape B.
Definition types.h:1539
b3ShapeProxy proxyA
The proxy for shape A.
Definition types.h:1536
bool useRadii
Should the proxy radius be considered?
Definition types.h:1546
b3Transform transform
Transform of shape B in shape A's frame, the relative pose B in A (b3InvMulWorldTransforms( worldA,...
Definition types.h:1543
b3DistanceOutput b3ShapeDistance(const b3DistanceInput *input, b3SimplexCache *cache, b3Simplex *simplexes, int simplexCapacity)
Compute the closest points between two shapes represented as point clouds.
Output for b3ShapeDistance.
Definition types.h:1551
Used to warm start the GJK simplex.
Definition types.h:1503
The query is origin independent and runs in frame A, so the witness points and normal come back in shape A's frame. Lift them into world space with shape A's transform if needed.
The simplex cache warm-starts the algorithm when shapes move by small amounts between calls. On the first call zero-initialize the cache (or use b3_emptyDistanceCache).
Time of Impact
If two shapes move fast they may tunnel through each other in a single time step.
b3TimeOfImpact finds the earliest time at which two swept shapes touch. Box3D uses this internally to prevent dynamic bodies from tunneling through static geometry.
The algorithm identifies an initial separating axis and advances the shapes along it until they touch or pass each other. It may miss collisions that only become apparent at the final positions, but those tend to be glancing contacts that rarely matter in practice.
input.sweepA = sweepA;
input.sweepB = sweepB;
input.maxFraction = 1.0f;
if (output.state == b3_toiStateHit)
{
}
b3TOIOutput b3TimeOfImpact(const b3TOIInput *input)
Compute the upper bound on time before two shapes penetrate.
Time of impact output.
Definition types.h:1612
b3Sweep describes a rigid body's motion as a translation of the center of mass plus a quaternion rotation, interpolated from (c1, q1) to (c2, q2). Use b3GetSweepTransform to evaluate the transform at any fraction.
Contact Manifolds
Box3D computes contact points for overlapping shapes. In 3D, hull-hull contact can produce up to B3_MAX_MANIFOLD_POINTS (4) points. All points share the same contact normal so Box3D groups them into a manifold. The contact solver uses this for stable stacking.
Normally you do not compute manifolds directly — you use the contact data returned by the simulation. The b3Manifold struct contains:
- normal: unit normal from shape A toward shape B
- points[B3_MAX_MANIFOLD_POINTS]: contact points with separation, impulses, and feature ids
- pointCount: 0–4 valid points
- frictionImpulse, twistImpulse, rollingImpulse: accumulated friction state
For direct use, the low-level collide functions produce a b3LocalManifold in the frame of shape A:
&hullA, &hullB, transformBtoA, &cache);
b3LocalManifoldPoint * points
The manifold points. From a point buffer.
Definition types.h:2714
void b3CollideHulls(b3LocalManifold *manifold, int capacity, const b3HullData *hullA, const b3HullData *hullB, b3Transform transformBtoA, b3SATCache *cache)
Collide two hulls.
A local manifold with no dynamic information. Used by b3Collide functions.
Definition types.h:2706
A local manifold point and normal in frame A.
Definition types.h:2690
Separating axis test cache. Provides temporal acceleration of collision routines.
Definition types.h:2653
Available collide functions:
The SAT cache in b3CollideHulls warm-starts the separating axis search between frames, the same idea as the simplex cache for GJK distance.
Box3D uses speculative collision: some contact points in a b3Manifold may report a positive (separated) separation. Check totalNormalImpulse to determine whether a speculative point actually had an interaction during the step.
Dynamic Tree
b3DynamicTree organizes large numbers of AABBs into a hierarchical binary tree for fast ray casts and region queries. Box3D uses it internally to manage the broad phase, but it is also available for organizing spatial game data unrelated to physics.
Each tree node stores a b3AABB and a 64-bit userData value. Internal nodes have two children; leaf nodes are proxies you manage directly.
b3AABB aabb = { lowerBound, upperBound };
Axis aligned bounding box.
Definition math_functions.h:105
void b3DynamicTree_MoveProxy(b3DynamicTree *tree, int proxyId, b3AABB aabb)
Move a proxy to a new AABB by removing and reinserting into the tree.
int b3DynamicTree_CreateProxy(b3DynamicTree *tree, b3AABB aabb, uint64_t categoryBits, uint64_t userData)
Create a proxy. Provide an AABB and a userData value.
b3DynamicTree b3DynamicTree_Create(int proxyCapacity)
Constructing the tree initializes the node pool.
void b3DynamicTree_DestroyProxy(b3DynamicTree *tree, int proxyId)
Destroy a proxy. This asserts if the id is invalid.
void b3DynamicTree_Destroy(b3DynamicTree *tree)
Destroy the tree, freeing the node pool.
The dynamic tree structure.
Definition types.h:1719
Category bits allow broad-phase filtering without invoking the callback. A proxy is only visited if (maskBits & node->categoryBits) != 0 (or if requireAllBits is set, the AND must equal maskBits).
AABB Query
Find all proxies whose AABBs overlap a query box:
&tree, queryAabb, maskBits, requireAllBits, myQueryCallback, context);
b3TreeStats b3DynamicTree_Query(const b3DynamicTree *tree, b3AABB aabb, uint64_t maskBits, bool requireAllBits, b3TreeQueryCallbackFcn *callback, void *context)
Query an AABB for overlapping proxies.
These are performance results returned by dynamic tree queries.
Definition types.h:1760
The callback receives proxyId and userData and returns true to continue.
Closest Query
Find the proxy closest to a point:
float minDistSqr = FLT_MAX;
&tree, point, maskBits, requireAllBits,
myClosestCallback, context, &minDistSqr);
b3TreeStats b3DynamicTree_QueryClosest(const b3DynamicTree *tree, b3Vec3 point, uint64_t maskBits, bool requireAllBits, b3TreeQueryClosestCallbackFcn *callback, void *context, float *minDistanceSqr)
Query an AABB for the closest object.
The callback receives the current minimum squared distance and returns the squared distance to the user object inside the proxy, allowing the tree to prune distant branches.
Ray Cast
&tree, &rayInput, maskBits, requireAllBits,
myRayCastCallback, context);
b3TreeStats b3DynamicTree_RayCast(const b3DynamicTree *tree, const b3RayCastInput *input, uint64_t maskBits, bool requireAllBits, b3TreeRayCastCallbackFcn *callback, void *context)
Ray cast against the proxies in the tree.
The callback returns a new maxFraction. Return 0 to stop, a fraction less than input->maxFraction to clip the ray (e.g. for closest-hit semantics), or input->maxFraction to continue unclipped.
Box Cast
&tree, &boxCastInput, maskBits, requireAllBits,
myBoxCastCallback, context);
b3TreeStats b3DynamicTree_BoxCast(const b3DynamicTree *tree, const b3BoxCastInput *input, uint64_t maskBits, bool requireAllBits, b3TreeBoxCastCallbackFcn *callback, void *context)
Sweep an AABB through the tree.
The tree sweeps the AABB in boxCastInput; the caller folds the cast shape's radius (and any world origin) into that box. The callback then does the precise narrow-phase cast against each leaf, taking only the advancing fraction from the tree.
b3TreeStats reports nodeVisits and leafVisits for performance profiling. The tree can be rebuilt with b3DynamicTree_Rebuild to reclaim quality after many insertions, and saved/loaded with b3DynamicTree_Save / b3DynamicTree_Load for debugging.
Normally you will not use b3DynamicTree directly. For world-level ray casts and overlap queries use b3World_CastRay, b3World_OverlapAABB, and b3World_OverlapShape. See the DynamicTree sample for direct usage examples.