UNPKG

@c-frame/aframe-physics-system

Version:

Physics system for A-Frame VR, built on Cannon.js & Ammo.js

174 lines (149 loc) 6.32 kB
/* global Ammo */ const CONSTRAINT = require("../constants").CONSTRAINT; module.exports = AFRAME.registerComponent("ammo-constraint", { multiple: true, schema: { // Type of constraint. type: { default: CONSTRAINT.LOCK, oneOf: [ CONSTRAINT.LOCK, CONSTRAINT.FIXED, CONSTRAINT.SPRING, CONSTRAINT.SLIDER, CONSTRAINT.HINGE, CONSTRAINT.CONE_TWIST, CONSTRAINT.POINT_TO_POINT ] }, // Target (other) body for the constraint. target: { type: "selector" }, // Offset of the hinge or point-to-point constraint, defined locally in the body. Used for hinge, coneTwist pointToPoint constraints. pivot: { type: "vec3" }, targetPivot: { type: "vec3" }, // An axis that each body can rotate around, defined locally to that body. Used for hinge constraints. axis: { type: "vec3", default: { x: 0, y: 0, z: 1 } }, targetAxis: { type: "vec3", default: { x: 0, y: 0, z: 1 } }, // damping & stuffness - used for spring contraints only damping: { type: "number", default: 1 }, stiffness: { type: "number", default: 100 }, }, init: function() { this.system = this.el.sceneEl.systems.physics; this.constraint = null; }, remove: function() { if (!this.constraint) return; this.system.removeConstraint(this.constraint); this.constraint = null; }, update: function() { const el = this.el, data = this.data; this.remove(); if (!el.body || !data.target.body) { (el.body ? data.target : el).addEventListener("body-loaded", this.update.bind(this, {}), { once: true }); return; } this.constraint = this.createConstraint(); this.system.addConstraint(this.constraint); }, /** * @return {Ammo.btTypedConstraint} */ createConstraint: function() { let constraint; const data = this.data, body = this.el.body, targetBody = data.target.body; const bodyTransform = body .getCenterOfMassTransform() .inverse() .op_mul(targetBody.getWorldTransform()); const targetTransform = new Ammo.btTransform(); targetTransform.setIdentity(); switch (data.type) { case CONSTRAINT.LOCK: { constraint = new Ammo.btGeneric6DofConstraint(body, targetBody, bodyTransform, targetTransform, true); const zero = new Ammo.btVector3(0, 0, 0); //TODO: allow these to be configurable constraint.setLinearLowerLimit(zero); constraint.setLinearUpperLimit(zero); constraint.setAngularLowerLimit(zero); constraint.setAngularUpperLimit(zero); Ammo.destroy(zero); break; } //TODO: test and verify all other constraint types case CONSTRAINT.FIXED: { //btFixedConstraint does not seem to debug render bodyTransform.setRotation(body.getWorldTransform().getRotation()); targetTransform.setRotation(targetBody.getWorldTransform().getRotation()); constraint = new Ammo.btFixedConstraint(body, targetBody, bodyTransform, targetTransform); break; } case CONSTRAINT.SPRING: { constraint = new Ammo.btGeneric6DofSpringConstraint(body, targetBody, bodyTransform, targetTransform, true); // Very limited initial implementation of spring constraint. // See: https://github.com/n5ro/aframe-physics-system/issues/171 for (var i in [0,1,2,3,4,5]) { constraint.enableSpring(1, true) constraint.setStiffness(1, this.data.stiffness) constraint.setDamping(1, this.data.damping) } const upper = new Ammo.btVector3(-1, -1, -1); const lower = new Ammo.btVector3(1, 1, 1); constraint.setLinearUpperLimit(upper); constraint.setLinearLowerLimit(lower) Ammo.destroy(upper); Ammo.destroy(lower); break; } case CONSTRAINT.SLIDER: { //TODO: support setting linear and angular limits constraint = new Ammo.btSliderConstraint(body, targetBody, bodyTransform, targetTransform, true); constraint.setLowerLinLimit(-1); constraint.setUpperLinLimit(1); // constraint.setLowerAngLimit(); // constraint.setUpperAngLimit(); break; } case CONSTRAINT.HINGE: { const pivot = new Ammo.btVector3(data.pivot.x, data.pivot.y, data.pivot.z); const targetPivot = new Ammo.btVector3(data.targetPivot.x, data.targetPivot.y, data.targetPivot.z); const axis = new Ammo.btVector3(data.axis.x, data.axis.y, data.axis.z); const targetAxis = new Ammo.btVector3(data.targetAxis.x, data.targetAxis.y, data.targetAxis.z); constraint = new Ammo.btHingeConstraint(body, targetBody, pivot, targetPivot, axis, targetAxis, true); Ammo.destroy(pivot); Ammo.destroy(targetPivot); Ammo.destroy(axis); Ammo.destroy(targetAxis); break; } case CONSTRAINT.CONE_TWIST: { const pivotTransform = new Ammo.btTransform(); pivotTransform.setIdentity(); pivotTransform.getOrigin().setValue(data.pivot.x, data.pivot.y, data.pivot.z); const targetPivotTransform = new Ammo.btTransform(); targetPivotTransform.setIdentity(); targetPivotTransform.getOrigin().setValue(data.targetPivot.x, data.targetPivot.y, data.targetPivot.z); constraint = new Ammo.btConeTwistConstraint(body, targetBody, pivotTransform, targetPivotTransform); Ammo.destroy(pivotTransform); Ammo.destroy(targetPivotTransform); break; } case CONSTRAINT.POINT_TO_POINT: { const pivot = new Ammo.btVector3(data.pivot.x, data.pivot.y, data.pivot.z); const targetPivot = new Ammo.btVector3(data.targetPivot.x, data.targetPivot.y, data.targetPivot.z); constraint = new Ammo.btPoint2PointConstraint(body, targetBody, pivot, targetPivot); Ammo.destroy(pivot); Ammo.destroy(targetPivot); break; } default: throw new Error("[constraint] Unexpected type: " + data.type); } Ammo.destroy(targetTransform); return constraint; } });