👨??? 主頁: gis分享者
👨??? 感謝各位大佬 點贊👍 收藏? 留言📝 加關注?!
👨??? 收錄于專欄:threejs gis工程師
文章目錄
- 一、🍀前言
- 1.1 ??Physijs 物理引擎
- 1.1.1 ??代碼示例
- 1.1.2 ??方法/屬性
- 二、🍀使用Physijs物理引擎
- 1. ??實現思路
- 2. ??代碼樣例
一、🍀前言
本文詳細介紹如何基于threejs在三維場景中使用Physijs物理引擎,親測可用。希望能幫助到您。一起學習,加油!加油!
1.1 ??Physijs 物理引擎
Three.js 的 Physi.js 是一個基于 Physijs 的物理引擎插件,用于為 Three.js 場景添加物理模擬(如碰撞檢測、重力、剛體動力學等)。
1.1.1 ??代碼示例
// 初始化 Physi.js 場景
const scene = new Physijs.Scene();// 創建帶有物理效果的立方體
const box = new Physijs.BoxMesh(new THREE.BoxGeometry(1, 1, 1),new THREE.MeshBasicMaterial({ color: 0xff0000 })
);
scene.add(box);// 監聽碰撞事件
box.addEventListener('collision', (otherObject) => {console.log('發生碰撞!', otherObject);
});// 在動畫循環中更新物理
function animate() {requestAnimationFrame(animate);scene.simulate(); // 更新物理模擬renderer.render(scene, camera);
}
animate();
1.1.2 ??方法/屬性
Physijs.Scene
創建支持物理的 Three.js 場景。
mesh.setLinearVelocity()
設置物體的線性速度(移動速度)。
mesh.setAngularVelocity()
設置物體的角速度(旋轉速度)。
mesh.addEventListener()
監聽碰撞事件(如 ‘collision’)。
new Physijs.BoxMesh()
創建帶有長方體碰撞體的物體。
new Physijs.SphereMesh()
創建帶有球體碰撞體的物體。
scene.simulate()
在渲染循環中調用,更新物理模擬。
Physijs.createMaterial(material, friction, restitution)
創建物理材質,影響摩擦力和彈性。
參數:
material:Three.js 材質(如 THREE.MeshPhongMaterial)。
friction:摩擦系數(默認 0.8)。
restitution:彈性系數(默認 0)。
二、🍀使用Physijs物理引擎
1. ??實現思路
- 1、引入‘physi.js’,創建Physijs物理引擎三維場景scene,設置scene場景重力信息。
- 2、初始化camera相機,定義相機位置 camera.position.set,設置相機方向camera.lookAt,場景scene添加camera。
- 3、創建THREE.SpotLight聚光燈光源light,設置light位置,scene場景加入light。
- 4、加載幾何模型:使用‘floor-wood.jpg’木紋貼圖創建地面網格對象ground以及四周突出邊框網格對象borderLeft、borderRight、borderTop、borderBottom,ground添加borderLeft、borderRight、borderTop、borderBottom。定義controls方法,內部定義addCubes方法用于添加物理碰撞立方體,定義addSpheres方法用于添加物理碰撞球體,定義clearMeshes方法用于清除添加的碰撞對象,定義碰撞物體restitution彈性形變和friction摩擦系數。定義render方法,實現ground的旋轉動畫。具體代碼參考下面代碼樣例。
- 5、加入gui控制。加入stats監控器,監控幀數信息。
2. ??代碼樣例
<!DOCTYPE html>
<html>
<style>body {margin: 0;overflow: hidden;}
</style><head><title>學習threejs,使用Physijs物理引擎</title><script type="text/javascript" src="../libs/three.js"></script><script type="text/javascript" src="../libs/stats.js"></script><script type="text/javascript" src="../libs/physi.js"></script><script type="text/javascript" src="../libs/dat.gui.js"></script><script type="text/javascript" src="../libs/chroma.js"></script><script type="text/javascript">'use strict';//任務線程Physijs.scripts.worker = '../libs/physijs_worker.js';//內部庫ammo.jsPhysijs.scripts.ammo = '../libs/ammo.js';var scale = chroma.scale(['white', 'blue', 'red', 'yellow']);var initScene, render, applyForce, setMousePosition, mouse_position,ground_material, box_material,projector, renderer, render_stats, physics_stats, scene, ground, light, camera, box, boxes = [];initScene = function () {renderer = new THREE.WebGLRenderer({antialias: true});renderer.setSize(window.innerWidth, window.innerHeight);renderer.setClearColor(new THREE.Color(0x000000));document.getElementById('viewport').appendChild(renderer.domElement);render_stats = new Stats();render_stats.domElement.style.position = 'absolute';render_stats.domElement.style.top = '1px';render_stats.domElement.style.zIndex = 100;document.getElementById('viewport').appendChild(render_stats.domElement);scene = new Physijs.Scene;scene.setGravity(new THREE.Vector3(0, -90, 0));camera = new THREE.PerspectiveCamera(35,window.innerWidth / window.innerHeight,1,1000);camera.position.set(80, 60, 80);camera.lookAt(scene.position);scene.add(camera);// Lightlight = new THREE.SpotLight(0xFFFFFF);light.position.set(20, 100, 50);scene.add(light);// Materialsground_material = Physijs.createMaterial(new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture('../assets/textures/general/floor-wood.jpg')}),.9,.6);ground_material.map.wrapS = ground_material.map.wrapT = THREE.RepeatWrapping;ground_material.map.repeat.set(4, 8);// Groundground = new Physijs.BoxMesh(new THREE.BoxGeometry(60, 1, 130),ground_material,0);ground.receiveShadow = true;var borderLeft = new Physijs.BoxMesh(new THREE.BoxGeometry(2, 6, 130),ground_material,0);borderLeft.position.x = -31;borderLeft.position.y = 2;ground.add(borderLeft);var borderRight = new Physijs.BoxMesh(new THREE.BoxGeometry(2, 6, 130),ground_material,0);borderRight.position.x = 31;borderRight.position.y = 2;ground.add(borderRight);var borderBottom = new Physijs.BoxMesh(new THREE.BoxGeometry(64, 6, 2),ground_material,0);borderBottom.position.z = 65;borderBottom.position.y = 2;ground.add(borderBottom);var borderTop = new Physijs.BoxMesh(new THREE.BoxGeometry(64, 6, 2),ground_material,0);borderTop.position.z = -65;borderTop.position.y = 2;ground.add(borderTop)scene.add(ground);var meshes = [];var controls = new function () {//參數 restitution(彈性形變)和friction(摩擦系數)this.cubeRestitution = 0.4;this.cubeFriction = 0.4;this.sphereRestitution = 0.9;this.sphereFriction = 0.1;this.clearMeshes = function () {meshes.forEach(function (e) {scene.remove(e);});meshes = [];};this.addSpheres = function () {var colorSphere = scale(Math.random()).hex();for (var i = 0; i < 5; i++) {box = new Physijs.SphereMesh(new THREE.SphereGeometry(2, 20),Physijs.createMaterial(new THREE.MeshPhongMaterial({color: colorSphere,opacity: 0.8,transparent: truecontrols.sphereFriction,controls.sphereRestitution));box.position.set(Math.random() * 50 - 25,20 + Math.random() * 5,Math.random() * 50 - 25);meshes.push(box);scene.add(box);}};this.addCubes = function () {var colorBox = scale(Math.random()).hex();for (var i = 0; i < 5; i++) {box = new Physijs.BoxMesh(new THREE.BoxGeometry(4, 4, 4),Physijs.createMaterial(new THREE.MeshPhongMaterial({color: colorBox,opacity: 0.8,transparent: truecontrols.cubeFriction,controls.cubeRestitution));box.position.set(Math.random() * 50 - 25,20 + Math.random() * 5,Math.random() * 50 - 25);box.rotation.set(Math.random() * Math.PI * 2,Math.random() * Math.PI * 2,Math.random() * Math.PI * 2);meshes.push(box);scene.add(box);}}};var gui = new dat.GUI();gui.add(controls, 'cubeRestitution', 0, 1);gui.add(controls, 'cubeFriction', 0, 1);gui.add(controls, 'sphereRestitution', 0, 1);gui.add(controls, 'sphereFriction', 0, 1);gui.add(controls, 'addCubes');gui.add(controls, 'addSpheres');gui.add(controls, 'clearMeshes');requestAnimationFrame(render);scene.simulate();};var stepX;var direction = 1;render = function () {requestAnimationFrame(render);renderer.render(scene, camera);render_stats.update();ground.rotation.x += 0.002 * direction;if (ground.rotation.x < -0.4) direction = 1;if (ground.rotation.x > 0.4) direction = -1;ground.__dirtyRotation = true;scene.simulate(undefined, 1);};window.onload = initScene;</script>
</head><body>
<div id="viewport"></div>
</body></html>
效果如下: