/home/lindsay/xeolabs/xeogl-next/xeogl/src/math/math.js
API Docs for:

File: /home/lindsay/xeolabs/xeogl-next/xeogl/src/math/math.js

  1. // Some temporary vars to help avoid garbage collection
  2.  
  3. const tempMat1 = new Float32Array(16);
  4. const tempMat2 = new Float32Array(16);
  5. const tempVec4 = new Float32Array(4);
  6.  
  7. let caching = false;
  8. const vec3Cache = [];
  9. let vec3CacheLen = 0;
  10.  
  11. const math = {
  12.  
  13. MAX_DOUBLE: Number.MAX_VALUE,
  14. MIN_DOUBLE: Number.MIN_VALUE,
  15.  
  16. /**
  17. * The number of radiians in a degree (0.0174532925).
  18. * @property DEGTORAD
  19. * @type {Number}
  20. */
  21. DEGTORAD: 0.0174532925,
  22.  
  23. /**
  24. * The number of degrees in a radian.
  25. * @property RADTODEG
  26. * @type {Number}
  27. */
  28. RADTODEG: 57.295779513,
  29.  
  30. openCache() {
  31. caching = true;
  32. vec3CacheLen = 0;
  33. },
  34.  
  35. cacheVec3(value) {
  36. return value || (caching ? (vec3Cache[vec3CacheLen++] || (vec3Cache[vec3CacheLen - 1] = new Float32Array(3))) : new Float32Array(3));
  37. },
  38.  
  39. cacheVec4(value) {
  40. return value || (caching ? (vec3Cache[vec4CacheLen++] || (vec3Cache[vec4CacheLen - 1] = new Float32Array(4))) : new Float32Array(4));
  41. },
  42.  
  43. closeCache() {
  44. caching = false;
  45. },
  46.  
  47. /**
  48. * Returns a new, uninitialized two-element vector.
  49. * @method vec2
  50. * @param [values] Initial values.
  51. * @static
  52. * @returns {Float32Array}
  53. */
  54. vec2(values) {
  55. return new Float32Array(values || 2);
  56. },
  57.  
  58. /**
  59. * Returns a new, uninitialized three-element vector.
  60. * @method vec3
  61. * @param [values] Initial values.
  62. * @static
  63. * @returns {Float32Array}
  64. */
  65. vec3(values) {
  66. return new Float32Array(values || 3);
  67. },
  68.  
  69. /**
  70. * Returns a new, uninitialized four-element vector.
  71. * @method vec4
  72. * @param [values] Initial values.
  73. * @static
  74. * @returns {Float32Array}
  75. */
  76. vec4(values) {
  77. return new Float32Array(values || 4);
  78. },
  79.  
  80. /**
  81. * Returns a new, uninitialized 3x3 matrix.
  82. * @method mat3
  83. * @param [values] Initial values.
  84. * @static
  85. * @returns {Float32Array}
  86. */
  87. mat3(values) {
  88. return new Float32Array(values || 9);
  89. },
  90.  
  91. /**
  92. * Converts a 3x3 matrix to 4x4
  93. * @method mat3ToMat4
  94. * @param mat3 3x3 matrix.
  95. * @param mat4 4x4 matrix
  96. * @static
  97. * @returns {Float32Array}
  98. */
  99. mat3ToMat4(mat3, mat4 = new Float32Array(16)) {
  100. mat4[0] = mat3[0];
  101. mat4[1] = mat3[1];
  102. mat4[2] = mat3[2];
  103. mat4[3] = 0;
  104. mat4[4] = mat3[3];
  105. mat4[5] = mat3[4];
  106. mat4[6] = mat3[5];
  107. mat4[7] = 0;
  108. mat4[8] = mat3[6];
  109. mat4[9] = mat3[7];
  110. mat4[10] = mat3[8];
  111. mat4[11] = 0;
  112. mat4[12] = 0;
  113. mat4[13] = 0;
  114. mat4[14] = 0;
  115. mat4[15] = 1;
  116. return mat4;
  117. },
  118.  
  119. /**
  120. * Returns a new, uninitialized 4x4 matrix.
  121. * @method mat4
  122. * @param [values] Initial values.
  123. * @static
  124. * @returns {Float32Array}
  125. */
  126. mat4(values) {
  127. return new Float32Array(values || 16);
  128. },
  129.  
  130. /**
  131. * Converts a 4x4 matrix to 3x3
  132. * @method mat4ToMat3
  133. * @param mat4 4x4 matrix.
  134. * @param mat3 3x3 matrix
  135. * @static
  136. * @returns {Float32Array}
  137. */
  138. mat4ToMat3(mat4, mat3) { // TODO
  139. //return new Float32Array(values || 9);
  140. },
  141.  
  142. /**
  143. * Returns a new UUID.
  144. * @method createUUID
  145. * @static
  146. * @return string The new UUID
  147. */
  148. //createUUID: function () {
  149. // // http://www.broofa.com/Tools/Math.uuid.htm
  150. // var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
  151. // var uuid = new Array(36);
  152. // var rnd = 0;
  153. // var r;
  154. // return function () {
  155. // for (var i = 0; i < 36; i++) {
  156. // if (i === 8 || i === 13 || i === 18 || i === 23) {
  157. // uuid[i] = '-';
  158. // } else if (i === 14) {
  159. // uuid[i] = '4';
  160. // } else {
  161. // if (rnd <= 0x02) {
  162. // rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0;
  163. // }
  164. // r = rnd & 0xf;
  165. // rnd = rnd >> 4;
  166. // uuid[i] = chars[( i === 19 ) ? ( r & 0x3 ) | 0x8 : r];
  167. // }
  168. // }
  169. // return uuid.join('');
  170. // };
  171. //}(),
  172. //
  173. createUUID: ((() => {
  174. const self = {};
  175. const lut = [];
  176. for (let i = 0; i < 256; i++) {
  177. lut[i] = (i < 16 ? '0' : '') + (i).toString(16);
  178. }
  179. return () => {
  180. const d0 = Math.random() * 0xffffffff | 0;
  181. const d1 = Math.random() * 0xffffffff | 0;
  182. const d2 = Math.random() * 0xffffffff | 0;
  183. const d3 = Math.random() * 0xffffffff | 0;
  184. return `${lut[d0 & 0xff] + lut[d0 >> 8 & 0xff] + lut[d0 >> 16 & 0xff] + lut[d0 >> 24 & 0xff]}-${lut[d1 & 0xff]}${lut[d1 >> 8 & 0xff]}-${lut[d1 >> 16 & 0x0f | 0x40]}${lut[d1 >> 24 & 0xff]}-${lut[d2 & 0x3f | 0x80]}${lut[d2 >> 8 & 0xff]}-${lut[d2 >> 16 & 0xff]}${lut[d2 >> 24 & 0xff]}${lut[d3 & 0xff]}${lut[d3 >> 8 & 0xff]}${lut[d3 >> 16 & 0xff]}${lut[d3 >> 24 & 0xff]}`;
  185. };
  186. }))(),
  187.  
  188. /**
  189. * Clamps a value to the given range.
  190. * @param {Number} value Value to clamp.
  191. * @param {Number} min Lower bound.
  192. * @param {Number} max Upper bound.
  193. * @returns {Number} Clamped result.
  194. */
  195. clamp(value, min, max) {
  196. return Math.max(min, Math.min(max, value));
  197. },
  198.  
  199. /**
  200. * Floating-point modulus
  201. * @method fmod
  202. * @static
  203. * @param {Number} a
  204. * @param {Number} b
  205. * @returns {*}
  206. */
  207. fmod(a, b) {
  208. if (a < b) {
  209. console.error("xeogl.math.fmod : Attempting to find modulus within negative range - would be infinite loop - ignoring");
  210. return a;
  211. }
  212. while (b <= a) {
  213. a -= b;
  214. }
  215. return a;
  216. },
  217.  
  218. /**
  219. * Negates a four-element vector.
  220. * @method negateVec4
  221. * @static
  222. * @param {Array(Number)} v Vector to negate
  223. * @param {Array(Number)} [dest] Destination vector
  224. * @return {Array(Number)} dest if specified, v otherwise
  225. */
  226. negateVec4(v, dest) {
  227. if (!dest) {
  228. dest = v;
  229. }
  230. dest[0] = -v[0];
  231. dest[1] = -v[1];
  232. dest[2] = -v[2];
  233. dest[3] = -v[3];
  234. return dest;
  235. },
  236.  
  237. /**
  238. * Adds one four-element vector to another.
  239. * @method addVec4
  240. * @static
  241. * @param {Array(Number)} u First vector
  242. * @param {Array(Number)} v Second vector
  243. * @param {Array(Number)} [dest] Destination vector
  244. * @return {Array(Number)} dest if specified, u otherwise
  245. */
  246. addVec4(u, v, dest) {
  247. if (!dest) {
  248. dest = u;
  249. }
  250. dest[0] = u[0] + v[0];
  251. dest[1] = u[1] + v[1];
  252. dest[2] = u[2] + v[2];
  253. dest[3] = u[3] + v[3];
  254. return dest;
  255. },
  256.  
  257. /**
  258. * Adds a scalar value to each element of a four-element vector.
  259. * @method addVec4Scalar
  260. * @static
  261. * @param {Array(Number)} v The vector
  262. * @param {Number} s The scalar
  263. * @param {Array(Number)} [dest] Destination vector
  264. * @return {Array(Number)} dest if specified, v otherwise
  265. */
  266. addVec4Scalar(v, s, dest) {
  267. if (!dest) {
  268. dest = v;
  269. }
  270. dest[0] = v[0] + s;
  271. dest[1] = v[1] + s;
  272. dest[2] = v[2] + s;
  273. dest[3] = v[3] + s;
  274. return dest;
  275. },
  276.  
  277. /**
  278. * Adds one three-element vector to another.
  279. * @method addVec3
  280. * @static
  281. * @param {Array(Number)} u First vector
  282. * @param {Array(Number)} v Second vector
  283. * @param {Array(Number)} [dest] Destination vector
  284. * @return {Array(Number)} dest if specified, u otherwise
  285. */
  286. addVec3(u, v, dest) {
  287. if (!dest) {
  288. dest = u;
  289. }
  290. dest[0] = u[0] + v[0];
  291. dest[1] = u[1] + v[1];
  292. dest[2] = u[2] + v[2];
  293. return dest;
  294. },
  295.  
  296. /**
  297. * Adds a scalar value to each element of a three-element vector.
  298. * @method addVec4Scalar
  299. * @static
  300. * @param {Array(Number)} v The vector
  301. * @param {Number} s The scalar
  302. * @param {Array(Number)} [dest] Destination vector
  303. * @return {Array(Number)} dest if specified, v otherwise
  304. */
  305. addVec3Scalar(v, s, dest) {
  306. if (!dest) {
  307. dest = v;
  308. }
  309. dest[0] = v[0] + s;
  310. dest[1] = v[1] + s;
  311. dest[2] = v[2] + s;
  312. return dest;
  313. },
  314.  
  315. /**
  316. * Subtracts one four-element vector from another.
  317. * @method subVec4
  318. * @static
  319. * @param {Array(Number)} u First vector
  320. * @param {Array(Number)} v Vector to subtract
  321. * @param {Array(Number)} [dest] Destination vector
  322. * @return {Array(Number)} dest if specified, u otherwise
  323. */
  324. subVec4(u, v, dest) {
  325. if (!dest) {
  326. dest = u;
  327. }
  328. dest[0] = u[0] - v[0];
  329. dest[1] = u[1] - v[1];
  330. dest[2] = u[2] - v[2];
  331. dest[3] = u[3] - v[3];
  332. return dest;
  333. },
  334.  
  335. /**
  336. * Subtracts one three-element vector from another.
  337. * @method subVec3
  338. * @static
  339. * @param {Array(Number)} u First vector
  340. * @param {Array(Number)} v Vector to subtract
  341. * @param {Array(Number)} [dest] Destination vector
  342. * @return {Array(Number)} dest if specified, u otherwise
  343. */
  344. subVec3(u, v, dest) {
  345. if (!dest) {
  346. dest = u;
  347. }
  348. dest[0] = u[0] - v[0];
  349. dest[1] = u[1] - v[1];
  350. dest[2] = u[2] - v[2];
  351. return dest;
  352. },
  353.  
  354. /**
  355. * Subtracts one two-element vector from another.
  356. * @method subVec2
  357. * @static
  358. * @param {Array(Number)} u First vector
  359. * @param {Array(Number)} v Vector to subtract
  360. * @param {Array(Number)} [dest] Destination vector
  361. * @return {Array(Number)} dest if specified, u otherwise
  362. */
  363. subVec2(u, v, dest) {
  364. if (!dest) {
  365. dest = u;
  366. }
  367. dest[0] = u[0] - v[0];
  368. dest[1] = u[1] - v[1];
  369. return dest;
  370. },
  371.  
  372. /**
  373. * Subtracts a scalar value from each element of a four-element vector.
  374. * @method subVec4Scalar
  375. * @static
  376. * @param {Array(Number)} v The vector
  377. * @param {Number} s The scalar
  378. * @param {Array(Number)} [dest] Destination vector
  379. * @return {Array(Number)} dest if specified, v otherwise
  380. */
  381. subVec4Scalar(v, s, dest) {
  382. if (!dest) {
  383. dest = v;
  384. }
  385. dest[0] = v[0] - s;
  386. dest[1] = v[1] - s;
  387. dest[2] = v[2] - s;
  388. dest[3] = v[3] - s;
  389. return dest;
  390. },
  391.  
  392. /**
  393. * Sets each element of a 4-element vector to a scalar value minus the value of that element.
  394. * @method subScalarVec4
  395. * @static
  396. * @param {Array(Number)} v The vector
  397. * @param {Number} s The scalar
  398. * @param {Array(Number)} [dest] Destination vector
  399. * @return {Array(Number)} dest if specified, v otherwise
  400. */
  401. subScalarVec4(v, s, dest) {
  402. if (!dest) {
  403. dest = v;
  404. }
  405. dest[0] = s - v[0];
  406. dest[1] = s - v[1];
  407. dest[2] = s - v[2];
  408. dest[3] = s - v[3];
  409. return dest;
  410. },
  411.  
  412. /**
  413. * Multiplies one three-element vector by another.
  414. * @method mulVec3
  415. * @static
  416. * @param {Array(Number)} u First vector
  417. * @param {Array(Number)} v Second vector
  418. * @param {Array(Number)} [dest] Destination vector
  419. * @return {Array(Number)} dest if specified, u otherwise
  420. */
  421. mulVec4(u, v, dest) {
  422. if (!dest) {
  423. dest = u;
  424. }
  425. dest[0] = u[0] * v[0];
  426. dest[1] = u[1] * v[1];
  427. dest[2] = u[2] * v[2];
  428. dest[3] = u[3] * v[3];
  429. return dest;
  430. },
  431.  
  432. /**
  433. * Multiplies each element of a four-element vector by a scalar.
  434. * @method mulVec34calar
  435. * @static
  436. * @param {Array(Number)} v The vector
  437. * @param {Number} s The scalar
  438. * @param {Array(Number)} [dest] Destination vector
  439. * @return {Array(Number)} dest if specified, v otherwise
  440. */
  441. mulVec4Scalar(v, s, dest) {
  442. if (!dest) {
  443. dest = v;
  444. }
  445. dest[0] = v[0] * s;
  446. dest[1] = v[1] * s;
  447. dest[2] = v[2] * s;
  448. dest[3] = v[3] * s;
  449. return dest;
  450. },
  451.  
  452. /**
  453. * Multiplies each element of a three-element vector by a scalar.
  454. * @method mulVec3Scalar
  455. * @static
  456. * @param {Array(Number)} v The vector
  457. * @param {Number} s The scalar
  458. * @param {Array(Number)} [dest] Destination vector
  459. * @return {Array(Number)} dest if specified, v otherwise
  460. */
  461. mulVec3Scalar(v, s, dest) {
  462. if (!dest) {
  463. dest = v;
  464. }
  465. dest[0] = v[0] * s;
  466. dest[1] = v[1] * s;
  467. dest[2] = v[2] * s;
  468. return dest;
  469. },
  470.  
  471. /**
  472. * Multiplies each element of a two-element vector by a scalar.
  473. * @method mulVec2Scalar
  474. * @static
  475. * @param {Array(Number)} v The vector
  476. * @param {Number} s The scalar
  477. * @param {Array(Number)} [dest] Destination vector
  478. * @return {Array(Number)} dest if specified, v otherwise
  479. */
  480. mulVec2Scalar(v, s, dest) {
  481. if (!dest) {
  482. dest = v;
  483. }
  484. dest[0] = v[0] * s;
  485. dest[1] = v[1] * s;
  486. return dest;
  487. },
  488.  
  489. /**
  490. * Divides one three-element vector by another.
  491. * @method divVec3
  492. * @static
  493. * @param {Array(Number)} u First vector
  494. * @param {Array(Number)} v Second vector
  495. * @param {Array(Number)} [dest] Destination vector
  496. * @return {Array(Number)} dest if specified, u otherwise
  497. */
  498. divVec3(u, v, dest) {
  499. if (!dest) {
  500. dest = u;
  501. }
  502. dest[0] = u[0] / v[0];
  503. dest[1] = u[1] / v[1];
  504. dest[2] = u[2] / v[2];
  505. return dest;
  506. },
  507.  
  508. /**
  509. * Divides one four-element vector by another.
  510. * @method divVec4
  511. * @static
  512. * @param {Array(Number)} u First vector
  513. * @param {Array(Number)} v Second vector
  514. * @param {Array(Number)} [dest] Destination vector
  515. * @return {Array(Number)} dest if specified, u otherwise
  516. */
  517. divVec4(u, v, dest) {
  518. if (!dest) {
  519. dest = u;
  520. }
  521. dest[0] = u[0] / v[0];
  522. dest[1] = u[1] / v[1];
  523. dest[2] = u[2] / v[2];
  524. dest[3] = u[3] / v[3];
  525. return dest;
  526. },
  527.  
  528. /**
  529. * Divides a scalar by a three-element vector, returning a new vector.
  530. * @method divScalarVec3
  531. * @static
  532. * @param v vec3
  533. * @param s scalar
  534. * @param dest vec3 - optional destination
  535. * @return [] dest if specified, v otherwise
  536. */
  537. divScalarVec3(s, v, dest) {
  538. if (!dest) {
  539. dest = v;
  540. }
  541. dest[0] = s / v[0];
  542. dest[1] = s / v[1];
  543. dest[2] = s / v[2];
  544. return dest;
  545. },
  546.  
  547. /**
  548. * Divides a three-element vector by a scalar.
  549. * @method divVec3Scalar
  550. * @static
  551. * @param v vec3
  552. * @param s scalar
  553. * @param dest vec3 - optional destination
  554. * @return [] dest if specified, v otherwise
  555. */
  556. divVec3Scalar(v, s, dest) {
  557. if (!dest) {
  558. dest = v;
  559. }
  560. dest[0] = v[0] / s;
  561. dest[1] = v[1] / s;
  562. dest[2] = v[2] / s;
  563. return dest;
  564. },
  565.  
  566. /**
  567. * Divides a four-element vector by a scalar.
  568. * @method divVec4Scalar
  569. * @static
  570. * @param v vec4
  571. * @param s scalar
  572. * @param dest vec4 - optional destination
  573. * @return [] dest if specified, v otherwise
  574. */
  575. divVec4Scalar(v, s, dest) {
  576. if (!dest) {
  577. dest = v;
  578. }
  579. dest[0] = v[0] / s;
  580. dest[1] = v[1] / s;
  581. dest[2] = v[2] / s;
  582. dest[3] = v[3] / s;
  583. return dest;
  584. },
  585.  
  586.  
  587. /**
  588. * Divides a scalar by a four-element vector, returning a new vector.
  589. * @method divScalarVec4
  590. * @static
  591. * @param s scalar
  592. * @param v vec4
  593. * @param dest vec4 - optional destination
  594. * @return [] dest if specified, v otherwise
  595. */
  596. divScalarVec4(s, v, dest) {
  597. if (!dest) {
  598. dest = v;
  599. }
  600. dest[0] = s / v[0];
  601. dest[1] = s / v[1];
  602. dest[2] = s / v[2];
  603. dest[3] = s / v[3];
  604. return dest;
  605. },
  606.  
  607. /**
  608. * Returns the dot product of two four-element vectors.
  609. * @method dotVec4
  610. * @static
  611. * @param {Array(Number)} u First vector
  612. * @param {Array(Number)} v Second vector
  613. * @return The dot product
  614. */
  615. dotVec4(u, v) {
  616. return (u[0] * v[0] + u[1] * v[1] + u[2] * v[2] + u[3] * v[3]);
  617. },
  618.  
  619. /**
  620. * Returns the cross product of two four-element vectors.
  621. * @method cross3Vec4
  622. * @static
  623. * @param {Array(Number)} u First vector
  624. * @param {Array(Number)} v Second vector
  625. * @return The cross product
  626. */
  627. cross3Vec4(u, v) {
  628. const u0 = u[0];
  629. const u1 = u[1];
  630. const u2 = u[2];
  631. const v0 = v[0];
  632. const v1 = v[1];
  633. const v2 = v[2];
  634. return [
  635. u1 * v2 - u2 * v1,
  636. u2 * v0 - u0 * v2,
  637. u0 * v1 - u1 * v0,
  638. 0.0];
  639. },
  640.  
  641. /**
  642. * Returns the cross product of two three-element vectors.
  643. * @method cross3Vec3
  644. * @static
  645. * @param {Array(Number)} u First vector
  646. * @param {Array(Number)} v Second vector
  647. * @return The cross product
  648. */
  649. cross3Vec3(u, v, dest) {
  650. if (!dest) {
  651. dest = u;
  652. }
  653. const x = u[0];
  654. const y = u[1];
  655. const z = u[2];
  656. const x2 = v[0];
  657. const y2 = v[1];
  658. const z2 = v[2];
  659. dest[0] = y * z2 - z * y2;
  660. dest[1] = z * x2 - x * z2;
  661. dest[2] = x * y2 - y * x2;
  662. return dest;
  663. },
  664.  
  665.  
  666. sqLenVec4(v) { // TODO
  667. return math.dotVec4(v, v);
  668. },
  669.  
  670. /**
  671. * Returns the length of a four-element vector.
  672. * @method lenVec4
  673. * @static
  674. * @param {Array(Number)} v The vector
  675. * @return The length
  676. */
  677. lenVec4(v) {
  678. return Math.sqrt(math.sqLenVec4(v));
  679. },
  680.  
  681. /**
  682. * Returns the dot product of two three-element vectors.
  683. * @method dotVec3
  684. * @static
  685. * @param {Array(Number)} u First vector
  686. * @param {Array(Number)} v Second vector
  687. * @return The dot product
  688. */
  689. dotVec3(u, v) {
  690. return (u[0] * v[0] + u[1] * v[1] + u[2] * v[2]);
  691. },
  692.  
  693. /**
  694. * Returns the dot product of two two-element vectors.
  695. * @method dotVec4
  696. * @static
  697. * @param {Array(Number)} u First vector
  698. * @param {Array(Number)} v Second vector
  699. * @return The dot product
  700. */
  701. dotVec2(u, v) {
  702. return (u[0] * v[0] + u[1] * v[1]);
  703. },
  704.  
  705.  
  706. sqLenVec3(v) {
  707. return math.dotVec3(v, v);
  708. },
  709.  
  710.  
  711. sqLenVec2(v) {
  712. return math.dotVec2(v, v);
  713. },
  714.  
  715. /**
  716. * Returns the length of a three-element vector.
  717. * @method lenVec3
  718. * @static
  719. * @param {Array(Number)} v The vector
  720. * @return The length
  721. */
  722. lenVec3(v) {
  723. return Math.sqrt(math.sqLenVec3(v));
  724. },
  725.  
  726. distVec3: ((() => {
  727. const vec = new Float32Array(3);
  728. return (v, w) => math.lenVec3(math.subVec3(v, w, vec));
  729. }))(),
  730.  
  731. /**
  732. * Returns the length of a two-element vector.
  733. * @method lenVec2
  734. * @static
  735. * @param {Array(Number)} v The vector
  736. * @return The length
  737. */
  738. lenVec2(v) {
  739. return Math.sqrt(math.sqLenVec2(v));
  740. },
  741.  
  742. distVec2: ((() => {
  743. const vec = new Float32Array(2);
  744. return (v, w) => math.lenVec2(math.subVec2(v, w, vec));
  745. }))(),
  746.  
  747. /**
  748. * @method rcpVec3
  749. * @static
  750. * @param v vec3
  751. * @param dest vec3 - optional destination
  752. * @return [] dest if specified, v otherwise
  753. *
  754. */
  755. rcpVec3(v, dest) {
  756. return math.divScalarVec3(1.0, v, dest);
  757. },
  758.  
  759. /**
  760. * Normalizes a four-element vector
  761. * @method normalizeVec4
  762. * @static
  763. * @param v vec4
  764. * @param dest vec4 - optional destination
  765. * @return [] dest if specified, v otherwise
  766. *
  767. */
  768. normalizeVec4(v, dest) {
  769. const f = 1.0 / math.lenVec4(v);
  770. return math.mulVec4Scalar(v, f, dest);
  771. },
  772.  
  773. /**
  774. * Normalizes a three-element vector
  775. * @method normalizeVec4
  776. * @static
  777. */
  778. normalizeVec3(v, dest) {
  779. const f = 1.0 / math.lenVec3(v);
  780. return math.mulVec3Scalar(v, f, dest);
  781. },
  782.  
  783. /**
  784. * Normalizes a two-element vector
  785. * @method normalizeVec2
  786. * @static
  787. */
  788. normalizeVec2(v, dest) {
  789. const f = 1.0 / math.lenVec2(v);
  790. return math.mulVec2Scalar(v, f, dest);
  791. },
  792.  
  793. /**
  794. * Gets the angle between two vectors
  795. * @method angleVec3
  796. * @param v
  797. * @param w
  798. * @returns {number}
  799. */
  800. angleVec3(v, w) {
  801. let theta = math.dotVec3(v, w) / ( Math.sqrt(math.sqLenVec3(v) * math.sqLenVec3(w)) );
  802. theta = theta < -1 ? -1 : (theta > 1 ? 1 : theta); // Clamp to handle numerical problems
  803. return Math.acos(theta);
  804. },
  805.  
  806. /**
  807. * Creates a three-element vector from the rotation part of a sixteen-element matrix.
  808. * @param m
  809. * @param dest
  810. */
  811. vec3FromMat4Scale: ((() => {
  812.  
  813. const tempVec3 = new Float32Array(3);
  814.  
  815. return (m, dest) => {
  816.  
  817. tempVec3[0] = m[0];
  818. tempVec3[1] = m[1];
  819. tempVec3[2] = m[2];
  820.  
  821. dest[0] = math.lenVec3(tempVec3);
  822.  
  823. tempVec3[0] = m[4];
  824. tempVec3[1] = m[5];
  825. tempVec3[2] = m[6];
  826.  
  827. dest[1] = math.lenVec3(tempVec3);
  828.  
  829. tempVec3[0] = m[8];
  830. tempVec3[1] = m[9];
  831. tempVec3[2] = m[10];
  832.  
  833. dest[2] = math.lenVec3(tempVec3);
  834.  
  835. return dest;
  836. };
  837. }))(),
  838.  
  839. /**
  840. * Converts an n-element vector to a JSON-serializable
  841. * array with values rounded to two decimal places.
  842. */
  843. vecToArray: ((() => {
  844. function trunc(v) {
  845. return Math.round(v * 100000) / 100000
  846. }
  847.  
  848. return v => {
  849. v = Array.prototype.slice.call(v);
  850. for (let i = 0, len = v.length; i < len; i++) {
  851. v[i] = trunc(v[i]);
  852. }
  853. return v;
  854. };
  855. }))(),
  856.  
  857. /**
  858. * Duplicates a 4x4 identity matrix.
  859. * @method dupMat4
  860. * @static
  861. */
  862. dupMat4(m) {
  863. return m.slice(0, 16);
  864. },
  865.  
  866. /**
  867. * Extracts a 3x3 matrix from a 4x4 matrix.
  868. * @method mat4To3
  869. * @static
  870. */
  871. mat4To3(m) {
  872. return [
  873. m[0], m[1], m[2],
  874. m[4], m[5], m[6],
  875. m[8], m[9], m[10]
  876. ];
  877. },
  878.  
  879. /**
  880. * Returns a 4x4 matrix with each element set to the given scalar value.
  881. * @method m4s
  882. * @static
  883. */
  884. m4s(s) {
  885. return [
  886. s, s, s, s,
  887. s, s, s, s,
  888. s, s, s, s,
  889. s, s, s, s
  890. ];
  891. },
  892.  
  893. /**
  894. * Returns a 4x4 matrix with each element set to zero.
  895. * @method setMat4ToZeroes
  896. * @static
  897. */
  898. setMat4ToZeroes() {
  899. return math.m4s(0.0);
  900. },
  901.  
  902. /**
  903. * Returns a 4x4 matrix with each element set to 1.0.
  904. * @method setMat4ToOnes
  905. * @static
  906. */
  907. setMat4ToOnes() {
  908. return math.m4s(1.0);
  909. },
  910.  
  911. /**
  912. * Returns a 4x4 matrix with each element set to 1.0.
  913. * @method setMat4ToOnes
  914. * @static
  915. */
  916. diagonalMat4v(v) {
  917. return new Float32Array([
  918. v[0], 0.0, 0.0, 0.0,
  919. 0.0, v[1], 0.0, 0.0,
  920. 0.0, 0.0, v[2], 0.0,
  921. 0.0, 0.0, 0.0, v[3]
  922. ]);
  923. },
  924.  
  925. /**
  926. * Returns a 4x4 matrix with diagonal elements set to the given vector.
  927. * @method diagonalMat4c
  928. * @static
  929. */
  930. diagonalMat4c(x, y, z, w) {
  931. return math.diagonalMat4v([x, y, z, w]);
  932. },
  933.  
  934. /**
  935. * Returns a 4x4 matrix with diagonal elements set to the given scalar.
  936. * @method diagonalMat4s
  937. * @static
  938. */
  939. diagonalMat4s(s) {
  940. return math.diagonalMat4c(s, s, s, s);
  941. },
  942.  
  943. /**
  944. * Returns a 4x4 identity matrix.
  945. * @method identityMat4
  946. * @static
  947. */
  948. identityMat4(mat = new Float32Array(16)) {
  949. mat[0] = 1.0;
  950. mat[1] = 0.0;
  951. mat[2] = 0.0;
  952. mat[3] = 0.0;
  953.  
  954. mat[4] = 0.0;
  955. mat[5] = 1.0;
  956. mat[6] = 0.0;
  957. mat[7] = 0.0;
  958.  
  959. mat[8] = 0.0;
  960. mat[9] = 0.0;
  961. mat[10] = 1.0;
  962. mat[11] = 0.0;
  963.  
  964. mat[12] = 0.0;
  965. mat[13] = 0.0;
  966. mat[14] = 0.0;
  967. mat[15] = 1.0;
  968.  
  969. return mat;
  970. },
  971.  
  972. /**
  973. * Returns a 3x3 identity matrix.
  974. * @method identityMat3
  975. * @static
  976. */
  977. identityMat3(mat = new Float32Array(9)) {
  978. mat[0] = 1.0;
  979. mat[1] = 0.0;
  980. mat[2] = 0.0;
  981.  
  982. mat[3] = 0.0;
  983. mat[4] = 1.0;
  984. mat[5] = 0.0;
  985.  
  986. mat[6] = 0.0;
  987. mat[7] = 0.0;
  988. mat[8] = 1.0;
  989.  
  990. return mat;
  991. },
  992.  
  993. /**
  994. * Tests if the given 4x4 matrix is the identity matrix.
  995. * @method isIdentityMat4
  996. * @static
  997. */
  998. isIdentityMat4(m) {
  999. if (m[0] !== 1.0 || m[1] !== 0.0 || m[2] !== 0.0 || m[3] !== 0.0 ||
  1000. m[4] !== 0.0 || m[5] !== 1.0 || m[6] !== 0.0 || m[7] !== 0.0 ||
  1001. m[8] !== 0.0 || m[9] !== 0.0 || m[10] !== 1.0 || m[11] !== 0.0 ||
  1002. m[12] !== 0.0 || m[13] !== 0.0 || m[14] !== 0.0 || m[15] !== 1.0) {
  1003. return false;
  1004. }
  1005. return true;
  1006. },
  1007.  
  1008. /**
  1009. * Negates the given 4x4 matrix.
  1010. * @method negateMat4
  1011. * @static
  1012. */
  1013. negateMat4(m, dest) {
  1014. if (!dest) {
  1015. dest = m;
  1016. }
  1017. dest[0] = -m[0];
  1018. dest[1] = -m[1];
  1019. dest[2] = -m[2];
  1020. dest[3] = -m[3];
  1021. dest[4] = -m[4];
  1022. dest[5] = -m[5];
  1023. dest[6] = -m[6];
  1024. dest[7] = -m[7];
  1025. dest[8] = -m[8];
  1026. dest[9] = -m[9];
  1027. dest[10] = -m[10];
  1028. dest[11] = -m[11];
  1029. dest[12] = -m[12];
  1030. dest[13] = -m[13];
  1031. dest[14] = -m[14];
  1032. dest[15] = -m[15];
  1033. return dest;
  1034. },
  1035.  
  1036. /**
  1037. * Adds the given 4x4 matrices together.
  1038. * @method addMat4
  1039. * @static
  1040. */
  1041. addMat4(a, b, dest) {
  1042. if (!dest) {
  1043. dest = a;
  1044. }
  1045. dest[0] = a[0] + b[0];
  1046. dest[1] = a[1] + b[1];
  1047. dest[2] = a[2] + b[2];
  1048. dest[3] = a[3] + b[3];
  1049. dest[4] = a[4] + b[4];
  1050. dest[5] = a[5] + b[5];
  1051. dest[6] = a[6] + b[6];
  1052. dest[7] = a[7] + b[7];
  1053. dest[8] = a[8] + b[8];
  1054. dest[9] = a[9] + b[9];
  1055. dest[10] = a[10] + b[10];
  1056. dest[11] = a[11] + b[11];
  1057. dest[12] = a[12] + b[12];
  1058. dest[13] = a[13] + b[13];
  1059. dest[14] = a[14] + b[14];
  1060. dest[15] = a[15] + b[15];
  1061. return dest;
  1062. },
  1063.  
  1064. /**
  1065. * Adds the given scalar to each element of the given 4x4 matrix.
  1066. * @method addMat4Scalar
  1067. * @static
  1068. */
  1069. addMat4Scalar(m, s, dest) {
  1070. if (!dest) {
  1071. dest = m;
  1072. }
  1073. dest[0] = m[0] + s;
  1074. dest[1] = m[1] + s;
  1075. dest[2] = m[2] + s;
  1076. dest[3] = m[3] + s;
  1077. dest[4] = m[4] + s;
  1078. dest[5] = m[5] + s;
  1079. dest[6] = m[6] + s;
  1080. dest[7] = m[7] + s;
  1081. dest[8] = m[8] + s;
  1082. dest[9] = m[9] + s;
  1083. dest[10] = m[10] + s;
  1084. dest[11] = m[11] + s;
  1085. dest[12] = m[12] + s;
  1086. dest[13] = m[13] + s;
  1087. dest[14] = m[14] + s;
  1088. dest[15] = m[15] + s;
  1089. return dest;
  1090. },
  1091.  
  1092. /**
  1093. * Adds the given scalar to each element of the given 4x4 matrix.
  1094. * @method addScalarMat4
  1095. * @static
  1096. */
  1097. addScalarMat4(s, m, dest) {
  1098. return math.addMat4Scalar(m, s, dest);
  1099. },
  1100.  
  1101. /**
  1102. * Subtracts the second 4x4 matrix from the first.
  1103. * @method subMat4
  1104. * @static
  1105. */
  1106. subMat4(a, b, dest) {
  1107. if (!dest) {
  1108. dest = a;
  1109. }
  1110. dest[0] = a[0] - b[0];
  1111. dest[1] = a[1] - b[1];
  1112. dest[2] = a[2] - b[2];
  1113. dest[3] = a[3] - b[3];
  1114. dest[4] = a[4] - b[4];
  1115. dest[5] = a[5] - b[5];
  1116. dest[6] = a[6] - b[6];
  1117. dest[7] = a[7] - b[7];
  1118. dest[8] = a[8] - b[8];
  1119. dest[9] = a[9] - b[9];
  1120. dest[10] = a[10] - b[10];
  1121. dest[11] = a[11] - b[11];
  1122. dest[12] = a[12] - b[12];
  1123. dest[13] = a[13] - b[13];
  1124. dest[14] = a[14] - b[14];
  1125. dest[15] = a[15] - b[15];
  1126. return dest;
  1127. },
  1128.  
  1129. /**
  1130. * Subtracts the given scalar from each element of the given 4x4 matrix.
  1131. * @method subMat4Scalar
  1132. * @static
  1133. */
  1134. subMat4Scalar(m, s, dest) {
  1135. if (!dest) {
  1136. dest = m;
  1137. }
  1138. dest[0] = m[0] - s;
  1139. dest[1] = m[1] - s;
  1140. dest[2] = m[2] - s;
  1141. dest[3] = m[3] - s;
  1142. dest[4] = m[4] - s;
  1143. dest[5] = m[5] - s;
  1144. dest[6] = m[6] - s;
  1145. dest[7] = m[7] - s;
  1146. dest[8] = m[8] - s;
  1147. dest[9] = m[9] - s;
  1148. dest[10] = m[10] - s;
  1149. dest[11] = m[11] - s;
  1150. dest[12] = m[12] - s;
  1151. dest[13] = m[13] - s;
  1152. dest[14] = m[14] - s;
  1153. dest[15] = m[15] - s;
  1154. return dest;
  1155. },
  1156.  
  1157. /**
  1158. * Subtracts the given scalar from each element of the given 4x4 matrix.
  1159. * @method subScalarMat4
  1160. * @static
  1161. */
  1162. subScalarMat4(s, m, dest) {
  1163. if (!dest) {
  1164. dest = m;
  1165. }
  1166. dest[0] = s - m[0];
  1167. dest[1] = s - m[1];
  1168. dest[2] = s - m[2];
  1169. dest[3] = s - m[3];
  1170. dest[4] = s - m[4];
  1171. dest[5] = s - m[5];
  1172. dest[6] = s - m[6];
  1173. dest[7] = s - m[7];
  1174. dest[8] = s - m[8];
  1175. dest[9] = s - m[9];
  1176. dest[10] = s - m[10];
  1177. dest[11] = s - m[11];
  1178. dest[12] = s - m[12];
  1179. dest[13] = s - m[13];
  1180. dest[14] = s - m[14];
  1181. dest[15] = s - m[15];
  1182. return dest;
  1183. },
  1184.  
  1185. /**
  1186. * Multiplies the two given 4x4 matrix by each other.
  1187. * @method mulMat4
  1188. * @static
  1189. */
  1190. mulMat4(a, b, dest) {
  1191. if (!dest) {
  1192. dest = a;
  1193. }
  1194.  
  1195. // Cache the matrix values (makes for huge speed increases!)
  1196. const a00 = a[0];
  1197.  
  1198. const a01 = a[1];
  1199. const a02 = a[2];
  1200. const a03 = a[3];
  1201. const a10 = a[4];
  1202. const a11 = a[5];
  1203. const a12 = a[6];
  1204. const a13 = a[7];
  1205. const a20 = a[8];
  1206. const a21 = a[9];
  1207. const a22 = a[10];
  1208. const a23 = a[11];
  1209. const a30 = a[12];
  1210. const a31 = a[13];
  1211. const a32 = a[14];
  1212. const a33 = a[15];
  1213. const b00 = b[0];
  1214. const b01 = b[1];
  1215. const b02 = b[2];
  1216. const b03 = b[3];
  1217. const b10 = b[4];
  1218. const b11 = b[5];
  1219. const b12 = b[6];
  1220. const b13 = b[7];
  1221. const b20 = b[8];
  1222. const b21 = b[9];
  1223. const b22 = b[10];
  1224. const b23 = b[11];
  1225. const b30 = b[12];
  1226. const b31 = b[13];
  1227. const b32 = b[14];
  1228. const b33 = b[15];
  1229.  
  1230. dest[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30;
  1231. dest[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31;
  1232. dest[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32;
  1233. dest[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33;
  1234. dest[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30;
  1235. dest[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31;
  1236. dest[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32;
  1237. dest[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33;
  1238. dest[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30;
  1239. dest[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31;
  1240. dest[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32;
  1241. dest[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33;
  1242. dest[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30;
  1243. dest[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31;
  1244. dest[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32;
  1245. dest[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33;
  1246.  
  1247. return dest;
  1248. },
  1249.  
  1250. /**
  1251. * Multiplies the two given 3x3 matrices by each other.
  1252. * @method mulMat4
  1253. * @static
  1254. */
  1255. mulMat3(a, b, dest) {
  1256. if (!dest) {
  1257. dest = new Float32Array(9);
  1258. }
  1259.  
  1260. const a11 = a[0];
  1261. const a12 = a[3];
  1262. const a13 = a[6];
  1263. const a21 = a[1];
  1264. const a22 = a[4];
  1265. const a23 = a[7];
  1266. const a31 = a[2];
  1267. const a32 = a[5];
  1268. const a33 = a[8];
  1269. const b11 = b[0];
  1270. const b12 = b[3];
  1271. const b13 = b[6];
  1272. const b21 = b[1];
  1273. const b22 = b[4];
  1274. const b23 = b[7];
  1275. const b31 = b[2];
  1276. const b32 = b[5];
  1277. const b33 = b[8];
  1278.  
  1279. dest[0] = a11 * b11 + a12 * b21 + a13 * b31;
  1280. dest[3] = a11 * b12 + a12 * b22 + a13 * b32;
  1281. dest[6] = a11 * b13 + a12 * b23 + a13 * b33;
  1282.  
  1283. dest[1] = a21 * b11 + a22 * b21 + a23 * b31;
  1284. dest[4] = a21 * b12 + a22 * b22 + a23 * b32;
  1285. dest[7] = a21 * b13 + a22 * b23 + a23 * b33;
  1286.  
  1287. dest[2] = a31 * b11 + a32 * b21 + a33 * b31;
  1288. dest[5] = a31 * b12 + a32 * b22 + a33 * b32;
  1289. dest[8] = a31 * b13 + a32 * b23 + a33 * b33;
  1290.  
  1291. return dest;
  1292. },
  1293.  
  1294. /**
  1295. * Multiplies each element of the given 4x4 matrix by the given scalar.
  1296. * @method mulMat4Scalar
  1297. * @static
  1298. */
  1299. mulMat4Scalar(m, s, dest) {
  1300. if (!dest) {
  1301. dest = m;
  1302. }
  1303. dest[0] = m[0] * s;
  1304. dest[1] = m[1] * s;
  1305. dest[2] = m[2] * s;
  1306. dest[3] = m[3] * s;
  1307. dest[4] = m[4] * s;
  1308. dest[5] = m[5] * s;
  1309. dest[6] = m[6] * s;
  1310. dest[7] = m[7] * s;
  1311. dest[8] = m[8] * s;
  1312. dest[9] = m[9] * s;
  1313. dest[10] = m[10] * s;
  1314. dest[11] = m[11] * s;
  1315. dest[12] = m[12] * s;
  1316. dest[13] = m[13] * s;
  1317. dest[14] = m[14] * s;
  1318. dest[15] = m[15] * s;
  1319. return dest;
  1320. },
  1321.  
  1322. /**
  1323. * Multiplies the given 4x4 matrix by the given four-element vector.
  1324. * @method mulMat4v4
  1325. * @static
  1326. */
  1327. mulMat4v4(m, v, dest = math.vec4()) {
  1328. const v0 = v[0];
  1329. const v1 = v[1];
  1330. const v2 = v[2];
  1331. const v3 = v[3];
  1332. dest[0] = m[0] * v0 + m[4] * v1 + m[8] * v2 + m[12] * v3;
  1333. dest[1] = m[1] * v0 + m[5] * v1 + m[9] * v2 + m[13] * v3;
  1334. dest[2] = m[2] * v0 + m[6] * v1 + m[10] * v2 + m[14] * v3;
  1335. dest[3] = m[3] * v0 + m[7] * v1 + m[11] * v2 + m[15] * v3;
  1336. return dest;
  1337. },
  1338.  
  1339. /**
  1340. * Transposes the given 4x4 matrix.
  1341. * @method transposeMat4
  1342. * @static
  1343. */
  1344. transposeMat4(mat, dest) {
  1345. // If we are transposing ourselves we can skip a few steps but have to cache some values
  1346. const m4 = mat[4];
  1347.  
  1348. const m14 = mat[14];
  1349. const m8 = mat[8];
  1350. const m13 = mat[13];
  1351. const m12 = mat[12];
  1352. const m9 = mat[9];
  1353. if (!dest || mat === dest) {
  1354. const a01 = mat[1];
  1355. const a02 = mat[2];
  1356. const a03 = mat[3];
  1357. const a12 = mat[6];
  1358. const a13 = mat[7];
  1359. const a23 = mat[11];
  1360. mat[1] = m4;
  1361. mat[2] = m8;
  1362. mat[3] = m12;
  1363. mat[4] = a01;
  1364. mat[6] = m9;
  1365. mat[7] = m13;
  1366. mat[8] = a02;
  1367. mat[9] = a12;
  1368. mat[11] = m14;
  1369. mat[12] = a03;
  1370. mat[13] = a13;
  1371. mat[14] = a23;
  1372. return mat;
  1373. }
  1374. dest[0] = mat[0];
  1375. dest[1] = m4;
  1376. dest[2] = m8;
  1377. dest[3] = m12;
  1378. dest[4] = mat[1];
  1379. dest[5] = mat[5];
  1380. dest[6] = m9;
  1381. dest[7] = m13;
  1382. dest[8] = mat[2];
  1383. dest[9] = mat[6];
  1384. dest[10] = mat[10];
  1385. dest[11] = m14;
  1386. dest[12] = mat[3];
  1387. dest[13] = mat[7];
  1388. dest[14] = mat[11];
  1389. dest[15] = mat[15];
  1390. return dest;
  1391. },
  1392.  
  1393. /**
  1394. * Transposes the given 3x3 matrix.
  1395. *
  1396. * @method transposeMat3
  1397. * @static
  1398. */
  1399. transposeMat3(mat, dest) {
  1400. if (dest === mat) {
  1401. const a01 = mat[1];
  1402. const a02 = mat[2];
  1403. const a12 = mat[5];
  1404. dest[1] = mat[3];
  1405. dest[2] = mat[6];
  1406. dest[3] = a01;
  1407. dest[5] = mat[7];
  1408. dest[6] = a02;
  1409. dest[7] = a12;
  1410. } else {
  1411. dest[0] = mat[0];
  1412. dest[1] = mat[3];
  1413. dest[2] = mat[6];
  1414. dest[3] = mat[1];
  1415. dest[4] = mat[4];
  1416. dest[5] = mat[7];
  1417. dest[6] = mat[2];
  1418. dest[7] = mat[5];
  1419. dest[8] = mat[8];
  1420. }
  1421. return dest;
  1422. },
  1423.  
  1424. /**
  1425. * Returns the determinant of the given 4x4 matrix.
  1426. * @method determinantMat4
  1427. * @static
  1428. */
  1429. determinantMat4(mat) {
  1430. // Cache the matrix values (makes for huge speed increases!)
  1431. const a00 = mat[0];
  1432.  
  1433. const a01 = mat[1];
  1434. const a02 = mat[2];
  1435. const a03 = mat[3];
  1436. const a10 = mat[4];
  1437. const a11 = mat[5];
  1438. const a12 = mat[6];
  1439. const a13 = mat[7];
  1440. const a20 = mat[8];
  1441. const a21 = mat[9];
  1442. const a22 = mat[10];
  1443. const a23 = mat[11];
  1444. const a30 = mat[12];
  1445. const a31 = mat[13];
  1446. const a32 = mat[14];
  1447. const a33 = mat[15];
  1448. return a30 * a21 * a12 * a03 - a20 * a31 * a12 * a03 - a30 * a11 * a22 * a03 + a10 * a31 * a22 * a03 +
  1449. a20 * a11 * a32 * a03 - a10 * a21 * a32 * a03 - a30 * a21 * a02 * a13 + a20 * a31 * a02 * a13 +
  1450. a30 * a01 * a22 * a13 - a00 * a31 * a22 * a13 - a20 * a01 * a32 * a13 + a00 * a21 * a32 * a13 +
  1451. a30 * a11 * a02 * a23 - a10 * a31 * a02 * a23 - a30 * a01 * a12 * a23 + a00 * a31 * a12 * a23 +
  1452. a10 * a01 * a32 * a23 - a00 * a11 * a32 * a23 - a20 * a11 * a02 * a33 + a10 * a21 * a02 * a33 +
  1453. a20 * a01 * a12 * a33 - a00 * a21 * a12 * a33 - a10 * a01 * a22 * a33 + a00 * a11 * a22 * a33;
  1454. },
  1455.  
  1456. /**
  1457. * Returns the inverse of the given 4x4 matrix.
  1458. * @method inverseMat4
  1459. * @static
  1460. */
  1461. inverseMat4(mat, dest) {
  1462. if (!dest) {
  1463. dest = mat;
  1464. }
  1465.  
  1466. // Cache the matrix values (makes for huge speed increases!)
  1467. const a00 = mat[0];
  1468.  
  1469. const a01 = mat[1];
  1470. const a02 = mat[2];
  1471. const a03 = mat[3];
  1472. const a10 = mat[4];
  1473. const a11 = mat[5];
  1474. const a12 = mat[6];
  1475. const a13 = mat[7];
  1476. const a20 = mat[8];
  1477. const a21 = mat[9];
  1478. const a22 = mat[10];
  1479. const a23 = mat[11];
  1480. const a30 = mat[12];
  1481. const a31 = mat[13];
  1482. const a32 = mat[14];
  1483. const a33 = mat[15];
  1484. const b00 = a00 * a11 - a01 * a10;
  1485. const b01 = a00 * a12 - a02 * a10;
  1486. const b02 = a00 * a13 - a03 * a10;
  1487. const b03 = a01 * a12 - a02 * a11;
  1488. const b04 = a01 * a13 - a03 * a11;
  1489. const b05 = a02 * a13 - a03 * a12;
  1490. const b06 = a20 * a31 - a21 * a30;
  1491. const b07 = a20 * a32 - a22 * a30;
  1492. const b08 = a20 * a33 - a23 * a30;
  1493. const b09 = a21 * a32 - a22 * a31;
  1494. const b10 = a21 * a33 - a23 * a31;
  1495. const b11 = a22 * a33 - a23 * a32;
  1496.  
  1497. // Calculate the determinant (inlined to avoid double-caching)
  1498. const invDet = 1 / (b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06);
  1499.  
  1500. dest[0] = (a11 * b11 - a12 * b10 + a13 * b09) * invDet;
  1501. dest[1] = (-a01 * b11 + a02 * b10 - a03 * b09) * invDet;
  1502. dest[2] = (a31 * b05 - a32 * b04 + a33 * b03) * invDet;
  1503. dest[3] = (-a21 * b05 + a22 * b04 - a23 * b03) * invDet;
  1504. dest[4] = (-a10 * b11 + a12 * b08 - a13 * b07) * invDet;
  1505. dest[5] = (a00 * b11 - a02 * b08 + a03 * b07) * invDet;
  1506. dest[6] = (-a30 * b05 + a32 * b02 - a33 * b01) * invDet;
  1507. dest[7] = (a20 * b05 - a22 * b02 + a23 * b01) * invDet;
  1508. dest[8] = (a10 * b10 - a11 * b08 + a13 * b06) * invDet;
  1509. dest[9] = (-a00 * b10 + a01 * b08 - a03 * b06) * invDet;
  1510. dest[10] = (a30 * b04 - a31 * b02 + a33 * b00) * invDet;
  1511. dest[11] = (-a20 * b04 + a21 * b02 - a23 * b00) * invDet;
  1512. dest[12] = (-a10 * b09 + a11 * b07 - a12 * b06) * invDet;
  1513. dest[13] = (a00 * b09 - a01 * b07 + a02 * b06) * invDet;
  1514. dest[14] = (-a30 * b03 + a31 * b01 - a32 * b00) * invDet;
  1515. dest[15] = (a20 * b03 - a21 * b01 + a22 * b00) * invDet;
  1516.  
  1517. return dest;
  1518. },
  1519.  
  1520. /**
  1521. * Returns the trace of the given 4x4 matrix.
  1522. * @method traceMat4
  1523. * @static
  1524. */
  1525. traceMat4(m) {
  1526. return (m[0] + m[5] + m[10] + m[15]);
  1527. },
  1528.  
  1529. /**
  1530. * Returns 4x4 translation matrix.
  1531. * @method translationMat4
  1532. * @static
  1533. */
  1534. translationMat4v(v, dest) {
  1535. const m = dest || math.identityMat4();
  1536. m[12] = v[0];
  1537. m[13] = v[1];
  1538. m[14] = v[2];
  1539. return m;
  1540. },
  1541.  
  1542. /**
  1543. * Returns 3x3 translation matrix.
  1544. * @method translationMat3
  1545. * @static
  1546. */
  1547. translationMat3v(v, dest) {
  1548. const m = dest || math.identityMat3();
  1549. m[6] = v[0];
  1550. m[7] = v[1];
  1551. return m;
  1552. },
  1553.  
  1554. /**
  1555. * Returns 4x4 translation matrix.
  1556. * @method translationMat4c
  1557. * @static
  1558. */
  1559. translationMat4c: ((() => {
  1560. const xyz = new Float32Array(3);
  1561. return (x, y, z, dest) => {
  1562. xyz[0] = x;
  1563. xyz[1] = y;
  1564. xyz[2] = z;
  1565. return math.translationMat4v(xyz, dest);
  1566. };
  1567. }))(),
  1568.  
  1569. /**
  1570. * Returns 4x4 translation matrix.
  1571. * @method translationMat4s
  1572. * @static
  1573. */
  1574. translationMat4s(s, dest) {
  1575. return math.translationMat4c(s, s, s, dest);
  1576. },
  1577.  
  1578. /**
  1579. * Efficiently post-concatenates a translation to the given matrix.
  1580. * @param v
  1581. * @param m
  1582. */
  1583. translateMat4v(xyz, m) {
  1584. return math.translateMat4c(xyz[0], xyz[1], xyz[2], m);
  1585. },
  1586.  
  1587. /**
  1588. * Efficiently post-concatenates a translation to the given matrix.
  1589. * @param x
  1590. * @param y
  1591. * @param z
  1592. * @param m
  1593. */
  1594. OLDtranslateMat4c(x, y, z, m) {
  1595.  
  1596. const m12 = m[12];
  1597. m[0] += m12 * x;
  1598. m[4] += m12 * y;
  1599. m[8] += m12 * z;
  1600.  
  1601. const m13 = m[13];
  1602. m[1] += m13 * x;
  1603. m[5] += m13 * y;
  1604. m[9] += m13 * z;
  1605.  
  1606. const m14 = m[14];
  1607. m[2] += m14 * x;
  1608. m[6] += m14 * y;
  1609. m[10] += m14 * z;
  1610.  
  1611. const m15 = m[15];
  1612. m[3] += m15 * x;
  1613. m[7] += m15 * y;
  1614. m[11] += m15 * z;
  1615.  
  1616. return m;
  1617. },
  1618.  
  1619. translateMat4c(x, y, z, m) {
  1620.  
  1621. const m3 = m[3];
  1622. m[0] += m3 * x;
  1623. m[1] += m3 * y;
  1624. m[2] += m3 * z;
  1625.  
  1626. const m7 = m[7];
  1627. m[4] += m7 * x;
  1628. m[5] += m7 * y;
  1629. m[6] += m7 * z;
  1630.  
  1631. const m11 = m[11];
  1632. m[8] += m11 * x;
  1633. m[9] += m11 * y;
  1634. m[10] += m11 * z;
  1635.  
  1636. const m15 = m[15];
  1637. m[12] += m15 * x;
  1638. m[13] += m15 * y;
  1639. m[14] += m15 * z;
  1640.  
  1641. return m;
  1642. },
  1643. /**
  1644. * Returns 4x4 rotation matrix.
  1645. * @method rotationMat4v
  1646. * @static
  1647. */
  1648. rotationMat4v(anglerad, axis, m) {
  1649. const ax = math.normalizeVec4([axis[0], axis[1], axis[2], 0.0], []);
  1650. const s = Math.sin(anglerad);
  1651. const c = Math.cos(anglerad);
  1652. const q = 1.0 - c;
  1653.  
  1654. const x = ax[0];
  1655. const y = ax[1];
  1656. const z = ax[2];
  1657.  
  1658. let xy;
  1659. let yz;
  1660. let zx;
  1661. let xs;
  1662. let ys;
  1663. let zs;
  1664.  
  1665. //xx = x * x; used once
  1666. //yy = y * y; used once
  1667. //zz = z * z; used once
  1668. xy = x * y;
  1669. yz = y * z;
  1670. zx = z * x;
  1671. xs = x * s;
  1672. ys = y * s;
  1673. zs = z * s;
  1674.  
  1675. m = m || math.mat4();
  1676.  
  1677. m[0] = (q * x * x) + c;
  1678. m[1] = (q * xy) + zs;
  1679. m[2] = (q * zx) - ys;
  1680. m[3] = 0.0;
  1681.  
  1682. m[4] = (q * xy) - zs;
  1683. m[5] = (q * y * y) + c;
  1684. m[6] = (q * yz) + xs;
  1685. m[7] = 0.0;
  1686.  
  1687. m[8] = (q * zx) + ys;
  1688. m[9] = (q * yz) - xs;
  1689. m[10] = (q * z * z) + c;
  1690. m[11] = 0.0;
  1691.  
  1692. m[12] = 0.0;
  1693. m[13] = 0.0;
  1694. m[14] = 0.0;
  1695. m[15] = 1.0;
  1696.  
  1697. return m;
  1698. },
  1699.  
  1700. /**
  1701. * Returns 4x4 rotation matrix.
  1702. * @method rotationMat4c
  1703. * @static
  1704. */
  1705. rotationMat4c(anglerad, x, y, z, mat) {
  1706. return math.rotationMat4v(anglerad, [x, y, z], mat);
  1707. },
  1708.  
  1709. /**
  1710. * Returns 4x4 scale matrix.
  1711. * @method scalingMat4v
  1712. * @static
  1713. */
  1714. scalingMat4v(v, m = math.identityMat4()) {
  1715. m[0] = v[0];
  1716. m[5] = v[1];
  1717. m[10] = v[2];
  1718. return m;
  1719. },
  1720.  
  1721. /**
  1722. * Returns 3x3 scale matrix.
  1723. * @method scalingMat3v
  1724. * @static
  1725. */
  1726. scalingMat3v(v, m = math.identityMat3()) {
  1727. m[0] = v[0];
  1728. m[4] = v[1];
  1729. return m;
  1730. },
  1731.  
  1732. /**
  1733. * Returns 4x4 scale matrix.
  1734. * @method scalingMat4c
  1735. * @static
  1736. */
  1737. scalingMat4c: ((() => {
  1738. const xyz = new Float32Array(3);
  1739. return (x, y, z, dest) => {
  1740. xyz[0] = x;
  1741. xyz[1] = y;
  1742. xyz[2] = z;
  1743. return math.scalingMat4v(xyz, dest);
  1744. };
  1745. }))(),
  1746.  
  1747. /**
  1748. * Efficiently post-concatenates a scaling to the given matrix.
  1749. * @method scaleMat4c
  1750. * @param x
  1751. * @param y
  1752. * @param z
  1753. * @param m
  1754. */
  1755. scaleMat4c(x, y, z, m) {
  1756.  
  1757. m[0] *= x;
  1758. m[4] *= y;
  1759. m[8] *= z;
  1760.  
  1761. m[1] *= x;
  1762. m[5] *= y;
  1763. m[9] *= z;
  1764.  
  1765. m[2] *= x;
  1766. m[6] *= y;
  1767. m[10] *= z;
  1768.  
  1769. m[3] *= x;
  1770. m[7] *= y;
  1771. m[11] *= z;
  1772. return m;
  1773. },
  1774.  
  1775. /**
  1776. * Efficiently post-concatenates a scaling to the given matrix.
  1777. * @method scaleMat4c
  1778. * @param xyz
  1779. * @param m
  1780. */
  1781. scaleMat4v(xyz, m) {
  1782.  
  1783. const x = xyz[0];
  1784. const y = xyz[1];
  1785. const z = xyz[2];
  1786.  
  1787. m[0] *= x;
  1788. m[4] *= y;
  1789. m[8] *= z;
  1790. m[1] *= x;
  1791. m[5] *= y;
  1792. m[9] *= z;
  1793. m[2] *= x;
  1794. m[6] *= y;
  1795. m[10] *= z;
  1796. m[3] *= x;
  1797. m[7] *= y;
  1798. m[11] *= z;
  1799.  
  1800. return m;
  1801. },
  1802.  
  1803. /**
  1804. * Returns 4x4 scale matrix.
  1805. * @method scalingMat4s
  1806. * @static
  1807. */
  1808. scalingMat4s(s) {
  1809. return math.scalingMat4c(s, s, s);
  1810. },
  1811.  
  1812. /**
  1813. * Creates a matrix from a quaternion rotation and vector translation
  1814. *
  1815. * @param {Float32Array} q Rotation quaternion
  1816. * @param {Float32Array} v Translation vector
  1817. * @param {Float32Array} dest Destination matrix
  1818. * @returns {Float32Array} dest
  1819. */
  1820. rotationTranslationMat4(q, v, dest = math.mat4()) {
  1821. const x = q[0];
  1822. const y = q[1];
  1823. const z = q[2];
  1824. const w = q[3];
  1825.  
  1826. const x2 = x + x;
  1827. const y2 = y + y;
  1828. const z2 = z + z;
  1829. const xx = x * x2;
  1830. const xy = x * y2;
  1831. const xz = x * z2;
  1832. const yy = y * y2;
  1833. const yz = y * z2;
  1834. const zz = z * z2;
  1835. const wx = w * x2;
  1836. const wy = w * y2;
  1837. const wz = w * z2;
  1838.  
  1839. dest[0] = 1 - (yy + zz);
  1840. dest[1] = xy + wz;
  1841. dest[2] = xz - wy;
  1842. dest[3] = 0;
  1843. dest[4] = xy - wz;
  1844. dest[5] = 1 - (xx + zz);
  1845. dest[6] = yz + wx;
  1846. dest[7] = 0;
  1847. dest[8] = xz + wy;
  1848. dest[9] = yz - wx;
  1849. dest[10] = 1 - (xx + yy);
  1850. dest[11] = 0;
  1851. dest[12] = v[0];
  1852. dest[13] = v[1];
  1853. dest[14] = v[2];
  1854. dest[15] = 1;
  1855.  
  1856. return dest;
  1857. },
  1858.  
  1859. /**
  1860. * Gets Euler angles from a 4x4 matrix.
  1861. *
  1862. * @param {Float32Array} mat The 4x4 matrix.
  1863. * @param {String} order Desired Euler angle order: "XYZ", "YXZ", "ZXY" etc.
  1864. * @param {Float32Array} [dest] Destination Euler angles, created by default.
  1865. * @returns {Float32Array} The Euler angles.
  1866. */
  1867. mat4ToEuler(mat, order, dest = math.vec4()) {
  1868. const clamp = math.clamp;
  1869.  
  1870. // Assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
  1871.  
  1872. const m11 = mat[0];
  1873.  
  1874. const m12 = mat[4];
  1875. const m13 = mat[8];
  1876. const m21 = mat[1];
  1877. const m22 = mat[5];
  1878. const m23 = mat[9];
  1879. const m31 = mat[2];
  1880. const m32 = mat[6];
  1881. const m33 = mat[10];
  1882.  
  1883. if (order === 'XYZ') {
  1884.  
  1885. dest[1] = Math.asin(clamp(m13, -1, 1));
  1886.  
  1887. if (Math.abs(m13) < 0.99999) {
  1888. dest[0] = Math.atan2(-m23, m33);
  1889. dest[2] = Math.atan2(-m12, m11);
  1890. } else {
  1891. dest[0] = Math.atan2(m32, m22);
  1892. dest[2] = 0;
  1893.  
  1894. }
  1895.  
  1896. } else if (order === 'YXZ') {
  1897.  
  1898. dest[0] = Math.asin(-clamp(m23, -1, 1));
  1899.  
  1900. if (Math.abs(m23) < 0.99999) {
  1901. dest[1] = Math.atan2(m13, m33);
  1902. dest[2] = Math.atan2(m21, m22);
  1903. } else {
  1904. dest[1] = Math.atan2(-m31, m11);
  1905. dest[2] = 0;
  1906. }
  1907.  
  1908. } else if (order === 'ZXY') {
  1909.  
  1910. dest[0] = Math.asin(clamp(m32, -1, 1));
  1911.  
  1912. if (Math.abs(m32) < 0.99999) {
  1913. dest[1] = Math.atan2(-m31, m33);
  1914. dest[2] = Math.atan2(-m12, m22);
  1915. } else {
  1916. dest[1] = 0;
  1917. dest[2] = Math.atan2(m21, m11);
  1918. }
  1919.  
  1920. } else if (order === 'ZYX') {
  1921.  
  1922. dest[1] = Math.asin(-clamp(m31, -1, 1));
  1923.  
  1924. if (Math.abs(m31) < 0.99999) {
  1925. dest[0] = Math.atan2(m32, m33);
  1926. dest[2] = Math.atan2(m21, m11);
  1927. } else {
  1928. dest[0] = 0;
  1929. dest[2] = Math.atan2(-m12, m22);
  1930. }
  1931.  
  1932. } else if (order === 'YZX') {
  1933.  
  1934. dest[2] = Math.asin(clamp(m21, -1, 1));
  1935.  
  1936. if (Math.abs(m21) < 0.99999) {
  1937. dest[0] = Math.atan2(-m23, m22);
  1938. dest[1] = Math.atan2(-m31, m11);
  1939. } else {
  1940. dest[0] = 0;
  1941. dest[1] = Math.atan2(m13, m33);
  1942. }
  1943.  
  1944. } else if (order === 'XZY') {
  1945.  
  1946. dest[2] = Math.asin(-clamp(m12, -1, 1));
  1947.  
  1948. if (Math.abs(m12) < 0.99999) {
  1949. dest[0] = Math.atan2(m32, m22);
  1950. dest[1] = Math.atan2(m13, m11);
  1951. } else {
  1952. dest[0] = Math.atan2(-m23, m33);
  1953. dest[1] = 0;
  1954. }
  1955. }
  1956.  
  1957. return dest;
  1958. },
  1959.  
  1960. composeMat4(position, quaternion, scale, mat = math.mat4()) {
  1961. math.quaternionToRotationMat4(quaternion, mat);
  1962. math.scaleMat4v(scale, mat);
  1963. math.translateMat4v(position, mat);
  1964.  
  1965. return mat;
  1966. },
  1967.  
  1968. decomposeMat4: (() => {
  1969.  
  1970. const vec = new Float32Array(3);
  1971. const matrix = new Float32Array(16);
  1972.  
  1973. return function decompose(mat, position, quaternion, scale) {
  1974.  
  1975. vec[0] = mat[0];
  1976. vec[1] = mat[1];
  1977. vec[2] = mat[2];
  1978.  
  1979. let sx = math.lenVec3(vec);
  1980.  
  1981. vec[0] = mat[4];
  1982. vec[1] = mat[5];
  1983. vec[2] = mat[6];
  1984.  
  1985. const sy = math.lenVec3(vec);
  1986.  
  1987. vec[8] = mat[8];
  1988. vec[9] = mat[9];
  1989. vec[10] = mat[10];
  1990.  
  1991. const sz = math.lenVec3(vec);
  1992.  
  1993. // if determine is negative, we need to invert one scale
  1994. const det = math.determinantMat4(mat);
  1995.  
  1996. if (det < 0) {
  1997. sx = -sx;
  1998. }
  1999.  
  2000. position[0] = mat[12];
  2001. position[1] = mat[13];
  2002. position[2] = mat[14];
  2003.  
  2004. // scale the rotation part
  2005. matrix.set(mat);
  2006.  
  2007. const invSX = 1 / sx;
  2008. const invSY = 1 / sy;
  2009. const invSZ = 1 / sz;
  2010.  
  2011. matrix[0] *= invSX;
  2012. matrix[1] *= invSX;
  2013. matrix[2] *= invSX;
  2014.  
  2015. matrix[4] *= invSY;
  2016. matrix[5] *= invSY;
  2017. matrix[6] *= invSY;
  2018.  
  2019. matrix[8] *= invSZ;
  2020. matrix[9] *= invSZ;
  2021. matrix[10] *= invSZ;
  2022.  
  2023. math.mat4ToQuaternion(matrix, quaternion);
  2024.  
  2025. scale[0] = sx;
  2026. scale[1] = sy;
  2027. scale[2] = sz;
  2028.  
  2029. return this;
  2030.  
  2031. };
  2032.  
  2033. })(),
  2034.  
  2035. /**
  2036. * Returns a 4x4 'lookat' viewing transform matrix.
  2037. * @method lookAtMat4v
  2038. * @param pos vec3 position of the viewer
  2039. * @param target vec3 point the viewer is looking at
  2040. * @param up vec3 pointing "up"
  2041. * @param dest mat4 Optional, mat4 matrix will be written into
  2042. *
  2043. * @return {mat4} dest if specified, a new mat4 otherwise
  2044. */
  2045. lookAtMat4v(pos, target, up, dest) {
  2046. if (!dest) {
  2047. dest = math.mat4();
  2048. }
  2049.  
  2050. const posx = pos[0];
  2051. const posy = pos[1];
  2052. const posz = pos[2];
  2053. const upx = up[0];
  2054. const upy = up[1];
  2055. const upz = up[2];
  2056. const targetx = target[0];
  2057. const targety = target[1];
  2058. const targetz = target[2];
  2059.  
  2060. if (posx === targetx && posy === targety && posz === targetz) {
  2061. return math.identityMat4();
  2062. }
  2063.  
  2064. let z0;
  2065. let z1;
  2066. let z2;
  2067. let x0;
  2068. let x1;
  2069. let x2;
  2070. let y0;
  2071. let y1;
  2072. let y2;
  2073. let len;
  2074.  
  2075. //vec3.direction(eye, center, z);
  2076. z0 = posx - targetx;
  2077. z1 = posy - targety;
  2078. z2 = posz - targetz;
  2079.  
  2080. // normalize (no check needed for 0 because of early return)
  2081. len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
  2082. z0 *= len;
  2083. z1 *= len;
  2084. z2 *= len;
  2085.  
  2086. //vec3.normalize(vec3.cross(up, z, x));
  2087. x0 = upy * z2 - upz * z1;
  2088. x1 = upz * z0 - upx * z2;
  2089. x2 = upx * z1 - upy * z0;
  2090. len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
  2091. if (!len) {
  2092. x0 = 0;
  2093. x1 = 0;
  2094. x2 = 0;
  2095. } else {
  2096. len = 1 / len;
  2097. x0 *= len;
  2098. x1 *= len;
  2099. x2 *= len;
  2100. }
  2101.  
  2102. //vec3.normalize(vec3.cross(z, x, y));
  2103. y0 = z1 * x2 - z2 * x1;
  2104. y1 = z2 * x0 - z0 * x2;
  2105. y2 = z0 * x1 - z1 * x0;
  2106.  
  2107. len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
  2108. if (!len) {
  2109. y0 = 0;
  2110. y1 = 0;
  2111. y2 = 0;
  2112. } else {
  2113. len = 1 / len;
  2114. y0 *= len;
  2115. y1 *= len;
  2116. y2 *= len;
  2117. }
  2118.  
  2119. dest[0] = x0;
  2120. dest[1] = y0;
  2121. dest[2] = z0;
  2122. dest[3] = 0;
  2123. dest[4] = x1;
  2124. dest[5] = y1;
  2125. dest[6] = z1;
  2126. dest[7] = 0;
  2127. dest[8] = x2;
  2128. dest[9] = y2;
  2129. dest[10] = z2;
  2130. dest[11] = 0;
  2131. dest[12] = -(x0 * posx + x1 * posy + x2 * posz);
  2132. dest[13] = -(y0 * posx + y1 * posy + y2 * posz);
  2133. dest[14] = -(z0 * posx + z1 * posy + z2 * posz);
  2134. dest[15] = 1;
  2135.  
  2136. return dest;
  2137. },
  2138.  
  2139. /**
  2140. * Returns a 4x4 'lookat' viewing transform matrix.
  2141. * @method lookAtMat4c
  2142. * @static
  2143. */
  2144. lookAtMat4c(posx, posy, posz, targetx, targety, targetz, upx, upy, upz) {
  2145. return math.lookAtMat4v([posx, posy, posz], [targetx, targety, targetz], [upx, upy, upz], []);
  2146. },
  2147.  
  2148. /**
  2149. * Returns a 4x4 orthographic projection matrix.
  2150. * @method orthoMat4c
  2151. * @static
  2152. */
  2153. orthoMat4c(left, right, bottom, top, near, far, dest) {
  2154. if (!dest) {
  2155. dest = math.mat4();
  2156. }
  2157. const rl = (right - left);
  2158. const tb = (top - bottom);
  2159. const fn = (far - near);
  2160.  
  2161. dest[0] = 2.0 / rl;
  2162. dest[1] = 0.0;
  2163. dest[2] = 0.0;
  2164. dest[3] = 0.0;
  2165.  
  2166. dest[4] = 0.0;
  2167. dest[5] = 2.0 / tb;
  2168. dest[6] = 0.0;
  2169. dest[7] = 0.0;
  2170.  
  2171. dest[8] = 0.0;
  2172. dest[9] = 0.0;
  2173. dest[10] = -2.0 / fn;
  2174. dest[11] = 0.0;
  2175.  
  2176. dest[12] = -(left + right) / rl;
  2177. dest[13] = -(top + bottom) / tb;
  2178. dest[14] = -(far + near) / fn;
  2179. dest[15] = 1.0;
  2180.  
  2181. return dest;
  2182. },
  2183.  
  2184. /**
  2185. * Returns a 4x4 perspective projection matrix.
  2186. * @method frustumMat4v
  2187. * @static
  2188. */
  2189. frustumMat4v(fmin, fmax, m) {
  2190. if (!m) {
  2191. m = math.mat4();
  2192. }
  2193.  
  2194. const fmin4 = [fmin[0], fmin[1], fmin[2], 0.0];
  2195. const fmax4 = [fmax[0], fmax[1], fmax[2], 0.0];
  2196.  
  2197. math.addVec4(fmax4, fmin4, tempMat1);
  2198. math.subVec4(fmax4, fmin4, tempMat2);
  2199.  
  2200. const t = 2.0 * fmin4[2];
  2201.  
  2202. const tempMat20 = tempMat2[0];
  2203. const tempMat21 = tempMat2[1];
  2204. const tempMat22 = tempMat2[2];
  2205.  
  2206. m[0] = t / tempMat20;
  2207. m[1] = 0.0;
  2208. m[2] = 0.0;
  2209. m[3] = 0.0;
  2210.  
  2211. m[4] = 0.0;
  2212. m[5] = t / tempMat21;
  2213. m[6] = 0.0;
  2214. m[7] = 0.0;
  2215.  
  2216. m[8] = tempMat1[0] / tempMat20;
  2217. m[9] = tempMat1[1] / tempMat21;
  2218. m[10] = -tempMat1[2] / tempMat22;
  2219. m[11] = -1.0;
  2220.  
  2221. m[12] = 0.0;
  2222. m[13] = 0.0;
  2223. m[14] = -t * fmax4[2] / tempMat22;
  2224. m[15] = 0.0;
  2225.  
  2226. return m;
  2227. },
  2228.  
  2229. /**
  2230. * Returns a 4x4 perspective projection matrix.
  2231. * @method frustumMat4v
  2232. * @static
  2233. */
  2234. frustumMat4(left, right, bottom, top, near, far, dest) {
  2235. if (!dest) {
  2236. dest = math.mat4();
  2237. }
  2238. const rl = (right - left);
  2239. const tb = (top - bottom);
  2240. const fn = (far - near);
  2241. dest[0] = (near * 2) / rl;
  2242. dest[1] = 0;
  2243. dest[2] = 0;
  2244. dest[3] = 0;
  2245. dest[4] = 0;
  2246. dest[5] = (near * 2) / tb;
  2247. dest[6] = 0;
  2248. dest[7] = 0;
  2249. dest[8] = (right + left) / rl;
  2250. dest[9] = (top + bottom) / tb;
  2251. dest[10] = -(far + near) / fn;
  2252. dest[11] = -1;
  2253. dest[12] = 0;
  2254. dest[13] = 0;
  2255. dest[14] = -(far * near * 2) / fn;
  2256. dest[15] = 0;
  2257. return dest;
  2258. },
  2259.  
  2260. /**
  2261. * Returns a 4x4 perspective projection matrix.
  2262. * @method perspectiveMat4v
  2263. * @static
  2264. */
  2265. perspectiveMat4(fovyrad, aspectratio, znear, zfar, m) {
  2266. const pmin = [];
  2267. const pmax = [];
  2268.  
  2269. pmin[2] = znear;
  2270. pmax[2] = zfar;
  2271.  
  2272. pmax[1] = pmin[2] * Math.tan(fovyrad / 2.0);
  2273. pmin[1] = -pmax[1];
  2274.  
  2275. pmax[0] = pmax[1] * aspectratio;
  2276. pmin[0] = -pmax[0];
  2277.  
  2278. return math.frustumMat4v(pmin, pmax, m);
  2279. },
  2280.  
  2281. /**
  2282. * Transforms a three-element position by a 4x4 matrix.
  2283. * @method transformPoint3
  2284. * @static
  2285. */
  2286. transformPoint3(m, p, dest = math.vec3()) {
  2287. dest[0] = (m[0] * p[0]) + (m[4] * p[1]) + (m[8] * p[2]) + m[12];
  2288. dest[1] = (m[1] * p[0]) + (m[5] * p[1]) + (m[9] * p[2]) + m[13];
  2289. dest[2] = (m[2] * p[0]) + (m[6] * p[1]) + (m[10] * p[2]) + m[14];
  2290.  
  2291. return dest;
  2292. },
  2293.  
  2294. /**
  2295. * Transforms a homogeneous coordinate by a 4x4 matrix.
  2296. * @method transformPoint3
  2297. * @static
  2298. */
  2299. transformPoint4(m, v, dest = math.vec4()) {
  2300. dest[0] = m[0] * v[0] + m[4] * v[1] + m[8] * v[2] + m[12] * v[3];
  2301. dest[1] = m[1] * v[0] + m[5] * v[1] + m[9] * v[2] + m[13] * v[3];
  2302. dest[2] = m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14] * v[3];
  2303. dest[3] = m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * v[3];
  2304.  
  2305. return dest;
  2306. },
  2307.  
  2308.  
  2309. /**
  2310. * Transforms an array of three-element positions by a 4x4 matrix.
  2311. * @method transformPoints3
  2312. * @static
  2313. */
  2314. transformPoints3(m, points, points2) {
  2315. const result = points2 || [];
  2316. const len = points.length;
  2317. let p0;
  2318. let p1;
  2319. let p2;
  2320. let pi;
  2321.  
  2322. // cache values
  2323. const m0 = m[0];
  2324.  
  2325. const m1 = m[1];
  2326. const m2 = m[2];
  2327. const m3 = m[3];
  2328. const m4 = m[4];
  2329. const m5 = m[5];
  2330. const m6 = m[6];
  2331. const m7 = m[7];
  2332. const m8 = m[8];
  2333. const m9 = m[9];
  2334. const m10 = m[10];
  2335. const m11 = m[11];
  2336. const m12 = m[12];
  2337. const m13 = m[13];
  2338. const m14 = m[14];
  2339. const m15 = m[15];
  2340.  
  2341. let r;
  2342.  
  2343. for (let i = 0; i < len; ++i) {
  2344.  
  2345. // cache values
  2346. pi = points[i];
  2347.  
  2348. p0 = pi[0];
  2349. p1 = pi[1];
  2350. p2 = pi[2];
  2351.  
  2352. r = result[i] || (result[i] = [0, 0, 0]);
  2353.  
  2354. r[0] = (m0 * p0) + (m4 * p1) + (m8 * p2) + m12;
  2355. r[1] = (m1 * p0) + (m5 * p1) + (m9 * p2) + m13;
  2356. r[2] = (m2 * p0) + (m6 * p1) + (m10 * p2) + m14;
  2357. r[3] = (m3 * p0) + (m7 * p1) + (m11 * p2) + m15;
  2358. }
  2359.  
  2360. result.length = len;
  2361.  
  2362. return result;
  2363. },
  2364.  
  2365. /**
  2366. * Transforms an array of positions by a 4x4 matrix.
  2367. * @method transformPositions3
  2368. * @static
  2369. */
  2370. transformPositions3(m, p, p2 = p) {
  2371. let i;
  2372. const len = p.length;
  2373.  
  2374. let x;
  2375. let y;
  2376. let z;
  2377.  
  2378. const m0 = m[0];
  2379. const m1 = m[1];
  2380. const m2 = m[2];
  2381. const m3 = m[3];
  2382. const m4 = m[4];
  2383. const m5 = m[5];
  2384. const m6 = m[6];
  2385. const m7 = m[7];
  2386. const m8 = m[8];
  2387. const m9 = m[9];
  2388. const m10 = m[10];
  2389. const m11 = m[11];
  2390. const m12 = m[12];
  2391. const m13 = m[13];
  2392. const m14 = m[14];
  2393. const m15 = m[15];
  2394.  
  2395. for (i = 0; i < len; i += 3) {
  2396.  
  2397. x = p[i + 0];
  2398. y = p[i + 1];
  2399. z = p[i + 2];
  2400.  
  2401. p2[i + 0] = (m0 * x) + (m4 * y) + (m8 * z) + m12;
  2402. p2[i + 1] = (m1 * x) + (m5 * y) + (m9 * z) + m13;
  2403. p2[i + 2] = (m2 * x) + (m6 * y) + (m10 * z) + m14;
  2404. p2[i + 3] = (m3 * x) + (m7 * y) + (m11 * z) + m15;
  2405. }
  2406.  
  2407. return p2;
  2408. },
  2409.  
  2410. /**
  2411. * Transforms an array of positions by a 4x4 matrix.
  2412. * @method transformPositions4
  2413. * @static
  2414. */
  2415. transformPositions4(m, p, p2 = p) {
  2416. let i;
  2417. const len = p.length;
  2418.  
  2419. let x;
  2420. let y;
  2421. let z;
  2422.  
  2423. const m0 = m[0];
  2424. const m1 = m[1];
  2425. const m2 = m[2];
  2426. const m3 = m[3];
  2427. const m4 = m[4];
  2428. const m5 = m[5];
  2429. const m6 = m[6];
  2430. const m7 = m[7];
  2431. const m8 = m[8];
  2432. const m9 = m[9];
  2433. const m10 = m[10];
  2434. const m11 = m[11];
  2435. const m12 = m[12];
  2436. const m13 = m[13];
  2437. const m14 = m[14];
  2438. const m15 = m[15];
  2439.  
  2440. for (i = 0; i < len; i += 4) {
  2441.  
  2442. x = p[i + 0];
  2443. y = p[i + 1];
  2444. z = p[i + 2];
  2445.  
  2446. p2[i + 0] = (m0 * x) + (m4 * y) + (m8 * z) + m12;
  2447. p2[i + 1] = (m1 * x) + (m5 * y) + (m9 * z) + m13;
  2448. p2[i + 2] = (m2 * x) + (m6 * y) + (m10 * z) + m14;
  2449. p2[i + 3] = (m3 * x) + (m7 * y) + (m11 * z) + m15;
  2450. }
  2451.  
  2452. return p2;
  2453. },
  2454.  
  2455. /**
  2456. * Transforms a three-element vector by a 4x4 matrix.
  2457. * @method transformVec3
  2458. * @static
  2459. */
  2460. transformVec3(m, v, dest) {
  2461. const v0 = v[0];
  2462. const v1 = v[1];
  2463. const v2 = v[2];
  2464. dest = dest || this.vec3();
  2465. dest[0] = (m[0] * v0) + (m[4] * v1) + (m[8] * v2);
  2466. dest[1] = (m[1] * v0) + (m[5] * v1) + (m[9] * v2);
  2467. dest[2] = (m[2] * v0) + (m[6] * v1) + (m[10] * v2);
  2468. return dest;
  2469. },
  2470.  
  2471. /**
  2472. * Transforms a four-element vector by a 4x4 matrix.
  2473. * @method transformVec4
  2474. * @static
  2475. */
  2476. transformVec4(m, v, dest) {
  2477. const v0 = v[0];
  2478. const v1 = v[1];
  2479. const v2 = v[2];
  2480. const v3 = v[3];
  2481. dest = dest || math.vec4();
  2482. dest[0] = m[0] * v0 + m[4] * v1 + m[8] * v2 + m[12] * v3;
  2483. dest[1] = m[1] * v0 + m[5] * v1 + m[9] * v2 + m[13] * v3;
  2484. dest[2] = m[2] * v0 + m[6] * v1 + m[10] * v2 + m[14] * v3;
  2485. dest[3] = m[3] * v0 + m[7] * v1 + m[11] * v2 + m[15] * v3;
  2486. return dest;
  2487. },
  2488.  
  2489. /**
  2490. * Rotate a 3D vector around the x-axis
  2491. *
  2492. * @method rotateVec3X
  2493. * @param {Float32Array} a The vec3 point to rotate
  2494. * @param {Float32Array} b The origin of the rotation
  2495. * @param {Number} c The angle of rotation
  2496. * @param {Float32Array} dest The receiving vec3
  2497. * @returns {Float32Array} dest
  2498. * @static
  2499. */
  2500. rotateVec3X(a, b, c, dest) {
  2501. const p = [];
  2502. const r = [];
  2503.  
  2504. //Translate point to the origin
  2505. p[0] = a[0] - b[0];
  2506. p[1] = a[1] - b[1];
  2507. p[2] = a[2] - b[2];
  2508.  
  2509. //perform rotation
  2510. r[0] = p[0];
  2511. r[1] = p[1] * Math.cos(c) - p[2] * Math.sin(c);
  2512. r[2] = p[1] * Math.sin(c) + p[2] * Math.cos(c);
  2513.  
  2514. //translate to correct position
  2515. dest[0] = r[0] + b[0];
  2516. dest[1] = r[1] + b[1];
  2517. dest[2] = r[2] + b[2];
  2518.  
  2519. return dest;
  2520. },
  2521.  
  2522. /**
  2523. * Rotate a 3D vector around the y-axis
  2524. *
  2525. * @method rotateVec3Y
  2526. * @param {Float32Array} a The vec3 point to rotate
  2527. * @param {Float32Array} b The origin of the rotation
  2528. * @param {Number} c The angle of rotation
  2529. * @param {Float32Array} dest The receiving vec3
  2530. * @returns {Float32Array} dest
  2531. * @static
  2532. */
  2533. rotateVec3Y(a, b, c, dest) {
  2534. const p = [];
  2535. const r = [];
  2536.  
  2537. //Translate point to the origin
  2538. p[0] = a[0] - b[0];
  2539. p[1] = a[1] - b[1];
  2540. p[2] = a[2] - b[2];
  2541.  
  2542. //perform rotation
  2543. r[0] = p[2] * Math.sin(c) + p[0] * Math.cos(c);
  2544. r[1] = p[1];
  2545. r[2] = p[2] * Math.cos(c) - p[0] * Math.sin(c);
  2546.  
  2547. //translate to correct position
  2548. dest[0] = r[0] + b[0];
  2549. dest[1] = r[1] + b[1];
  2550. dest[2] = r[2] + b[2];
  2551.  
  2552. return dest;
  2553. },
  2554.  
  2555. /**
  2556. * Rotate a 3D vector around the z-axis
  2557. *
  2558. * @method rotateVec3Z
  2559. * @param {Float32Array} a The vec3 point to rotate
  2560. * @param {Float32Array} b The origin of the rotation
  2561. * @param {Number} c The angle of rotation
  2562. * @param {Float32Array} dest The receiving vec3
  2563. * @returns {Float32Array} dest
  2564. * @static
  2565. */
  2566. rotateVec3Z(a, b, c, dest) {
  2567. const p = [];
  2568. const r = [];
  2569.  
  2570. //Translate point to the origin
  2571. p[0] = a[0] - b[0];
  2572. p[1] = a[1] - b[1];
  2573. p[2] = a[2] - b[2];
  2574.  
  2575. //perform rotation
  2576. r[0] = p[0] * Math.cos(c) - p[1] * Math.sin(c);
  2577. r[1] = p[0] * Math.sin(c) + p[1] * Math.cos(c);
  2578. r[2] = p[2];
  2579.  
  2580. //translate to correct position
  2581. dest[0] = r[0] + b[0];
  2582. dest[1] = r[1] + b[1];
  2583. dest[2] = r[2] + b[2];
  2584.  
  2585. return dest;
  2586. },
  2587.  
  2588. /**
  2589. * Transforms a four-element vector by a 4x4 projection matrix.
  2590. *
  2591. * @method projectVec4
  2592. * @param {Float32Array} p 3D View-space coordinate
  2593. * @param {Float32Array} q 2D Projected coordinate
  2594. * @returns {Float32Array} 2D Projected coordinate
  2595. * @static
  2596. */
  2597. projectVec4(p, q) {
  2598. const f = 1.0 / p[3];
  2599. q = q || math.vec2();
  2600. q[0] = v[0] * f;
  2601. q[1] = v[1] * f;
  2602. return q;
  2603. },
  2604.  
  2605. /**
  2606. * Unprojects a three-element vector.
  2607. *
  2608. * @method unprojectVec3
  2609. * @param {Float32Array} p 3D Projected coordinate
  2610. * @param {Float32Array} viewMat View matrix
  2611. * @returns {Float32Array} projMat Projection matrix
  2612. * @static
  2613. */
  2614. unprojectVec3: ((() => {
  2615. const mat = new Float32Array(16);
  2616. const mat2 = new Float32Array(16);
  2617. const mat3 = new Float32Array(16);
  2618. return function (p, viewMat, projMat, q) {
  2619. return this.transformVec3(this.mulMat4(this.inverseMat4(viewMat, mat), this.inverseMat4(projMat, mat2), mat3), p, q)
  2620. };
  2621. }))(),
  2622.  
  2623. /**
  2624. * Linearly interpolates between two 3D vectors.
  2625. * @method lerpVec3
  2626. * @static
  2627. */
  2628. lerpVec3(t, t1, t2, p1, p2, dest) {
  2629. const result = dest || math.vec3();
  2630. const f = (t - t1) / (t2 - t1);
  2631. result[0] = p1[0] + (f * (p2[0] - p1[0]));
  2632. result[1] = p1[1] + (f * (p2[1] - p1[1]));
  2633. result[2] = p1[2] + (f * (p2[2] - p1[2]));
  2634. return result;
  2635. },
  2636.  
  2637.  
  2638. /**
  2639. * Flattens a two-dimensional array into a one-dimensional array.
  2640. *
  2641. * @method flatten
  2642. * @static
  2643. * @param {Array of Arrays} a A 2D array
  2644. * @returns Flattened 1D array
  2645. */
  2646. flatten(a) {
  2647.  
  2648. const result = [];
  2649.  
  2650. let i;
  2651. let leni;
  2652. let j;
  2653. let lenj;
  2654. let item;
  2655.  
  2656. for (i = 0, leni = a.length; i < leni; i++) {
  2657. item = a[i];
  2658. for (j = 0, lenj = item.length; j < lenj; j++) {
  2659. result.push(item[j]);
  2660. }
  2661. }
  2662.  
  2663. return result;
  2664. },
  2665.  
  2666.  
  2667. identityQuaternion(dest = math.vec4()) {
  2668. dest[0] = 0.0;
  2669. dest[1] = 0.0;
  2670. dest[2] = 0.0;
  2671. dest[3] = 1.0;
  2672. return dest;
  2673. },
  2674.  
  2675. /**
  2676. * Initializes a quaternion from Euler angles.
  2677. *
  2678. * @param {Float32Array} euler The Euler angles.
  2679. * @param {String} order Euler angle order: "XYZ", "YXZ", "ZXY" etc.
  2680. * @param {Float32Array} [dest] Destination quaternion, created by default.
  2681. * @returns {Float32Array} The quaternion.
  2682. */
  2683. eulerToQuaternion(euler, order, dest = math.vec4()) {
  2684. // http://www.mathworks.com/matlabcentral/fileexchange/
  2685. // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
  2686. // content/SpinCalc.m
  2687.  
  2688. const a = (euler[0] * math.DEGTORAD) / 2;
  2689. const b = (euler[1] * math.DEGTORAD) / 2;
  2690. const c = (euler[2] * math.DEGTORAD) / 2;
  2691.  
  2692. const c1 = Math.cos(a);
  2693. const c2 = Math.cos(b);
  2694. const c3 = Math.cos(c);
  2695. const s1 = Math.sin(a);
  2696. const s2 = Math.sin(b);
  2697. const s3 = Math.sin(c);
  2698.  
  2699. if (order === 'XYZ') {
  2700.  
  2701. dest[0] = s1 * c2 * c3 + c1 * s2 * s3;
  2702. dest[1] = c1 * s2 * c3 - s1 * c2 * s3;
  2703. dest[2] = c1 * c2 * s3 + s1 * s2 * c3;
  2704. dest[3] = c1 * c2 * c3 - s1 * s2 * s3;
  2705.  
  2706. } else if (order === 'YXZ') {
  2707.  
  2708. dest[0] = s1 * c2 * c3 + c1 * s2 * s3;
  2709. dest[1] = c1 * s2 * c3 - s1 * c2 * s3;
  2710. dest[2] = c1 * c2 * s3 - s1 * s2 * c3;
  2711. dest[3] = c1 * c2 * c3 + s1 * s2 * s3;
  2712.  
  2713. } else if (order === 'ZXY') {
  2714.  
  2715. dest[0] = s1 * c2 * c3 - c1 * s2 * s3;
  2716. dest[1] = c1 * s2 * c3 + s1 * c2 * s3;
  2717. dest[2] = c1 * c2 * s3 + s1 * s2 * c3;
  2718. dest[3] = c1 * c2 * c3 - s1 * s2 * s3;
  2719.  
  2720. } else if (order === 'ZYX') {
  2721.  
  2722. dest[0] = s1 * c2 * c3 - c1 * s2 * s3;
  2723. dest[1] = c1 * s2 * c3 + s1 * c2 * s3;
  2724. dest[2] = c1 * c2 * s3 - s1 * s2 * c3;
  2725. dest[3] = c1 * c2 * c3 + s1 * s2 * s3;
  2726.  
  2727. } else if (order === 'YZX') {
  2728.  
  2729. dest[0] = s1 * c2 * c3 + c1 * s2 * s3;
  2730. dest[1] = c1 * s2 * c3 + s1 * c2 * s3;
  2731. dest[2] = c1 * c2 * s3 - s1 * s2 * c3;
  2732. dest[3] = c1 * c2 * c3 - s1 * s2 * s3;
  2733.  
  2734. } else if (order === 'XZY') {
  2735.  
  2736. dest[0] = s1 * c2 * c3 - c1 * s2 * s3;
  2737. dest[1] = c1 * s2 * c3 - s1 * c2 * s3;
  2738. dest[2] = c1 * c2 * s3 + s1 * s2 * c3;
  2739. dest[3] = c1 * c2 * c3 + s1 * s2 * s3;
  2740. }
  2741.  
  2742. return dest;
  2743. },
  2744.  
  2745. mat4ToQuaternion(m, dest = math.vec4()) {
  2746. // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
  2747.  
  2748. // Assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
  2749.  
  2750. const m11 = m[0];
  2751. const m12 = m[4];
  2752. const m13 = m[8];
  2753. const m21 = m[1];
  2754. const m22 = m[5];
  2755. const m23 = m[9];
  2756. const m31 = m[2];
  2757. const m32 = m[6];
  2758. const m33 = m[10];
  2759. let s;
  2760.  
  2761. const trace = m11 + m22 + m33;
  2762.  
  2763. if (trace > 0) {
  2764.  
  2765. s = 0.5 / Math.sqrt(trace + 1.0);
  2766.  
  2767. dest[3] = 0.25 / s;
  2768. dest[0] = ( m32 - m23 ) * s;
  2769. dest[1] = ( m13 - m31 ) * s;
  2770. dest[2] = ( m21 - m12 ) * s;
  2771.  
  2772. } else if (m11 > m22 && m11 > m33) {
  2773.  
  2774. s = 2.0 * Math.sqrt(1.0 + m11 - m22 - m33);
  2775.  
  2776. dest[3] = ( m32 - m23 ) / s;
  2777. dest[0] = 0.25 * s;
  2778. dest[1] = ( m12 + m21 ) / s;
  2779. dest[2] = ( m13 + m31 ) / s;
  2780.  
  2781. } else if (m22 > m33) {
  2782.  
  2783. s = 2.0 * Math.sqrt(1.0 + m22 - m11 - m33);
  2784.  
  2785. dest[3] = ( m13 - m31 ) / s;
  2786. dest[0] = ( m12 + m21 ) / s;
  2787. dest[1] = 0.25 * s;
  2788. dest[2] = ( m23 + m32 ) / s;
  2789.  
  2790. } else {
  2791.  
  2792. s = 2.0 * Math.sqrt(1.0 + m33 - m11 - m22);
  2793.  
  2794. dest[3] = ( m21 - m12 ) / s;
  2795. dest[0] = ( m13 + m31 ) / s;
  2796. dest[1] = ( m23 + m32 ) / s;
  2797. dest[2] = 0.25 * s;
  2798. }
  2799.  
  2800. return dest;
  2801. },
  2802.  
  2803. vec3PairToQuaternion(u, v, dest = math.vec4()) {
  2804. const norm_u_norm_v = Math.sqrt(math.dotVec3(u, u) * math.dotVec3(v, v));
  2805. let real_part = norm_u_norm_v + math.dotVec3(u, v);
  2806.  
  2807. if (real_part < 0.00000001 * norm_u_norm_v) {
  2808.  
  2809. // If u and v are exactly opposite, rotate 180 degrees
  2810. // around an arbitrary orthogonal axis. Axis normalisation
  2811. // can happen later, when we normalise the quaternion.
  2812.  
  2813. real_part = 0.0;
  2814.  
  2815. if (Math.abs(u[0]) > Math.abs(u[2])) {
  2816.  
  2817. dest[0] = -u[1];
  2818. dest[1] = u[0];
  2819. dest[2] = 0;
  2820.  
  2821. } else {
  2822. dest[0] = 0;
  2823. dest[1] = -u[2];
  2824. dest[2] = u[1]
  2825. }
  2826.  
  2827. } else {
  2828.  
  2829. // Otherwise, build quaternion the standard way.
  2830. math.cross3Vec3(u, v, dest);
  2831. }
  2832.  
  2833. dest[3] = real_part;
  2834.  
  2835. return math.normalizeQuaternion(dest);
  2836. },
  2837.  
  2838. angleAxisToQuaternion(angleAxis, dest = math.vec4()) {
  2839. const halfAngle = angleAxis[3] / 2.0;
  2840. const fsin = Math.sin(halfAngle);
  2841. dest[0] = fsin * angleAxis[0];
  2842. dest[1] = fsin * angleAxis[1];
  2843. dest[2] = fsin * angleAxis[2];
  2844. dest[3] = Math.cos(halfAngle);
  2845. return dest;
  2846. },
  2847.  
  2848. quaternionToEuler: ((() => {
  2849. const mat = new Float32Array(16);
  2850. return (q, order, dest) => {
  2851. dest = dest || math.vec3();
  2852. math.quaternionToRotationMat4(q, mat);
  2853. math.mat4ToEuler(mat, order, dest);
  2854. return dest;
  2855. };
  2856. }))(),
  2857.  
  2858. mulQuaternions(p, q, dest = math.vec4()) {
  2859. const p0 = p[0];
  2860. const p1 = p[1];
  2861. const p2 = p[2];
  2862. const p3 = p[3];
  2863. const q0 = q[0];
  2864. const q1 = q[1];
  2865. const q2 = q[2];
  2866. const q3 = q[3];
  2867. dest[0] = p3 * q0 + p0 * q3 + p1 * q2 - p2 * q1;
  2868. dest[1] = p3 * q1 + p1 * q3 + p2 * q0 - p0 * q2;
  2869. dest[2] = p3 * q2 + p2 * q3 + p0 * q1 - p1 * q0;
  2870. dest[3] = p3 * q3 - p0 * q0 - p1 * q1 - p2 * q2;
  2871. return dest;
  2872. },
  2873.  
  2874. vec3ApplyQuaternion(q, vec, dest = math.vec3()) {
  2875. const x = vec[0];
  2876. const y = vec[1];
  2877. const z = vec[2];
  2878.  
  2879. const qx = q[0];
  2880. const qy = q[1];
  2881. const qz = q[2];
  2882. const qw = q[3];
  2883.  
  2884. // calculate quat * vector
  2885.  
  2886. const ix = qw * x + qy * z - qz * y;
  2887. const iy = qw * y + qz * x - qx * z;
  2888. const iz = qw * z + qx * y - qy * x;
  2889. const iw = -qx * x - qy * y - qz * z;
  2890.  
  2891. // calculate result * inverse quat
  2892.  
  2893. dest[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
  2894. dest[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
  2895. dest[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
  2896.  
  2897. return dest;
  2898. },
  2899.  
  2900. quaternionToMat4(q, dest) {
  2901.  
  2902. dest = math.identityMat4(dest);
  2903.  
  2904. const q0 = q[0]; //x
  2905. const q1 = q[1]; //y
  2906. const q2 = q[2]; //z
  2907. const q3 = q[3]; //w
  2908.  
  2909. const tx = 2.0 * q0;
  2910. const ty = 2.0 * q1;
  2911. const tz = 2.0 * q2;
  2912.  
  2913. const twx = tx * q3;
  2914. const twy = ty * q3;
  2915. const twz = tz * q3;
  2916.  
  2917. const txx = tx * q0;
  2918. const txy = ty * q0;
  2919. const txz = tz * q0;
  2920.  
  2921. const tyy = ty * q1;
  2922. const tyz = tz * q1;
  2923. const tzz = tz * q2;
  2924.  
  2925. dest[0] = 1.0 - (tyy + tzz);
  2926. dest[1] = txy + twz;
  2927. dest[2] = txz - twy;
  2928.  
  2929. dest[4] = txy - twz;
  2930. dest[5] = 1.0 - (txx + tzz);
  2931. dest[6] = tyz + twx;
  2932.  
  2933. dest[8] = txz + twy;
  2934. dest[9] = tyz - twx;
  2935.  
  2936. dest[10] = 1.0 - (txx + tyy);
  2937.  
  2938. return dest;
  2939. },
  2940.  
  2941. quaternionToRotationMat4(q, m) {
  2942. const x = q[0];
  2943. const y = q[1];
  2944. const z = q[2];
  2945. const w = q[3];
  2946.  
  2947. const x2 = x + x;
  2948. const y2 = y + y;
  2949. const z2 = z + z;
  2950. const xx = x * x2;
  2951. const xy = x * y2;
  2952. const xz = x * z2;
  2953. const yy = y * y2;
  2954. const yz = y * z2;
  2955. const zz = z * z2;
  2956. const wx = w * x2;
  2957. const wy = w * y2;
  2958. const wz = w * z2;
  2959.  
  2960. m[0] = 1 - ( yy + zz );
  2961. m[4] = xy - wz;
  2962. m[8] = xz + wy;
  2963.  
  2964. m[1] = xy + wz;
  2965. m[5] = 1 - ( xx + zz );
  2966. m[9] = yz - wx;
  2967.  
  2968. m[2] = xz - wy;
  2969. m[6] = yz + wx;
  2970. m[10] = 1 - ( xx + yy );
  2971.  
  2972. // last column
  2973. m[3] = 0;
  2974. m[7] = 0;
  2975. m[11] = 0;
  2976.  
  2977. // bottom row
  2978. m[12] = 0;
  2979. m[13] = 0;
  2980. m[14] = 0;
  2981. m[15] = 1;
  2982.  
  2983. return m;
  2984. },
  2985.  
  2986. normalizeQuaternion(q, dest = q) {
  2987. const len = math.lenVec4([q[0], q[1], q[2], q[3]]);
  2988. dest[0] = q[0] / len;
  2989. dest[1] = q[1] / len;
  2990. dest[2] = q[2] / len;
  2991. dest[3] = q[3] / len;
  2992. return dest;
  2993. },
  2994.  
  2995. conjugateQuaternion(q, dest = q) {
  2996. dest[0] = -q[0];
  2997. dest[1] = -q[1];
  2998. dest[2] = -q[2];
  2999. dest[3] = q[3];
  3000. return dest;
  3001. },
  3002.  
  3003. inverseQuaternion(q, dest) {
  3004. return math.normalizeQuaternion(math.conjugateQuaternion(q, dest));
  3005. },
  3006.  
  3007. quaternionToAngleAxis(q, angleAxis = math.vec4()) {
  3008. q = math.normalizeQuaternion(q, tempVec4);
  3009. const q3 = q[3];
  3010. const angle = 2 * Math.acos(q3);
  3011. const s = Math.sqrt(1 - q3 * q3);
  3012. if (s < 0.001) { // test to avoid divide by zero, s is always positive due to sqrt
  3013. angleAxis[0] = q[0];
  3014. angleAxis[1] = q[1];
  3015. angleAxis[2] = q[2];
  3016. } else {
  3017. angleAxis[0] = q[0] / s;
  3018. angleAxis[1] = q[1] / s;
  3019. angleAxis[2] = q[2] / s;
  3020. }
  3021. angleAxis[3] = angle; // * 57.295779579;
  3022. return angleAxis;
  3023. },
  3024.  
  3025. decompressPosition(position, decodeMatrix, dest) {
  3026. dest[0] = position[0] * decodeMatrix[0] + decodeMatrix[12];
  3027. dest[1] = position[1] * decodeMatrix[5] + decodeMatrix[13];
  3028. dest[2] = position[2] * decodeMatrix[10] + decodeMatrix[14];
  3029. },
  3030.  
  3031. decompressPositions(positions, decodeMatrix, dest = new Float32Array(positions.length)) {
  3032. for (let i = 0, len = positions.length; i < len; i += 3) {
  3033. dest[i + 0] = positions[i + 0] * decodeMatrix[0] + decodeMatrix[12];
  3034. dest[i + 1] = positions[i + 1] * decodeMatrix[5] + decodeMatrix[13];
  3035. dest[i + 2] = positions[i + 2] * decodeMatrix[10] + decodeMatrix[14];
  3036. }
  3037. return dest;
  3038. },
  3039.  
  3040. decompressUV(uv, decodeMatrix, dest) {
  3041. dest[0] = uv[0] * decodeMatrix[0] + decodeMatrix[6];
  3042. dest[1] = uv[1] * decodeMatrix[4] + decodeMatrix[7];
  3043. },
  3044.  
  3045. decompressUVs(uvs, decodeMatrix, dest = new Float32Array(uvs.length)) {
  3046. for (let i = 0, len = uvs.length; i < len; i += 3) {
  3047. dest[i + 0] = uvs[i + 0] * decodeMatrix[0] + decodeMatrix[6];
  3048. dest[i + 1] = uvs[i + 1] * decodeMatrix[4] + decodeMatrix[7];
  3049. }
  3050. return dest;
  3051. },
  3052.  
  3053. octDecodeVec2(oct, result) {
  3054. let x = oct[0];
  3055. let y = oct[1];
  3056. x = (2 * x + 1) / 255;
  3057. y = (2 * y + 1) / 255;
  3058. const z = 1 - Math.abs(x) - Math.abs(y);
  3059. if (z < 0) {
  3060. x = (1 - Math.abs(y)) * (x >= 0 ? 1 : -1);
  3061. y = (1 - Math.abs(x)) * (y >= 0 ? 1 : -1);
  3062. }
  3063. const length = Math.sqrt(x * x + y * y + z * z);
  3064. result[0] = x / length;
  3065. result[1] = y / length;
  3066. result[2] = z / length;
  3067. return result;
  3068. },
  3069.  
  3070. octDecodeVec2s(octs, result) {
  3071. for (let i = 0, j = 0, len = octs.length; i < len; i += 2) {
  3072. let x = octs[i + 0];
  3073. let y = octs[i + 1];
  3074. x = (2 * x + 1) / 255;
  3075. y = (2 * y + 1) / 255;
  3076. const z = 1 - Math.abs(x) - Math.abs(y);
  3077. if (z < 0) {
  3078. x = (1 - Math.abs(y)) * (x >= 0 ? 1 : -1);
  3079. y = (1 - Math.abs(x)) * (y >= 0 ? 1 : -1);
  3080. }
  3081. const length = Math.sqrt(x * x + y * y + z * z);
  3082. result[j + 0] = x / length;
  3083. result[j + 1] = y / length;
  3084. result[j + 2] = z / length;
  3085. j += 3;
  3086. }
  3087. return result;
  3088. },
  3089.  
  3090. //------------------------------------------------------------------------------------------------------------------
  3091. // Boundaries
  3092. //------------------------------------------------------------------------------------------------------------------
  3093.  
  3094. /**
  3095. * Returns a new, uninitialized 3D axis-aligned bounding box.
  3096. *
  3097. * @private
  3098. */
  3099. AABB3(values) {
  3100. return new Float32Array(values || 6);
  3101. },
  3102.  
  3103. /**
  3104. * Returns a new, uninitialized 2D axis-aligned bounding box.
  3105. *
  3106. * @private
  3107. */
  3108. AABB2(values) {
  3109. return new Float32Array(values || 4);
  3110. },
  3111.  
  3112. /**
  3113. * Returns a new, uninitialized 3D oriented bounding box (OBB).
  3114. *
  3115. * @private
  3116. */
  3117. OBB3(values) {
  3118. return new Float32Array(values || 32);
  3119. },
  3120.  
  3121. /**
  3122. * Returns a new, uninitialized 2D oriented bounding box (OBB).
  3123. *
  3124. * @private
  3125. */
  3126. OBB2(values) {
  3127. return new Float32Array(values || 16);
  3128. },
  3129.  
  3130.  
  3131. /**
  3132. * Transforms an OBB3 by a 4x4 matrix.
  3133. *
  3134. * @private
  3135. */
  3136. transformOBB3(m, p, p2 = p) {
  3137. let i;
  3138. const len = p.length;
  3139.  
  3140. let x;
  3141. let y;
  3142. let z;
  3143.  
  3144. const m0 = m[0];
  3145. const m1 = m[1];
  3146. const m2 = m[2];
  3147. const m3 = m[3];
  3148. const m4 = m[4];
  3149. const m5 = m[5];
  3150. const m6 = m[6];
  3151. const m7 = m[7];
  3152. const m8 = m[8];
  3153. const m9 = m[9];
  3154. const m10 = m[10];
  3155. const m11 = m[11];
  3156. const m12 = m[12];
  3157. const m13 = m[13];
  3158. const m14 = m[14];
  3159. const m15 = m[15];
  3160.  
  3161. for (i = 0; i < len; i += 4) {
  3162.  
  3163. x = p[i + 0];
  3164. y = p[i + 1];
  3165. z = p[i + 2];
  3166.  
  3167. p2[i + 0] = (m0 * x) + (m4 * y) + (m8 * z) + m12;
  3168. p2[i + 1] = (m1 * x) + (m5 * y) + (m9 * z) + m13;
  3169. p2[i + 2] = (m2 * x) + (m6 * y) + (m10 * z) + m14;
  3170. p2[i + 3] = (m3 * x) + (m7 * y) + (m11 * z) + m15;
  3171. }
  3172.  
  3173. return p2;
  3174. },
  3175.  
  3176. /**
  3177. * Gets the diagonal size of an AABB3 given as minima and maxima.
  3178. *
  3179. * @private
  3180. */
  3181. getAABB3Diag: ((() => {
  3182.  
  3183. const min = new Float32Array(3);
  3184. const max = new Float32Array(3);
  3185. const tempVec3 = new Float32Array(3);
  3186.  
  3187. return aabb => {
  3188.  
  3189. min[0] = aabb[0];
  3190. min[1] = aabb[1];
  3191. min[2] = aabb[2];
  3192.  
  3193. max[0] = aabb[3];
  3194. max[1] = aabb[4];
  3195. max[2] = aabb[5];
  3196.  
  3197. math.subVec3(max, min, tempVec3);
  3198.  
  3199. return Math.abs(math.lenVec3(tempVec3));
  3200. };
  3201. }))(),
  3202.  
  3203. /**
  3204. * Get a diagonal boundary size that is symmetrical about the given point.
  3205. *
  3206. * @private
  3207. */
  3208. getAABB3DiagPoint: ((() => {
  3209.  
  3210. const min = new Float32Array(3);
  3211. const max = new Float32Array(3);
  3212. const tempVec3 = new Float32Array(3);
  3213.  
  3214. return (aabb, p) => {
  3215.  
  3216. min[0] = aabb[0];
  3217. min[1] = aabb[1];
  3218. min[2] = aabb[2];
  3219.  
  3220. max[0] = aabb[3];
  3221. max[1] = aabb[4];
  3222. max[2] = aabb[5];
  3223.  
  3224. const diagVec = math.subVec3(max, min, tempVec3);
  3225.  
  3226. const xneg = p[0] - aabb[0];
  3227. const xpos = aabb[3] - p[0];
  3228. const yneg = p[1] - aabb[1];
  3229. const ypos = aabb[4] - p[1];
  3230. const zneg = p[2] - aabb[2];
  3231. const zpos = aabb[5] - p[2];
  3232.  
  3233. diagVec[0] += (xneg > xpos) ? xneg : xpos;
  3234. diagVec[1] += (yneg > ypos) ? yneg : ypos;
  3235. diagVec[2] += (zneg > zpos) ? zneg : zpos;
  3236.  
  3237. return Math.abs(math.lenVec3(diagVec));
  3238. };
  3239. }))(),
  3240.  
  3241. /**
  3242. * Gets the center of an AABB.
  3243. *
  3244. * @private
  3245. */
  3246. getAABB3Center(aabb, dest) {
  3247. const r = dest || math.vec3();
  3248.  
  3249. r[0] = (aabb[0] + aabb[3] ) / 2;
  3250. r[1] = (aabb[1] + aabb[4] ) / 2;
  3251. r[2] = (aabb[2] + aabb[5] ) / 2;
  3252.  
  3253. return r;
  3254. },
  3255.  
  3256. /**
  3257. * Gets the center of a 2D AABB.
  3258. *
  3259. * @private
  3260. */
  3261. getAABB2Center(aabb, dest) {
  3262. const r = dest || math.vec2();
  3263.  
  3264. r[0] = (aabb[2] + aabb[0] ) / 2;
  3265. r[1] = (aabb[3] + aabb[1] ) / 2;
  3266.  
  3267. return r;
  3268. },
  3269.  
  3270. /**
  3271. * Collapses a 3D axis-aligned boundary, ready to expand to fit 3D points.
  3272. * Creates new AABB if none supplied.
  3273. *
  3274. * @private
  3275. */
  3276. collapseAABB3(aabb = math.AABB3()) {
  3277. aabb[0] = math.MAX_DOUBLE;
  3278. aabb[1] = math.MAX_DOUBLE;
  3279. aabb[2] = math.MAX_DOUBLE;
  3280. aabb[3] = -math.MAX_DOUBLE;
  3281. aabb[4] = -math.MAX_DOUBLE;
  3282. aabb[5] = -math.MAX_DOUBLE;
  3283.  
  3284. return aabb;
  3285. },
  3286.  
  3287. /**
  3288. * Converts an axis-aligned 3D boundary into an oriented boundary consisting of
  3289. * an array of eight 3D positions, one for each corner of the boundary.
  3290. *
  3291. * @private
  3292. */
  3293. AABB3ToOBB3(aabb, obb = math.OBB3()) {
  3294. obb[0] = aabb[0];
  3295. obb[1] = aabb[1];
  3296. obb[2] = aabb[2];
  3297. obb[3] = 1;
  3298.  
  3299. obb[4] = aabb[3];
  3300. obb[5] = aabb[1];
  3301. obb[6] = aabb[2];
  3302. obb[7] = 1;
  3303.  
  3304. obb[8] = aabb[3];
  3305. obb[9] = aabb[4];
  3306. obb[10] = aabb[2];
  3307. obb[11] = 1;
  3308.  
  3309. obb[12] = aabb[0];
  3310. obb[13] = aabb[4];
  3311. obb[14] = aabb[2];
  3312. obb[15] = 1;
  3313.  
  3314. obb[16] = aabb[0];
  3315. obb[17] = aabb[1];
  3316. obb[18] = aabb[5];
  3317. obb[19] = 1;
  3318.  
  3319. obb[20] = aabb[3];
  3320. obb[21] = aabb[1];
  3321. obb[22] = aabb[5];
  3322. obb[23] = 1;
  3323.  
  3324. obb[24] = aabb[3];
  3325. obb[25] = aabb[4];
  3326. obb[26] = aabb[5];
  3327. obb[27] = 1;
  3328.  
  3329. obb[28] = aabb[0];
  3330. obb[29] = aabb[4];
  3331. obb[30] = aabb[5];
  3332. obb[31] = 1;
  3333.  
  3334. return obb;
  3335. },
  3336.  
  3337. /**
  3338. * Finds the minimum axis-aligned 3D boundary enclosing the homogeneous 3D points (x,y,z,w) given in a flattened array.
  3339. *
  3340. * @private
  3341. */
  3342. positions3ToAABB3: ((() => {
  3343.  
  3344. const p = new Float32Array(3);
  3345.  
  3346. return (positions, aabb, positionsDecodeMatrix) => {
  3347. aabb = aabb || math.AABB3();
  3348.  
  3349. let xmin = math.MAX_DOUBLE;
  3350. let ymin = math.MAX_DOUBLE;
  3351. let zmin = math.MAX_DOUBLE;
  3352. let xmax = -math.MAX_DOUBLE;
  3353. let ymax = -math.MAX_DOUBLE;
  3354. let zmax = -math.MAX_DOUBLE;
  3355.  
  3356. let x;
  3357. let y;
  3358. let z;
  3359.  
  3360. for (let i = 0, len = positions.length; i < len; i += 3) {
  3361.  
  3362. if (positionsDecodeMatrix) {
  3363.  
  3364. p[0] = positions[i + 0];
  3365. p[1] = positions[i + 1];
  3366. p[2] = positions[i + 2];
  3367.  
  3368. math.decompressPosition(p, positionsDecodeMatrix, p);
  3369.  
  3370. x = p[0];
  3371. y = p[1];
  3372. z = p[2];
  3373.  
  3374. } else {
  3375. x = positions[i + 0];
  3376. y = positions[i + 1];
  3377. z = positions[i + 2];
  3378. }
  3379.  
  3380. if (x < xmin) {
  3381. xmin = x;
  3382. }
  3383.  
  3384. if (y < ymin) {
  3385. ymin = y;
  3386. }
  3387.  
  3388. if (z < zmin) {
  3389. zmin = z;
  3390. }
  3391.  
  3392. if (x > xmax) {
  3393. xmax = x;
  3394. }
  3395.  
  3396. if (y > ymax) {
  3397. ymax = y;
  3398. }
  3399.  
  3400. if (z > zmax) {
  3401. zmax = z;
  3402. }
  3403. }
  3404.  
  3405. aabb[0] = xmin;
  3406. aabb[1] = ymin;
  3407. aabb[2] = zmin;
  3408. aabb[3] = xmax;
  3409. aabb[4] = ymax;
  3410. aabb[5] = zmax;
  3411.  
  3412. return aabb;
  3413. };
  3414. }))(),
  3415.  
  3416. /**
  3417. * Finds the minimum axis-aligned 3D boundary enclosing the homogeneous 3D points (x,y,z,w) given in a flattened array.
  3418. *
  3419. * @private
  3420. */
  3421. OBB3ToAABB3(obb, aabb = math.AABB3()) {
  3422. let xmin = math.MAX_DOUBLE;
  3423. let ymin = math.MAX_DOUBLE;
  3424. let zmin = math.MAX_DOUBLE;
  3425. let xmax = -math.MAX_DOUBLE;
  3426. let ymax = -math.MAX_DOUBLE;
  3427. let zmax = -math.MAX_DOUBLE;
  3428.  
  3429. let x;
  3430. let y;
  3431. let z;
  3432.  
  3433. for (let i = 0, len = obb.length; i < len; i += 4) {
  3434.  
  3435. x = obb[i + 0];
  3436. y = obb[i + 1];
  3437. z = obb[i + 2];
  3438.  
  3439. if (x < xmin) {
  3440. xmin = x;
  3441. }
  3442.  
  3443. if (y < ymin) {
  3444. ymin = y;
  3445. }
  3446.  
  3447. if (z < zmin) {
  3448. zmin = z;
  3449. }
  3450.  
  3451. if (x > xmax) {
  3452. xmax = x;
  3453. }
  3454.  
  3455. if (y > ymax) {
  3456. ymax = y;
  3457. }
  3458.  
  3459. if (z > zmax) {
  3460. zmax = z;
  3461. }
  3462. }
  3463.  
  3464. aabb[0] = xmin;
  3465. aabb[1] = ymin;
  3466. aabb[2] = zmin;
  3467. aabb[3] = xmax;
  3468. aabb[4] = ymax;
  3469. aabb[5] = zmax;
  3470.  
  3471. return aabb;
  3472. },
  3473.  
  3474. /**
  3475. * Finds the minimum axis-aligned 3D boundary enclosing the given 3D points.
  3476. *
  3477. * @private
  3478. */
  3479. points3ToAABB3(points, aabb = math.AABB3()) {
  3480. let xmin = math.MAX_DOUBLE;
  3481. let ymin = math.MAX_DOUBLE;
  3482. let zmin = math.MAX_DOUBLE;
  3483. let xmax = -math.MAX_DOUBLE;
  3484. let ymax = -math.MAX_DOUBLE;
  3485. let zmax = -math.MAX_DOUBLE;
  3486.  
  3487. let x;
  3488. let y;
  3489. let z;
  3490.  
  3491. for (let i = 0, len = points.length; i < len; i++) {
  3492.  
  3493. x = points[i][0];
  3494. y = points[i][1];
  3495. z = points[i][2];
  3496.  
  3497. if (x < xmin) {
  3498. xmin = x;
  3499. }
  3500.  
  3501. if (y < ymin) {
  3502. ymin = y;
  3503. }
  3504.  
  3505. if (z < zmin) {
  3506. zmin = z;
  3507. }
  3508.  
  3509. if (x > xmax) {
  3510. xmax = x;
  3511. }
  3512.  
  3513. if (y > ymax) {
  3514. ymax = y;
  3515. }
  3516.  
  3517. if (z > zmax) {
  3518. zmax = z;
  3519. }
  3520. }
  3521.  
  3522. aabb[0] = xmin;
  3523. aabb[1] = ymin;
  3524. aabb[2] = zmin;
  3525. aabb[3] = xmax;
  3526. aabb[4] = ymax;
  3527. aabb[5] = zmax;
  3528.  
  3529. return aabb;
  3530. },
  3531.  
  3532. /**
  3533. * Finds the minimum boundary sphere enclosing the given 3D points.
  3534. *
  3535. * @private
  3536. */
  3537. points3ToSphere3: ((() => {
  3538.  
  3539. const tempVec3 = new Float32Array(3);
  3540.  
  3541. return (points, sphere) => {
  3542.  
  3543. sphere = sphere || math.vec4();
  3544.  
  3545. let x = 0;
  3546. let y = 0;
  3547. let z = 0;
  3548.  
  3549. let i;
  3550. const numPoints = points.length;
  3551.  
  3552. for (i = 0; i < numPoints; i++) {
  3553. x += points[i][0];
  3554. y += points[i][1];
  3555. z += points[i][2];
  3556. }
  3557.  
  3558. sphere[0] = x / numPoints;
  3559. sphere[1] = y / numPoints;
  3560. sphere[2] = z / numPoints;
  3561.  
  3562. let radius = 0;
  3563. let dist;
  3564.  
  3565. for (i = 0; i < numPoints; i++) {
  3566.  
  3567. dist = Math.abs(math.lenVec3(math.subVec3(points[i], sphere, tempVec3)));
  3568.  
  3569. if (dist > radius) {
  3570. radius = dist;
  3571. }
  3572. }
  3573.  
  3574. sphere[3] = radius;
  3575.  
  3576. return sphere;
  3577. };
  3578. }))(),
  3579.  
  3580. /**
  3581. * Finds the minimum boundary sphere enclosing the given 3D points.
  3582. *
  3583. * @private
  3584. */
  3585. OBB3ToSphere3: ((() => {
  3586.  
  3587. const point = new Float32Array(3);
  3588. const tempVec3 = new Float32Array(3);
  3589.  
  3590. return (points, sphere) => {
  3591.  
  3592. sphere = sphere || math.vec4();
  3593.  
  3594. let x = 0;
  3595. let y = 0;
  3596. let z = 0;
  3597.  
  3598. let i;
  3599. const lenPoints = points.length;
  3600. const numPoints = lenPoints / 4;
  3601.  
  3602. for (i = 0; i < lenPoints; i += 4) {
  3603. x += points[i + 0];
  3604. y += points[i + 1];
  3605. z += points[i + 2];
  3606. }
  3607.  
  3608. sphere[0] = x / numPoints;
  3609. sphere[1] = y / numPoints;
  3610. sphere[2] = z / numPoints;
  3611.  
  3612. let radius = 0;
  3613. let dist;
  3614.  
  3615. for (i = 0; i < lenPoints; i += 4) {
  3616.  
  3617. point[0] = points[i + 0];
  3618. point[1] = points[i + 1];
  3619. point[2] = points[i + 2];
  3620.  
  3621. dist = Math.abs(math.lenVec3(math.subVec3(point, sphere, tempVec3)));
  3622.  
  3623. if (dist > radius) {
  3624. radius = dist;
  3625. }
  3626. }
  3627.  
  3628. sphere[3] = radius;
  3629.  
  3630. return sphere;
  3631. };
  3632. }))(),
  3633.  
  3634. /**
  3635. * Gets the center of a bounding sphere.
  3636. *
  3637. * @private
  3638. */
  3639. getSphere3Center(sphere, dest = math.vec3()) {
  3640. dest[0] = sphere[0];
  3641. dest[1] = sphere[1];
  3642. dest[2] = sphere[2];
  3643.  
  3644. return dest;
  3645. },
  3646.  
  3647. /**
  3648. * Expands the first axis-aligned 3D boundary to enclose the second, if required.
  3649. *
  3650. * @private
  3651. */
  3652. expandAABB3(aabb1, aabb2) {
  3653.  
  3654. if (aabb1[0] > aabb2[0]) {
  3655. aabb1[0] = aabb2[0];
  3656. }
  3657.  
  3658. if (aabb1[1] > aabb2[1]) {
  3659. aabb1[1] = aabb2[1];
  3660. }
  3661.  
  3662. if (aabb1[2] > aabb2[2]) {
  3663. aabb1[2] = aabb2[2];
  3664. }
  3665.  
  3666. if (aabb1[3] < aabb2[3]) {
  3667. aabb1[3] = aabb2[3];
  3668. }
  3669.  
  3670. if (aabb1[4] < aabb2[4]) {
  3671. aabb1[4] = aabb2[4];
  3672. }
  3673.  
  3674. if (aabb1[5] < aabb2[5]) {
  3675. aabb1[5] = aabb2[5];
  3676. }
  3677.  
  3678. return aabb1;
  3679. },
  3680.  
  3681. /**
  3682. * Expands an axis-aligned 3D boundary to enclose the given point, if needed.
  3683. *
  3684. * @private
  3685. */
  3686. expandAABB3Point3(aabb, p) {
  3687.  
  3688. if (aabb[0] < p[0]) {
  3689. aabb[0] = p[0];
  3690. }
  3691.  
  3692. if (aabb[1] < p[1]) {
  3693. aabb[1] = p[1];
  3694. }
  3695.  
  3696. if (aabb[2] < p[2]) {
  3697. aabb[2] = p[2];
  3698. }
  3699.  
  3700. if (aabb[3] > p[0]) {
  3701. aabb[3] = p[0];
  3702. }
  3703.  
  3704. if (aabb[4] > p[1]) {
  3705. aabb[4] = p[1];
  3706. }
  3707.  
  3708. if (aabb[5] > p[2]) {
  3709. aabb[5] = p[2];
  3710. }
  3711.  
  3712. return aabb;
  3713. },
  3714.  
  3715. /**
  3716. * Collapses a 2D axis-aligned boundary, ready to expand to fit 2D points.
  3717. * Creates new AABB if none supplied.
  3718. *
  3719. * @private
  3720. */
  3721. collapseAABB2(aabb = math.AABB2()) {
  3722. aabb[0] = math.MAX_DOUBLE;
  3723. aabb[1] = math.MAX_DOUBLE;
  3724. aabb[2] = -math.MAX_DOUBLE;
  3725. aabb[3] = -math.MAX_DOUBLE;
  3726.  
  3727. return aabb;
  3728. },
  3729.  
  3730. /**
  3731. * Finds the minimum 2D projected axis-aligned boundary enclosing the given 3D points.
  3732. *
  3733. * @private
  3734. */
  3735. OBB3ToAABB2(points, aabb = math.AABB2()) {
  3736. let xmin = math.MAX_DOUBLE;
  3737. let ymin = math.MAX_DOUBLE;
  3738. let xmax = -math.MAX_DOUBLE;
  3739. let ymax = -math.MAX_DOUBLE;
  3740.  
  3741. let x;
  3742. let y;
  3743. let w;
  3744. let f;
  3745.  
  3746. for (let i = 0, len = points.length; i < len; i += 4) {
  3747.  
  3748. x = points[i + 0];
  3749. y = points[i + 1];
  3750. w = points[i + 3] || 1.0;
  3751.  
  3752. f = 1.0 / w;
  3753.  
  3754. x *= f;
  3755. y *= f;
  3756.  
  3757. if (x < xmin) {
  3758. xmin = x;
  3759. }
  3760.  
  3761. if (y < ymin) {
  3762. ymin = y;
  3763. }
  3764.  
  3765. if (x > xmax) {
  3766. xmax = x;
  3767. }
  3768.  
  3769. if (y > ymax) {
  3770. ymax = y;
  3771. }
  3772. }
  3773.  
  3774. aabb[0] = xmin;
  3775. aabb[1] = ymin;
  3776. aabb[2] = xmax;
  3777. aabb[3] = ymax;
  3778.  
  3779. return aabb;
  3780. },
  3781.  
  3782. /**
  3783. * Expands the first axis-aligned 2D boundary to enclose the second, if required.
  3784. *
  3785. * @private
  3786. */
  3787. expandAABB2(aabb1, aabb2) {
  3788.  
  3789. if (aabb1[0] > aabb2[0]) {
  3790. aabb1[0] = aabb2[0];
  3791. }
  3792.  
  3793. if (aabb1[1] > aabb2[1]) {
  3794. aabb1[1] = aabb2[1];
  3795. }
  3796.  
  3797. if (aabb1[2] < aabb2[2]) {
  3798. aabb1[2] = aabb2[2];
  3799. }
  3800.  
  3801. if (aabb1[3] < aabb2[3]) {
  3802. aabb1[3] = aabb2[3];
  3803. }
  3804.  
  3805. return aabb1;
  3806. },
  3807.  
  3808. /**
  3809. * Expands an axis-aligned 2D boundary to enclose the given point, if required.
  3810. *
  3811. * @private
  3812. */
  3813. expandAABB2Point2(aabb, p) {
  3814.  
  3815. if (aabb[0] > p[0]) {
  3816. aabb[0] = p[0];
  3817. }
  3818.  
  3819. if (aabb[1] > p[1]) {
  3820. aabb[1] = p[1];
  3821. }
  3822.  
  3823. if (aabb[2] < p[0]) {
  3824. aabb[2] = p[0];
  3825. }
  3826.  
  3827. if (aabb[3] < p[1]) {
  3828. aabb[3] = p[1];
  3829. }
  3830.  
  3831. return aabb;
  3832. },
  3833.  
  3834. AABB2ToCanvas(aabb, canvasWidth, canvasHeight, aabb2 = aabb) {
  3835. const xmin = (aabb[0] + 1.0) * 0.5;
  3836. const ymin = (aabb[1] + 1.0) * 0.5;
  3837. const xmax = (aabb[2] + 1.0) * 0.5;
  3838. const ymax = (aabb[3] + 1.0) * 0.5;
  3839.  
  3840. aabb2[0] = Math.floor(xmin * canvasWidth);
  3841. aabb2[1] = canvasHeight - Math.floor(ymax * canvasHeight);
  3842. aabb2[2] = Math.floor(xmax * canvasWidth);
  3843. aabb2[3] = canvasHeight - Math.floor(ymin * canvasHeight);
  3844.  
  3845. return aabb2;
  3846. },
  3847.  
  3848. //------------------------------------------------------------------------------------------------------------------
  3849. // Curves
  3850. //------------------------------------------------------------------------------------------------------------------
  3851.  
  3852. tangentQuadraticBezier(t, p0, p1, p2) {
  3853. return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 );
  3854. },
  3855.  
  3856. tangentQuadraticBezier3(t, p0, p1, p2, p3) {
  3857. return -3 * p0 * (1 - t) * (1 - t) +
  3858. 3 * p1 * (1 - t) * (1 - t) - 6 * t * p1 * (1 - t) +
  3859. 6 * t * p2 * (1 - t) - 3 * t * t * p2 +
  3860. 3 * t * t * p3;
  3861. },
  3862.  
  3863. tangentSpline(t) {
  3864. const h00 = 6 * t * t - 6 * t;
  3865. const h10 = 3 * t * t - 4 * t + 1;
  3866. const h01 = -6 * t * t + 6 * t;
  3867. const h11 = 3 * t * t - 2 * t;
  3868. return h00 + h10 + h01 + h11;
  3869. },
  3870.  
  3871. catmullRomInterpolate(p0, p1, p2, p3, t) {
  3872. const v0 = ( p2 - p0 ) * 0.5;
  3873. const v1 = ( p3 - p1 ) * 0.5;
  3874. const t2 = t * t;
  3875. const t3 = t * t2;
  3876. return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( -3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
  3877. },
  3878.  
  3879. // Bezier Curve formulii from http://en.wikipedia.org/wiki/B%C3%A9zier_curve
  3880.  
  3881. // Quad Bezier Functions
  3882.  
  3883. b2p0(t, p) {
  3884. const k = 1 - t;
  3885. return k * k * p;
  3886.  
  3887. },
  3888.  
  3889. b2p1(t, p) {
  3890. return 2 * ( 1 - t ) * t * p;
  3891. },
  3892.  
  3893. b2p2(t, p) {
  3894. return t * t * p;
  3895. },
  3896.  
  3897. b2(t, p0, p1, p2) {
  3898. return this.b2p0(t, p0) + this.b2p1(t, p1) + this.b2p2(t, p2);
  3899. },
  3900.  
  3901. // Cubic Bezier Functions
  3902.  
  3903. b3p0(t, p) {
  3904. const k = 1 - t;
  3905. return k * k * k * p;
  3906. },
  3907.  
  3908. b3p1(t, p) {
  3909. const k = 1 - t;
  3910. return 3 * k * k * t * p;
  3911. },
  3912.  
  3913. b3p2(t, p) {
  3914. const k = 1 - t;
  3915. return 3 * k * t * t * p;
  3916. },
  3917.  
  3918. b3p3(t, p) {
  3919. return t * t * t * p;
  3920. },
  3921.  
  3922. b3(t, p0, p1, p2, p3) {
  3923. return this.b3p0(t, p0) + this.b3p1(t, p1) + this.b3p2(t, p2) + this.b3p3(t, p3);
  3924. },
  3925.  
  3926. //------------------------------------------------------------------------------------------------------------------
  3927. // Geometry
  3928. //------------------------------------------------------------------------------------------------------------------
  3929.  
  3930. /**
  3931. * Calculates the normal vector of a triangle.
  3932. *
  3933. * @private
  3934. */
  3935. triangleNormal(a, b, c, normal = math.vec3()) {
  3936. const p1x = b[0] - a[0];
  3937. const p1y = b[1] - a[1];
  3938. const p1z = b[2] - a[2];
  3939.  
  3940. const p2x = c[0] - a[0];
  3941. const p2y = c[1] - a[1];
  3942. const p2z = c[2] - a[2];
  3943.  
  3944. const p3x = p1y * p2z - p1z * p2y;
  3945. const p3y = p1z * p2x - p1x * p2z;
  3946. const p3z = p1x * p2y - p1y * p2x;
  3947.  
  3948. const mag = Math.sqrt(p3x * p3x + p3y * p3y + p3z * p3z);
  3949. if (mag === 0) {
  3950. normal[0] = 0;
  3951. normal[1] = 0;
  3952. normal[2] = 0;
  3953. } else {
  3954. normal[0] = p3x / mag;
  3955. normal[1] = p3y / mag;
  3956. normal[2] = p3z / mag;
  3957. }
  3958.  
  3959. return normal
  3960. },
  3961.  
  3962. /**
  3963. * Finds the intersection of a 3D ray with a 3D triangle.
  3964. *
  3965. * @private
  3966. */
  3967. rayTriangleIntersect: ((() => {
  3968.  
  3969. const tempVec3 = new Float32Array(3);
  3970. const tempVec3b = new Float32Array(3);
  3971. const tempVec3c = new Float32Array(3);
  3972. const tempVec3d = new Float32Array(3);
  3973. const tempVec3e = new Float32Array(3);
  3974.  
  3975. return (origin, dir, a, b, c, isect) => {
  3976.  
  3977. isect = isect || math.vec3();
  3978.  
  3979. const EPSILON = 0.000001;
  3980.  
  3981. const edge1 = math.subVec3(b, a, tempVec3);
  3982. const edge2 = math.subVec3(c, a, tempVec3b);
  3983.  
  3984. const pvec = math.cross3Vec3(dir, edge2, tempVec3c);
  3985. const det = math.dotVec3(edge1, pvec);
  3986. if (det < EPSILON) {
  3987. return null;
  3988. }
  3989.  
  3990. const tvec = math.subVec3(origin, a, tempVec3d);
  3991. const u = math.dotVec3(tvec, pvec);
  3992. if (u < 0 || u > det) {
  3993. return null;
  3994. }
  3995.  
  3996. const qvec = math.cross3Vec3(tvec, edge1, tempVec3e);
  3997. const v = math.dotVec3(dir, qvec);
  3998. if (v < 0 || u + v > det) {
  3999. return null;
  4000. }
  4001.  
  4002. const t = math.dotVec3(edge2, qvec) / det;
  4003. isect[0] = origin[0] + t * dir[0];
  4004. isect[1] = origin[1] + t * dir[1];
  4005. isect[2] = origin[2] + t * dir[2];
  4006.  
  4007. return isect;
  4008. };
  4009. }))(),
  4010.  
  4011. /**
  4012. * Finds the intersection of a 3D ray with a plane defined by 3 points.
  4013. *
  4014. * @private
  4015. */
  4016. rayPlaneIntersect: ((() => {
  4017.  
  4018. const tempVec3 = new Float32Array(3);
  4019. const tempVec3b = new Float32Array(3);
  4020. const tempVec3c = new Float32Array(3);
  4021. const tempVec3d = new Float32Array(3);
  4022.  
  4023. return (origin, dir, a, b, c, isect) => {
  4024.  
  4025. isect = isect || math.vec3();
  4026.  
  4027. dir = math.normalizeVec3(dir, tempVec3);
  4028.  
  4029. const edge1 = math.subVec3(b, a, tempVec3b);
  4030. const edge2 = math.subVec3(c, a, tempVec3c);
  4031.  
  4032. const n = math.cross3Vec3(edge1, edge2, tempVec3d);
  4033. math.normalizeVec3(n, n);
  4034.  
  4035. const d = -math.dotVec3(a, n);
  4036.  
  4037. const t = -(math.dotVec3(origin, n) + d) / math.dotVec3(dir, n);
  4038.  
  4039. isect[0] = origin[0] + t * dir[0];
  4040. isect[1] = origin[1] + t * dir[1];
  4041. isect[2] = origin[2] + t * dir[2];
  4042.  
  4043. return isect;
  4044. };
  4045. }))(),
  4046.  
  4047. /**
  4048. * Gets barycentric coordinates from cartesian coordinates within a triangle.
  4049. * Gets barycentric coordinates from cartesian coordinates within a triangle.
  4050. *
  4051. * @private
  4052. */
  4053. cartesianToBarycentric: ((() => {
  4054.  
  4055. const tempVec3 = new Float32Array(3);
  4056. const tempVec3b = new Float32Array(3);
  4057. const tempVec3c = new Float32Array(3);
  4058.  
  4059. return (cartesian, a, b, c, dest) => {
  4060.  
  4061. const v0 = math.subVec3(c, a, tempVec3);
  4062. const v1 = math.subVec3(b, a, tempVec3b);
  4063. const v2 = math.subVec3(cartesian, a, tempVec3c);
  4064.  
  4065. const dot00 = math.dotVec3(v0, v0);
  4066. const dot01 = math.dotVec3(v0, v1);
  4067. const dot02 = math.dotVec3(v0, v2);
  4068. const dot11 = math.dotVec3(v1, v1);
  4069. const dot12 = math.dotVec3(v1, v2);
  4070.  
  4071. const denom = ( dot00 * dot11 - dot01 * dot01 );
  4072.  
  4073. // Colinear or singular triangle
  4074.  
  4075. if (denom === 0) {
  4076.  
  4077. // Arbitrary location outside of triangle
  4078.  
  4079. return null;
  4080. }
  4081.  
  4082. const invDenom = 1 / denom;
  4083.  
  4084. const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
  4085. const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
  4086.  
  4087. dest[0] = 1 - u - v;
  4088. dest[1] = v;
  4089. dest[2] = u;
  4090.  
  4091. return dest;
  4092. };
  4093. }))(),
  4094.  
  4095. /**
  4096. * Returns true if the given barycentric coordinates are within their triangle.
  4097. *
  4098. * @private
  4099. */
  4100. barycentricInsideTriangle(bary) {
  4101.  
  4102. const v = bary[1];
  4103. const u = bary[2];
  4104.  
  4105. return (u >= 0) && (v >= 0) && (u + v < 1);
  4106. },
  4107.  
  4108. /**
  4109. * Gets cartesian coordinates from barycentric coordinates within a triangle.
  4110. *
  4111. * @private
  4112. */
  4113. barycentricToCartesian(bary, a, b, c, cartesian = math.vec3()) {
  4114. const u = bary[0];
  4115. const v = bary[1];
  4116. const w = bary[2];
  4117.  
  4118. cartesian[0] = a[0] * u + b[0] * v + c[0] * w;
  4119. cartesian[1] = a[1] * u + b[1] * v + c[1] * w;
  4120. cartesian[2] = a[2] * u + b[2] * v + c[2] * w;
  4121.  
  4122. return cartesian;
  4123. },
  4124.  
  4125. /**
  4126. * Given geometry defined as an array of positions, optional normals, option uv and an array of indices, returns
  4127. * modified arrays that have duplicate vertices removed.
  4128. *
  4129. * Note: does not work well when co-incident vertices have same positions but different normals and UVs.
  4130. *
  4131. * @param positions
  4132. * @param normals
  4133. * @param uv
  4134. * @param indices
  4135. * @returns {{positions: Array, indices: Array}}
  4136. * @private
  4137. */
  4138. mergeVertices(positions, normals, uv, indices) {
  4139. const positionsMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique)
  4140. const indicesLookup = [];
  4141. const uniquePositions = [];
  4142. const uniqueNormals = normals ? [] : null;
  4143. const uniqueUV = uv ? [] : null;
  4144. const indices2 = [];
  4145. let vx;
  4146. let vy;
  4147. let vz;
  4148. let key;
  4149. const precisionPoints = 4; // number of decimal points, e.g. 4 for epsilon of 0.0001
  4150. const precision = 10 ** precisionPoints;
  4151. let i;
  4152. let len;
  4153. let uvi = 0;
  4154. for (i = 0, len = positions.length; i < len; i += 3) {
  4155. vx = positions[i];
  4156. vy = positions[i + 1];
  4157. vz = positions[i + 2];
  4158. key = `${Math.round(vx * precision)}_${Math.round(vy * precision)}_${Math.round(vz * precision)}`;
  4159. if (positionsMap[key] === undefined) {
  4160. positionsMap[key] = uniquePositions.length / 3;
  4161. uniquePositions.push(vx);
  4162. uniquePositions.push(vy);
  4163. uniquePositions.push(vz);
  4164. if (normals) {
  4165. uniqueNormals.push(normals[i]);
  4166. uniqueNormals.push(normals[i + 1]);
  4167. uniqueNormals.push(normals[i + 2]);
  4168. }
  4169. if (uv) {
  4170. uniqueUV.push(uv[uvi]);
  4171. uniqueUV.push(uv[uvi + 1]);
  4172. }
  4173. }
  4174. indicesLookup[i / 3] = positionsMap[key];
  4175. uvi += 2;
  4176. }
  4177. for (i = 0, len = indices.length; i < len; i++) {
  4178. indices2[i] = indicesLookup[indices[i]];
  4179. }
  4180. const result = {
  4181. positions: uniquePositions,
  4182. indices: indices2
  4183. };
  4184. if (uniqueNormals) {
  4185. result.normals = uniqueNormals;
  4186. }
  4187. if (uniqueUV) {
  4188. result.uv = uniqueUV;
  4189.  
  4190. }
  4191. return result;
  4192. },
  4193.  
  4194. /**
  4195. * Builds normal vectors from positions and indices.
  4196. *
  4197. * @private
  4198. */
  4199. buildNormals: ((() => {
  4200.  
  4201. const a = new Float32Array(3);
  4202. const b = new Float32Array(3);
  4203. const c = new Float32Array(3);
  4204. const ab = new Float32Array(3);
  4205. const ac = new Float32Array(3);
  4206. const crossVec = new Float32Array(3);
  4207.  
  4208. return (positions, indices, normals) => {
  4209.  
  4210. let i;
  4211. let len;
  4212. const nvecs = new Array(positions.length / 3);
  4213. let j0;
  4214. let j1;
  4215. let j2;
  4216.  
  4217. for (i = 0, len = indices.length; i < len; i += 3) {
  4218.  
  4219. j0 = indices[i];
  4220. j1 = indices[i + 1];
  4221. j2 = indices[i + 2];
  4222.  
  4223. a[0] = positions[j0 * 3];
  4224. a[1] = positions[j0 * 3 + 1];
  4225. a[2] = positions[j0 * 3 + 2];
  4226.  
  4227. b[0] = positions[j1 * 3];
  4228. b[1] = positions[j1 * 3 + 1];
  4229. b[2] = positions[j1 * 3 + 2];
  4230.  
  4231. c[0] = positions[j2 * 3];
  4232. c[1] = positions[j2 * 3 + 1];
  4233. c[2] = positions[j2 * 3 + 2];
  4234.  
  4235. math.subVec3(b, a, ab);
  4236. math.subVec3(c, a, ac);
  4237.  
  4238. const normVec = new Float32Array(3);
  4239.  
  4240. math.normalizeVec3(math.cross3Vec3(ab, ac, crossVec), normVec);
  4241.  
  4242. if (!nvecs[j0]) {
  4243. nvecs[j0] = [];
  4244. }
  4245. if (!nvecs[j1]) {
  4246. nvecs[j1] = [];
  4247. }
  4248. if (!nvecs[j2]) {
  4249. nvecs[j2] = [];
  4250. }
  4251.  
  4252. nvecs[j0].push(normVec);
  4253. nvecs[j1].push(normVec);
  4254. nvecs[j2].push(normVec);
  4255. }
  4256.  
  4257. normals = (normals && normals.length === positions.length) ? normals : new Float32Array(positions.length);
  4258.  
  4259. let count;
  4260. let x;
  4261. let y;
  4262. let z;
  4263.  
  4264. for (i = 0, len = nvecs.length; i < len; i++) { // Now go through and average out everything
  4265.  
  4266. count = nvecs[i].length;
  4267.  
  4268. x = 0;
  4269. y = 0;
  4270. z = 0;
  4271.  
  4272. for (let j = 0; j < count; j++) {
  4273. x += nvecs[i][j][0];
  4274. y += nvecs[i][j][1];
  4275. z += nvecs[i][j][2];
  4276. }
  4277.  
  4278. normals[i * 3] = (x / count);
  4279. normals[i * 3 + 1] = (y / count);
  4280. normals[i * 3 + 2] = (z / count);
  4281. }
  4282.  
  4283. return normals;
  4284. };
  4285. }))(),
  4286.  
  4287. /**
  4288. * Builds vertex tangent vectors from positions, UVs and indices.
  4289. *
  4290. * @private
  4291. */
  4292. buildTangents: ((() => {
  4293.  
  4294. const tempVec3 = new Float32Array(3);
  4295. const tempVec3b = new Float32Array(3);
  4296. const tempVec3c = new Float32Array(3);
  4297. const tempVec3d = new Float32Array(3);
  4298. const tempVec3e = new Float32Array(3);
  4299. const tempVec3f = new Float32Array(3);
  4300. const tempVec3g = new Float32Array(3);
  4301.  
  4302. return (positions, indices, uv) => {
  4303.  
  4304. const tangents = new Float32Array(positions.length);
  4305.  
  4306. // The vertex arrays needs to be calculated
  4307. // before the calculation of the tangents
  4308.  
  4309. for (let location = 0; location < indices.length; location += 3) {
  4310.  
  4311. // Recontructing each vertex and UV coordinate into the respective vectors
  4312.  
  4313. let index = indices[location];
  4314.  
  4315. const v0 = positions.subarray(index * 3, index * 3 + 3);
  4316. const uv0 = uv.subarray(index * 2, index * 2 + 2);
  4317.  
  4318. index = indices[location + 1];
  4319.  
  4320. const v1 = positions.subarray(index * 3, index * 3 + 3);
  4321. const uv1 = uv.subarray(index * 2, index * 2 + 2);
  4322.  
  4323. index = indices[location + 2];
  4324.  
  4325. const v2 = positions.subarray(index * 3, index * 3 + 3);
  4326. const uv2 = uv.subarray(index * 2, index * 2 + 2);
  4327.  
  4328. const deltaPos1 = math.subVec3(v1, v0, tempVec3);
  4329. const deltaPos2 = math.subVec3(v2, v0, tempVec3b);
  4330.  
  4331. const deltaUV1 = math.subVec2(uv1, uv0, tempVec3c);
  4332. const deltaUV2 = math.subVec2(uv2, uv0, tempVec3d);
  4333.  
  4334. const r = 1 / ((deltaUV1[0] * deltaUV2[1]) - (deltaUV1[1] * deltaUV2[0]));
  4335.  
  4336. const tangent = math.mulVec3Scalar(
  4337. math.subVec3(
  4338. math.mulVec3Scalar(deltaPos1, deltaUV2[1], tempVec3e),
  4339. math.mulVec3Scalar(deltaPos2, deltaUV1[1], tempVec3f),
  4340. tempVec3g
  4341. ),
  4342. r,
  4343. tempVec3f
  4344. );
  4345.  
  4346. // Average the value of the vectors
  4347.  
  4348. let addTo;
  4349.  
  4350. for (let v = 0; v < 3; v++) {
  4351. addTo = indices[location + v] * 3;
  4352. tangents[addTo] += tangent[0];
  4353. tangents[addTo + 1] += tangent[1];
  4354. tangents[addTo + 2] += tangent[2];
  4355. }
  4356. }
  4357.  
  4358. return tangents;
  4359. };
  4360. }))(),
  4361.  
  4362. /**
  4363. * Builds vertex and index arrays needed by color-indexed triangle picking.
  4364. *
  4365. * @private
  4366. */
  4367. buildPickTriangles(positions, indices, quantized) {
  4368.  
  4369. const numIndices = indices.length;
  4370. const pickPositions = quantized ? new Uint16Array(numIndices * 9) : new Float32Array(numIndices * 9);
  4371. const pickColors = new Uint8Array(numIndices * 12);
  4372. let primIndex = 0;
  4373. let vi;// Positions array index
  4374. let pvi = 0;// Picking positions array index
  4375. let pci = 0; // Picking color array index
  4376.  
  4377. // Triangle indices
  4378. let i;
  4379. let r;
  4380. let g;
  4381. let b;
  4382. let a;
  4383.  
  4384. for (let location = 0; location < numIndices; location += 3) {
  4385.  
  4386. // Primitive-indexed triangle pick color
  4387.  
  4388. a = (primIndex >> 24 & 0xFF);
  4389. b = (primIndex >> 16 & 0xFF);
  4390. g = (primIndex >> 8 & 0xFF);
  4391. r = (primIndex & 0xFF);
  4392.  
  4393. // A
  4394.  
  4395. i = indices[location];
  4396. vi = i * 3;
  4397.  
  4398. pickPositions[pvi++] = positions[vi];
  4399. pickPositions[pvi++] = positions[vi + 1];
  4400. pickPositions[pvi++] = positions[vi + 2];
  4401.  
  4402. pickColors[pci++] = r;
  4403. pickColors[pci++] = g;
  4404. pickColors[pci++] = b;
  4405. pickColors[pci++] = a;
  4406.  
  4407. // B
  4408.  
  4409. i = indices[location + 1];
  4410. vi = i * 3;
  4411.  
  4412. pickPositions[pvi++] = positions[vi];
  4413. pickPositions[pvi++] = positions[vi + 1];
  4414. pickPositions[pvi++] = positions[vi + 2];
  4415.  
  4416. pickColors[pci++] = r;
  4417. pickColors[pci++] = g;
  4418. pickColors[pci++] = b;
  4419. pickColors[pci++] = a;
  4420.  
  4421. // C
  4422.  
  4423. i = indices[location + 2];
  4424. vi = i * 3;
  4425.  
  4426. pickPositions[pvi++] = positions[vi];
  4427. pickPositions[pvi++] = positions[vi + 1];
  4428. pickPositions[pvi++] = positions[vi + 2];
  4429.  
  4430. pickColors[pci++] = r;
  4431. pickColors[pci++] = g;
  4432. pickColors[pci++] = b;
  4433. pickColors[pci++] = a;
  4434.  
  4435. primIndex++;
  4436. }
  4437.  
  4438. return {
  4439. positions: pickPositions,
  4440. colors: pickColors
  4441. };
  4442. },
  4443.  
  4444. /**
  4445. * Converts surface-perpendicular face normals to vertex normals. Assumes that the mesh contains disjoint triangles
  4446. * that don't share vertex array elements. Works by finding groups of vertices that have the same location and
  4447. * averaging their normal vectors.
  4448. *
  4449. * @returns {{positions: Array, normals: *}}
  4450. */
  4451. faceToVertexNormals(positions, normals, options = {}) {
  4452. const smoothNormalsAngleThreshold = options.smoothNormalsAngleThreshold || 20;
  4453. const vertexMap = {};
  4454. const vertexNormals = [];
  4455. const vertexNormalAccum = {};
  4456. let acc;
  4457. let vx;
  4458. let vy;
  4459. let vz;
  4460. let key;
  4461. const precisionPoints = 4; // number of decimal points, e.g. 4 for epsilon of 0.0001
  4462. const precision = 10 ** precisionPoints;
  4463. let posi;
  4464. let i;
  4465. let j;
  4466. let len;
  4467. let a;
  4468. let b;
  4469. let c;
  4470.  
  4471. for (i = 0, len = positions.length; i < len; i += 3) {
  4472.  
  4473. posi = i / 3;
  4474.  
  4475. vx = positions[i];
  4476. vy = positions[i + 1];
  4477. vz = positions[i + 2];
  4478.  
  4479. key = `${Math.round(vx * precision)}_${Math.round(vy * precision)}_${Math.round(vz * precision)}`;
  4480.  
  4481. if (vertexMap[key] === undefined) {
  4482. vertexMap[key] = [posi];
  4483. } else {
  4484. vertexMap[key].push(posi);
  4485. }
  4486.  
  4487. const normal = math.normalizeVec3([normals[i], normals[i + 1], normals[i + 2]]);
  4488.  
  4489. vertexNormals[posi] = normal;
  4490.  
  4491. acc = math.vec4([normal[0], normal[1], normal[2], 1]);
  4492.  
  4493. vertexNormalAccum[posi] = acc;
  4494. }
  4495.  
  4496. for (key in vertexMap) {
  4497.  
  4498. if (vertexMap.hasOwnProperty(key)) {
  4499.  
  4500. const vertices = vertexMap[key];
  4501. const numVerts = vertices.length;
  4502.  
  4503. for (i = 0; i < numVerts; i++) {
  4504.  
  4505. const ii = vertices[i];
  4506.  
  4507. acc = vertexNormalAccum[ii];
  4508.  
  4509. for (j = 0; j < numVerts; j++) {
  4510.  
  4511. if (i === j) {
  4512. continue;
  4513. }
  4514.  
  4515. const jj = vertices[j];
  4516.  
  4517. a = vertexNormals[ii];
  4518. b = vertexNormals[jj];
  4519.  
  4520. const angle = Math.abs(math.angleVec3(a, b) / math.DEGTORAD);
  4521.  
  4522. if (angle < smoothNormalsAngleThreshold) {
  4523.  
  4524. acc[0] += b[0];
  4525. acc[1] += b[1];
  4526. acc[2] += b[2];
  4527. acc[3] += 1.0;
  4528. }
  4529. }
  4530. }
  4531. }
  4532. }
  4533.  
  4534. for (i = 0, len = normals.length; i < len; i += 3) {
  4535.  
  4536. acc = vertexNormalAccum[i / 3];
  4537.  
  4538. normals[i + 0] = acc[0] / acc[3];
  4539. normals[i + 1] = acc[1] / acc[3];
  4540. normals[i + 2] = acc[2] / acc[3];
  4541.  
  4542. }
  4543. },
  4544.  
  4545. //------------------------------------------------------------------------------------------------------------------
  4546. // Ray casting
  4547. //------------------------------------------------------------------------------------------------------------------
  4548.  
  4549. /**
  4550. Transforms a Canvas-space position into a World-space ray, in the context of a Camera.
  4551. @method canvasPosToWorldRay
  4552. @static
  4553. @param {Camera} camera The Camera.
  4554. @param {Float32Array} canvasPos The Canvas-space position.
  4555. @param {Float32Array} worldRayOrigin The World-space ray origin.
  4556. @param {Float32Array} worldRayDir The World-space ray direction.
  4557. */
  4558. canvasPosToWorldRay: ((() => {
  4559.  
  4560. const tempMat4b = new Float32Array(16);
  4561. const tempMat4c = new Float32Array(16);
  4562. const tempVec4a = new Float32Array(4);
  4563. const tempVec4b = new Float32Array(4);
  4564. const tempVec4c = new Float32Array(4);
  4565. const tempVec4d = new Float32Array(4);
  4566.  
  4567. return (camera, canvasPos, worldRayOrigin, worldRayDir) => {
  4568.  
  4569. const canvas = camera.scene.canvas.canvas;
  4570.  
  4571. const viewMat = camera.viewMatrix;
  4572. const projMat = camera.projection === "ortho" ? camera.ortho.matrix : camera.perspective.matrix;
  4573.  
  4574. const pvMat = math.mulMat4(projMat, viewMat, tempMat4b);
  4575. const pvMatInverse = math.inverseMat4(pvMat, tempMat4c);
  4576.  
  4577. // Calculate clip space coordinates, which will be in range
  4578. // of x=[-1..1] and y=[-1..1], with y=(+1) at top
  4579.  
  4580. const canvasWidth = canvas.width;
  4581. const canvasHeight = canvas.height;
  4582.  
  4583. const clipX = (canvasPos[0] - canvasWidth / 2) / (canvasWidth / 2); // Calculate clip space coordinates
  4584. const clipY = -(canvasPos[1] - canvasHeight / 2) / (canvasHeight / 2);
  4585.  
  4586. tempVec4a[0] = clipX;
  4587. tempVec4a[1] = clipY;
  4588. tempVec4a[2] = -1;
  4589. tempVec4a[3] = 1;
  4590.  
  4591. math.transformVec4(pvMatInverse, tempVec4a, tempVec4b);
  4592. math.mulVec4Scalar(tempVec4b, 1 / tempVec4b[3]);
  4593.  
  4594. tempVec4c[0] = clipX;
  4595. tempVec4c[1] = clipY;
  4596. tempVec4c[2] = 1;
  4597. tempVec4c[3] = 1;
  4598.  
  4599. math.transformVec4(pvMatInverse, tempVec4c, tempVec4d);
  4600. math.mulVec4Scalar(tempVec4d, 1 / tempVec4d[3]);
  4601.  
  4602. worldRayOrigin[0] = tempVec4d[0];
  4603. worldRayOrigin[1] = tempVec4d[1];
  4604. worldRayOrigin[2] = tempVec4d[2];
  4605.  
  4606. math.subVec3(tempVec4d, tempVec4b, worldRayDir);
  4607.  
  4608. math.normalizeVec3(worldRayDir);
  4609. };
  4610. }))(),
  4611.  
  4612. /**
  4613. Transforms a Canvas-space position to a Mesh's Local-space coordinate system, in the context of a Camera.
  4614. @method canvasPosToLocalRay
  4615. @static
  4616. @param {Camera} camera The Camera.
  4617. @param {Mesh} mesh The Mesh.
  4618. @param {Float32Array} canvasPos The Canvas-space position.
  4619. @param {Float32Array} localRayOrigin The Local-space ray origin.
  4620. @param {Float32Array} localRayDir The Local-space ray direction.
  4621. */
  4622. canvasPosToLocalRay: ((() => {
  4623.  
  4624. const worldRayOrigin = new Float32Array(3);
  4625. const worldRayDir = new Float32Array(3);
  4626.  
  4627. return (camera, mesh, canvasPos, localRayOrigin, localRayDir) => {
  4628. math.canvasPosToWorldRay(camera, canvasPos, worldRayOrigin, worldRayDir);
  4629. math.worldRayToLocalRay(mesh, worldRayOrigin, worldRayDir, localRayOrigin, localRayDir);
  4630. };
  4631. }))(),
  4632.  
  4633. /**
  4634. Transforms a ray from World-space to a Mesh's Local-space coordinate system.
  4635. @method worldRayToLocalRay
  4636. @static
  4637. @param {Mesh} mesh The Mesh.
  4638. @param {Float32Array} worldRayOrigin The World-space ray origin.
  4639. @param {Float32Array} worldRayDir The World-space ray direction.
  4640. @param {Float32Array} localRayOrigin The Local-space ray origin.
  4641. @param {Float32Array} localRayDir The Local-space ray direction.
  4642. */
  4643. worldRayToLocalRay: ((() => {
  4644.  
  4645. const tempMat4 = new Float32Array(16);
  4646. const tempVec4a = new Float32Array(4);
  4647. const tempVec4b = new Float32Array(4);
  4648.  
  4649. return (mesh, worldRayOrigin, worldRayDir, localRayOrigin, localRayDir) => {
  4650.  
  4651. const modelMat = mesh.worldMatrix || mesh.matrix;
  4652. const modelMatInverse = math.inverseMat4(modelMat, tempMat4);
  4653.  
  4654. tempVec4a[0] = worldRayOrigin[0];
  4655. tempVec4a[1] = worldRayOrigin[1];
  4656. tempVec4a[2] = worldRayOrigin[2];
  4657. tempVec4a[3] = 1;
  4658.  
  4659. math.transformVec4(modelMatInverse, tempVec4a, tempVec4b);
  4660.  
  4661. localRayOrigin[0] = tempVec4b[0];
  4662. localRayOrigin[1] = tempVec4b[1];
  4663. localRayOrigin[2] = tempVec4b[2];
  4664.  
  4665. math.transformVec3(modelMatInverse, worldRayDir, localRayDir);
  4666. };
  4667. }))(),
  4668.  
  4669. buildKDTree: ((() => {
  4670.  
  4671. const KD_TREE_MAX_DEPTH = 10;
  4672. const KD_TREE_MIN_TRIANGLES = 20;
  4673.  
  4674. const dimLength = new Float32Array();
  4675.  
  4676. function buildNode(triangles, indices, positions, depth) {
  4677. const aabb = new Float32Array(6);
  4678.  
  4679. const node = {
  4680. triangles: null,
  4681. left: null,
  4682. right: null,
  4683. leaf: false,
  4684. splitDim: 0,
  4685. aabb
  4686. };
  4687.  
  4688. aabb[0] = aabb[1] = aabb[2] = Number.POSITIVE_INFINITY;
  4689. aabb[3] = aabb[4] = aabb[5] = Number.NEGATIVE_INFINITY;
  4690.  
  4691. let t;
  4692. let i;
  4693. let len;
  4694.  
  4695. for (t = 0, len = triangles.length; t < len; ++t) {
  4696. var ii = triangles[t] * 3;
  4697. for (let j = 0; j < 3; ++j) {
  4698. const pi = indices[ii + j] * 3;
  4699. if (positions[pi] < aabb[0]) {
  4700. aabb[0] = positions[pi]
  4701. }
  4702. if (positions[pi] > aabb[3]) {
  4703. aabb[3] = positions[pi]
  4704. }
  4705. if (positions[pi + 1] < aabb[1]) {
  4706. aabb[1] = positions[pi + 1]
  4707. }
  4708. if (positions[pi + 1] > aabb[4]) {
  4709. aabb[4] = positions[pi + 1]
  4710. }
  4711. if (positions[pi + 2] < aabb[2]) {
  4712. aabb[2] = positions[pi + 2]
  4713. }
  4714. if (positions[pi + 2] > aabb[5]) {
  4715. aabb[5] = positions[pi + 2]
  4716. }
  4717. }
  4718. }
  4719.  
  4720. if (triangles.length < KD_TREE_MIN_TRIANGLES || depth > KD_TREE_MAX_DEPTH) {
  4721. node.triangles = triangles;
  4722. node.leaf = true;
  4723. return node;
  4724. }
  4725.  
  4726. dimLength[0] = aabb[3] - aabb[0];
  4727. dimLength[1] = aabb[4] - aabb[1];
  4728. dimLength[2] = aabb[5] - aabb[2];
  4729.  
  4730. let dim = 0;
  4731.  
  4732. if (dimLength[1] > dimLength[dim]) {
  4733. dim = 1;
  4734. }
  4735.  
  4736. if (dimLength[2] > dimLength[dim]) {
  4737. dim = 2;
  4738. }
  4739.  
  4740. node.splitDim = dim;
  4741.  
  4742. const mid = (aabb[dim] + aabb[dim + 3]) / 2;
  4743. const left = new Array(triangles.length);
  4744. let numLeft = 0;
  4745. const right = new Array(triangles.length);
  4746. let numRight = 0;
  4747.  
  4748. for (t = 0, len = triangles.length; t < len; ++t) {
  4749.  
  4750. var ii = triangles[t] * 3;
  4751. const i0 = indices[ii];
  4752. const i1 = indices[ii + 1];
  4753. const i2 = indices[ii + 2];
  4754.  
  4755. const pi0 = i0 * 3;
  4756. const pi1 = i1 * 3;
  4757. const pi2 = i2 * 3;
  4758.  
  4759. if (positions[pi0 + dim] <= mid || positions[pi1 + dim] <= mid || positions[pi2 + dim] <= mid) {
  4760. left[numLeft++] = triangles[t];
  4761. } else {
  4762. right[numRight++] = triangles[t];
  4763. }
  4764. }
  4765.  
  4766. left.length = numLeft;
  4767. right.length = numRight;
  4768.  
  4769. node.left = buildNode(left, indices, positions, depth + 1);
  4770. node.right = buildNode(right, indices, positions, depth + 1);
  4771.  
  4772. return node;
  4773. }
  4774.  
  4775. return (indices, positions) => {
  4776. const numTris = indices.length / 3;
  4777. const triangles = new Array(numTris);
  4778. for (let i = 0; i < numTris; ++i) {
  4779. triangles[i] = i;
  4780. }
  4781. return buildNode(triangles, indices, positions, 0);
  4782. };
  4783. }))()
  4784. };
  4785.  
  4786. export {math};