Skip to content

Instantly share code, notes, and snippets.

@flekschas
Created October 19, 2018 02:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save flekschas/4467a9ae8c0fd9f687ab76e91cb53da1 to your computer and use it in GitHub Desktop.
Save flekschas/4467a9ae8c0fd9f687ab76e91cb53da1 to your computer and use it in GitHub Desktop.
A small library for rigid body transformations for WebGL.
import { quat, vec3 } from 'gl-matrix';
import * as rbt from './rigid-body-transform.js';
const myFancyRbt = rbt.create();
// Rotate 45 degree around the x axis
const r = rbt.create({ r: quat.fromEuler(45, 0, 0) });
myFancyRbt.multiply(r);
// Translate
const t = rbt.create({ t: vec3.fromValues(1, 2, 3) });
myFancyRbt.multiply(t);
// Translate and rotate!1!! (I know, now we're going crazy!)
const rt = rbt.create({ t: vec3.fromValues(1, 2, 3), r: quat.fromEuler(1, 33, 7) });
// And store this crazy transformation as a new RBT
const myCrazyRbt = rbt.multiply(rbt.create(), myFancyRbt, rt);
import { mat4, quat, vec3, vec4 } from "gl-matrix";
const scratch0 = new Float32Array(4);
const scratch1 = new Float32Array(4);
const scratch2 = new Float32Array(4);
const quatMulVec3 = (q, v) => {
const newQ = quat.multiply(
quat.create(),
quat.multiply(scratch0, q, quat.fromValues(0, v[0], v[1], v[2])),
quat.invert(scratch1, q),
);
return vec3.fromValues(newQ[1], newQ[2], newQ[3]);
};
const quatMulVec4 = (q, v) => {
const newQ = quat.multiply(
quat.create(),
quat.multiply(scratch0, q, quat.fromValues(0, v[0], v[1], v[2])),
quat.invert(scratch1, q),
);
return vec4.fromValues(newQ[0], newQ[1], newQ[2], newQ[3]);
};
const multiplyWithVec4 = (out, a, b) => vec4.add(
quatMulVec4(a.r, b),
vec4.scale(scratch2, [...a.getTranslation, 0], b[3]),
);
const multiplyWithRigidBodyTransform = (out, a, b) => {
vec3.add(
out.t,
a.t,
quatMulVec3(a.r, b.t),
);
quat.multiply(out.r, a.r, b.r);
return out;
};
const multiply = (out, a, b, log = false) => {
if (!a.isRigidBodyTransform) {
console.warn('Param `a` needs to be a rigid body transformation.');
return null;
}
if (b.length && b.length === 4) return multiplyWithVec4(out, a, b, log);
if (b.isRigidBodyTransform) return multiplyWithRigidBodyTransform(out, a, b, log);
console.warn(
'Variable `b` is of unknown datatype. '
+ 'Only vec4 and rigid body transformations are supported.',
);
return null;
};
const invert = (out, tform) => {
const rInv = quat.invert(quat.create(), tform.r);
out.setTranslation(quatMulVec3(rInv, vec3.negate(scratch2, tform.t)));
out.setRotation(rInv);
return out;
};
const toMatrix = tform => mat4.fromRotationTranslation(
mat4.create(),
tform.r,
tform.t,
);
const create = ({
t = vec3.create(),
r = quat.create(),
} = {}) => {
// Used for identifying this data type;
const isRigidBodyTransform = true;
const getTranslation = () => t;
const getRotation = () => r;
const setTranslation = (newT) => { t = newT; };
const setRotation = (newR) => { r = newR; };
const invertThis = function () { invert(this, this); };
const multiplyThis = function (a) { multiply(this, this, a); };
const toMatrixThis = function () { return toMatrix(this); };
return {
isRigidBodyTransform,
get t() { return t; },
get translation() { return t; },
getTranslation,
get r() { return r; },
get rotation() { return r; },
getRotation,
set t(v) { return setTranslation(v); },
set translation(v) { return setTranslation(v); },
setTranslation,
set r(v) { return setRotation(v); },
set rotation(v) { return setRotation(v); },
setRotation,
invert: invertThis,
multiply: multiplyThis,
toMatrix: toMatrixThis,
};
};
export default create;
export {
create,
invert,
multiply,
toMatrix,
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment