box3d
Libraryerincatto/box3d
A 3D physics engine for games with collision detection and rigid body simulation.
Overview
Box3D is a portable C17 physics engine featuring continuous collision detection, a soft-step rigid body solver, and data-oriented design. It supports multithreading, SIMD, and cross-platform determinism for large stacks of rigid bodies.
README Preview
# Box3D\n\n[](https://github.com/erincatto/box3d/actions)\n[](https://cla-assistant.io/erincatto/box3d)\n\n\n\nBox3D is a 3D physics engine for games.\n\n[](https://www.youtube.com/watch?v=jr_Fzl2XwKU)\n\n## Features\n\n### Collision\n\n- Continuous collision detection\n- Contact events\n- Convex hulls, capsules, spheres, triangle meshes, and height fields\n- Multiple shapes per body\n- Collision filtering\n- Ray casts, shape casts, and overlap queries\n- Sensor system\n- Character mover\n\n### Physics\n\n- Robust _Soft Step_ rigid body solver\n- Continuous physics for fast translations and rotations\n- Island based sleep\n- Revolute, prismatic, distance, motor, weld, and wheel joints\n- Joint limits, motors, springs, and friction\n- Joint and contact forces\n- Body movement events and sleep notification\n\n### System\n\n- Data-oriented design\n- Written in portable C17\n- Extensive multithreading and SIMD\n- Optimized for large piles of bodies\n- Cross platform determinism\n- Recording and replay\n\n### Samples\n\n- Uses sokol to run with D3D11 on Windows, Metal on macOS, and OpenGL 4.5 on Linux.\n- Graphical user interface with imgui.\n- Many samples to demonstrate features and performance.\n\n## Building all platforms\n\n- Install [CMake](https://cmake.org/)\n- Install [git](https://git-scm.com/)\n- Ensure these run from the command line\n\n## Building with CMake presets (recommended)\n\nThis uses the presets in `CMakePresets.json`.\n\n- Windows: `cmake --preset windows` then `cmake --build --preset windows-release`\n- Linux: `cmake --preset linux-release` then `cmake --build --preset linux-release`\n- macOS: `cmake --preset macos` then `cmake --build --preset macos-release`\n- Windows MinGW: `cmake --preset mingw-release` then `cmake --build --preset mingw-release`\n\nRun the samples app (must be in the Box3D directory).\n\n- Windows: `.\build\bin\Release\samples.exe`\n- Linux: `./build/bin/samples`\n- macOS: `./build/bin/Release/samples`\n\n## Building for Visu
FAQ (5)
TroubleshootingWhy is b3AddHullToDatabase very slow when creating many voxel-shaped box hulls in Box3D?
The slowdown is caused by severe hash-table collisions. The old djb2-style hull hash did not sufficiently mix regularly spaced float coordinates such as multiples of 0.25f, while bucket selection used only the low hash bits (hash & buckets_mask). Thousands of voxel hulls could therefore map to the same bucket chain, forcing repeated hull comparisons and excessive table growth. This is fixed in PR #126 by using improved 64-bit hull hashes. Update Box3D to a version containing that PR. In the reported 3,000-hull repro, the fix reduced time from about 159.9 ms to 3.9 ms and bucket count from 2,097,152 to 4,096. A temporary workaround is to add a small unique jitter to hull offsets, such as 1.0e-4f, but this changes the collider geometry and should be avoided if exact voxel alignment is required.
TroubleshootingHow do I fix the UBSan misaligned address panic in b3FreeElement when stepping a Box3D world?
The crash occurs because b3Manifold is 268 bytes. When an odd number of manifolds are packed together, the next element can start 4 bytes off an 8-byte boundary, but b3FreeElement stores a void* there, requiring 8-byte alignment.
Fix it by rounding each allocator element size up to pointer alignment in b3CreateBlockAllocator (block_allocator.c):
elementSize = (elementSize + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
Apply this before the element size is used to initialize blocks/free lists. Using sizeof(void *) is sufficient on the affected 64-bit platforms; rounding to a 64-byte cache-line size also works but wastes more space.
For Box3D v0.1.0, either apply this alignment patch or, as a temporary workaround, disable only the alignment check for the Box3D target:
-fno-sanitize=alignment
Disabling all sanitization also avoids the panic, but keeping ASan/UBSan enabled and suppressing only alignment is preferable until the patch is applied.
TroubleshootingHow do I fix two Box3D bodies still colliding after creating a joint with collideConnected set to false?
This occurs because creating the joint changes future collision filtering but does not destroy b3Contact objects that already exist between the two bodies. It was officially fixed in Box3D PR #157, so update to a Box3D version containing that PR. As a workaround on older versions, immediately after creating the joint, explicitly destroy contacts between the connected bodies before the next simulation step, e.g. call b3DestroyContactsBetweenBodies(world, bodyA, bodyB) when jointDef.collideConnected == false.
TroubleshootingHow to fix Box3D b3World_Step pushing a deeply overlapping dynamic body through a thin static wall?
This is expected solver behavior, not a bug in Box3D. The "set velocity to zero, call b3World_Step, repeat" pattern is not a supported quasi-static depenetration method. Once a large dynamic body's center crosses the far side of a thin wall, the contact solver cannot infer which side you intended as "inside the room." It resolves along the current contact normal, which may point toward the far side, so repeated corrections compound and push the object farther out.
Use one of these approaches:
1. **Prevent deep overlap before stepping.** Before spawning or accepting a dragged pose, run an overlap/shape-cast query against wall colliders. Reject the candidate pose or clamp it to the correct wall face before calling b3World_Step.
2. **Track the entry side explicitly.** If the object was on the interior side, project it back to interiorWallFace - objectHalfExtent; do not rely on the solver to choose that side after the center has crossed the wall.
3. **Drive dragging with a motor joint.** Create a motor joint for the dynamic item and update its target transform/linear offset toward the pointer target. Configure sufficient maxForce and maxTorque, then let contact constraints stop it at the wall. Do not use b3Body_SetLinearVelocity followed by zero-velocity steps as a positional relaxer.
4. **Manually repair already-invalid states.** If a body is already deeply penetrating or past the wall centerline, move it back to a known non-penetrating transform before stepping.
Enabling continuous collision helps prevent high-speed tunneling, but it does not resolve an initially invalid, deeply overlapping placement. This behavior was confirmed on commits 3fc20f5b45 and 30c67b5e6d; the maintainer recommends overlap validation and a motor joint.
TroubleshootingWhy does my mover get stuck on mesh triangle edges when moving at a near-perpendicular or shallow angle?
This is caused by backside triangle collision during mover shape casts. It is fixed in PR #130: update to a physics engine build containing that PR and rebuild. Shape casts now ignore backside collisions on mesh and height-field triangles, matching ray-cast behavior, and mover collision includes the triangle information needed for smoother contact. If you define a custom mesh, verify its triangle winding and set the new b3MeshDef clockwise option (and stride) correctly.