使用 Cannon.js 实现物理模拟效果

概述
Cannon.js 是一个开源的 JavaScript 物理引擎,可以模拟刚体(rigid body)的碰撞、重力、约束等物理行为。
它在处理碰撞检测、约束求解、弹性、摩擦力等方面都非常高效,让我们可以在浏览器里用相对简单的代码实现逼真的物理效果。
Three.js 负责三维场景的渲染与可视化,Cannon.js 则专注于物理模拟。
两者结合后,一方面,Three.js 让我们能把物理模拟的结果渲染为精致的三维画面;另一方面,Cannon.js 提供的真实物理效果能让 Three.js 的场景更加逼真、有互动感。
简单来说,Three.js+物理引擎=更逼真、更好玩的三维世界。
核心功能和特点:
- 刚体模拟:支持刚体的重力、速度、加速度以及碰撞行为。
- 碰撞检测:提供精准的碰撞检测,包括球体、盒子、平面等多种形状。
- 力学计算:支持施加外力、模拟弹性、摩擦力等多种物理现象。
- 优化性能:支持休眠机制和多种碰撞检测算法,提升物理计算效率。
使用场景:
- 创建交互式游戏中的物理效果,例如角色运动、物体掉落等。
- 模拟机械结构的动态行为,如齿轮、滑块。
- 在建筑仿真中实现结构受力分析。
Cannon.js 依赖安装
npm install cannon
Cannon.js 核心功能详解
1. 创建物理世界
物理世界是 Cannon.js 的核心,它是所有物理运算的基础。在 Cannon.js 中,World 是所有物理对象和规则的统筹管理者。它包含重力、碰撞检测、约束等各种物理要素。所有刚体都会被加入到这个世界中,之后进行物理模拟并更新状态。
物理世界离不开重力。我们需要设置 world.gravity,让 Cannon.js 知道所有刚体该往哪个方向坠落。另外,为了在碰撞时获得更准确的效果,Cannon.js 提供了迭代器设置,如 world.solver.iterations,它决定物理引擎对碰撞进行求解时迭代计算的次数。
CANNON.World 的核心属性和方法:
gravity: 设置世界的重力方向和大小,通常通过Vec3向量来定义,例如world.gravity.set(0, -9.82, 0)表示沿 y 轴向下的重力。allowSleep: 是否允许物体进入休眠状态,提高性能。默认值为false。broadphase: 使用碰撞检测算法,例如NaiveBroadphase或SAPBroadphase。step: 用于更新物理世界的方法,接收时间步长和子步数。
在下面的代码里,我们先创建一个 Cannon.js 的世界,然后定义了重力,让物体朝 y 轴负方向掉落。同时我们会设置一些迭代器参数,以确保在碰撞时有更准确的结果。这样你就获得了一个最基础的物理引擎舞台,所有的物体都会在这个舞台里被物理规则驱动、计算。
// 创建物理世界实例
const world = new CANNON.World();
// 设置重力,y轴方向为 -9.82 m/s^2
world.gravity.set(0, -9.82, 0); // 模拟和地球相近的重力加速度
// 允许物体进入休眠状态,提高性能
world.allowSleep = true;
// 设置碰撞检测算法
world.broadphase = new CANNON.NaiveBroadphase();
2. 添加刚体
在 Cannon.js 中,我们一般通过 Body 来定义物体的物理属性(质量、摩擦、弹性等),再结合特定的 Shape(例如 Sphere、Box、Plane 等)来描述它的形状。形状会影响碰撞检测算法以及物体的运动行为,比如球体的碰撞行为和方盒子就不一样。
在 Cannon.js 中,刚体由 CANNON.Body 类创建,该类提供了多种属性来控制物体的行为。
在实际应用里,我们通常会为 Cannon.js 里的刚体创建相对应的 Three.js 网格(Mesh)。这样做是为了:
- Cannon.js 里负责计算物体的物理行为。
- Three.js 里负责将该物体的三维模型渲染出来。
两者之间通过位置和旋转等参数来保持同步。
CANNON.Body 的主要属性和方法:
mass: 刚体的质量,单位为千克(kg)。设置为 0 时,该刚体为静态物体。position: 用于设置刚体在物理世界中的初始位置。velocity: 控制刚体的线速度,决定其移动方向和速度。angularVelocity: 控制刚体的角速度。material: 用于设置刚体的材质属性,可影响碰撞的摩擦力和弹性。linearDamping: 线性阻尼,用于模拟空气阻力等效果,值在 0(无阻尼)到 1(完全阻尼)之间。angularDamping: 角阻尼,控制刚体旋转的衰减效果。
设置属性如 material 和 linearDamping 十分重要。例如,material 可以结合 CANNON.ContactMaterial 来定义碰撞时的摩擦力和弹性,从而提高模拟的真实感;而 linearDamping 则可以防止物体因惯性不断移动。
创建一个球形刚体,设置其材质、线性阻尼等属性,并添加到物理世界。
// 创建球体形状
const sphereShape = new CANNON.Sphere(1); // 半径为 1
// 定义刚体属性
const sphereMaterial = new CANNON.Material("sphereMaterial");
const sphereBody = new CANNON.Body({
mass: 1, // 质量为 1 kg
shape: sphereShape,
material: sphereMaterial, // 设置材质
linearDamping: 0.2, // 设置线性阻尼
});
// 设置初始位置
sphereBody.position.set(0, 10, 0);
// 将刚体添加到物理世界
world.addBody(sphereBody);
3. 为地板添加物理碰撞属性
虽然我们在 Three.js 场景里画了一个 plane 当地板,但如果不在 Cannon.js 里再加一个对应的平面刚体,它在物理世界中就不存在,球体会无限坠落。
以下代码创建了一个质量为 0 的平面刚体,并设置它的位置和朝向。质量为 0 代表这个物体不会被重力影响,它是一个“静止不动”的碰撞体,用来接住球体。
mass: 0:物体不会受到重力影响,也就是一个静止的碰撞体。CANNON.Plane():一个无限延伸的平面碰撞形状。quaternion.setFromAxisAngle(轴, 角度):用于旋转刚体,和 Three.js 中的rotateX()功能相似,只是这里用四元数来描述旋转。
// 创建一个平面形状
const groundShape = new CANNON.Plane();
const groundBody = new CANNON.Body({
mass: 0, // 质量为 0 的物体不会移动
});
// 将平面形状添加到刚体,并设置方向
groundBody.addShape(groundShape);
// 让平面朝上,所以绕 x 轴旋转 -90°
groundBody.quaternion.

3879

被折叠的 条评论
为什么被折叠?



