Home | History | Annotate | Download | only in gl-matrix
      1 /* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
      2 
      3 Permission is hereby granted, free of charge, to any person obtaining a copy
      4 of this software and associated documentation files (the "Software"), to deal
      5 in the Software without restriction, including without limitation the rights
      6 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      7 copies of the Software, and to permit persons to whom the Software is
      8 furnished to do so, subject to the following conditions:
      9 
     10 The above copyright notice and this permission notice shall be included in
     11 all copies or substantial portions of the Software.
     12 
     13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     14 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     16 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     17 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     18 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     19 THE SOFTWARE. */
     20 
     21 var glMatrix = require("./common.js");
     22 var mat3 = require("./mat3.js");
     23 var vec3 = require("./vec3.js");
     24 var vec4 = require("./vec4.js");
     25 
     26 /**
     27  * @class Quaternion
     28  * @name quat
     29  */
     30 var quat = {};
     31 
     32 /**
     33  * Creates a new identity quat
     34  *
     35  * @returns {quat} a new quaternion
     36  */
     37 quat.create = function() {
     38     var out = new glMatrix.ARRAY_TYPE(4);
     39     out[0] = 0;
     40     out[1] = 0;
     41     out[2] = 0;
     42     out[3] = 1;
     43     return out;
     44 };
     45 
     46 /**
     47  * Sets a quaternion to represent the shortest rotation from one
     48  * vector to another.
     49  *
     50  * Both vectors are assumed to be unit length.
     51  *
     52  * @param {quat} out the receiving quaternion.
     53  * @param {vec3} a the initial vector
     54  * @param {vec3} b the destination vector
     55  * @returns {quat} out
     56  */
     57 quat.rotationTo = (function() {
     58     var tmpvec3 = vec3.create();
     59     var xUnitVec3 = vec3.fromValues(1,0,0);
     60     var yUnitVec3 = vec3.fromValues(0,1,0);
     61 
     62     return function(out, a, b) {
     63         var dot = vec3.dot(a, b);
     64         if (dot < -0.999999) {
     65             vec3.cross(tmpvec3, xUnitVec3, a);
     66             if (vec3.length(tmpvec3) < 0.000001)
     67                 vec3.cross(tmpvec3, yUnitVec3, a);
     68             vec3.normalize(tmpvec3, tmpvec3);
     69             quat.setAxisAngle(out, tmpvec3, Math.PI);
     70             return out;
     71         } else if (dot > 0.999999) {
     72             out[0] = 0;
     73             out[1] = 0;
     74             out[2] = 0;
     75             out[3] = 1;
     76             return out;
     77         } else {
     78             vec3.cross(tmpvec3, a, b);
     79             out[0] = tmpvec3[0];
     80             out[1] = tmpvec3[1];
     81             out[2] = tmpvec3[2];
     82             out[3] = 1 + dot;
     83             return quat.normalize(out, out);
     84         }
     85     };
     86 })();
     87 
     88 /**
     89  * Sets the specified quaternion with values corresponding to the given
     90  * axes. Each axis is a vec3 and is expected to be unit length and
     91  * perpendicular to all other specified axes.
     92  *
     93  * @param {vec3} view  the vector representing the viewing direction
     94  * @param {vec3} right the vector representing the local "right" direction
     95  * @param {vec3} up    the vector representing the local "up" direction
     96  * @returns {quat} out
     97  */
     98 quat.setAxes = (function() {
     99     var matr = mat3.create();
    100 
    101     return function(out, view, right, up) {
    102         matr[0] = right[0];
    103         matr[3] = right[1];
    104         matr[6] = right[2];
    105 
    106         matr[1] = up[0];
    107         matr[4] = up[1];
    108         matr[7] = up[2];
    109 
    110         matr[2] = -view[0];
    111         matr[5] = -view[1];
    112         matr[8] = -view[2];
    113 
    114         return quat.normalize(out, quat.fromMat3(out, matr));
    115     };
    116 })();
    117 
    118 /**
    119  * Creates a new quat initialized with values from an existing quaternion
    120  *
    121  * @param {quat} a quaternion to clone
    122  * @returns {quat} a new quaternion
    123  * @function
    124  */
    125 quat.clone = vec4.clone;
    126 
    127 /**
    128  * Creates a new quat initialized with the given values
    129  *
    130  * @param {Number} x X component
    131  * @param {Number} y Y component
    132  * @param {Number} z Z component
    133  * @param {Number} w W component
    134  * @returns {quat} a new quaternion
    135  * @function
    136  */
    137 quat.fromValues = vec4.fromValues;
    138 
    139 /**
    140  * Copy the values from one quat to another
    141  *
    142  * @param {quat} out the receiving quaternion
    143  * @param {quat} a the source quaternion
    144  * @returns {quat} out
    145  * @function
    146  */
    147 quat.copy = vec4.copy;
    148 
    149 /**
    150  * Set the components of a quat to the given values
    151  *
    152  * @param {quat} out the receiving quaternion
    153  * @param {Number} x X component
    154  * @param {Number} y Y component
    155  * @param {Number} z Z component
    156  * @param {Number} w W component
    157  * @returns {quat} out
    158  * @function
    159  */
    160 quat.set = vec4.set;
    161 
    162 /**
    163  * Set a quat to the identity quaternion
    164  *
    165  * @param {quat} out the receiving quaternion
    166  * @returns {quat} out
    167  */
    168 quat.identity = function(out) {
    169     out[0] = 0;
    170     out[1] = 0;
    171     out[2] = 0;
    172     out[3] = 1;
    173     return out;
    174 };
    175 
    176 /**
    177  * Sets a quat from the given angle and rotation axis,
    178  * then returns it.
    179  *
    180  * @param {quat} out the receiving quaternion
    181  * @param {vec3} axis the axis around which to rotate
    182  * @param {Number} rad the angle in radians
    183  * @returns {quat} out
    184  **/
    185 quat.setAxisAngle = function(out, axis, rad) {
    186     rad = rad * 0.5;
    187     var s = Math.sin(rad);
    188     out[0] = s * axis[0];
    189     out[1] = s * axis[1];
    190     out[2] = s * axis[2];
    191     out[3] = Math.cos(rad);
    192     return out;
    193 };
    194 
    195 /**
    196  * Adds two quat's
    197  *
    198  * @param {quat} out the receiving quaternion
    199  * @param {quat} a the first operand
    200  * @param {quat} b the second operand
    201  * @returns {quat} out
    202  * @function
    203  */
    204 quat.add = vec4.add;
    205 
    206 /**
    207  * Multiplies two quat's
    208  *
    209  * @param {quat} out the receiving quaternion
    210  * @param {quat} a the first operand
    211  * @param {quat} b the second operand
    212  * @returns {quat} out
    213  */
    214 quat.multiply = function(out, a, b) {
    215     var ax = a[0], ay = a[1], az = a[2], aw = a[3],
    216         bx = b[0], by = b[1], bz = b[2], bw = b[3];
    217 
    218     out[0] = ax * bw + aw * bx + ay * bz - az * by;
    219     out[1] = ay * bw + aw * by + az * bx - ax * bz;
    220     out[2] = az * bw + aw * bz + ax * by - ay * bx;
    221     out[3] = aw * bw - ax * bx - ay * by - az * bz;
    222     return out;
    223 };
    224 
    225 /**
    226  * Alias for {@link quat.multiply}
    227  * @function
    228  */
    229 quat.mul = quat.multiply;
    230 
    231 /**
    232  * Scales a quat by a scalar number
    233  *
    234  * @param {quat} out the receiving vector
    235  * @param {quat} a the vector to scale
    236  * @param {Number} b amount to scale the vector by
    237  * @returns {quat} out
    238  * @function
    239  */
    240 quat.scale = vec4.scale;
    241 
    242 /**
    243  * Rotates a quaternion by the given angle about the X axis
    244  *
    245  * @param {quat} out quat receiving operation result
    246  * @param {quat} a quat to rotate
    247  * @param {number} rad angle (in radians) to rotate
    248  * @returns {quat} out
    249  */
    250 quat.rotateX = function (out, a, rad) {
    251     rad *= 0.5;
    252 
    253     var ax = a[0], ay = a[1], az = a[2], aw = a[3],
    254         bx = Math.sin(rad), bw = Math.cos(rad);
    255 
    256     out[0] = ax * bw + aw * bx;
    257     out[1] = ay * bw + az * bx;
    258     out[2] = az * bw - ay * bx;
    259     out[3] = aw * bw - ax * bx;
    260     return out;
    261 };
    262 
    263 /**
    264  * Rotates a quaternion by the given angle about the Y axis
    265  *
    266  * @param {quat} out quat receiving operation result
    267  * @param {quat} a quat to rotate
    268  * @param {number} rad angle (in radians) to rotate
    269  * @returns {quat} out
    270  */
    271 quat.rotateY = function (out, a, rad) {
    272     rad *= 0.5;
    273 
    274     var ax = a[0], ay = a[1], az = a[2], aw = a[3],
    275         by = Math.sin(rad), bw = Math.cos(rad);
    276 
    277     out[0] = ax * bw - az * by;
    278     out[1] = ay * bw + aw * by;
    279     out[2] = az * bw + ax * by;
    280     out[3] = aw * bw - ay * by;
    281     return out;
    282 };
    283 
    284 /**
    285  * Rotates a quaternion by the given angle about the Z axis
    286  *
    287  * @param {quat} out quat receiving operation result
    288  * @param {quat} a quat to rotate
    289  * @param {number} rad angle (in radians) to rotate
    290  * @returns {quat} out
    291  */
    292 quat.rotateZ = function (out, a, rad) {
    293     rad *= 0.5;
    294 
    295     var ax = a[0], ay = a[1], az = a[2], aw = a[3],
    296         bz = Math.sin(rad), bw = Math.cos(rad);
    297 
    298     out[0] = ax * bw + ay * bz;
    299     out[1] = ay * bw - ax * bz;
    300     out[2] = az * bw + aw * bz;
    301     out[3] = aw * bw - az * bz;
    302     return out;
    303 };
    304 
    305 /**
    306  * Calculates the W component of a quat from the X, Y, and Z components.
    307  * Assumes that quaternion is 1 unit in length.
    308  * Any existing W component will be ignored.
    309  *
    310  * @param {quat} out the receiving quaternion
    311  * @param {quat} a quat to calculate W component of
    312  * @returns {quat} out
    313  */
    314 quat.calculateW = function (out, a) {
    315     var x = a[0], y = a[1], z = a[2];
    316 
    317     out[0] = x;
    318     out[1] = y;
    319     out[2] = z;
    320     out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
    321     return out;
    322 };
    323 
    324 /**
    325  * Calculates the dot product of two quat's
    326  *
    327  * @param {quat} a the first operand
    328  * @param {quat} b the second operand
    329  * @returns {Number} dot product of a and b
    330  * @function
    331  */
    332 quat.dot = vec4.dot;
    333 
    334 /**
    335  * Performs a linear interpolation between two quat's
    336  *
    337  * @param {quat} out the receiving quaternion
    338  * @param {quat} a the first operand
    339  * @param {quat} b the second operand
    340  * @param {Number} t interpolation amount between the two inputs
    341  * @returns {quat} out
    342  * @function
    343  */
    344 quat.lerp = vec4.lerp;
    345 
    346 /**
    347  * Performs a spherical linear interpolation between two quat
    348  *
    349  * @param {quat} out the receiving quaternion
    350  * @param {quat} a the first operand
    351  * @param {quat} b the second operand
    352  * @param {Number} t interpolation amount between the two inputs
    353  * @returns {quat} out
    354  */
    355 quat.slerp = function (out, a, b, t) {
    356     // benchmarks:
    357     //    http://jsperf.com/quaternion-slerp-implementations
    358 
    359     var ax = a[0], ay = a[1], az = a[2], aw = a[3],
    360         bx = b[0], by = b[1], bz = b[2], bw = b[3];
    361 
    362     var        omega, cosom, sinom, scale0, scale1;
    363 
    364     // calc cosine
    365     cosom = ax * bx + ay * by + az * bz + aw * bw;
    366     // adjust signs (if necessary)
    367     if ( cosom < 0.0 ) {
    368         cosom = -cosom;
    369         bx = - bx;
    370         by = - by;
    371         bz = - bz;
    372         bw = - bw;
    373     }
    374     // calculate coefficients
    375     if ( (1.0 - cosom) > 0.000001 ) {
    376         // standard case (slerp)
    377         omega  = Math.acos(cosom);
    378         sinom  = Math.sin(omega);
    379         scale0 = Math.sin((1.0 - t) * omega) / sinom;
    380         scale1 = Math.sin(t * omega) / sinom;
    381     } else {
    382         // "from" and "to" quaternions are very close
    383         //  ... so we can do a linear interpolation
    384         scale0 = 1.0 - t;
    385         scale1 = t;
    386     }
    387     // calculate final values
    388     out[0] = scale0 * ax + scale1 * bx;
    389     out[1] = scale0 * ay + scale1 * by;
    390     out[2] = scale0 * az + scale1 * bz;
    391     out[3] = scale0 * aw + scale1 * bw;
    392 
    393     return out;
    394 };
    395 
    396 /**
    397  * Performs a spherical linear interpolation with two control points
    398  *
    399  * @param {quat} out the receiving quaternion
    400  * @param {quat} a the first operand
    401  * @param {quat} b the second operand
    402  * @param {quat} c the third operand
    403  * @param {quat} d the fourth operand
    404  * @param {Number} t interpolation amount
    405  * @returns {quat} out
    406  */
    407 quat.sqlerp = (function () {
    408   var temp1 = quat.create();
    409   var temp2 = quat.create();
    410 
    411   return function (out, a, b, c, d, t) {
    412     quat.slerp(temp1, a, d, t);
    413     quat.slerp(temp2, b, c, t);
    414     quat.slerp(out, temp1, temp2, 2 * t * (1 - t));
    415 
    416     return out;
    417   };
    418 }());
    419 
    420 /**
    421  * Calculates the inverse of a quat
    422  *
    423  * @param {quat} out the receiving quaternion
    424  * @param {quat} a quat to calculate inverse of
    425  * @returns {quat} out
    426  */
    427 quat.invert = function(out, a) {
    428     var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
    429         dot = a0*a0 + a1*a1 + a2*a2 + a3*a3,
    430         invDot = dot ? 1.0/dot : 0;
    431 
    432     // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
    433 
    434     out[0] = -a0*invDot;
    435     out[1] = -a1*invDot;
    436     out[2] = -a2*invDot;
    437     out[3] = a3*invDot;
    438     return out;
    439 };
    440 
    441 /**
    442  * Calculates the conjugate of a quat
    443  * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
    444  *
    445  * @param {quat} out the receiving quaternion
    446  * @param {quat} a quat to calculate conjugate of
    447  * @returns {quat} out
    448  */
    449 quat.conjugate = function (out, a) {
    450     out[0] = -a[0];
    451     out[1] = -a[1];
    452     out[2] = -a[2];
    453     out[3] = a[3];
    454     return out;
    455 };
    456 
    457 /**
    458  * Calculates the length of a quat
    459  *
    460  * @param {quat} a vector to calculate length of
    461  * @returns {Number} length of a
    462  * @function
    463  */
    464 quat.length = vec4.length;
    465 
    466 /**
    467  * Alias for {@link quat.length}
    468  * @function
    469  */
    470 quat.len = quat.length;
    471 
    472 /**
    473  * Calculates the squared length of a quat
    474  *
    475  * @param {quat} a vector to calculate squared length of
    476  * @returns {Number} squared length of a
    477  * @function
    478  */
    479 quat.squaredLength = vec4.squaredLength;
    480 
    481 /**
    482  * Alias for {@link quat.squaredLength}
    483  * @function
    484  */
    485 quat.sqrLen = quat.squaredLength;
    486 
    487 /**
    488  * Normalize a quat
    489  *
    490  * @param {quat} out the receiving quaternion
    491  * @param {quat} a quaternion to normalize
    492  * @returns {quat} out
    493  * @function
    494  */
    495 quat.normalize = vec4.normalize;
    496 
    497 /**
    498  * Creates a quaternion from the given 3x3 rotation matrix.
    499  *
    500  * NOTE: The resultant quaternion is not normalized, so you should be sure
    501  * to renormalize the quaternion yourself where necessary.
    502  *
    503  * @param {quat} out the receiving quaternion
    504  * @param {mat3} m rotation matrix
    505  * @returns {quat} out
    506  * @function
    507  */
    508 quat.fromMat3 = function(out, m) {
    509     // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
    510     // article "Quaternion Calculus and Fast Animation".
    511     var fTrace = m[0] + m[4] + m[8];
    512     var fRoot;
    513 
    514     if ( fTrace > 0.0 ) {
    515         // |w| > 1/2, may as well choose w > 1/2
    516         fRoot = Math.sqrt(fTrace + 1.0);  // 2w
    517         out[3] = 0.5 * fRoot;
    518         fRoot = 0.5/fRoot;  // 1/(4w)
    519         out[0] = (m[5]-m[7])*fRoot;
    520         out[1] = (m[6]-m[2])*fRoot;
    521         out[2] = (m[1]-m[3])*fRoot;
    522     } else {
    523         // |w| <= 1/2
    524         var i = 0;
    525         if ( m[4] > m[0] )
    526           i = 1;
    527         if ( m[8] > m[i*3+i] )
    528           i = 2;
    529         var j = (i+1)%3;
    530         var k = (i+2)%3;
    531 
    532         fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);
    533         out[i] = 0.5 * fRoot;
    534         fRoot = 0.5 / fRoot;
    535         out[3] = (m[j*3+k] - m[k*3+j]) * fRoot;
    536         out[j] = (m[j*3+i] + m[i*3+j]) * fRoot;
    537         out[k] = (m[k*3+i] + m[i*3+k]) * fRoot;
    538     }
    539 
    540     return out;
    541 };
    542 
    543 /**
    544  * Returns a string representation of a quatenion
    545  *
    546  * @param {quat} vec vector to represent as a string
    547  * @returns {String} string representation of the vector
    548  */
    549 quat.str = function (a) {
    550     return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
    551 };
    552 
    553 module.exports = quat;
    554