入门
cannon-es 是一个web端轻量化并且很简单的3D物理引擎。
它的灵感来源于three.js的简单API,并基于ammon.js和Bullet物理引擎。
首先要建立的是我们的物理世界,它将容纳我们所有的物理体,并推动模拟向前发展。
让我们用地球引力创造一个世界。请注意,canon.js使用国际单位制(米、千克、秒等)。
const world = new CANNON.World({
gravity: new CANNON.Vec3(0, -9.82, 0), // m/s²
})
为了推进模拟,我们必须在每帧调用world.fixedStep()。作为第一个参数,我们可以通过我们希望模拟运行的固定时间步长,默认值为1/60,即60fps。world.fixedStep()会跟踪上次调用它的时间,以使模拟保持相同的速度,而与帧速率无关,因为requestAnimationFrame调用在不同的设备上可能会有所不同,或者存在性能问题。
function animate() {
requestAnimationFrame(animate)
// Run the simulation independently of framerate every 1 / 60 ms
world.fixedStep()
}
// Start the simulation loop
animate()
如果你想手动设置每帧间隔(就是游戏世界中的 dt),你可以使用更高级的world.step()。
下面是例子:
const timeStep = 1 / 60 // seconds
let lastCallTime
function animate() {
requestAnimationFrame(animate)
const time = performance.now() / 1000 // seconds
if (!lastCallTime) {
world.step(timeStep)
} else {
const dt = time - lastCallTime
world.step(timeStep, dt)
}
lastCallTime = time
}
// Start the simulation loop
animate()
物体是将在世界上模拟的实体,它们可以是简单的形状,如球体、长方体、平面、圆柱体,也可以是更复杂的形状,例如凸多面体、粒子、Heightfield、Trimesh。
让我们创建一个基本的球体。
const radius = 1 // m
const sphereBody = new CANNON.Body({
mass: 5, // kg
shape: new CANNON.Sphere(radius),
})
sphereBody.position.set(0, 10, 0) // m
world.addBody(sphereBody)
正如你所看到的,我们指定了一个质量特性,质量定义了物体受力影响时的行为。
当物体有质量并受到力的影响时,它们被称为动力学物体。还有一些运动学物体不受力的影响,但可以有一定的速度并四处移动。第三类物体是静态物体,它只能定位在世界上,不受力和速度的影响。
如果将质量0传递给实体,则该实体将自动标记为静态实体。也可以在实体选项中显式显示实体类型。例如,让我们创建一个静态地面。
const groundBody = new CANNON.Body({
type: CANNON.Body.STATIC,
shape: new CANNON.Plane(),
})
groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0) // make it face up
world.addBody(groundBody)
以下是前面的所有片段,它们组合在一个完整的示例中。
import * as CANNON from 'cannon-es'
// Setup our physics world
const world = new CANNON.World({
gravity: new CANNON.Vec3(0, -9.82, 0), // m/s²
})
// Create a sphere body
const radius = 1 // m
const sphereBody = new CANNON.Body({
mass: 5, // kg
shape: new CANNON.Sphere(radius),
})
sphereBody.position.set(0, 10, 0) // m
world.addBody(sphereBody)
// Create a static plane for the ground
const groundBody = new CANNON.Body({
type: CANNON.Body.STATIC, // can also be achieved by setting the mass to 0
shape: new CANNON.Plane(),
})
groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0) // make it face up
world.addBody(groundBody)
// Start the simulation loop
function animate() {
requestAnimationFrame(animate)
world.fixedStep()
// the sphere y position shows the sphere falling
console.log(`Sphere y position: ${sphereBody.position.y}`)
}
animate()
请注意,cannon并不负责将任何东西渲染到屏幕上,它只计算模拟的数学运算。要真正在屏幕上显示内容,您必须使用诸如three.js之类的渲染库。让我们看看如何实现这一点。
首先,你必须在three.js中创建身体的对应实体。例如,下面是如何在three.js中创建球体的。
const radius = 1 // m
const geometry = new THREE.SphereGeometry(radius)
const material = new THREE.MeshNormalMaterial()
const sphereMesh = new THREE.Mesh(geometry, material)
scene.add(sphereMesh)
然后,您必须将three.js网格与cannon.js主体连接起来。要做到这一点,请在步进世界后的每一帧将位置和旋转数据从实体复制到网格。
function animate() {
requestAnimationFrame(animate)
// world stepping...
sphereMesh.position.copy(sphereBody.position)
sphereMesh.quaternion.copy(sphereBody.quaternion)
// three.js render...
}
animate()
你现在应该在屏幕上看到一个落下的球了!查看基本的three.js示例以获取完整的代码。