之前有做过关于Threejs基础功能的一些演示,这里引入一个新的组件Cannon,这是一个开源3D屋里引擎,可以用来开发和模拟真实世界的物理效果,包括碰撞,重力,约束等,
Cannon.js的特点如下:
- 轻量级和高性能:Cannon.js被设计为一个快速而轻便的物理引擎,代码简洁且易于理解。
- 真实的物理模拟:Cannon.js提供了一套完整的3D物理模拟功能,包括刚体碰撞、力学模拟和约束等。这使得开发者可以模拟真实世界中的物理效果。
- 灵活的约束系统:Cannon.js的约束系统非常灵活,并且支持各种类型的约束,如距离约束、弹簧约束、旋转约束等。开发者可以根据需要创建各种类型的约束。
- 基于WebGL:Cannon.js与WebGL技术结合使用,可以轻松实现在浏览器中展示3D物理效果,并且与其他WebGL应用程序进行集成。
- 跨平台兼容性:Cannon.js可以在多种浏览器上运行,并且支持移动设备和桌面设备。这使得开发者可以轻松地在各种平台上开发和运行物理模拟应用程序。
下面来制作一个通过cannon来制作的一个自由落体的效果,因为传统threejs,即使做成动画效果一般也只是匀速移动,很难做出下落时有重力加速度的效果,首先还是需要用threejs绘制一个场景,在场景中去添加cannon的一些属性和方法,主要流程如下,先创建一个物理世界,在物理世界中添加一个球体和一个底面,让球落到底面,但是因为cannon中不提供具体的模型显示,所以我们需要根据物理模型来构建实体模型,并同步物理模型中的球体位置到实体模型中的物体位置,相关代码如下:
initCarton(){
//新建一个物理模型世界
this.world = new CANNON.World();
// 设置物理世界重力加速度,此处设置为y轴的反方向,也就是往y轴反方向存在重力
this.world.gravity.set(0, -9.8, 0);
// 新建一个物理小球:对应threejs的网格小球
const sphereMaterial = new CANNON.Material()
this.box = new CANNON.Body({
mass: 1,//碰撞体质量
material: sphereMaterial,//设置小球的材质
shape:new CANNON.Sphere(3),//设置小球的半径大小
});
this.box.position.y = 100;//设置小球的位置
this.world.addBody(this.box);//将小球添加到物理世界中
// 新建物理地面
const groundMaterial = new CANNON.Material()
const groundBody = new CANNON.Body({
mass: 0, // 质量为0,始终保持静止,不会受到力碰撞或加速度影响
shape:new CANNON.Plane(),//新建物理模型的底面
material: groundMaterial,//地面材质
});
// 改变平面默认的方向,法线默认沿着z轴,旋转到平面向上朝着y方向
groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0);
this.world.addBody(groundBody);
// 设置地面材质和小球材质之间的碰撞反弹恢复系数,也就是底面和小球的材质之间存在的反弹系数,
const contactMaterial = new CANNON.ContactMaterial(groundMaterial, sphereMaterial, {
restitution: 0.5 //反弹恢复系数
})
// 把关联的材质添加到物理世界中
this.world.addContactMaterial(contactMaterial)
// 实体模型的网格小球,这里是用来对应显示物理模型下的球体位置
const geometry = new THREE.SphereGeometry(3);
const material = new THREE.MeshLambertMaterial({
color: 0x00ffff,
});
this.boxmesh = new THREE.Mesh(geometry, material);
this.scene.add(this.boxmesh)
//实体地面的网格模型,这里用来显示对应物理对应的地面
const planeGeometry = new THREE.PlaneGeometry(200, 200);
const planeMaterial = new THREE.MeshLambertMaterial({
color:0x777777,
});
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
planeMesh.rotateX(-Math.PI / 2);
this.scene.add(planeMesh)
},
initAnimate() {
requestAnimationFrame(this.initAnimate);
this.world.step(1/60);
// 渲染循环中,同步物理球body与网格球mesh的位置
this.boxmesh.position.copy(this.box.position);
this.renderer.render(this.scene, this.camera);
},
小球自由落体
效果如上视频,小球会在y轴上方100的高度,因为收到y轴负方向重力加速度的原因加速下落,在碰到地面后反弹,根据设置的材质反弹系数弹起一定的高度后,再次下落,循环此过程直到不再反弹。