刚体约束 Constraint
本节目标
学习如何使用 cannon-es 的约束(Constraint)系统,让多个刚体之间具有物理连接,如铰链、点对点连接等。
基础知识讲解
Cannon.js 中的约束用于在两个刚体之间建立某种规则限制,使它们表现出类似于物理连接(链条、铰链、弹簧等)的行为。
常见约束类型
| 约束类型 | 描述 |
|---|---|
PointToPointConstraint | 点对点连接(类似绳子连接两点) |
HingeConstraint | 铰链连接(门的转动效果) |
LockConstraint | 锁定两个刚体之间的所有自由度 |
DistanceConstraint | 固定两个点的距离(距离保持不变) |
示例:点对点约束连接两个小球
我们将创建两个小球,并使用 PointToPointConstraint 将它们连接在一起,实现“弹簧绳索”的效果。
示例代码(Vue3 + cannon-es)
vue复制编辑<!-- App.vue -->
<template>
<canvas ref="canvasRef"></canvas>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import * as THREE from 'three'
import * as CANNON from 'cannon-es'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
const canvasRef = ref()
onMounted(() => {
// 创建 Three.js 场景
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
camera.position.set(0, 5, 15)
const renderer = new THREE.WebGLRenderer({ canvas: canvasRef.value })
renderer.setSize(window.innerWidth, window.innerHeight)
const controls = new OrbitControls(camera, renderer.domElement)
controls.enableDamping = true
// 添加光源
const light = new THREE.DirectionalLight(0xffffff, 1)
light.position.set(5, 10, 5)
scene.add(light)
// 初始化物理世界
const world = new CANNON.World()
world.gravity.set(0, -9.82, 0)
// 创建地面
const groundBody = new CANNON.Body({
mass: 0,
shape: new CANNON.Plane()
})
groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0)
world.addBody(groundBody)
const ground = new THREE.Mesh(
new THREE.PlaneGeometry(20, 20),
new THREE.MeshStandardMaterial({ color: 0x999999, side: THREE.DoubleSide })
)
ground.rotation.x = -Math.PI / 2
scene.add(ground)
// 创建两个球体
const sphereGeo = new THREE.SphereGeometry(0.5, 32, 32)
const sphereMat = new THREE.MeshStandardMaterial({ color: 0x00aaff })
const createSphere = (x, y) => {
const mesh = new THREE.Mesh(sphereGeo, sphereMat)
mesh.position.set(x, y, 0)
scene.add(mesh)
const body = new CANNON.Body({
mass: 1,
shape: new CANNON.Sphere(0.5),
position: new CANNON.Vec3(x, y, 0)
})
world.addBody(body)
return { mesh, body }
}
const ballA = createSphere(-2, 5)
const ballB = createSphere(2, 5)
// 添加点对点约束(连接 ballA 和 ballB)
const constraint = new CANNON.PointToPointConstraint(
ballA.body, new CANNON.Vec3(0.5, 0, 0),
ballB.body, new CANNON.Vec3(-0.5, 0, 0)
)
world.addConstraint(constraint)
// 动画循环
const clock = new THREE.Clock()
function animate() {
requestAnimationFrame(animate)
const delta = clock.getDelta()
world.step(1 / 60, delta)
// 同步位置
[ballA, ballB].forEach(({ mesh, body }) => {
mesh.position.copy(body.position)
mesh.quaternion.copy(body.quaternion)
})
controls.update()
renderer.render(scene, camera)
}
animate()
})
</script>
重点解释
| 代码片段 | 解释 |
|---|---|
PointToPointConstraint | 将两个球体通过世界坐标系中的特定点连接起来,模拟绳索连接的效果。 |
new CANNON.Vec3(0.5, 0, 0) | 约束在 ballA 的局部空间的连接点 |
new CANNON.Vec3(-0.5, 0, 0) | 约束在 ballB 的局部空间的连接点 |
world.addConstraint(...) | 将该约束注册到物理世界中 |
你可以尝试的拓展
- 使用
DistanceConstraint来实现固定距离效果 - 将其中一个球体
mass: 0变为固定点 - 尝试加入多个球体,实现链条式连接(类似吊桥)
总结
- 刚体约束是 Cannon.js 中实现刚体间连接的重要方式
- 本节展示了点对点约束的用法
- 可以用来实现链条、吊桥、布料物理等效果