mirror of
https://github.com/tengge1/ShadowEditor.git
synced 2026-01-25 15:08:11 +00:00
171 lines
5.4 KiB
JavaScript
171 lines
5.4 KiB
JavaScript
/**
|
|
* 物理
|
|
* @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; |