如上图简单生成box,实现自由落体
// 安装cannon
npm i cannon
director.js内容,注:添加地面ground:mass为0;添加box:mass为1
import Template from "../common/Template"
import * as THREE from 'three'
import * as CANNON from 'cannon'
export default class Director extends Template{
constructor (ele) {
super()
this.ele = ele
this.PCamera.fov = 45
this.PCamera.far = 10000
this.PCamera.near = 1
this.rendererColor = new THREE.Color(0x01031c)
this.cameraPostion = new THREE.Vector3(300, 200, 0)
this.init(this.ele)
this.addLight()
this.addAxesHelper(1000)
if(this.camera && this.renderer) this.addOrbitControls(this.camera, this.renderer.domElement);
this.animate()
// 初始化物理世界
this.world = undefined
this.initCannon()
this.addGround()
this.interval = setInterval(() => {
this.addBoox()
}, 2000);
}
addBoox(){
let w = 10;let h = 10;let l = 10
let height = Math.random()*200
const geometry = new THREE.BoxBufferGeometry(l,w,h)
const material = new THREE.MeshLambertMaterial({
color:0xb99b75
})
let box = new THREE.Mesh(geometry, material)
box.position.set(0,height,0)
this.scene.add(box)
let bodyBox = new CANNON.Body({
mass: 1,
position: new CANNON.Vec3(0, height, 0),
shape: new CANNON.Box(new CANNON.Vec3(10,w/2,10)),
material: new CANNON.Material({friction: 0.1, restitution: 0})
});//创建一个质量为1kg,位置为(x,20,z),形状为halfSize为1,1,1的正方形刚体,材质中摩擦系数为0.1,弹性系数为0。
box.userData = bodyBox;//给box的userData属性添加刚体数据
this.world.addBody(bodyBox);//在物理世界中添加该刚体
setTimeout(() => { //10秒钟之后在场景中移除box,并在物理世界中移除该刚体
this.scene.remove(box);
box.material.dispose();
box.geometry.dispose();
this.world.removeBody(bodyBox);
}, 8000)
}
initCannon() {
this.world = new CANNON.World(); //该方法初始化物理世界,里面包含着物理世界的相关数据(如刚体数据,世界中所受外力等等)
this.world.gravity.set(0,-9.8,0); //设置物理世界的重力为沿y轴向上-9.8米每二次方秒
this.world.broadphase = new CANNON.NaiveBroadphase();//NaiveBroadphase是默认的碰撞检测方式,该碰撞检测速度比较高
this.world.solver.iterations = 5;//解算器的迭代次数,更高的迭代次数意味着更加精确同时性能将会降低
}
addGround(){
const groundGeometry = new THREE.BoxBufferGeometry(300,1,500)
const groundMaterial = new THREE.MeshLambertMaterial({
color:0x454942
})
let ground = new THREE.Mesh(groundGeometry, groundMaterial)
ground.rotation.y = -Math.PI/2
ground.name = '地'
this.scene.add(ground)
this.meshList.push(ground)
let body = new CANNON.Body({
mass:0,
position: new CANNON.Vec3(0, 0, 0),
shape: new CANNON.Box(new CANNON.Vec3(300,1,500)),
material: new CANNON.Material({friction: 0.05, restitution: 0})
});//创建一个质量为1kg,位置为(x,20,z),形状为halfSize为1,1,1的正方形刚体,材质中摩擦系数为0.1,弹性系数为0。
ground.userData = body;//给box的userData属性添加刚体数据
this.world.addBody(body);//在物理世界中添加该刚体
}
addLight(){
this.addAmbientLight(0x666666)
this.addDirectionalLight(0xdfebff,{x:50, y:200, z:100},1)
}
updatePhysics() { // world.step
this.world.step(0.1); //第一个参数是以固定步长更新物理世界参数(详情请看api)
this.scene.children.forEach(d => {//遍历场景中的子对象,如果对象的isMesh属性为true,我们就将更新改对象的position和quaternion属性(他们对应的刚体数据存在对应的userData中)。
if(d.isMesh == true) {
d.position.copy(d.userData.position);
d.quaternion.copy(d.userData.quaternion);
}
})
}
animate () {
// 执行运动动画
if(this.renderer && this.camera){
this.renderer.render(this.scene, this.camera)
requestAnimationFrame(this.animate.bind(this))
this.world?this.updatePhysics():null
}
}
}
其他template等文件见