/** * 物理 * @author tengge / https://github.com/tengge1 * @param {*} options */ function Physics(options) { this.app = options.app; this.app.physics = this; // 各种参数 var gravityConstant = -9.8; this.margin = 0.05; this.transformAux1 = new Ammo.btTransform(); this.time = 0; this.armMovement = 0; // 物理环境配置 this.collisionConfiguration = new Ammo.btSoftBodyRigidBodyCollisionConfiguration(); // 软体刚体碰撞配置 this.dispatcher = new Ammo.btCollisionDispatcher(this.collisionConfiguration); // 碰撞调度器 this.broadphase = new Ammo.btDbvtBroadphase(); // dbvt粗测 this.solver = new Ammo.btSequentialImpulseConstraintSolver(); // 顺序脉冲约束求解器 this.softBodySolver = new Ammo.btDefaultSoftBodySolver(); // 默认软体求解器 this.world = new Ammo.btSoftRigidDynamicsWorld(this.dispatcher, this.broadphase, this.solver, this.collisionConfiguration, this.softBodySolver); var gravity = new Ammo.btVector3(0, gravityConstant, 0); this.world.setGravity(gravity); this.world.getWorldInfo().set_m_gravity(gravity); this.rigidBodies = []; // 扔球 this.enableThrowBall = false; } Physics.prototype.start = function () { this.app.on(`animate.Physics`, this.update.bind(this)); this.app.on(`mThrowBall.Physics`, this.onEnableThrowBall.bind(this)); }; /** * 创建刚体 * @param {*} threeObject three.js中Object3D对象 * @param {*} physicsShape 物理形状 * @param {*} mass 重力 * @param {*} pos 位置 * @param {*} quat 旋转 */ Physics.prototype.createRigidBody = function (threeObject, physicsShape, mass, pos, quat) { threeObject.position.copy(pos); threeObject.quaternion.copy(quat); var transform = new Ammo.btTransform(); transform.setIdentity(); transform.setOrigin(new Ammo.btVector3(pos.x, pos.y, pos.z)); transform.setRotation(new Ammo.btQuaternion(quat.x, quat.y, quat.z, quat.w)); var motionState = new Ammo.btDefaultMotionState(transform); // 惯性 var localInertia = new Ammo.btVector3(0, 0, 0); physicsShape.calculateLocalInertia(mass, localInertia); var rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, physicsShape, localInertia); var body = new Ammo.btRigidBody(rbInfo); threeObject.userData.physicsBody = body; // 重力大于0才响应物理事件 if (mass > 0) { this.rigidBodies.push(threeObject); body.setActivationState(4); } this.world.addRigidBody(body); return body; }; /** * 创建一个平板 * @param {*} sx 长度 * @param {*} sy 厚度 * @param {*} sz 宽度 * @param {*} mass 重力 * @param {*} pos 位置 * @param {*} quat 旋转 * @param {*} material 材质 */ Physics.prototype.createParalellepiped = function (sx, sy, sz, mass, pos, quat, material) { var threeObject = new THREE.Mesh(new THREE.BoxBufferGeometry(sx, sy, sz, 1, 1, 1), material); var shape = new Ammo.btBoxShape(new Ammo.btVector3(sx * 0.5, sy * 0.5, sz * 0.5)); shape.setMargin(this.margin); this.createRigidBody(threeObject, shape, mass, pos, quat); return threeObject; }; Physics.prototype.onThrowBall = function (event) { var mouse = new THREE.Vector2(); var raycaster = new THREE.Raycaster(); var camera = this.app.editor.camera; var width = UI.get('viewport').dom.clientWidth; var height = UI.get('viewport').dom.clientHeight; mouse.set((event.offsetX / width) * 2 - 1, -(event.offsetY / height) * 2 + 1); raycaster.setFromCamera(mouse, camera); // Creates a ball and throws it var ballMass = 35; var ballRadius = 0.4; var ballMaterial = new THREE.MeshPhongMaterial({ color: 0x202020 }); var ball = new THREE.Mesh(new THREE.SphereBufferGeometry(ballRadius, 14, 10), ballMaterial); ball.castShadow = true; ball.receiveShadow = true; this.app.editor.scene.add(ball); var ballShape = new Ammo.btSphereShape(ballRadius); ballShape.setMargin(this.margin); var pos = new THREE.Vector3(); pos.copy(raycaster.ray.direction); pos.add(raycaster.ray.origin); var quat = new THREE.Quaternion(); quat.set(0, 0, 0, 1); var ballBody = this.createRigidBody(ball, ballShape, ballMass, pos, quat); pos.copy(raycaster.ray.direction); pos.multiplyScalar(24); ballBody.setLinearVelocity(new Ammo.btVector3(pos.x, pos.y, pos.z)); }; Physics.prototype.update = function (clock, deltaTime) { this.world.stepSimulation(deltaTime, 10); // Update rigid bodies for (var i = 0, il = this.rigidBodies.length; i < il; i++) { var objThree = this.rigidBodies[i]; var objPhys = objThree.userData.physicsBody; var ms = objPhys.getMotionState(); if (ms) { ms.getWorldTransform(this.transformAux1); var p = this.transformAux1.getOrigin(); var q = this.transformAux1.getRotation(); objThree.position.set(p.x(), p.y(), p.z()); objThree.quaternion.set(q.x(), q.y(), q.z(), q.w()); } } }; Physics.prototype.onEnableThrowBall = function () { if (this.enableThrowBall) { this.enableThrowBall = false; UI.get('mThrowBall').dom.innerHTML = '开启探测小球'; this.app.on(`click.Physics`, null); } else { this.enableThrowBall = true; UI.get('mThrowBall').dom.innerHTML = '关闭探测小球'; this.app.on(`click.Physics`, this.onThrowBall.bind(this)); } }; export default Physics;