webphysics-avbd-engine
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesewebphysics-avbd-engine
webphysics-avbd-engine
What It Does
功能介绍
webphysics- Rigid-body simulation with contacts, friction, and joints
- GPU broad-phase collision detection via LBVH (Linear BVH)
- Narrow-phase manifold generation with warm-start persistence
- Graph-coloring-based parallel body solves
- Springs and soft-body constraints
- Body sleeping/diagnostics
Browser support: Chrome only (requires WebGPU). This is an experimental proof-of-concept, not a production library.
webphysics- 包含接触、摩擦与关节的刚体模拟
- 基于LBVH(线性包围体层次结构)的GPU宽阶段碰撞检测
- 带热启动持久化的窄阶段流形生成
- 基于图着色的并行物体求解
- 弹簧与软体约束
- 物体休眠/诊断功能
**浏览器支持:**仅Chrome浏览器(需WebGPU支持)。这是一个实验性概念验证项目,并非生产级库。
Installation & Setup
安装与设置
sh
git clone https://github.com/jure/webphysics.git
cd webphysics
npm install
npm run dev # development server
npm run build # production buildThe dev server typically starts at (Vite-based).
http://localhost:5173sh
git clone https://github.com/jure/webphysics.git
cd webphysics
npm install
npm run dev # 开发服务器
npm run build # 生产构建开发服务器通常启动于(基于Vite)。
http://localhost:5173Project Structure
项目结构
src/
├── physics/
│ ├── PhysicsEngine.ts # Main orchestration: substep loop, init, step
│ └── gpu/
│ ├── avbdState.ts # Primal/dual solve, coloring, velocity finalization
│ ├── broadPhase.ts # LBVH broad-phase candidate generation
│ ├── contactGeneration.ts # Narrow-phase manifolds, per-body constraint lists
│ ├── contactRecord.ts # Warm-start state persistence
│ └── avbdState.ts # Inertial targets, primal init, iteration
├── lvbh/
│ └── GPULBVHBuilder.ts # GPU LBVH construction
└── ...src/
├── physics/
│ ├── PhysicsEngine.ts # 主编排模块:子步循环、初始化、步进
│ └── gpu/
│ ├── avbdState.ts # 原始/对偶求解、着色、速度最终化
│ ├── broadPhase.ts # LBVH宽阶段候选生成
│ ├── contactGeneration.ts # 窄阶段流形、逐物体约束列表
│ ├── contactRecord.ts # 热启动状态持久化
│ └── avbdState.ts # 惯性目标、原始初始化、迭代
├── lvbh/
│ └── GPULBVHBuilder.ts # GPU LBVH构建
└── ...Core API Usage
核心API使用
Initializing the Physics Engine
初始化物理引擎
typescript
import { PhysicsEngine } from './src/physics/PhysicsEngine';
// Requires an existing GPUDevice
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const engine = new PhysicsEngine(device);
await engine.init();typescript
import { PhysicsEngine } from './src/physics/PhysicsEngine';
// 需要已有的GPUDevice
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const engine = new PhysicsEngine(device);
await engine.init();Adding Rigid Bodies
添加刚体
typescript
// Add a static ground plane
engine.addBody({
type: 'box',
position: [0, -1, 0],
rotation: [0, 0, 0, 1], // quaternion [x, y, z, w]
halfExtents: [10, 0.5, 10],
mass: 0, // 0 = static/infinite mass
restitution: 0.3,
friction: 0.5,
});
// Add a dynamic rigid box
engine.addBody({
type: 'box',
position: [0, 5, 0],
rotation: [0, 0, 0, 1],
halfExtents: [0.5, 0.5, 0.5],
mass: 1.0,
restitution: 0.2,
friction: 0.6,
});typescript
// 添加静态地面平面
engine.addBody({
type: 'box',
position: [0, -1, 0],
rotation: [0, 0, 0, 1], // 四元数 [x, y, z, w]
halfExtents: [10, 0.5, 10],
mass: 0, // 0 = 静态/无限质量
restitution: 0.3,
friction: 0.5,
});
// 添加动态刚体盒子
engine.addBody({
type: 'box',
position: [0, 5, 0],
rotation: [0, 0, 0, 1],
halfExtents: [0.5, 0.5, 0.5],
mass: 1.0,
restitution: 0.2,
friction: 0.6,
});Stepping the Simulation
运行模拟步进
typescript
const TIMESTEP = 1 / 60;
const SUBSTEPS = 10;
function gameLoop(dt: number) {
engine.step(dt, SUBSTEPS);
// Read back positions for rendering
const bodyStates = engine.getBodyStates();
renderBodies(bodyStates);
requestAnimationFrame(gameLoop);
}
requestAnimationFrame(gameLoop);typescript
const TIMESTEP = 1 / 60;
const SUBSTEPS = 10;
function gameLoop(dt: number) {
engine.step(dt, SUBSTEPS);
// 读取位置用于渲染
const bodyStates = engine.getBodyStates();
renderBodies(bodyStates);
requestAnimationFrame(gameLoop);
}
requestAnimationFrame(gameLoop);Reading Body State for Rendering
读取物体状态用于渲染
typescript
// After engine.step(), retrieve updated transforms
const states = engine.getBodyStates();
for (const state of states) {
const { position, rotation, bodyIndex } = state;
// position: [x, y, z]
// rotation: quaternion [x, y, z, w]
updateMeshTransform(bodyIndex, position, rotation);
}typescript
// 在engine.step()之后,获取更新后的变换
const states = engine.getBodyStates();
for (const state of states) {
const { position, rotation, bodyIndex } = state;
// position: [x, y, z]
// rotation: 四元数 [x, y, z, w]
updateMeshTransform(bodyIndex, position, rotation);
}Adding Joints / Constraints
添加关节/约束
typescript
// Distance joint between two bodies
engine.addJoint({
type: 'distance',
bodyA: 0,
bodyB: 1,
anchorA: [0, 0.5, 0], // local-space anchor on body A
anchorB: [0, -0.5, 0], // local-space anchor on body B
restLength: 1.0,
stiffness: 1e4,
});typescript
// 两个物体间的距离关节
engine.addJoint({
type: 'distance',
bodyA: 0,
bodyB: 1,
anchorA: [0, 0.5, 0], // 物体A本地空间锚点
anchorB: [0, -0.5, 0], // 物体B本地空间锚点
restLength: 1.0,
stiffness: 1e4,
});Adding Springs (Soft Bodies)
添加弹簧(软体)
typescript
engine.addSpring({
bodyA: 2,
bodyB: 3,
anchorA: [0, 0, 0],
anchorB: [0, 0, 0],
restLength: 0.8,
stiffness: 500,
damping: 10,
});typescript
engine.addSpring({
bodyA: 2,
bodyB: 3,
anchorA: [0, 0, 0],
anchorB: [0, 0, 0],
restLength: 0.8,
stiffness: 500,
damping: 10,
});AVBD Pipeline Reference
AVBD管线参考
The solver follows Algorithm 1 from the AVBD paper:
1. collision detection (x^t)
↓
2. broad phase (LBVH) → src/lvbh/GPULBVHBuilder.ts
↓
3. narrow phase + warm start → src/physics/gpu/contactGeneration.ts
↓
4. per-body constraint lists → src/physics/gpu/avbdState.ts
↓
5. graph coloring → src/physics/gpu/avbdState.ts
↓
6. inertial target y, primal init, warm-start α/γ
↓
7. [loop] colored primal body solve (approx Hessian)
↓
8. [loop] dual + stiffness update
↓
9. finalize velocitiesKey files per stage:
| Stage | File |
|---|---|
| Orchestration | |
| Broad phase | |
| Narrow phase | |
| Contact records | |
| AVBD solve | |
| LBVH builder | |
求解器遵循AVBD论文中的算法1:
1. 碰撞检测 (x^t)
↓
2. 宽阶段(LBVH) → src/lvbh/GPULBVHBuilder.ts
↓
3. 窄阶段 + 热启动 → src/physics/gpu/contactGeneration.ts
↓
4. 逐物体约束列表 → src/physics/gpu/avbdState.ts
↓
5. 图着色 → src/physics/gpu/avbdState.ts
↓
6. 惯性目标y、原始初始化、热启动α/γ
↓
7. [循环] 着色原始物体求解(近似海森矩阵)
↓
8. [循环] 对偶 + 刚度更新
↓
9. 最终化速度各阶段对应的关键文件:
| 阶段 | 文件 |
|---|---|
| 编排 | |
| 宽阶段 | |
| 窄阶段 | |
| 接触记录 | |
| AVBD求解 | |
| LBVH构建 | |
Configuration Patterns
配置模式
Solver Parameters
求解器参数
typescript
// Passed during engine construction or step
engine.step(dt, substeps, {
gravity: [0, -9.81, 0],
iterations: 10, // AVBD inner iterations per substep
restitutionThreshold: 1.0,
});typescript
// 在引擎构造或步进时传入
engine.step(dt, substeps, {
gravity: [0, -9.81, 0],
iterations: 10, // 每个子步的AVBD内部迭代次数
restitutionThreshold: 1.0,
});Tuning Stability
稳定性调优
- Increase (e.g., 20) for stiff stacks or fast-moving bodies
substeps - Increase for better constraint convergence
iterations - Use for static bodies (never moves, acts as infinite mass)
mass: 0 - Lower values for softer, more stable joints
stiffness - Set + high
restitution: 0for non-bouncy stackingfriction
- 增加(如20)以处理刚性堆叠或高速运动物体
substeps - 增加以提升约束收敛效果
iterations - 静态物体设置(不会移动,视为无限质量)
mass: 0 - 降低关节值以获得更柔软、稳定的关节
stiffness - 设置+ 高
restitution: 0以实现无弹跳堆叠friction
Common Patterns
常见模式
Stack of Boxes
盒子堆叠
typescript
const groundIndex = engine.addBody({
type: 'box',
position: [0, 0, 0],
halfExtents: [5, 0.25, 5],
mass: 0,
friction: 0.7,
restitution: 0.1,
});
for (let i = 0; i < 8; i++) {
engine.addBody({
type: 'box',
position: [0, 0.5 + i * 1.05, 0],
halfExtents: [0.5, 0.5, 0.5],
mass: 1.0,
friction: 0.5,
restitution: 0.1,
});
}typescript
const groundIndex = engine.addBody({
type: 'box',
position: [0, 0, 0],
halfExtents: [5, 0.25, 5],
mass: 0,
friction: 0.7,
restitution: 0.1,
});
for (let i = 0; i < 8; i++) {
engine.addBody({
type: 'box',
position: [0, 0.5 + i * 1.05, 0],
halfExtents: [0.5, 0.5, 0.5],
mass: 1.0,
friction: 0.5,
restitution: 0.1,
});
}Pendulum Chain with Distance Joints
带距离关节的摆链
typescript
let prevIndex = engine.addBody({
type: 'box', position: [0, 5, 0],
halfExtents: [0.1, 0.1, 0.1], mass: 0,
friction: 0, restitution: 0,
});
for (let i = 1; i <= 5; i++) {
const curr = engine.addBody({
type: 'box', position: [0, 5 - i, 0],
halfExtents: [0.15, 0.15, 0.15], mass: 1.0,
friction: 0.1, restitution: 0,
});
engine.addJoint({
type: 'distance',
bodyA: prevIndex, bodyB: curr,
anchorA: [0, -0.15, 0], anchorB: [0, 0.15, 0],
restLength: 0.7,
stiffness: 1e5,
});
prevIndex = curr;
}typescript
let prevIndex = engine.addBody({
type: 'box', position: [0, 5, 0],
halfExtents: [0.1, 0.1, 0.1], mass: 0,
friction: 0, restitution: 0,
});
for (let i = 1; i <= 5; i++) {
const curr = engine.addBody({
type: 'box', position: [0, 5 - i, 0],
halfExtents: [0.15, 0.15, 0.15], mass: 1.0,
friction: 0.1, restitution: 0,
});
engine.addJoint({
type: 'distance',
bodyA: prevIndex, bodyB: curr,
anchorA: [0, -0.15, 0], anchorB: [0, 0.15, 0],
restLength: 0.7,
stiffness: 1e5,
});
prevIndex = curr;
}Integrate with Three.js Rendering
与Three.js渲染集成
typescript
import * as THREE from 'three';
const meshes: THREE.Mesh[] = [];
function syncPhysicsToRender() {
const states = engine.getBodyStates();
states.forEach((state, i) => {
if (!meshes[i]) return;
meshes[i].position.set(...state.position);
meshes[i].quaternion.set(
state.rotation[0], state.rotation[1],
state.rotation[2], state.rotation[3]
);
});
}
function animate() {
engine.step(1 / 60, 10);
syncPhysicsToRender();
renderer.render(scene, camera);
requestAnimationFrame(animate);
}typescript
import * as THREE from 'three';
const meshes: THREE.Mesh[] = [];
function syncPhysicsToRender() {
const states = engine.getBodyStates();
states.forEach((state, i) => {
if (!meshes[i]) return;
meshes[i].position.set(...state.position);
meshes[i].quaternion.set(
state.rotation[0], state.rotation[1],
state.rotation[2], state.rotation[3]
);
});
}
function animate() {
engine.step(1 / 60, 10);
syncPhysicsToRender();
renderer.render(scene, camera);
requestAnimationFrame(animate);
}Troubleshooting
故障排除
WebGPU Not Available
WebGPU不可用
Error: navigator.gpu is undefined- Only Chrome 113+ supports WebGPU by default
- Enable via on older versions
chrome://flags/#enable-unsafe-webgpu - Firefox/Safari do not currently support WebGPU
Error: navigator.gpu is undefined- 仅Chrome 113+默认支持WebGPU
- 旧版本可通过开启
chrome://flags/#enable-unsafe-webgpu - Firefox/Safari目前不支持WebGPU
Simulation Explodes / Bodies Flying Off
模拟崩溃/物体飞散
- Reduce timestep or increase
substeps - Lower joint values
stiffness - Ensure static bodies have
mass: 0 - Check that are positive and non-zero
halfExtents
- 减小时间步长或增加
substeps - 降低关节值
stiffness - 确保静态物体设置
mass: 0 - 检查为正数且非零
halfExtents
Bodies Sinking Through Ground
物体穿透地面
- Increase (try 15–20)
iterations - Increase
substeps - Check collision shape sizing matches visual mesh
- 增加(尝试15–20)
iterations - 增加
substeps - 确保碰撞形状尺寸与可视网格匹配
Performance Issues
性能问题
- This is a Chrome-only WebGPU project; GPU driver issues can cause slowdowns
- Reduce body count or iteration count
- Check to ensure hardware acceleration is active
chrome://gpu
- 这是仅支持Chrome的WebGPU项目;GPU驱动问题可能导致性能下降
- 减少物体数量或迭代次数
- 查看确保硬件加速已激活
chrome://gpu
Build Errors
构建错误
sh
undefinedsh
undefinedEnsure Node.js >= 18
确保Node.js >= 18
node --version
node --version
Clear cache
清除缓存
rm -rf node_modules dist
npm install
npm run build
undefinedrm -rf node_modules dist
npm install
npm run build
undefinedLimitations & Roadmap Notes
限制与路线图说明
- Chrome only — no Firefox/Safari support yet
- Not a drop-in npm package; must clone and integrate manually
- Double-buffered position updates (for same-color conflict safety) not yet implemented — current path uses in-place colored body solve in
avbdState.ts - Experimental API — breaking changes expected
- No TypeScript type declarations exported for external use yet
- 仅支持Chrome——暂不支持Firefox/Safari
- 并非开箱即用的npm包;必须克隆后手动集成
- 双缓冲位置更新(用于同色冲突安全)尚未实现——当前路径在中使用原地着色物体求解
avbdState.ts - API为实验性——可能会有破坏性变更
- 尚未导出供外部使用的TypeScript类型声明