物理引擎可以在 3D 场景中模拟重力、碰撞、受力等物理现象。
在常规 three.js 场景中,我们通常直接修改对象位置和旋转;
而在使用物理引擎时,会额外维护一个并行的“物理世界”,
刚体在其中响应力和碰撞。然后每帧把 three.js 网格与物理刚体状态同步,
从而呈现出“真实物理”效果。
需要注意的是,物理引擎不一定要每帧更新。为了保持模拟稳定,
通常会采用固定时间步。比如游戏循环运行于 60fps,
物理更新运行于 30fps(1/30 秒),
同时每帧使用物理引擎的最新状态更新 three.js 网格变换(位置、旋转等)。
物理模拟尤其适用于游戏、交互可视化,以及任何需要真实对象行为的应用,
例如下落、弹跳、滑动等效果。
集成方式
在 three.js 项目中集成物理引擎,主要有三种方式:
1. 使用 three.js 物理插件
Three.js 在 examples/jsm/physics 目录中为多个常见物理引擎提供了封装类。
这些插件可简化接入流程,完成物理世界初始化与网格同步。
可用插件包括:
- AmmoPhysics:Ammo.js(Bullet 物理)的封装。
- JoltPhysics:Jolt Physics 的封装。
- RapierPhysics:Rapier 的封装。
这些插件屏蔽了大量底层复杂性。对于常规需求,它们是最快的入门路径之一。
示例
2. 使用第三方 JS/TS 物理库
许多物理引擎直接由 JavaScript / TypeScript 编写,
与 Web 生态集成较容易。像 cannon-es 这类库因轻量且接入简单而常被采用。
使用这类库时,你需要自己创建物理世界和刚体,
并在动画循环中手动把刚体的位置、四元数同步到 three.js 网格。
项目
- cannon-es:纯 JS/TS 的轻量 3D 物理引擎,MIT 协议。看起来维护已不活跃(最近提交距今较久)。
- cannon.js:纯 JavaScript 的轻量 3D 物理引擎,MIT 协议。已基本停止维护。建议优先使用其较新的分支 cannon-es。
- phy:面向 three.js 的纯 JavaScript 物理引擎,MIT 协议。当前仍在维护。
- Oimo.js:纯 JavaScript 轻量 3D 物理引擎,已不再维护。作者建议改用 phy。
另外还有一类“看似 JS/TS、实则调用外部引擎”的方案,例如:
- Physijs:底层调用 ammo.js,并借助 Web Worker 在独立线程处理物理,MIT 协议。维护不活跃(最近提交距今多年)。
- enable3d:基于 ammo.js 的 three.js 3D 物理框架,LGPL-3.0 协议。看起来仍在维护。
3. 引入基于 WASM 的引擎
如果你需要更高性能、稳定性和精度(尤其复杂模拟),
可以选择 C++/Rust 等语言编写并编译为 WebAssembly(WASM)的物理引擎。
例如 Ammo.js(Bullet 的移植版)和 Rapier 都属于这一类。
这种方式通常功能最完整、性能最好,但接入成本更高,
需要处理 WASM 内存管理及与物理 API 的直接交互。
示例
项目
- JoltPhysics:面向多核的刚体物理与碰撞检测库,C++ 编写,MIT 协议,活跃维护。已在《Horizon Forbidden West》《Death Stranding 2》等知名作品中得到验证,并获得 Godot 游戏引擎官方支持。
- PhysX:NVIDIA 提供的工业级实时 3D 物理引擎,BSD-3-Clause 协议,稳定且持续维护。
- Rapier:注重性能的 2D/3D 物理引擎,Rust 编写,MIT 协议,活跃维护。
- Bullet:
用于 VR、游戏、视觉特效、机器人、机器学习等场景的实时碰撞检测与多物理模拟库,C++ 编写,ZLIB 协议。维护状态可能不活跃。
其中一些跨平台 3D 物理引擎已有可直接使用的 WASM 版本,例如:
- JoltPhysics.js:使用 Emscripten 将 JoltPhysics 移植到 JavaScript,MIT 协议,当前维护中。
- physx-js-webidl:NVIDIA PhysX 的 JavaScript WASM 绑定,MIT 协议,当前维护中。
- Rapier.js:Rapier 的官方 JavaScript 绑定,Apache-2.0 协议,活跃维护。
- Ammo.js:使用 Emscripten 将 Bullet 直接移植到 JavaScript,维护不活跃(最近提交距今多年),采用类似 MIT 的宽松自定义协议。