Source: math/Matrix44.js

  1. /**
  2. * @class Matrix44
  3. * @memberof SQR
  4. *
  5. * @description A multi-purpose 4x4 matrix.
  6. */
  7. SQR.Matrix44 = function(data) {
  8. this.data = data || new Float32Array(16);
  9. this.identity = function(m) {
  10. var d = m || this.data;
  11. d[0] = 1,d[4] = 0,d[8] = 0,d[12] = 0;
  12. d[1] = 0,d[5] = 1,d[9] = 0,d[13] = 0;
  13. d[2] = 0,d[6] = 0,d[10] = 1,d[14] = 0;
  14. d[3] = 0,d[7] = 0,d[11] = 0,d[15] = 1;
  15. return this;
  16. }
  17. /**
  18. * @memberof SQR.Matrix44.prototype
  19. * @description Multiplies the vector v by my this matrix and stores the result in the vector pv.
  20. *
  21. * @param {SQR.V3} v - the vector to be multiplies by this matrix
  22. * @param {SQR.V3=} pv - the vector in which to store the result. If ommited, result is stored in v.
  23. */
  24. this.transformVector = function (v, pv) {
  25. var d = this.data;
  26. var x = v.x, y = v.y, z = v.z, w = v.w;
  27. pv = pv || v;
  28. pv.x = d[0] * x + d[4] * y + d[8] * z + d[12] * w;
  29. pv.y = d[1] * x + d[5] * y + d[9] * z + d[13] * w;
  30. pv.z = d[2] * x + d[6] * y + d[10] * z + d[14] * w;
  31. // pv.w = d[3] * x + d[7] * y + d[11] * z + d[15] * w;
  32. return pv;
  33. }
  34. this.rotateVector = function (v, pv) {
  35. var d = this.data;
  36. var x = v.x, y = v.y, z = v.z, w = v.w;
  37. pv = pv || v;
  38. pv.x = d[0] * x + d[4] * y + d[8] * z;
  39. pv.y = d[1] * x + d[5] * y + d[9] * z;
  40. pv.z = d[2] * x + d[6] * y + d[10] * z;
  41. // pv.w = d[3] * x + d[7] * y + d[11] * z + d[15] * w;
  42. return pv;
  43. }
  44. /**
  45. * @memberof SQR.Matrix44.prototype
  46. * @description Multiplies this matrix by m
  47. * @param {SQR.Matrix44} m - matrix to multiply this matrix by
  48. */
  49. this.multiply = function(m) {
  50. var a = this.data, b = m.data || m;
  51. var a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13, a14, a15;
  52. var b00, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10, b11, b12, b13, b14, b15;
  53. a00 = a[0],a01 = a[1],a02 = a[2],a03 = a[3];
  54. a04 = a[4],a05 = a[5],a06 = a[6],a07 = a[7];
  55. a08 = a[8],a09 = a[9],a10 = a[10],a11 = a[11];
  56. a12 = a[12],a13 = a[13],a14 = a[14],a15 = a[15];
  57. b00 = b[0],b01 = b[1],b02 = b[2],b03 = b[3];
  58. b04 = b[4],b05 = b[5],b06 = b[6],b07 = b[7];
  59. b08 = b[8],b09 = b[9],b10 = b[10],b11 = b[11];
  60. b12 = b[12],b13 = b[13],b14 = b[14],b15 = b[15];
  61. a[0] = a00 * b00 + a04 * b01 + a08 * b02 + a12 * b03;
  62. a[1] = a01 * b00 + a05 * b01 + a09 * b02 + a13 * b03;
  63. a[2] = a02 * b00 + a06 * b01 + a10 * b02 + a14 * b03;
  64. a[3] = a03 * b00 + a07 * b01 + a11 * b02 + a15 * b03;
  65. a[4] = a00 * b04 + a04 * b05 + a08 * b06 + a12 * b07;
  66. a[5] = a01 * b04 + a05 * b05 + a09 * b06 + a13 * b07;
  67. a[6] = a02 * b04 + a06 * b05 + a10 * b06 + a14 * b07;
  68. a[7] = a03 * b04 + a07 * b05 + a11 * b06 + a15 * b07;
  69. a[8] = a00 * b08 + a04 * b09 + a08 * b10 + a12 * b11;
  70. a[9] = a01 * b08 + a05 * b09 + a09 * b10 + a13 * b11;
  71. a[10] = a02 * b08 + a06 * b09 + a10 * b10 + a14 * b11;
  72. a[11] = a03 * b08 + a07 * b09 + a11 * b10 + a15 * b11;
  73. a[12] = a00 * b12 + a04 * b13 + a08 * b14 + a12 * b15;
  74. a[13] = a01 * b12 + a05 * b13 + a09 * b14 + a13 * b15;
  75. a[14] = a02 * b12 + a06 * b13 + a10 * b14 + a14 * b15;
  76. a[15] = a03 * b12 + a07 * b13 + a11 * b14 + a15 * b15;
  77. return this;
  78. }
  79. /**
  80. * @method setTQS
  81. * @memberof SQR.Matrix44.prototype
  82. * @description Sets the translation/rotation/scale values at once.
  83. * Similar to setTRS but the rotation is defined as a quaternion.
  84. * @param tx x translation
  85. * @param ty y translation
  86. * @param tz y translation
  87. * @param qw w compoment of the quaternion
  88. * @param qx x compoment of the quaternion
  89. * @param qx y compoment of the quaternion
  90. * @param qx z compoment of the quaternion
  91. * @param sx x scale
  92. * @param sy y scale
  93. * @param sz z scale
  94. * @param m the matrix to set scale to, applies to `this` if ommited
  95. */
  96. this.setTQS = function(tx, ty, tz, qw, qx, qy, qz, sx, sy, sz, m) {
  97. var d = m || this.data;
  98. this.identity(m);
  99. var sqx = qx * qx;
  100. var sqy = qy * qy;
  101. var sqz = qz * qz;
  102. // fliping this part changes from left handed to right handed (I think)
  103. if(SQR.flipMatrix) {
  104. d[0] = (1 - 2 * sqy - 2 * sqz) * sx;
  105. d[1] = (2 * qx * qy - 2 * qz * qw) * sx;
  106. d[2] = (2 * qx * qz + 2 * qy * qw) * sx;
  107. d[4] = (2 * qx * qy + 2 * qz * qw) * sy;
  108. d[5] = (1 - 2 * sqx - 2 * sqz) * sy;
  109. d[6] = (2 * qy * qz - 2 * qx * qw) * sy;
  110. d[8] = (2 * qx * qz - 2 * qy * qw) * sz;
  111. d[9] = (2 * qy * qz + 2 * qx * qw) * sz;
  112. d[10] = (1 - 2 * sqx - 2 * sqy) * sz;
  113. } else {
  114. d[0] = (1 - 2 * sqy - 2 * sqz) * sx;
  115. d[4] = (2 * qx * qy - 2 * qz * qw) * sx;
  116. d[8] = (2 * qx * qz + 2 * qy * qw) * sx;
  117. d[1] = (2 * qx * qy + 2 * qz * qw) * sy;
  118. d[5] = (1 - 2 * sqx - 2 * sqz) * sy;
  119. d[9] = (2 * qy * qz - 2 * qx * qw) * sy;
  120. d[2] = (2 * qx * qz - 2 * qy * qw) * sz;
  121. d[6] = (2 * qy * qz + 2 * qx * qw) * sz;
  122. d[10] = (1 - 2 * sqx - 2 * sqy) * sz;
  123. }
  124. d[12] = tx;
  125. d[13] = ty;
  126. d[14] = tz;
  127. return m || this;
  128. }
  129. /**
  130. * @method setTRS
  131. * @memberof SQR.Matrix44.prototype
  132. * @description Sets the translation/rotation/scale values at once.
  133. * @param tx x translation
  134. * @param ty y translation
  135. * @param tz y translation
  136. * @param rx rotation angle in radians on the x axis
  137. * @param ry rotation angle in radians on the y axis
  138. * @param rz rotation angle in radians on the z axis
  139. * @param sx x scale
  140. * @param sy y scale
  141. * @param sz z scale
  142. * @param m the matrix to set scale to, applies to `this` if ommited
  143. */
  144. this.setTRS = function(tx, ty, tz, rx, ry, rz, sx, sy, sz, m) {
  145. var d = m || this.data;
  146. this.identity(m);
  147. var six = Math.sin(rx), cox = Math.cos(rx), siy = Math.sin(ry), coy = Math.cos(ry), siz = Math.sin(rz), coz = Math.cos(rz);
  148. // fliping this part changes from left handed to right handed (I think)
  149. if(SQR.flipMatrix) {
  150. d[0] = (coy * coz + siy * six * siz) * sx;
  151. d[1] = (-coy * siz + siy * six * coz) * sx;
  152. d[2] = siy * cox * sx;
  153. d[4] = siz * cox * sy;
  154. d[5] = coz * cox * sy;
  155. d[6] = -six * sy;
  156. d[8] = (-siy * coz + coy * six * siz) * sz;
  157. d[9] = (siz * siy + coy * six * coz) * sz;
  158. d[10] = coy * cox * sz;
  159. } else {
  160. d[0] = (coy * coz + siy * six * siz) * sx;
  161. d[4] = (-coy * siz + siy * six * coz) * sx;
  162. d[8] = siy * cox * sx;
  163. d[1] = siz * cox * sy;
  164. d[5] = coz * cox * sy;
  165. d[9] = -six * sy;
  166. d[2] = (-siy * coz + coy * six * siz) * sz;
  167. d[6] = (siz * siy + coy * six * coz) * sz;
  168. d[10] = coy * cox * sz;
  169. }
  170. d[12] = tx;
  171. d[13] = ty;
  172. d[14] = tz;
  173. return m || this;
  174. }
  175. /**
  176. * @method setScale
  177. * @memberof SQR.Matrix44.prototype
  178. * @description Sets the scale values.
  179. * @param sx x scale
  180. * @param sy y scale
  181. * @param sz z scale
  182. * @param m the matrix to set scale to, applies to `this` if ommited
  183. */
  184. this.setScale = function(sx, sy, sz, m) {
  185. var d = m || this.data;
  186. d[0] = sx, d[5] = sy, d[10] = sz;
  187. return m || this;
  188. }
  189. /**
  190. * @method setTranslation
  191. * @memberof SQR.Matrix44.prototype
  192. * @description Sets the translation values.
  193. * @param tx x translation
  194. * @param ty y translation
  195. * @param tz z translation
  196. * @param m the matrix to set translation to, applies to `this` if ommited
  197. */
  198. this.setTranslation = function(tx, ty, tz, m) {
  199. var d = m || this.data;
  200. d[12] = tx, d[13] = ty, d[14] = tz;
  201. return m || this;
  202. }
  203. /**
  204. * @method setRotation
  205. * @memberof SQR.Matrix44.prototype
  206. * @description Sets the rotation value.
  207. * @param rx angle in radians of the rotation on x axis
  208. * @param ry angle in radians of the rotation on y axis
  209. * @param rz angle in radians of the rotation on z axis
  210. * @param m the matrix to set rotation to, applies to `this` if ommited
  211. */
  212. this.setRotation = function(rx, ry, rz, m) {
  213. var d = m || this.data;
  214. var six = Math.sin(rx), cox = Math.cos(rx),
  215. siy = Math.sin(ry), coy = Math.cos(ry),
  216. siz = Math.sin(rz), coz = Math.cos(rz);
  217. d[0] = coy * coz + siy * six * siz;
  218. d[1] = -coy * siz + siy * six * coz;
  219. d[2] = siy * cox;
  220. d[4] = siz * cox;
  221. d[5] = coz * cox;
  222. d[6] = -six;
  223. d[8] = -siy * coz + coy * six * siz;
  224. d[9] = siz * siy + coy * six * coz;
  225. d[10] = coy * cox;
  226. return m || this;
  227. }
  228. /**
  229. * @method translate
  230. * @memberof SQR.Matrix44.prototype
  231. * @description Applies translation to matrix
  232. * @param tx x translation
  233. * @param ty y translation
  234. * @param tz z translation
  235. */
  236. this.translate = function(tx, ty, tz) {
  237. this.identity(SQR.Matrix44.__temp);
  238. this.setTranslation(tx, ty, tz, SQR.Matrix44.__temp);
  239. return this.multiply(SQR.Matrix44.__temp);
  240. }
  241. /**
  242. * @method rotate
  243. * @memberof SQR.Matrix44.prototype
  244. * @param rx angle in radians of the rotation on x axis
  245. * @param ry angle in radians of the rotation on y axis
  246. * @param rz angle in radians of the rotation on z axis
  247. * @description Applies rotation to matrix
  248. */
  249. this.rotate = function(rx, ry, rz) {
  250. this.identity(SQR.Matrix44.__temp);
  251. this.setRotation(rx, ry, rz, SQR.Matrix44.__temp);
  252. return this.multiply(SQR.Matrix44.__temp);
  253. }
  254. /**
  255. * @method scale
  256. * @memberof SQR.Matrix44.prototype
  257. * @param sx x scale
  258. * @param sy y scale
  259. * @param sz z scale
  260. * @description Applies scale to matrix
  261. */
  262. this.scale = function(sx, sy, sz) {
  263. this.identity(SQR.Matrix44.__temp);
  264. this.setScale(sx, sy, sz, SQR.Matrix44.__temp);
  265. return this.multiply(SQR.Matrix44.__temp);
  266. }
  267. /**
  268. * @method copyTo
  269. * @memberof SQR.Matrix44.prototype
  270. * Copies the values from this matrix into m
  271. *
  272. * @param {SQR.Matrix44|Float32Array} m - the matrix or 16-compoment array to copy the values to
  273. */
  274. this.copyTo = function(m) {
  275. var a = this.data, b = m.data || m;
  276. for (var i = 0; i < 16; i++) b[i] = a[i];
  277. return this;
  278. }
  279. this.copyFrom = function(m) {
  280. var a = this.data, b = m.data || m;
  281. for (var i = 0; i < 16; i++) a[i] = b[i];
  282. return this;
  283. }
  284. /**
  285. * @method copyRotationTo
  286. * @memberof SQR.Matrix44.prototype
  287. * Copies only the rotation/scale portion of the matrix into m to the current matrix
  288. *
  289. * @param {SQR.Matrix44|Float32Array} m - the matrix or 16-compoment array to copy the values to
  290. */
  291. this.copyRotationTo = function(m) {
  292. var a = this.data, b = m.data || m;
  293. b[0] = a[0];
  294. b[1] = a[1];
  295. b[2] = a[2];
  296. b[3] = a[4];
  297. b[4] = a[5];
  298. b[5] = a[6];
  299. b[6] = a[8];
  300. b[7] = a[9];
  301. b[8] = a[10];
  302. return m;
  303. }
  304. /**
  305. * @method extractPosition
  306. * @memberof SQR.Matrix44.prototype
  307. * Sets v to the translation vakue of this matrix. Useful for extracting position of an element
  308. * based on it's transformation matrix, ex. this is how the the global position of a {@link SQR.Transform}
  309. * is obtained.
  310. *
  311. * @param {SQR.V3} v - the vector to copy the translation values to
  312. */
  313. this.extractPosition = function(v) {
  314. var d = this.data;
  315. v.set(d[12], d[13], d[14]);
  316. return v;
  317. }
  318. this.determinant = function() {
  319. var d = this.data;
  320. return d[0] * (d[5] * d[10] - d[9] * d[6]) +
  321. d[4] * (d[9] * d[2] - d[1] * d[10]) +
  322. d[8] * (d[1] * d[6] - d[5] * d[2]);
  323. }
  324. this.inverse = function(m) {
  325. var a = this.data;
  326. var d = (m) ? m.data || m : this.data;
  327. var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
  328. a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
  329. a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
  330. a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
  331. b00 = a00 * a11 - a01 * a10,
  332. b01 = a00 * a12 - a02 * a10,
  333. b02 = a00 * a13 - a03 * a10,
  334. b03 = a01 * a12 - a02 * a11,
  335. b04 = a01 * a13 - a03 * a11,
  336. b05 = a02 * a13 - a03 * a12,
  337. b06 = a20 * a31 - a21 * a30,
  338. b07 = a20 * a32 - a22 * a30,
  339. b08 = a20 * a33 - a23 * a30,
  340. b09 = a21 * a32 - a22 * a31,
  341. b10 = a21 * a33 - a23 * a31,
  342. b11 = a22 * a33 - a23 * a32,
  343. // Calculate the determinant
  344. det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
  345. if (!det) {
  346. return null;
  347. }
  348. det = 1.0 / det;
  349. d[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
  350. d[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
  351. d[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
  352. d[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
  353. d[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
  354. d[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
  355. d[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
  356. d[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
  357. d[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
  358. d[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
  359. d[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
  360. d[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
  361. d[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
  362. d[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
  363. d[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
  364. d[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
  365. return m;
  366. };
  367. this.inverseMat3 = function(m) {
  368. // adapted from gl-Matrix.js
  369. var d = this.data;
  370. var a = m.data;
  371. var det = this.determinant();
  372. if (Math.abs(det) < 0.0001) {
  373. console.warn("> SQR.Matrix44 - Attempt to inverse a singular matrix44. ", this.data);
  374. console.trace();
  375. return m;
  376. }
  377. var d0 = d[0], d4 = d[4], d8 = d[8], d12 = d[12],
  378. d1 = d[1], d5 = d[5], d9 = d[9], d13 = d[13],
  379. d2 = d[2], d6 = d[6], d10 = d[10], d14 = d[14];
  380. det = 1 / det;
  381. // To make a NormalMatrix - needs to be transposed
  382. a[0] = (d5 * d10 - d9 * d6) * det;
  383. a[1] = (d8 * d6 - d4 * d10) * det;
  384. a[2] = (d4 * d9 - d8 * d5) * det;
  385. a[3] = (d9 * d2 - d1 * d10) * det;
  386. a[4] = (d0 * d10 - d8 * d2) * det;
  387. a[5] = (d8 * d1 - d0 * d9) * det;
  388. a[6] = (d1 * d6 - d5 * d2) * det;
  389. a[7] = (d4 * d2 - d0 * d6) * det;
  390. a[8] = (d0 * d5 - d4 * d1) * det;
  391. // To make a NormalMatrix - doesn't need to be transposed
  392. // a[0] = (d5 * d10 - d9 * d6) * det;
  393. // a[3] = (d8 * d6 - d4 * d10) * det;
  394. // a[6] = (d4 * d9 - d8 * d5) * det;
  395. // a[1] = (d9 * d2 - d1 * d10) * det;
  396. // a[4] = (d0 * d10 - d8 * d2) * det;
  397. // a[7] = (d8 * d1 - d0 * d9) * det;
  398. // a[2] = (d1 * d6 - d5 * d2) * det;
  399. // a[5] = (d4 * d2 - d0 * d6) * det;
  400. // a[8] = (d0 * d5 - d4 * d1) * det;
  401. return m;
  402. }
  403. this.transpose = function(m) {
  404. var d = this.data;
  405. var a = (m) ? m.data || m : this.data;
  406. var d0 = d[0], d4 = d[4], d8 = d[8],
  407. d1 = d[1], d5 = d[5], d9 = d[9],
  408. d2 = d[2], d6 = d[6], d10 = d[10];
  409. a[0] = d0;
  410. a[1] = d4;
  411. a[2] = d8;
  412. a[4] = d1;
  413. a[5] = d5;
  414. a[6] = d9;
  415. a[8] = d2;
  416. a[9] = d6;
  417. a[10] = d10;
  418. }
  419. this.lookAt = function (target, up) {
  420. var d = this.data;
  421. var x = SQR.V3.__tv1;
  422. var y = SQR.V3.__tv2;
  423. var z = SQR.V3.__tv3;
  424. up = up || SQR.V3.up;
  425. // console.log(target, up);
  426. z.set(d[12], d[13], d[14]);
  427. z.sub(z, target).norm();
  428. if (z.magsq() === 0) z.z = 1;
  429. x.cross(up, z).norm();
  430. if (x.magsq() === 0) {
  431. z.x += 0.0001;
  432. x.cross(up, z).norm();
  433. }
  434. y.cross(z, x);
  435. d[0] = x.x, d[4] = y.x, d[8] = z.x;
  436. d[1] = x.y, d[5] = y.y, d[9] = z.y;
  437. d[2] = x.z, d[6] = y.z, d[10] = z.z;
  438. return this;
  439. }
  440. if(!data) this.identity();
  441. }
  442. SQR.Matrix44.__temp = new Float32Array(16);