Skip to content

152. cannon 物理引擎:弹簧效果(二)

Published:

上节画了弹簧:

2025-11-29 20.28.10.gif

这节加上物理效果。

我们先创建 cannon 物理世界:

image.png

import * as CANNON from 'cannon-es';

const world = new CANNON.World();
world.gravity.set(0, -9.82, 0);

设置重力。

image.png

const body = new CANNON.Body({ mass: 0 });
body.addShape(new CANNON.Plane());
body.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2);
world.addBody(body);

地面的刚体,质量为 0,也就是固定不动。

然后加一下球在物理世界的刚体:

image.png

const ballBody = new CANNON.Body({ mass: 1, position: new CANNON.Vec3(2, 4, 0) });
ballBody.addShape(new CANNON.Sphere(radius));
world.addBody(ballBody);

还有固定点的:

image.png

const anchorBody = new CANNON.Body({ mass: 0, position: new CANNON.Vec3(0, 6, 0) });
world.addBody(anchorBody);

先不加弹簧,加一下物理世界和 Three.js 场景的同步:

image.png

function animate() {
    requestAnimationFrame(animate);

    world.fixedStep();
    ballMesh.position.copy(ballBody.position);
    ballMesh.quaternion.copy(ballBody.quaternion);
}
animate();

2025-11-29 20.59.21.gif

很明显,球会在重力的作用下掉到地面。

固定点因为质量是 0 ,所以不动。

加一下视觉上的弹簧效果:

image.png

updateSpringVisualization();

image.png

因为每一帧都会基于起点和终点重新生成管道,所以可以实现弹簧的拉伸:

2025-11-29 21.03.27.gif

但这只是视觉上的,并没有对应的物理效果。

我们加一下弹簧效果:

image.png

const spring = new CANNON.Spring(anchorBody, ballBody, {
    localAnchorA: new CANNON.Vec3(0, 0, 0),
    localAnchorB: new CANNON.Vec3(0, 0, 0),
    restLength: 2.5, // 自然长度
    stiffness: 40,   // 刚度
    damping: 1.5     // 阻尼
});

world.addEventListener('postStep', () => {
    spring.applyForce();
});

弹簧连接 anchorBody、ballBody 两个刚体。

localAnchorA、localAnchorB 是连接点在物体上的局部位置。

restLength 是自然状态下的弹簧长度,也就是不受力的时候。

stiffness 是弹簧刚度(弹性系数),值越大,弹簧越硬,恢复越快;值越小,弹簧越软

damping 是阻尼系数,用于减少振荡,值越大,振动衰减越快,但过大可能使运动过于迟缓

postStep 顾名思义就是完成每一步的物理计算后,应用这个弹簧的力。

看下效果:

2025-11-29 21.10.15.gif

这样就是一个弹簧的物理效果了。

当然,我们这样不明显。

加一个向下的力拉扯下:

image.png

window.addEventListener('click', () => {
    const force = new CANNON.Vec3(0, -30, 0);
    ballBody.applyImpulse(force, ballBody.position);
});

点击屏幕的时候,加一个向下的力。

2025-11-29 21.14.31.gif

可以看到,确实是弹簧的物理效果。

案例代码上传了小册仓库

总结

这节我们加上了 cannon 物理效果。

其余的刚体都比较常见,主要是这里用到了 Spring,它需要指定弹簧的长度、弹簧硬度、阻尼系数等。

这样吧两个物理连接起来后,拉动下面的物体,就会给弹簧一个拉扯的物理效果。

后面实现的很多 3D 场景里都会用到这种物理效果。

评论