three.js 之cannon.js物理引擎
今天郭先生說(shuō)的是一個(gè)物理引擎,它十分小巧并且操作簡(jiǎn)單,沒(méi)錯(cuò)他就是cannon.js。這些優(yōu)點(diǎn)都源自于他是基于js編寫(xiě)的,對(duì)于js使用者來(lái)說(shuō)cannon.js擁有其他物理引擎沒(méi)有的純粹性。從學(xué)習(xí)成本來(lái)看,cannon.js的學(xué)習(xí)成本比較低,對(duì)于新手來(lái)說(shuō)比較友好,因?yàn)樗邢鄬?duì)完善的api,學(xué)習(xí)cannon.js之前我們不妨來(lái)看看cannon.js的官方網(wǎng)站以及他的API,對(duì)于js學(xué)習(xí)者來(lái)說(shuō)這是十分必要的。官網(wǎng)上面有一些example,他們十分典型并囊括了大多數(shù)的知識(shí)點(diǎn),配合api一起學(xué)習(xí)是個(gè)不錯(cuò)的選擇。在線案例請(qǐng)點(diǎn)擊博客原文。效果如下圖,接下來(lái)以一個(gè)小案例,簡(jiǎn)單的介紹一下cannon.js。
1. 初始化three場(chǎng)景
創(chuàng)建three場(chǎng)景(或者說(shuō)three世界)來(lái)作為物理世界的載體,這一步很簡(jiǎn)單,主要就是添加渲染器、場(chǎng)景、相機(jī)和網(wǎng)格等three元素,沒(méi)必要多說(shuō)。
scene = new THREE.Scene();//step 1 創(chuàng)建場(chǎng)景
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.y = 30;
camera.position.z = 20;
camera.lookAt(0,5,0);
scene.add( camera ); //step 2 場(chǎng)景中添加相機(jī)
scene.add(new THREE.AmbientLight(0x888888));
const light = new THREE.DirectionalLight(0xbbbbbb, 1);
light.position.set(6, 30, 6);
scene.add(light); //step 3 場(chǎng)景中添加另種光源
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.shadowMap.enabled = true;
renderer.setClearColor(0xbfd1e5);
this.$refs.box.appendChild(renderer.domElement); //step 4 dom中添加渲染器
let groundGeom = new THREE.BoxBufferGeometry(40, 0.2, 40);
let groundMate = new THREE.MeshPhongMaterial({color: 0xdddddd, map: texture})
ground = new THREE.Mesh(groundGeom, groundMate);
ground.position.y = -0.1;
ground.receiveShadow = true;
scene.add(ground); //step 5 添加地面網(wǎng)格
2. 初始化物理世界
這里是初始化物理世界,我們?cè)敿?xì)的講一下他們的用法。
initCannon() {
world = new CANNON.World(); //該方法初始化物理世界,里面包含著物理世界的相關(guān)數(shù)據(jù)(如剛體數(shù)據(jù),世界中所受外力等等)
world.gravity.set(0,-9.8,0); //設(shè)置物理世界的重力為沿y軸向上-9.8米每二次方秒
world.broadphase = new CANNON.NaiveBroadphase();//NaiveBroadphase是默認(rèn)的碰撞檢測(cè)方式,該碰撞檢測(cè)速度比較高
world.solver.iterations = 5;//解算器的迭代次數(shù),更高的迭代次數(shù)意味著更加精確同時(shí)性能將會(huì)降低
bodyGround = new CANNON.Body({ //創(chuàng)建一個(gè)剛體(物理世界的剛體數(shù)據(jù))
mass: 0, //剛體的質(zhì)量,這里單位為kg
position: new CANNON.Vec3(0, -0.1, 0), //剛體的位置,單位是米
shape: new CANNON.Box(new CANNON.Vec3(20, 0.1, 20)), //剛體的形狀(這里是立方體,立方體的參數(shù)是一個(gè)包含半長(zhǎng)、半寬、半高的三維向量,具體我們以后會(huì)說(shuō))
material: new CANNON.Material({friction: 0.05, restitution: 0}) //材質(zhì)數(shù)據(jù),里面規(guī)定了摩擦系數(shù)和彈性系數(shù)
});
ground.userData = bodyGround; //將剛體的數(shù)據(jù)賦值給地面網(wǎng)格的userData屬性
world.addBody(bodyGround); //物理世界添加地面剛體
},
3. 向場(chǎng)景中添加網(wǎng)格并向物理世界中添加剛體數(shù)據(jù)
這里我們通過(guò)setInterval函數(shù)我們定時(shí)向場(chǎng)景中添加網(wǎng)格并向物理世界中添加剛體數(shù)據(jù),
interval = setInterval(() => {
this.createBox(); //創(chuàng)建網(wǎng)格和剛體的方法
}, 200);
下面是具體的方法
createBox() {
let x = Math.random() * 10 - 5;
let z = Math.random() * 10 - 5;
let box = new THREE.Mesh( geometry, this.createRandomMaterial() ); //createRandomMaterial創(chuàng)建隨機(jī)顏色的材質(zhì)
box.position.set(x, 20, z);
scene.add( box ); //創(chuàng)建box,并添加到場(chǎng)景
let bodyBox = new CANNON.Body({
mass: 1,
position: new CANNON.Vec3(x, 20, z),
shape: new CANNON.Box(new CANNON.Vec3(1,1,1)),
material: new CANNON.Material({friction: 0.1, restitution: 0})
});//創(chuàng)建一個(gè)質(zhì)量為1kg,位置為(x,20,z),形狀為halfSize為1,1,1的正方形剛體,材質(zhì)中摩擦系數(shù)為0.1,彈性系數(shù)為0。
box.userData = bodyBox;//給box的userData屬性添加剛體數(shù)據(jù)
world.addBody(bodyBox);//在物理世界中添加該剛體
setTimeout(() => { //10秒鐘之后在場(chǎng)景中移除box,并在物理世界中移除該剛體
scene.remove(box);
box.material.dispose();
box.geometry.dispose();
world.removeBody(bodyBox);
}, 10000)
},
4. 根據(jù)物理引擎的數(shù)據(jù)更新three網(wǎng)格數(shù)據(jù)
這一步我們逐幀根據(jù)物理引擎的數(shù)據(jù)渲染three場(chǎng)景
animation() { //requestAnimationFrame動(dòng)畫(huà)中調(diào)用render方法
this.globalID = requestAnimationFrame(this.animation);
this.render();
},
render() { //更新性能插件,根據(jù)物理引擎數(shù)據(jù)更新網(wǎng)格數(shù)據(jù),最后渲染場(chǎng)景
stats.update();
this.updatePhysics();
renderer.render( scene, camera );
},
updatePhysics() { // world.step
world.step(timeStep); //第一個(gè)參數(shù)是以固定步長(zhǎng)更新物理世界參數(shù)(詳情請(qǐng)看api)
scene.children.forEach(d => {//遍歷場(chǎng)景中的子對(duì)象,如果對(duì)象的isMesh屬性為true,我們就將更新改對(duì)象的position和quaternion屬性(他們對(duì)應(yīng)的剛體數(shù)據(jù)存在對(duì)應(yīng)的userData中)。
if(d.isMesh == true) {
d.position.copy(d.userData.position);
d.quaternion.copy(d.userData.quaternion);
}
})
}
這樣我們就將cannon.js物理引擎應(yīng)用到了three中。不出意外的話,接下來(lái)我會(huì)講解一下官方的examples。
轉(zhuǎn)載請(qǐng)注明地址:郭先生的博客
總結(jié)
以上是生活随笔為你收集整理的three.js 之cannon.js物理引擎的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Flutter中Expanded组件用法
- 下一篇: fmj耳机是什么牌子