@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
JavaScript
/* 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;
}
});