万字深度解析 Box3D:当 Box2D 作者遇见 3D 物理引擎——从 Erin Catto 的传奇生涯到 Soft Step 求解器、从 Continuous Collision 到生产级游戏集成的完整技术指南(2026)
Box2D 影响了整整一代游戏开发者。如今,它的创造者 Erin Catto 把二十年物理引擎经验浓缩进 Box3D——一个为现代游戏设计的开源 3D 物理引擎。本文从算法原理、架构设计、SIMD 优化、多线程并行、与 Unreal Chaos 对比,到完整可运行的集成代码,全方位拆解这款 2026 年最值得关注的开源物理引擎。
目录
- 背景:从 Box2D 到 Box3D,Erin Catto 的物理引擎传奇
- 为什么要做 Box3D?两个核心原因
- Box3D 核心架构设计
- 碰撞检测系统:从 Broad-phase 到 Continuous Collision
- Soft Step 求解器:比 PGS 更稳定的约束求解
- SIMD 与多线程:宽接触求解与图着色并行
- Compound Collision:5 万碰撞体的优化之道
- 代码实战:从零构建并运行 Box3D
- 集成到真实游戏:Unreal / 自研引擎接入指南
- 性能对比:Box3D vs Jolt vs Chaos vs Bullet
- Box3D 的限制与未来路线
- 总结与展望
1. 背景:从 Box2D 到 Box3D,Erin Catto 的物理引擎传奇
如果你做过 2D 游戏,大概率听说过 Box2D。它是 Erin Catto 在 2004 年开始开发的 2D 物理引擎,如今已成为游戏行业的基石之一:
- Angry Birds 的物理核心就是 Box2D
- Terraria、Limbo、Shovel Knight 等独立游戏标杆均使用 Box2D
- 累计 GitHub Stars 超过 8.5k,被移植到几乎所有游戏引擎(Unity、Godot、Cocos2d-x 等)
Erin Catto 本人则是游戏物理领域的传奇人物:
- 连续多年在 GDC(Game Developer Conference) 讲授物理引擎课程
- 发明了 Soft Step(子步求解器)等核心算法
- 在 Naughty Dog、Media Molecule 等顶尖工作室有深厚的工程背景
- 2022 年加入 Kintsugiyama,开发开放世界生存游戏 The Legend of California
Box3D 是 Erin 二十年物理引擎经验的结晶——它本质上是 Box2D 的 3D 化 fork,但加入了大量为现代 3D 游戏设计的新特性。
Box2D (2004) ──→ 影响一代 2D 游戏
│
▼
Box3D (2026) ──→ 专为 3D 游戏重新设计
│
├── 三角网格碰撞
├── 高度场碰撞
├── Compound 碰撞(烘焙优化)
├── Soft Step 求解器
├── 连续碰撞检测(CCD)
├── 图着色大 Island 并行
├── 宽 SIMD 接触求解器
├── 多线程钩子 + 内置调度器
└── 双精度大世界支持
2. 为什么要做 Box3D?两个核心原因
原因一:The Legend of California 的技术需求
Erin 自 2022 年起在 Kintsugiyama 开发开放世界生存游戏 The Legend of California(基于 Unreal Engine 5)。在项目早期,他们遇到了 Unreal 原生物理引擎 Chaos 的几个严重问题:
问题 1:不支持陀螺扭矩(Gyroscopic Torque)
细长轴体(如步枪)在 Chaos 中会永远旋转,无法模拟真实的进动(precession)和章动(nutation)行为。Erin 早在 2015 年 GDC 就提出了仅需约 10 行代码的陀螺扭矩算法(Numerical Methods GDC 2015),但 Chaos 直到 2024 年底才合并相关 PR。
// Erin 的陀螺扭矩算法核心(简化版)
// 在每步求解器中加入这项,即可模拟陀螺效应
b3Vec3 omega = body->GetAngularVelocity();
b3Vec3 L = b3Mul(body->GetInertiaTensor(), omega); // 角动量
b3Vec3 tau = b3Cross(omega, L); // 陀螺扭矩
body->ApplyTorque(tau);
问题 2:树倒下的异常行为
作为生存游戏,砍树是核心玩法。但 Chaos 模拟的树倒下时会出现"瞬移"和"抖动"——大胶囊(树)落在平滑三角网格(地形)上的 CCD 逻辑存在 fallback bug。
问题 3:大规模实体的 Broad-phase 性能
The Legend of California 的服务器需要管理 数十万个实体 的物理模拟。Chaos 的 broad-phase 在这种规模下表现不佳,而 Erin 在 broad-phase 数据结构(Dynamic BVH)上有深入研究(GDC 演讲)。
Valve 的 Dirk Gregorius 伸出援手
Erin 的朋友 Dirk Gregorius(Valve 物理程序员,Half-Life: Alyx 的 Rubikon 物理引擎作者)建议他 fork 自己维护的"Rubikon-Lite"(个人版 Rubikon)。
Erin 照做了,并且跑得很好——陀螺扭矩、树倒下、broad-phase 全部解决。
但随后 Erin 发现:Box2D v3.0 的许多优化也想移植过来。为了保持 2D 和 3D 代码的一致性,他逐步用 Box2D 的数据结构和算法替换了 Rubikon-Lite 的代码。最终,这个 fork 演变成了 Box3D。
"Rubikon-Lite 的代码仍保留在凸包生成和部分碰撞算法中。其余部分来自 Box2D,以及我为 Box3D 编写的新代码。" — Erin Catto
原因二:知识传承(与理智维持)
Erin 自 2004 年以来一直在做物理引擎。但每次换工作,这些代码就得留下来。Box2D 的存在就是为了解决这个问题——它是一个开源项目,捕捉了他的知识和努力,可以作为未来工作的基础。
但在 3D 方面,他一直在"重新发明轮子"。Box3D 的公开,意味着:
- 知识固化:Erin 的物理引擎知识被永久保存
- 社区受益:开发者可以免费使用工业级 3D 物理引擎
- 可持续维护:Kintsugiyama 允许 Erin 在工作时间内维护 Box3D
3. Box3D 核心架构设计
Box3D 的架构几乎与 Box2D 完全一致,但扩展到 3D。理解 Box3D 的架构,关键是理解以下几个核心模块:
┌─────────────────────────────────────────────────────┐
│ Application Layer │
│ (Your Game / Engine) │
└──────────────────┬──────────────────────────────────┘
│ b3WorldId API
┌──────────────────▼──────────────────────────────────┐
│ Box3D Core (C17) │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌─────────────┐ │
│ │ Broad-phase │ │ Solver │ │ Collision │ │
│ │ (Dynamic │ │ (Soft Step │ │ Detection │ │
│ │ BVH) │ │ PGS) │ │ (GJK/EPA) │ │
│ └──────┬──────┘ └──────┬───────┘ └──────┬──────┘ │
│ │ │ │ │
│ ┌──────▼──────┐ ┌──────▼───────┐ ┌──────▼──────┐ │
│ │ Island │ │ Constraint │ │ Continuous │ │
│ │ Graph │ │ Graph │ │ Collision │ │
│ │ Coloring │ │ (Joints + │ │ (TOI) │ │
│ │ (Parallel) │ │ Contacts) │ │ │ │
│ └─────────────┘ └──────────────┘ └─────────────┘ │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ SIMD Layer (SSE2 / Neon) + Thread Pool │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
3.1 数据导向设计(Data-Oriented Design)
Box3D 全部使用 C17 编写,采用数据导向设计:
- 物理对象通过 Id 引用(
b3BodyId、b3ShapeId、b3JointId),而非指针 - Ids 有 64k 代际(generation)保护,使用已释放的 id 会触发断言
- 所有内存由引擎内部管理,支持确定性和回放
// Box3D 的 Id 系统设计(简化)
typedef struct b3BodyId {
uint16_t index; // 数组索引
uint16_t generation; // 代际计数(防止悬空引用)
} b3BodyId;
// 创建物体
b3BodyDef bodyDef = b3DefaultBodyDef();
bodyDef.type = b3_dynamicBody;
bodyDef.position = (b3Vec3){0.0f, 3.0f, 0.0f};
b3BodyId bodyId = b3CreateBody(worldId, &bodyDef);
// 销毁物体
b3DestroyBody(bodyId);
bodyId = b3_nullBodyId; // 立即置空,防止误用
3.2 C API 设计哲学
Box3D 提供 纯 C API(头文件在 include/box3d/),这意味着:
- 可以被任何语言绑定(C++、C#、Rust、Python、Lua...)
- ABI 稳定,不用担心 C++ 名称修饰(name mangling)
- 与 Box2D v3.0 的 API 风格高度一致,降低迁移成本
// 典型的 Box3D 程序结构
#include <box3d/box3d.h>
int main() {
// 1. 创建世界
b3WorldDef worldDef = b3DefaultWorldDef();
worldDef.gravity = (b3Vec3){0.0f, -9.8f, 0.0f};
b3WorldId worldId = b3CreateWorld(&worldDef);
// 2. 创建地面
b3BodyDef groundDef = b3DefaultBodyDef();
groundDef.type = b3_staticBody;
b3BodyId groundId = b3CreateBody(worldId, &groundDef);
b3ShapeDef shapeDef = b3DefaultShapeDef();
b3BoxHull groundHull = b3MakeBoxHull(50.0f, 1.0f, 50.0f);
b3CreateHullShape(groundId, &shapeDef, &groundHull.base);
// 3. 模拟循环
float timeStep = 1.0f / 60.0f;
for (int i = 0; i < 300; ++i) {
b3WorldStep(worldId, timeStep, 4); // 4 次子步
}
// 4. 清理
b3DestroyWorld(worldId);
return 0;
}
4. 碰撞检测系统:从 Broad-phase 到 Continuous Collision
4.1 Broad-phase:Dynamic BVH
Box3D 的 broad-phase 使用 Dynamic BVH(边界体积层次结构),这是 Erin 在 GDC 2019 详细讲解过的数据结构。
核心思路:每个碰撞体用一个 AABB(轴对齐包围盒)表示,所有 AABB 组织成一棵动态 BVH 树。当物体移动时,只更新受影响节点的 AABB,并局部重新平衡树。
// Broad-phase 的查询接口(Ray-cast 示例)
b3RayCastInput input;
input.origin = (b3Vec3){0.0f, 10.0f, 0.0f};
input.direction = (b3Vec3){0.0f, -1.0f, 0.0f};
input.maxFraction = 1.0f;
// 回调函数:处理每个命中
b3RayCastOutput output;
b3ShapeId hitShapeId = b3WorldCastRay(worldId, &input,
[](b3ShapeId shapeId, const b3RayCastInput* input,
b3RayCastOutput* output, void* context) -> float {
// 返回命中分数(0~1),或 -1 忽略
return 0.5f; // 简化:直接返回中点
}, NULL);
4.2 Narrow-phase:GJK/EPA + SAT
对于凸体碰撞,Box3D 使用 GJK(Gilbert-Johnson-Keerthi)算法计算分离轴,用 EPA(Expanding Polytope Algorithm)计算穿透深度。
对于特殊的形状对(如球-球、球-胶囊),Box3D 使用专门的解析解,避免 GJK 的开销。
碰撞检测流程:
Broad-phase (BVH)
│
│ 返回潜在的碰撞对(AABB 重叠)
▼
Narrow-phase (GJK/EPA)
│
│ 计算分离轴和穿透深度
▼
Contact Point Generation
│
│ 生成接触点(最多 4 个)
▼
Contact Solver (Soft Step)
│
│ 求解约束,防止穿透
▼
Post-solve (Friction + Restitution)
4.3 Continuous Collision Detection (CCD)
离散时间步长会导致"穿隧"(tunneling)问题:高速物体可能在一帧内完全穿过薄墙。
Box3D 的 CCD 解法:
- Speculative Collision:在物体接触前就生成接触约束
- Time of Impact (TOI) 求解:对每对高速物体,插值运动并找到首次碰撞时间
- Sub-stepping:在 TOI 时刻拆分时间步,分别求解
// 开启 CCD(对高速物体很重要)
b3BodyDef bodyDef = b3DefaultBodyDef();
bodyDef.type = b3_dynamicBody;
bodyDef.ccd = true; // 开启连续碰撞检测
bodyDef.ccdRadius = 0.5f; // CCD 包络半径
bodyDef.ccdThreshold = 0.25f; // 最小 CCD 步长
5. Soft Step 求解器:比 PGS 更稳定的约束求解
5.1 传统 PGS 的问题
PGS(Projected Gauss-Seidel)是物理引擎中最常用的约束求解器。但它有一个根本问题:收敛慢,且对质量比敏感。
当两个质量相差巨大的物体连接在一起时(如汽车悬挂连接车轮和车身),PGS 需要非常多子步才能收敛。
5.2 Soft Step 算法
Erin 在 Box2D v3.0 中引入了 Soft Step 求解器,Box3D 也采用了这一设计。
Soft Step 的核心思想:
- 约束软化:给所有约束加入适当的"柔软度"(compliance),避免过约束
- 质量加权分割:将大质量比约束分解成多个子约束
- 预热(Warm Starting):利用上一帧的约束冲量作为初始猜测
// Soft Step 的数值参数(在 b3WorldDef 中配置)
b3WorldDef worldDef = b3DefaultWorldDef();
worldDef.velocityIterations = 4; // 速度迭代次数
worldDef.positionIterations = 1; // 位置修正迭代
worldDef.hertz = 60.0f; // 更新频率(影响软约束的刚度)
b3WorldId worldId = b3CreateWorld(&worldDef);
5.3 关节(Joint)中的弹簧刚度
Box3D 的关节弹簧使用 赫兹(Hertz) 表示刚度,而非传统的弹簧常数 $k$。
这样做的好处:弹簧的反应速度与物体质量无关。无论物体是 1kg 还是 1000kg,相同 Hertz 值的弹簧"感觉"是一样的。
// 创建一个弹簧关节( Hertz 表示法)
b3DistanceJointDef jointDef = b3DefaultDistanceJointDef();
jointDef.bodyIdA = bodyA;
jointDef.bodyIdB = bodyB;
jointDef.anchorA = (b3Vec3){0.0f, 1.0f, 0.0f};
jointDef.anchorB = (b3Vec3){0.0f, -1.0f, 0.0f};
jointDef.hertz = 4.0f; // 4 Hz 自然频率
jointDef.dampingRatio = 0.7f; // 阻尼比(临界阻尼的 70%)
jointDef.minLength = 0.5f;
jointDef.maxLength = 2.0f;
b3JointId jointId = b3CreateJoint(worldId, &jointDef);
6. SIMD 与多线程:宽接触求解与图着色并行
6.1 SIMD 接触求解器
Box3D 的接触求解器使用 宽 SIMD(SSE2 on x86, Neon on ARM)来并行处理多个接触约束。
核心思路:将 4 个接触约束打包成一组,用 SIMD 指令同时求解。
// SIMD 接触求解的核心循环(概念性)
// 实际代码在 src/solver/solve_contact.c 中
void b3SolveContactsSIMD(b3ContactConstraint* constraints, int count) {
// 将约束按 4 个一组打包
for (int i = 0; i < count; i += 4) {
// 加载 4 个约束的法线、穿透深度、冲量
__m128 normals_x = _mm_load_ps(&constraints[i].normal.x);
__m128 normals_y = _mm_load_ps(&constraints[i].normal.y);
__m128 normals_z = _mm_load_ps(&constraints[i].normal.z);
// SIMD 求解冲量(同时处理 4 个约束)
__m128 impulses = solve_impulse_simd(normals_x, normals_y,
normals_z, ...);
// 写回结果
_mm_store_ps(&constraints[i].impulse, impulses);
}
}
6.2 图着色(Graph Coloring)并行
物理引擎的传统瓶颈:约束求解是串行的(约束图是密集的)。
Box3D 使用 图着色 算法将约束图分解成可以并行求解的"颜色组":
约束图:
Body1 ──contact── Body2 ──joint── Body3
│ │
└────── contact ───────────────┘
图着色结果:
Color 0: Body1-Body2 contact
Color 1: Body2-Body3 joint ← 与 Color 0 不冲突,可并行
Color 2: Body1-Body3 contact
同颜色的约束可以安全并行求解,因为不涉及相同的物体。
// Box3D 内置线程调度器(可选)
b3WorldDef worldDef = b3DefaultWorldDef();
worldDef.workerCount = 4; // 使用 4 个 worker 线程
worldDef.enableInternalScheduler = true;
b3WorldId worldId = b3CreateWorld(&worldDef);
7. Compound Collision:5 万碰撞体的优化之道
7.1 问题:大型 stronghold 的性能灾难
The Legend of California 的 stronghold(要塞)使用 kitbashing(套件拼接)建造。一个大型 stronghold 可能有 5 万个独立的碰撞网格。
如果为每个网格创建一个 b3Body + b3Shape,光是创建/销毁的开销就足以拖垮游戏。
7.2 Compound Collision 解法
Box3D 的 Compound Collision 系统允许将多个碰撞形状"烘焙"成一个优化的单一形状:
传统方式:
Body1 (Shape1) ──┐
Body2 (Shape2) ──┤── 5 万个独立 Body,无法并行
... ──┤
Body50000 (Shape50000)
Compound 方式:
CompoundBody (BakedCompoundShape)
├── 内部包含 50000 个形状
├── 统一的 BVH 加速结构
└── 单次创建,极低内存开销
// 创建 Compound Shape(简化示例)
b3CompoundDef compoundDef = b3DefaultCompoundDef();
// 添加多个子形状到 compound
for (int i = 0; i < 50000; i++) {
b3ShapeDef subShapeDef = b3DefaultShapeDef();
b3BoxHull subHull = b3MakeBoxHull(widths[i], heights[i], depths[i]);
// 注意:这里不立即创建,而是先"记录"
b3AddHullToCompound(&compoundDef, &subHull.base, transforms[i]);
}
// 烘焙成一个统一的 Compound Shape
b3ShapeId compoundShapeId = b3CreateCompoundShape(bodyId, &shapeDef, &compoundDef);
// 之后加载时,直接加载烘焙好的二进制数据(极快)
b3LoadCompoundShape(bodyId, &shapeDef, bakedData, bakedSize);
8. 代码实战:从零构建并运行 Box3D
8.1 环境准备
# 安装依赖
# macOS
brew install cmake git
# Ubuntu/Debian
sudo apt install cmake git build-essential
# Windows: 安装 Visual Studio 2022+ 和 CMake
8.2 克隆与构建
# 克隆仓库
git clone https://github.com/erincatto/box3d.git
cd box3d
# 方式一:CMake Presets(推荐)
# macOS
cmake --preset macos
cmake --build --preset macos-release
# Linux
cmake --preset linux-release
cmake --build --preset linux-release
# Windows
cmake --preset windows
cmake --build --preset windows-release
# 运行示例
# macOS
./build/bin/Release/samples
# Linux
./build/bin/samples
# Windows
.\build\bin\Release\samples.exe
8.3 最小可运行示例:Hello Physics
// hello_box3d.c
#include <stdio.h>
#include <box3d/box3d.h>
int main() {
printf("Box3D Hello World\n");
// 1. 创建物理世界
b3WorldDef worldDef = b3DefaultWorldDef();
worldDef.gravity = (b3Vec3){0.0f, -9.8f, 0.0f};
b3WorldId worldId = b3CreateWorld(&worldDef);
// 2. 创建地面
b3BodyDef groundBodyDef = b3DefaultBodyDef();
groundBodyDef.type = b3_staticBody;
b3BodyId groundId = b3CreateBody(worldId, &groundBodyDef);
b3ShapeDef groundShapeDef = b3DefaultShapeDef();
groundShapeDef.baseMaterial.friction = 0.6f;
groundShapeDef.baseMaterial.restitution = 0.1f;
b3BoxHull groundHull = b3MakeBoxHull(50.0f, 1.0f, 50.0f);
b3CreateHullShape(groundId, &groundShapeDef, &groundHull.base);
// 3. 创建一个动态球体(用胶囊近似)
b3BodyDef ballBodyDef = b3DefaultBodyDef();
ballBodyDef.type = b3_dynamicBody;
ballBodyDef.position = (b3Vec3){0.0f, 5.0f, 0.0f};
ballBodyDef.linearDamping = 0.1f;
b3BodyId ballId = b3CreateBody(worldId, &ballBodyDef);
b3ShapeDef ballShapeDef = b3DefaultShapeDef();
ballShapeDef.density = 1.0f;
ballShapeDef.baseMaterial.friction = 0.3f;
// Box3D 没有原生球体,用胶囊(capsule)近似
b3Capsule capsule = {{0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, 0.5f};
b3CreateCapsuleShape(ballId, &ballShapeDef, &capsule);
// 4. 模拟循环
float timeStep = 1.0f / 60.0f;
int stepCount = 300; // 5 秒
printf("时间(s)\t球Y位置\t球Y速度\n");
for (int i = 0; i < stepCount; i++) {
b3WorldStep(worldId, timeStep, 4);
// 查询球的位置和速度
b3Vec3 pos = b3Body_GetPosition(ballId);
b3Vec3 vel = b3Body_GetLinearVelocity(ballId);
if (i % 60 == 0) { // 每秒打印一次
printf("%.1f\t\t%.3f\t\t%.3f\n",
i / 60.0f, pos.y, vel.y);
}
}
// 5. 清理
b3DestroyWorld(worldId);
return 0;
}
8.4 用 CMake 构建你的项目
# CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(HelloBox3D C)
# 获取 Box3D(推荐:FetchContent)
include(FetchContent)
FetchContent_Declare(box3d
GIT_REPOSITORY https://github.com/erincatto/box3d.git
GIT_TAG v0.1.0 # 使用具体 tag,保证可复现
)
FetchContent_MakeAvailable(box3d)
# 你的可执行文件
add_executable(hello_box3d hello_box3d.c)
target_link_libraries(hello_box3d PRIVATE box3d::box3d)
构建并运行:
mkdir build && cd build
cmake ..
cmake --build .
./hello_box3d
9. 集成到真实游戏:Unreal / 自研引擎接入指南
9.1 替换 Unreal Chaos(高级)
Erin 在 The Legend of California 中成功将 Box3D 接入 Unreal Engine 5。关键步骤:
- 创建自定义 Scene Component:包装 Box3D 的
b3BodyId - 同步 Transform:每帧将 Box3D 的位置/旋转同步到 Unreal 的
FTransform - 绕过 Chaos:对需要 Box3D 模拟的物体,禁用 Chaos 的模拟
// UE5 中的 Box3D Component(简化)
UCLASS()
class BOX3DPLUGIN_API UBox3DBodyComponent : public USceneComponent {
GENERATED_BODY()
private:
b3BodyId BodyId; // Box3D 物体句柄
public:
virtual void TickComponent(float DeltaTime,
ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction) override {
// 从 Box3D 读取位置,同步到 Unreal
if (b3IsValidBodyId(BodyId)) {
b3Vec3 pos = b3Body_GetPosition(BodyId);
b3Quat rot = b3Body_GetRotation(BodyId);
SetWorldLocation(FVector(pos.x, pos.z, pos.y)); // Y-up 转 Z-up
SetWorldRotation(FQuat(rot.x, rot.z, rot.y, rot.w));
}
}
};
9.2 自研引擎集成要点
- 坐标系转换:Box3D 使用 Y-up,大多数引擎使用 Z-up
- 单位统一:Box3D 使用 MKS(米-千克-秒),确保你的引擎也用米
- 回调设计:用 Box3D 的事件系统(contact begin/end、sensor overlap)触发游戏逻辑
// 注册接触事件回调
b3WorldListener listener = {
.context = myGameContext,
.beginContact = MyBeginContactCallback,
.endContact = MyEndContactCallback,
.beginSensor = MyBeginSensorCallback,
};
b3World_SetListener(worldId, &listener);
10. 性能对比:Box3D vs Jolt vs Chaos vs Bullet
| 特性 | Box3D | Jolt | Chaos | Bullet |
|---|---|---|---|---|
| 语言 | C17 | C++17 | C++ | C++ |
| API | C(稳定 ABI) | C++ | C++ | C++ |
| SIMD | SSE2/Neon | AVX2/SSE4/Neon | SSE2/Neon | SSE2(可选) |
| 多线程 | 图着色 + 内置调度器 | Job System | Task Graph | 基本无 |
| CCD | 完整支持 | 完整支持 | 部分支持 | 部分支持 |
| 大世界 | 双精度支持 | 双精度支持 | 双精度 | 单精度 |
| 确定性 | 跨平台确定性 | 跨平台确定性 | 不确定 | 不确定 |
| 陀螺扭矩 | 原生支持 | 原生支持 | 2024 年底加入 | 需手动实现 |
| 开源协议 | MIT | MIT | 专有(UE 内置) | zlib |
| 学习曲线 | 低(API 清晰) | 中 | 高(引擎耦合深) | 中 |
结论:
Jolt(https://github.com/jrouwe/JoltPhysics)是目前最强大的开源 3D 物理引擎,被 Stormgate、S&box 等使用。Box3D 的定位不是取代 Jolt,而是提供一个 更简单、更易理解、API 风格与 Box2D 一致 的替代方案。
Chaos 是 Unreal 内置方案,但耦合深、调试困难。Box3D 适合需要深度定制物理的游戏。
Bullet 是老牌开源引擎,但架构较老,性能不如 Jolt/Box3D。
11. Box3D 的限制与未来路线
11.1 当前限制(v0.1)
- Alpha 状态:API 可能变化,文档不完整
- 无 GPU 加速:所有计算在 CPU 上完成(对大多数游戏足够)
- 关节类型有限:相比 Jolt,缺少一些高级关节
- 不接受 PR:Erin 暂时不接收外部 Pull Request(但欢迎 Issue 和 Discussion)
11.2 未来计划
根据 Erin 的公告,以下功能是近期重点:
- 增强角色移动功能(Character Controller)
- 改进幽灵碰撞(Ghost Collision)缓解
- 进一步优化性能
- 改进关节求解器
- 开放 Pull Request(可能使用 CLA)
12. 总结与展望
Box3D 的发布是 2026 年游戏物理领域的一件大事。它不仅仅是一个新的物理引擎,更是 Erin Catto 二十年物理引擎知识的开源传承。
为什么你应该关注 Box3D?
- 学习价值极高:代码清晰,算法经典,是学习物理引擎实现的绝佳材料
- 生产可用:已被 The Legend of California、s&box、Esoterica 等使用
- API 优雅:纯 C API,易于绑定,与 Box2D 风格一致
- 性能优秀:SIMD + 多线程 + Soft Step,足以应对大多数游戏场景
快速上手清单
- Star 仓库:https://github.com/erincatto/box3d
- 阅读公告博客:https://box2d.org/posts/2026/06/announcing-box3d/
- 克隆并运行示例:
git clone+cmake --preset - 加入 Discord:https://discord.gg/NKYgCBP
- 阅读文档:https://box2d.org/documentation3d/
- 赞助 Erin:https://github.com/sponsors/erincatto
本文撰写于 2026 年 7 月,基于 Box3D v0.1.0。API 可能在未来版本中变化,请以官方文档为准。
如果你觉得这篇文章有价值,欢迎分享给更多游戏开发者。Box3D 这样的高质量开源项目,需要社区的支持才能持续发展。