UNPKG

threefiz

Version:

Implementation of a physics engine based on the [Three.js](https://github.com/mrdoob/three.js) library.

208 lines (182 loc) 5.97 kB
import { Matrix3, Vector3 } from "three"; import RigidBody from "./RigidBody"; const v1 = new Vector3(); const v2 = new Vector3(); const v3 = new Vector3(); const r1 = new Vector3(); const r2 = new Vector3(); const t1 = new Vector3(); const t2 = new Vector3(); const relativeVelocity = new Vector3(); const Point = new Vector3(); const Normal = new Vector3(); const Tangent = new Vector3(); class ObjectData { parent: RigidBody; linearVelocity: Vector3; angularVelocity: Vector3; invertedMass: number; invertedInerttia: Matrix3; massCenter: Vector3; collisionArm: Vector3; constructor() { this.parent = null!; this.linearVelocity = new Vector3(); this.angularVelocity = new Vector3(); this.invertedMass = 0; this.invertedInerttia = new Matrix3(); this.massCenter = new Vector3(); this.collisionArm = new Vector3(); } set(object: RigidBody) { this.parent = object; object.getPosition(this.massCenter); object.getInvertedInertia(this.invertedInerttia); this.invertedMass = this.getInvertMass(object); this.update(); } update() { this.parent.getVelocity(this.linearVelocity); this.parent.getAngularVelocity(this.angularVelocity); this.collisionArm.set(0, 0, 0); if (!this.parent.isStatic) this.getCollisionArm(Point, this.collisionArm); } getInvertMass(obj: RigidBody) { return obj.isStatic ? 0 : 1 / obj.mass; } getCollisionArm(point: Vector3, target: Vector3) { return target.copy(point).sub(this.massCenter); } } const thisObject = new ObjectData(); const otherObject = new ObjectData(); const update = ( obj_A: RigidBody, obj_B: RigidBody, point: Vector3, normal: Vector3 ) => { Point.copy(point); Normal.copy(normal); thisObject.set(obj_A); otherObject.set(obj_B); }; const getVelocityAtPoint = (object: ObjectData, target: Vector3) => { const omega = object.angularVelocity; const r = object.collisionArm; const linear = object.linearVelocity; return target.copy(linear).add(v3.crossVectors(omega, r)); }; const setRelativeVelocity = () => { getVelocityAtPoint(thisObject, v1); getVelocityAtPoint(otherObject, v2); relativeVelocity.copy(v1).sub(v2); }; //-----------------normal impulse equation-------------- const getRotationalImpulse = (obj: ObjectData, target: Vector3) => { if (obj.parent.isStatic) { target.set(0, 0, 0); return target; } const r = obj.collisionArm; const invertInertia = obj.invertedInerttia; return target.crossVectors(r, Normal).applyMatrix3(invertInertia).cross(r); }; const getImpulse_Numerator = () => -(1 + (thisObject.parent.restitution + otherObject.parent.restitution) / 2) * relativeVelocity.dot(Normal); const getImpulse_Denominator = () => { getRotationalImpulse(thisObject, r1); getRotationalImpulse(otherObject, r2); return ( thisObject.invertedMass + otherObject.invertedMass + Normal.dot(r1) + Normal.dot(r2) ); }; const getImpulse = () => { thisObject.update(); otherObject.update(); setRelativeVelocity(); return getImpulse_Numerator() / getImpulse_Denominator(); }; //-----------------tangent impulse equation-------------- const setTangent = () => { v3.copy(Normal).multiplyScalar(relativeVelocity.dot(Normal)); Tangent.copy(relativeVelocity).sub(v3); if (Tangent.lengthSq() > 1e-6) Tangent.normalize(); else Tangent.set(0, 0, 0); }; const getTangentialCollisionArm = (collisionArm: Vector3, target: Vector3) => target.copy(collisionArm).cross(Tangent); const getTangentialInertialComponent = ( tangentialArm: Vector3, invInertia: Matrix3 ) => { return tangentialArm.applyMatrix3(invInertia).dot(tangentialArm); }; const getFrictionImpulse_Denominator = () => { getTangentialCollisionArm(thisObject.collisionArm, t1); getTangentialCollisionArm(otherObject.collisionArm, t2); return ( thisObject.invertedMass + otherObject.invertedMass + getTangentialInertialComponent(t1, thisObject.invertedInerttia) + getTangentialInertialComponent(t2, otherObject.invertedInerttia) ); }; const getFrictionImpulse = () => { thisObject.update(); otherObject.update(); setRelativeVelocity(); setTangent(); return -relativeVelocity.dot(Tangent) / getFrictionImpulse_Denominator(); }; //-----------------impulse application-------------- const applyLinearVelocity = (obj: RigidBody, j: number) => { const object = obj === thisObject.parent ? thisObject : otherObject; const invertMass = object.invertedMass; v1.copy(Normal); object.parent.setVelocity((oldV) => oldV.add(v1.multiplyScalar(j * invertMass)) ); }; const applyAngularVelocity = (obj: RigidBody, j: number) => { const object = obj === thisObject.parent ? thisObject : otherObject; const invertInertia = object.invertedInerttia; const r = object.collisionArm; v1.copy(Normal); object.parent.setAngularVelocity((oldV) => oldV.add( v2.crossVectors(r, v1.multiplyScalar(j)).applyMatrix3(invertInertia) ) ); }; const applyFriction = ( obj: RigidBody, friction: number, jT: number, j: number ) => { const object = obj === thisObject.parent ? thisObject : otherObject; const impulseMagnitude = Math.min(Math.max(jT, -friction * j), friction * j); v1.copy(Tangent); v1.multiplyScalar(impulseMagnitude); const invertMass = object.invertedMass; const invertInertia = object.invertedInerttia; const r = object.collisionArm; v2.copy(v1); object.parent.setVelocity((oldV) => oldV.add(v1.multiplyScalar(invertMass))); object.parent.setAngularVelocity((oldV) => oldV.add(v3.crossVectors(r, v2).applyMatrix3(invertInertia)) ); }; export { update, getImpulse, getFrictionImpulse, applyLinearVelocity, applyAngularVelocity, applyFriction, };