3d.ts 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318
  1. /**
  2. * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  6. */
  7. /*
  8. * This code has been modified from https://github.com/toji/gl-matrix/,
  9. * copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. */
  18. export interface Mat4 { [d: number]: number, '@type': 'mat4' }
  19. export interface Mat3 { [d: number]: number, '@type': 'mat3' }
  20. export interface Vec3 { [d: number]: number, '@type': 'vec3' | 'vec4' }
  21. export interface Vec4 { [d: number]: number, '@type': 'vec4' }
  22. export interface Quat { [d: number]: number, '@type': 'quat' }
  23. const enum EPSILON { Value = 0.000001 }
  24. export function Mat4() {
  25. return Mat4.zero();
  26. }
  27. export function Quat() {
  28. return Quat.zero();
  29. }
  30. /**
  31. * Stores a 4x4 matrix in a column major (j * 4 + i indexing) format.
  32. */
  33. export namespace Mat4 {
  34. export function zero(): Mat4 {
  35. // force double backing array by 0.1.
  36. const ret = [0.1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
  37. ret[0] = 0.0;
  38. return ret as any;
  39. }
  40. export function identity(): Mat4 {
  41. const out = zero();
  42. out[0] = 1;
  43. out[1] = 0;
  44. out[2] = 0;
  45. out[3] = 0;
  46. out[4] = 0;
  47. out[5] = 1;
  48. out[6] = 0;
  49. out[7] = 0;
  50. out[8] = 0;
  51. out[9] = 0;
  52. out[10] = 1;
  53. out[11] = 0;
  54. out[12] = 0;
  55. out[13] = 0;
  56. out[14] = 0;
  57. out[15] = 1;
  58. return out;
  59. }
  60. export function setIdentity(mat: Mat4): Mat4 {
  61. mat[0] = 1;
  62. mat[1] = 0;
  63. mat[2] = 0;
  64. mat[3] = 0;
  65. mat[4] = 0;
  66. mat[5] = 1;
  67. mat[6] = 0;
  68. mat[7] = 0;
  69. mat[8] = 0;
  70. mat[9] = 0;
  71. mat[10] = 1;
  72. mat[11] = 0;
  73. mat[12] = 0;
  74. mat[13] = 0;
  75. mat[14] = 0;
  76. mat[15] = 1;
  77. return mat;
  78. }
  79. export function ofRows(rows: number[][]): Mat4 {
  80. const out = zero();
  81. for (let i = 0; i < 4; i++) {
  82. const r = rows[i];
  83. for (let j = 0; j < 4; j++) {
  84. out[4 * j + i] = r[j];
  85. }
  86. }
  87. return out;
  88. }
  89. const _id = identity();
  90. export function isIdentity(m: Mat4, eps?: number) {
  91. return areEqual(m, _id, typeof eps === 'undefined' ? EPSILON.Value : eps);
  92. }
  93. export function areEqual(a: Mat4, b: Mat4, eps: number) {
  94. for (let i = 0; i < 16; i++) {
  95. if (Math.abs(a[i] - b[i]) > eps) return false;
  96. }
  97. return true;
  98. }
  99. export function setValue(a: Mat4, i: number, j: number, value: number) {
  100. a[4 * j + i] = value;
  101. }
  102. export function toArray(a: Mat4, out: number[]|Helpers.TypedArray, offset = 0) {
  103. out[offset + 0] = a[0];
  104. out[offset + 1] = a[1];
  105. out[offset + 2] = a[2];
  106. out[offset + 3] = a[3];
  107. out[offset + 4] = a[4];
  108. out[offset + 5] = a[5];
  109. out[offset + 6] = a[6];
  110. out[offset + 7] = a[7];
  111. out[offset + 8] = a[8];
  112. out[offset + 9] = a[9];
  113. out[offset + 10] = a[10];
  114. out[offset + 11] = a[11];
  115. out[offset + 12] = a[12];
  116. out[offset + 13] = a[13];
  117. out[offset + 14] = a[14];
  118. out[offset + 15] = a[15];
  119. }
  120. export function copy(out: Mat4, a: Mat4) {
  121. out[0] = a[0];
  122. out[1] = a[1];
  123. out[2] = a[2];
  124. out[3] = a[3];
  125. out[4] = a[4];
  126. out[5] = a[5];
  127. out[6] = a[6];
  128. out[7] = a[7];
  129. out[8] = a[8];
  130. out[9] = a[9];
  131. out[10] = a[10];
  132. out[11] = a[11];
  133. out[12] = a[12];
  134. out[13] = a[13];
  135. out[14] = a[14];
  136. out[15] = a[15];
  137. return out;
  138. }
  139. export function clone(a: Mat4) {
  140. return Mat4.copy(Mat4.zero(), a);
  141. }
  142. export function invert(out: Mat4, a: Mat4) {
  143. const a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
  144. a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
  145. a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
  146. a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
  147. b00 = a00 * a11 - a01 * a10,
  148. b01 = a00 * a12 - a02 * a10,
  149. b02 = a00 * a13 - a03 * a10,
  150. b03 = a01 * a12 - a02 * a11,
  151. b04 = a01 * a13 - a03 * a11,
  152. b05 = a02 * a13 - a03 * a12,
  153. b06 = a20 * a31 - a21 * a30,
  154. b07 = a20 * a32 - a22 * a30,
  155. b08 = a20 * a33 - a23 * a30,
  156. b09 = a21 * a32 - a22 * a31,
  157. b10 = a21 * a33 - a23 * a31,
  158. b11 = a22 * a33 - a23 * a32;
  159. // Calculate the determinant
  160. let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
  161. if (!det) {
  162. console.warn('non-invertible matrix.', a);
  163. return out;
  164. }
  165. det = 1.0 / det;
  166. out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
  167. out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
  168. out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
  169. out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
  170. out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
  171. out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
  172. out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
  173. out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
  174. out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
  175. out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
  176. out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
  177. out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
  178. out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
  179. out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
  180. out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
  181. out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
  182. return out;
  183. }
  184. export function mul(out: Mat4, a: Mat4, b: Mat4) {
  185. const a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
  186. a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
  187. a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
  188. a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
  189. // Cache only the current line of the second matrix
  190. let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
  191. out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
  192. out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
  193. out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
  194. out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
  195. b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];
  196. out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
  197. out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
  198. out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
  199. out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
  200. b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];
  201. out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
  202. out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
  203. out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
  204. out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
  205. b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];
  206. out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
  207. out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
  208. out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
  209. out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
  210. return out;
  211. }
  212. export function mul3(out: Mat4, a: Mat4, b: Mat4, c: Mat4) {
  213. return mul(out, mul(out, a, b), c);
  214. }
  215. export function translate(out: Mat4, a: Mat4, v: Vec3) {
  216. const x = v[0], y = v[1], z = v[2];
  217. let a00: number, a01: number, a02: number, a03: number,
  218. a10: number, a11: number, a12: number, a13: number,
  219. a20: number, a21: number, a22: number, a23: number;
  220. if (a === out) {
  221. out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
  222. out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
  223. out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
  224. out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
  225. } else {
  226. a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
  227. a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
  228. a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
  229. out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03;
  230. out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13;
  231. out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23;
  232. out[12] = a00 * x + a10 * y + a20 * z + a[12];
  233. out[13] = a01 * x + a11 * y + a21 * z + a[13];
  234. out[14] = a02 * x + a12 * y + a22 * z + a[14];
  235. out[15] = a03 * x + a13 * y + a23 * z + a[15];
  236. }
  237. return out;
  238. }
  239. export function fromTranslation(out: Mat4, v: Vec3) {
  240. out[0] = 1;
  241. out[1] = 0;
  242. out[2] = 0;
  243. out[3] = 0;
  244. out[4] = 0;
  245. out[5] = 1;
  246. out[6] = 0;
  247. out[7] = 0;
  248. out[8] = 0;
  249. out[9] = 0;
  250. out[10] = 1;
  251. out[11] = 0;
  252. out[12] = v[0];
  253. out[13] = v[1];
  254. out[14] = v[2];
  255. out[15] = 1;
  256. return out;
  257. }
  258. export function setTranslation(out: Mat4, v: Vec3) {
  259. out[12] = v[0];
  260. out[13] = v[1];
  261. out[14] = v[2];
  262. return out;
  263. }
  264. export function rotate(out: Mat4, a: Mat4, rad: number, axis: Mat4) {
  265. let x = axis[0], y = axis[1], z = axis[2],
  266. len = Math.sqrt(x * x + y * y + z * z),
  267. s, c, t,
  268. a00, a01, a02, a03,
  269. a10, a11, a12, a13,
  270. a20, a21, a22, a23,
  271. b00, b01, b02,
  272. b10, b11, b12,
  273. b20, b21, b22;
  274. if (Math.abs(len) < EPSILON.Value) {
  275. return Mat4.identity();
  276. }
  277. len = 1 / len;
  278. x *= len;
  279. y *= len;
  280. z *= len;
  281. s = Math.sin(rad);
  282. c = Math.cos(rad);
  283. t = 1 - c;
  284. a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
  285. a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
  286. a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
  287. // Construct the elements of the rotation matrix
  288. b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
  289. b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
  290. b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;
  291. // Perform rotation-specific matrix multiplication
  292. out[0] = a00 * b00 + a10 * b01 + a20 * b02;
  293. out[1] = a01 * b00 + a11 * b01 + a21 * b02;
  294. out[2] = a02 * b00 + a12 * b01 + a22 * b02;
  295. out[3] = a03 * b00 + a13 * b01 + a23 * b02;
  296. out[4] = a00 * b10 + a10 * b11 + a20 * b12;
  297. out[5] = a01 * b10 + a11 * b11 + a21 * b12;
  298. out[6] = a02 * b10 + a12 * b11 + a22 * b12;
  299. out[7] = a03 * b10 + a13 * b11 + a23 * b12;
  300. out[8] = a00 * b20 + a10 * b21 + a20 * b22;
  301. out[9] = a01 * b20 + a11 * b21 + a21 * b22;
  302. out[10] = a02 * b20 + a12 * b21 + a22 * b22;
  303. out[11] = a03 * b20 + a13 * b21 + a23 * b22;
  304. if (a !== out) { // If the source and destination differ, copy the unchanged last row
  305. out[12] = a[12];
  306. out[13] = a[13];
  307. out[14] = a[14];
  308. out[15] = a[15];
  309. }
  310. return out;
  311. }
  312. export function fromRotation(out: Mat4, rad: number, axis: Vec3) {
  313. let x = axis[0], y = axis[1], z = axis[2],
  314. len = Math.sqrt(x * x + y * y + z * z),
  315. s, c, t;
  316. if (Math.abs(len) < EPSILON.Value) { return setIdentity(out); }
  317. len = 1 / len;
  318. x *= len;
  319. y *= len;
  320. z *= len;
  321. s = Math.sin(rad);
  322. c = Math.cos(rad);
  323. t = 1 - c;
  324. // Perform rotation-specific matrix multiplication
  325. out[0] = x * x * t + c;
  326. out[1] = y * x * t + z * s;
  327. out[2] = z * x * t - y * s;
  328. out[3] = 0;
  329. out[4] = x * y * t - z * s;
  330. out[5] = y * y * t + c;
  331. out[6] = z * y * t + x * s;
  332. out[7] = 0;
  333. out[8] = x * z * t + y * s;
  334. out[9] = y * z * t - x * s;
  335. out[10] = z * z * t + c;
  336. out[11] = 0;
  337. out[12] = 0;
  338. out[13] = 0;
  339. out[14] = 0;
  340. out[15] = 1;
  341. return out;
  342. }
  343. export function scale(out: Mat4, a: Mat4, v: Vec3) {
  344. const x = v[0], y = v[1], z = v[2];
  345. out[0] = a[0] * x;
  346. out[1] = a[1] * x;
  347. out[2] = a[2] * x;
  348. out[3] = a[3] * x;
  349. out[4] = a[4] * y;
  350. out[5] = a[5] * y;
  351. out[6] = a[6] * y;
  352. out[7] = a[7] * y;
  353. out[8] = a[8] * z;
  354. out[9] = a[9] * z;
  355. out[10] = a[10] * z;
  356. out[11] = a[11] * z;
  357. out[12] = a[12];
  358. out[13] = a[13];
  359. out[14] = a[14];
  360. out[15] = a[15];
  361. return out;
  362. }
  363. export function fromScaling(out: Mat4, v: Vec3) {
  364. out[0] = v[0];
  365. out[1] = 0;
  366. out[2] = 0;
  367. out[3] = 0;
  368. out[4] = 0;
  369. out[5] = v[1];
  370. out[6] = 0;
  371. out[7] = 0;
  372. out[8] = 0;
  373. out[9] = 0;
  374. out[10] = v[2];
  375. out[11] = 0;
  376. out[12] = 0;
  377. out[13] = 0;
  378. out[14] = 0;
  379. out[15] = 1;
  380. return out;
  381. }
  382. export function makeTable(m: Mat4) {
  383. let ret = '';
  384. for (let i = 0; i < 4; i++) {
  385. for (let j = 0; j < 4; j++) {
  386. ret += m[4 * j + i].toString();
  387. if (j < 3) ret += ' ';
  388. }
  389. if (i < 3) ret += '\n';
  390. }
  391. return ret;
  392. }
  393. export function determinant(a: Mat4) {
  394. const a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
  395. a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
  396. a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
  397. a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
  398. b00 = a00 * a11 - a01 * a10,
  399. b01 = a00 * a12 - a02 * a10,
  400. b02 = a00 * a13 - a03 * a10,
  401. b03 = a01 * a12 - a02 * a11,
  402. b04 = a01 * a13 - a03 * a11,
  403. b05 = a02 * a13 - a03 * a12,
  404. b06 = a20 * a31 - a21 * a30,
  405. b07 = a20 * a32 - a22 * a30,
  406. b08 = a20 * a33 - a23 * a30,
  407. b09 = a21 * a32 - a22 * a31,
  408. b10 = a21 * a33 - a23 * a31,
  409. b11 = a22 * a33 - a23 * a32;
  410. // Calculate the determinant
  411. return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
  412. }
  413. /**
  414. * Check if the matrix has the form
  415. * [ Rotation Translation ]
  416. * [ 0 1 ]
  417. */
  418. export function isRotationAndTranslation(a: Mat4, eps?: number) {
  419. return _isRotationAndTranslation(a, typeof eps !== 'undefined' ? eps : EPSILON.Value)
  420. }
  421. function _isRotationAndTranslation(a: Mat4, eps: number) {
  422. const a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
  423. a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
  424. a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
  425. /* a30 = a[12], a31 = a[13], a32 = a[14],*/ a33 = a[15];
  426. if (a33 !== 1 || a03 !== 0 || a13 !== 0 || a23 !== 0) {
  427. return false;
  428. }
  429. const det3x3 = a00 * (a11 * a22 - a12 * a21) - a01 * (a10 * a22 - a12 * a20) + a02 * (a10 * a21 - a11 * a20);
  430. if (det3x3 < 1 - eps || det3x3 > 1 + eps) {
  431. return false;
  432. }
  433. return true;
  434. }
  435. export function fromQuat(out: Mat4, q: Quat) {
  436. const x = q[0], y = q[1], z = q[2], w = q[3];
  437. const x2 = x + x;
  438. const y2 = y + y;
  439. const z2 = z + z;
  440. const xx = x * x2;
  441. const yx = y * x2;
  442. const yy = y * y2;
  443. const zx = z * x2;
  444. const zy = z * y2;
  445. const zz = z * z2;
  446. const wx = w * x2;
  447. const wy = w * y2;
  448. const wz = w * z2;
  449. out[0] = 1 - yy - zz;
  450. out[1] = yx + wz;
  451. out[2] = zx - wy;
  452. out[3] = 0;
  453. out[4] = yx - wz;
  454. out[5] = 1 - xx - zz;
  455. out[6] = zy + wx;
  456. out[7] = 0;
  457. out[8] = zx + wy;
  458. out[9] = zy - wx;
  459. out[10] = 1 - xx - yy;
  460. out[11] = 0;
  461. out[12] = 0;
  462. out[13] = 0;
  463. out[14] = 0;
  464. out[15] = 1;
  465. return out;
  466. }
  467. /**
  468. * Generates a frustum matrix with the given bounds
  469. */
  470. export function frustum(out: Mat4, left: number, right: number, bottom: number, top: number, near: number, far: number) {
  471. let rl = 1 / (right - left);
  472. let tb = 1 / (top - bottom);
  473. let nf = 1 / (near - far);
  474. out[0] = (near * 2) * rl;
  475. out[1] = 0;
  476. out[2] = 0;
  477. out[3] = 0;
  478. out[4] = 0;
  479. out[5] = (near * 2) * tb;
  480. out[6] = 0;
  481. out[7] = 0;
  482. out[8] = (right + left) * rl;
  483. out[9] = (top + bottom) * tb;
  484. out[10] = (far + near) * nf;
  485. out[11] = -1;
  486. out[12] = 0;
  487. out[13] = 0;
  488. out[14] = (far * near * 2) * nf;
  489. out[15] = 0;
  490. return out;
  491. }
  492. /**
  493. * Generates a perspective projection matrix with the given bounds
  494. */
  495. export function perspective(out: Mat4, fovy: number, aspect: number, near: number, far: number) {
  496. let f = 1.0 / Math.tan(fovy / 2);
  497. let nf = 1 / (near - far);
  498. out[0] = f / aspect;
  499. out[1] = 0;
  500. out[2] = 0;
  501. out[3] = 0;
  502. out[4] = 0;
  503. out[5] = f;
  504. out[6] = 0;
  505. out[7] = 0;
  506. out[8] = 0;
  507. out[9] = 0;
  508. out[10] = (far + near) * nf;
  509. out[11] = -1;
  510. out[12] = 0;
  511. out[13] = 0;
  512. out[14] = (2 * far * near) * nf;
  513. out[15] = 0;
  514. return out;
  515. }
  516. /**
  517. * Generates a orthogonal projection matrix with the given bounds
  518. */
  519. export function ortho(out: Mat4, left: number, right: number, bottom: number, top: number, near: number, far: number) {
  520. let lr = 1 / (left - right);
  521. let bt = 1 / (bottom - top);
  522. let nf = 1 / (near - far);
  523. out[0] = -2 * lr;
  524. out[1] = 0;
  525. out[2] = 0;
  526. out[3] = 0;
  527. out[4] = 0;
  528. out[5] = -2 * bt;
  529. out[6] = 0;
  530. out[7] = 0;
  531. out[8] = 0;
  532. out[9] = 0;
  533. out[10] = 2 * nf;
  534. out[11] = 0;
  535. out[12] = (left + right) * lr;
  536. out[13] = (top + bottom) * bt;
  537. out[14] = (far + near) * nf;
  538. out[15] = 1;
  539. return out;
  540. }
  541. /**
  542. * Generates a look-at matrix with the given eye position, focal point, and up axis
  543. */
  544. export function lookAt(out: Mat4, eye: Vec3, center: Vec3, up: Vec3) {
  545. let x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
  546. let eyex = eye[0];
  547. let eyey = eye[1];
  548. let eyez = eye[2];
  549. let upx = up[0];
  550. let upy = up[1];
  551. let upz = up[2];
  552. let centerx = center[0];
  553. let centery = center[1];
  554. let centerz = center[2];
  555. if (Math.abs(eyex - centerx) < EPSILON.Value &&
  556. Math.abs(eyey - centery) < EPSILON.Value &&
  557. Math.abs(eyez - centerz) < EPSILON.Value
  558. ) {
  559. return setIdentity(out);
  560. }
  561. z0 = eyex - centerx;
  562. z1 = eyey - centery;
  563. z2 = eyez - centerz;
  564. len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
  565. z0 *= len;
  566. z1 *= len;
  567. z2 *= len;
  568. x0 = upy * z2 - upz * z1;
  569. x1 = upz * z0 - upx * z2;
  570. x2 = upx * z1 - upy * z0;
  571. len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
  572. if (!len) {
  573. x0 = 0;
  574. x1 = 0;
  575. x2 = 0;
  576. } else {
  577. len = 1 / len;
  578. x0 *= len;
  579. x1 *= len;
  580. x2 *= len;
  581. }
  582. y0 = z1 * x2 - z2 * x1;
  583. y1 = z2 * x0 - z0 * x2;
  584. y2 = z0 * x1 - z1 * x0;
  585. len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
  586. if (!len) {
  587. y0 = 0;
  588. y1 = 0;
  589. y2 = 0;
  590. } else {
  591. len = 1 / len;
  592. y0 *= len;
  593. y1 *= len;
  594. y2 *= len;
  595. }
  596. out[0] = x0;
  597. out[1] = y0;
  598. out[2] = z0;
  599. out[3] = 0;
  600. out[4] = x1;
  601. out[5] = y1;
  602. out[6] = z1;
  603. out[7] = 0;
  604. out[8] = x2;
  605. out[9] = y2;
  606. out[10] = z2;
  607. out[11] = 0;
  608. out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
  609. out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
  610. out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
  611. out[15] = 1;
  612. return out;
  613. }
  614. }
  615. export namespace Mat3 {
  616. export function zero(): Mat3 {
  617. // force double backing array by 0.1.
  618. const ret = [0.1, 0, 0, 0, 0, 0, 0, 0, 0];
  619. ret[0] = 0.0;
  620. return ret as any;
  621. }
  622. }
  623. export namespace Vec3 {
  624. export function zero(): Vec3 {
  625. const out = [0.1, 0.0, 0.0];
  626. out[0] = 0;
  627. return out as any;
  628. }
  629. export function clone(a: Vec3): Vec3 {
  630. const out = zero();
  631. out[0] = a[0];
  632. out[1] = a[1];
  633. out[2] = a[2];
  634. return out;
  635. }
  636. export function fromObj(v: { x: number, y: number, z: number }): Vec3 {
  637. return create(v.x, v.y, v.z);
  638. }
  639. export function toObj(v: Vec3) {
  640. return { x: v[0], y: v[1], z: v[2] };
  641. }
  642. export function create(x: number, y: number, z: number): Vec3 {
  643. const out = zero();
  644. out[0] = x;
  645. out[1] = y;
  646. out[2] = z;
  647. return out;
  648. }
  649. export function set(out: Vec3, x: number, y: number, z: number): Vec3 {
  650. out[0] = x;
  651. out[1] = y;
  652. out[2] = z;
  653. return out;
  654. }
  655. export function copy(out: Vec3, a: Vec3) {
  656. out[0] = a[0];
  657. out[1] = a[1];
  658. out[2] = a[2];
  659. return out;
  660. }
  661. export function add(out: Vec3, a: Vec3, b: Vec3) {
  662. out[0] = a[0] + b[0];
  663. out[1] = a[1] + b[1];
  664. out[2] = a[2] + b[2];
  665. return out;
  666. }
  667. export function sub(out: Vec3, a: Vec3, b: Vec3) {
  668. out[0] = a[0] - b[0];
  669. out[1] = a[1] - b[1];
  670. out[2] = a[2] - b[2];
  671. return out;
  672. }
  673. export function scale(out: Vec3, a: Vec3, b: number) {
  674. out[0] = a[0] * b;
  675. out[1] = a[1] * b;
  676. out[2] = a[2] * b;
  677. return out;
  678. }
  679. export function scaleAndAdd(out: Vec3, a: Vec3, b: Vec3, scale: number) {
  680. out[0] = a[0] + (b[0] * scale);
  681. out[1] = a[1] + (b[1] * scale);
  682. out[2] = a[2] + (b[2] * scale);
  683. return out;
  684. }
  685. export function distance(a: Vec3, b: Vec3) {
  686. const x = b[0] - a[0],
  687. y = b[1] - a[1],
  688. z = b[2] - a[2];
  689. return Math.sqrt(x * x + y * y + z * z);
  690. }
  691. export function squaredDistance(a: Vec3, b: Vec3) {
  692. const x = b[0] - a[0],
  693. y = b[1] - a[1],
  694. z = b[2] - a[2];
  695. return x * x + y * y + z * z;
  696. }
  697. export function magnitude(a: Vec3) {
  698. const x = a[0],
  699. y = a[1],
  700. z = a[2];
  701. return Math.sqrt(x * x + y * y + z * z);
  702. }
  703. export function squaredMagnitude(a: Vec3) {
  704. const x = a[0],
  705. y = a[1],
  706. z = a[2];
  707. return x * x + y * y + z * z;
  708. }
  709. export function normalize(out: Vec3, a: Vec3) {
  710. const x = a[0],
  711. y = a[1],
  712. z = a[2];
  713. let len = x * x + y * y + z * z;
  714. if (len > 0) {
  715. len = 1 / Math.sqrt(len);
  716. out[0] = a[0] * len;
  717. out[1] = a[1] * len;
  718. out[2] = a[2] * len;
  719. }
  720. return out;
  721. }
  722. export function dot(a: Vec3, b: Vec3) {
  723. return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
  724. }
  725. export function cross(out: Vec3, a: Vec3, b: Vec3) {
  726. const ax = a[0], ay = a[1], az = a[2],
  727. bx = b[0], by = b[1], bz = b[2];
  728. out[0] = ay * bz - az * by;
  729. out[1] = az * bx - ax * bz;
  730. out[2] = ax * by - ay * bx;
  731. return out;
  732. }
  733. export function lerp(out: Vec3, a: Vec3, b: Vec3, t: number) {
  734. const ax = a[0],
  735. ay = a[1],
  736. az = a[2];
  737. out[0] = ax + t * (b[0] - ax);
  738. out[1] = ay + t * (b[1] - ay);
  739. out[2] = az + t * (b[2] - az);
  740. return out;
  741. }
  742. export function transformMat4(out: Vec3, a: Vec3, m: Mat4) {
  743. const x = a[0], y = a[1], z = a[2],
  744. w = (m[3] * x + m[7] * y + m[11] * z + m[15]) || 1.0;
  745. out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
  746. out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
  747. out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
  748. return out;
  749. }
  750. const angleTempA = zero(), angleTempB = zero();
  751. export function angle(a: Vec3, b: Vec3) {
  752. copy(angleTempA, a);
  753. copy(angleTempB, b);
  754. normalize(angleTempA, angleTempA);
  755. normalize(angleTempB, angleTempB);
  756. const cosine = dot(angleTempA, angleTempB);
  757. if (cosine > 1.0) {
  758. return 0;
  759. }
  760. else if (cosine < -1.0) {
  761. return Math.PI;
  762. } else {
  763. return Math.acos(cosine);
  764. }
  765. }
  766. const rotTemp = zero();
  767. export function makeRotation(mat: Mat4, a: Vec3, b: Vec3): Mat4 {
  768. const by = angle(a, b);
  769. if (Math.abs(by) < 0.0001) return Mat4.setIdentity(mat);
  770. const axis = cross(rotTemp, a, b);
  771. return Mat4.fromRotation(mat, by, axis);
  772. }
  773. }
  774. export namespace Vec4 {
  775. export function zero(): Vec4 {
  776. // force double backing array by 0.1.
  777. const ret = [0.1, 0, 0, 0];
  778. ret[0] = 0.0;
  779. return ret as any;
  780. }
  781. export function clone(a: Vec4) {
  782. const out = zero();
  783. out[0] = a[0];
  784. out[1] = a[1];
  785. out[2] = a[2];
  786. out[3] = a[3];
  787. return out;
  788. }
  789. export function create(x: number, y: number, z: number, w: number) {
  790. const out = zero();
  791. out[0] = x;
  792. out[1] = y;
  793. out[2] = z;
  794. out[3] = w;
  795. return out;
  796. }
  797. export function copy(out: Vec4, a: Vec4) {
  798. out[0] = a[0];
  799. out[1] = a[1];
  800. out[2] = a[2];
  801. out[3] = a[3];
  802. return out;
  803. }
  804. export function set(out: Vec4, x: number, y: number, z: number, w: number) {
  805. out[0] = x;
  806. out[1] = y;
  807. out[2] = z;
  808. out[3] = w;
  809. return out;
  810. }
  811. export function add(out: Quat, a: Quat, b: Quat) {
  812. out[0] = a[0] + b[0];
  813. out[1] = a[1] + b[1];
  814. out[2] = a[2] + b[2];
  815. out[3] = a[3] + b[3];
  816. return out;
  817. }
  818. export function distance(a: Vec4, b: Vec4) {
  819. const x = b[0] - a[0],
  820. y = b[1] - a[1],
  821. z = b[2] - a[2],
  822. w = b[3] - a[3];
  823. return Math.sqrt(x * x + y * y + z * z + w * w);
  824. }
  825. export function squaredDistance(a: Vec4, b: Vec4) {
  826. const x = b[0] - a[0],
  827. y = b[1] - a[1],
  828. z = b[2] - a[2],
  829. w = b[3] - a[3];
  830. return x * x + y * y + z * z + w * w;
  831. }
  832. export function norm(a: Vec4) {
  833. const x = a[0],
  834. y = a[1],
  835. z = a[2],
  836. w = a[3];
  837. return Math.sqrt(x * x + y * y + z * z + w * w);
  838. }
  839. export function squaredNorm(a: Vec4) {
  840. const x = a[0],
  841. y = a[1],
  842. z = a[2],
  843. w = a[3];
  844. return x * x + y * y + z * z + w * w;
  845. }
  846. export function transform(out: Vec4, a: Vec4, m: Mat4) {
  847. const x = a[0], y = a[1], z = a[2], w = a[3];
  848. out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
  849. out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
  850. out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
  851. out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
  852. return out;
  853. }
  854. }
  855. export namespace Quat {
  856. export function zero(): Quat {
  857. // force double backing array by 0.1.
  858. const ret = [0.1, 0, 0, 0];
  859. ret[0] = 0.0;
  860. return ret as any;
  861. }
  862. export function identity(): Quat {
  863. const out = zero();
  864. out[3] = 1;
  865. return out;
  866. }
  867. export function create(x: number, y: number, z: number, w: number) {
  868. const out = identity();
  869. out[0] = x;
  870. out[1] = y;
  871. out[2] = z;
  872. out[3] = w;
  873. return out;
  874. }
  875. export function setAxisAngle(out: Quat, axis: Vec3, rad: number) {
  876. rad = rad * 0.5;
  877. let s = Math.sin(rad);
  878. out[0] = s * axis[0];
  879. out[1] = s * axis[1];
  880. out[2] = s * axis[2];
  881. out[3] = Math.cos(rad);
  882. return out;
  883. }
  884. /**
  885. * Gets the rotation axis and angle for a given
  886. * quaternion. If a quaternion is created with
  887. * setAxisAngle, this method will return the same
  888. * values as providied in the original parameter list
  889. * OR functionally equivalent values.
  890. * Example: The quaternion formed by axis [0, 0, 1] and
  891. * angle -90 is the same as the quaternion formed by
  892. * [0, 0, 1] and 270. This method favors the latter.
  893. */
  894. export function getAxisAngle(out_axis: Vec3, q: Quat) {
  895. let rad = Math.acos(q[3]) * 2.0;
  896. let s = Math.sin(rad / 2.0);
  897. if (s !== 0.0) {
  898. out_axis[0] = q[0] / s;
  899. out_axis[1] = q[1] / s;
  900. out_axis[2] = q[2] / s;
  901. } else {
  902. // If s is zero, return any axis (no rotation - axis does not matter)
  903. out_axis[0] = 1;
  904. out_axis[1] = 0;
  905. out_axis[2] = 0;
  906. }
  907. return rad;
  908. }
  909. export function multiply(out: Quat, a: Quat, b: Quat) {
  910. let ax = a[0], ay = a[1], az = a[2], aw = a[3];
  911. let bx = b[0], by = b[1], bz = b[2], bw = b[3];
  912. out[0] = ax * bw + aw * bx + ay * bz - az * by;
  913. out[1] = ay * bw + aw * by + az * bx - ax * bz;
  914. out[2] = az * bw + aw * bz + ax * by - ay * bx;
  915. out[3] = aw * bw - ax * bx - ay * by - az * bz;
  916. return out;
  917. }
  918. export function rotateX(out: Quat, a: Quat, rad: number) {
  919. rad *= 0.5;
  920. let ax = a[0], ay = a[1], az = a[2], aw = a[3];
  921. let bx = Math.sin(rad), bw = Math.cos(rad);
  922. out[0] = ax * bw + aw * bx;
  923. out[1] = ay * bw + az * bx;
  924. out[2] = az * bw - ay * bx;
  925. out[3] = aw * bw - ax * bx;
  926. return out;
  927. }
  928. export function rotateY(out: Quat, a: Quat, rad: number) {
  929. rad *= 0.5;
  930. let ax = a[0], ay = a[1], az = a[2], aw = a[3];
  931. let by = Math.sin(rad), bw = Math.cos(rad);
  932. out[0] = ax * bw - az * by;
  933. out[1] = ay * bw + aw * by;
  934. out[2] = az * bw + ax * by;
  935. out[3] = aw * bw - ay * by;
  936. return out;
  937. }
  938. export function rotateZ(out: Quat, a: Quat, rad: number) {
  939. rad *= 0.5;
  940. let ax = a[0], ay = a[1], az = a[2], aw = a[3];
  941. let bz = Math.sin(rad), bw = Math.cos(rad);
  942. out[0] = ax * bw + ay * bz;
  943. out[1] = ay * bw - ax * bz;
  944. out[2] = az * bw + aw * bz;
  945. out[3] = aw * bw - az * bz;
  946. return out;
  947. }
  948. /**
  949. * Calculates the W component of a quat from the X, Y, and Z components.
  950. * Assumes that quaternion is 1 unit in length.
  951. * Any existing W component will be ignored.
  952. */
  953. export function calculateW(out: Quat, a: Quat) {
  954. let x = a[0], y = a[1], z = a[2];
  955. out[0] = x;
  956. out[1] = y;
  957. out[2] = z;
  958. out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
  959. return out;
  960. }
  961. /**
  962. * Performs a spherical linear interpolation between two quat
  963. */
  964. export function slerp(out: Quat, a: Quat, b: Quat, t: number) {
  965. // benchmarks:
  966. // http://jsperf.com/quaternion-slerp-implementations
  967. let ax = a[0], ay = a[1], az = a[2], aw = a[3];
  968. let bx = b[0], by = b[1], bz = b[2], bw = b[3];
  969. let omega, cosom, sinom, scale0, scale1;
  970. // calc cosine
  971. cosom = ax * bx + ay * by + az * bz + aw * bw;
  972. // adjust signs (if necessary)
  973. if ( cosom < 0.0 ) {
  974. cosom = -cosom;
  975. bx = - bx;
  976. by = - by;
  977. bz = - bz;
  978. bw = - bw;
  979. }
  980. // calculate coefficients
  981. if ( (1.0 - cosom) > 0.000001 ) {
  982. // standard case (slerp)
  983. omega = Math.acos(cosom);
  984. sinom = Math.sin(omega);
  985. scale0 = Math.sin((1.0 - t) * omega) / sinom;
  986. scale1 = Math.sin(t * omega) / sinom;
  987. } else {
  988. // "from" and "to" quaternions are very close
  989. // ... so we can do a linear interpolation
  990. scale0 = 1.0 - t;
  991. scale1 = t;
  992. }
  993. // calculate final values
  994. out[0] = scale0 * ax + scale1 * bx;
  995. out[1] = scale0 * ay + scale1 * by;
  996. out[2] = scale0 * az + scale1 * bz;
  997. out[3] = scale0 * aw + scale1 * bw;
  998. return out;
  999. }
  1000. export function invert(out: Quat, a: Quat) {
  1001. let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
  1002. let dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
  1003. let invDot = dot ? 1.0/dot : 0;
  1004. // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
  1005. out[0] = -a0 * invDot;
  1006. out[1] = -a1 * invDot;
  1007. out[2] = -a2 * invDot;
  1008. out[3] = a3 * invDot;
  1009. return out;
  1010. }
  1011. /**
  1012. * Calculates the conjugate of a quat
  1013. * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
  1014. */
  1015. export function conjugate(out: Quat, a: Quat) {
  1016. out[0] = -a[0];
  1017. out[1] = -a[1];
  1018. out[2] = -a[2];
  1019. out[3] = a[3];
  1020. return out;
  1021. }
  1022. /**
  1023. * Creates a quaternion from the given 3x3 rotation matrix.
  1024. *
  1025. * NOTE: The resultant quaternion is not normalized, so you should be sure
  1026. * to renormalize the quaternion yourself where necessary.
  1027. */
  1028. export function fromMat3(out: Quat, m: Mat3) {
  1029. // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
  1030. // article "Quaternion Calculus and Fast Animation".
  1031. const fTrace = m[0] + m[4] + m[8];
  1032. let fRoot;
  1033. if ( fTrace > 0.0 ) {
  1034. // |w| > 1/2, may as well choose w > 1/2
  1035. fRoot = Math.sqrt(fTrace + 1.0); // 2w
  1036. out[3] = 0.5 * fRoot;
  1037. fRoot = 0.5/fRoot; // 1/(4w)
  1038. out[0] = (m[5]-m[7])*fRoot;
  1039. out[1] = (m[6]-m[2])*fRoot;
  1040. out[2] = (m[1]-m[3])*fRoot;
  1041. } else {
  1042. // |w| <= 1/2
  1043. let i = 0;
  1044. if ( m[4] > m[0] ) i = 1;
  1045. if ( m[8] > m[i*3+i] ) i = 2;
  1046. let j = (i+1)%3;
  1047. let k = (i+2)%3;
  1048. fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);
  1049. out[i] = 0.5 * fRoot;
  1050. fRoot = 0.5 / fRoot;
  1051. out[3] = (m[j*3+k] - m[k*3+j]) * fRoot;
  1052. out[j] = (m[j*3+i] + m[i*3+j]) * fRoot;
  1053. out[k] = (m[k*3+i] + m[i*3+k]) * fRoot;
  1054. }
  1055. return out;
  1056. }
  1057. export function clone(a: Quat) {
  1058. const out = zero();
  1059. out[0] = a[0];
  1060. out[1] = a[1];
  1061. out[2] = a[2];
  1062. out[3] = a[3];
  1063. return out;
  1064. }
  1065. export function copy(out: Quat, a: Quat) {
  1066. out[0] = a[0];
  1067. out[1] = a[1];
  1068. out[2] = a[2];
  1069. out[3] = a[3];
  1070. return out;
  1071. }
  1072. export function set(out: Quat, x: number, y: number, z: number, w: number) {
  1073. out[0] = x;
  1074. out[1] = y;
  1075. out[2] = z;
  1076. out[3] = w;
  1077. return out;
  1078. }
  1079. export function add(out: Quat, a: Quat, b: Quat) {
  1080. out[0] = a[0] + b[0];
  1081. out[1] = a[1] + b[1];
  1082. out[2] = a[2] + b[2];
  1083. out[3] = a[3] + b[3];
  1084. return out;
  1085. }
  1086. export function normalize(out: Quat, a: Quat) {
  1087. let x = a[0];
  1088. let y = a[1];
  1089. let z = a[2];
  1090. let w = a[3];
  1091. let len = x*x + y*y + z*z + w*w;
  1092. if (len > 0) {
  1093. len = 1 / Math.sqrt(len);
  1094. out[0] = x * len;
  1095. out[1] = y * len;
  1096. out[2] = z * len;
  1097. out[3] = w * len;
  1098. }
  1099. return out;
  1100. }
  1101. /**
  1102. * Sets a quaternion to represent the shortest rotation from one
  1103. * vector to another.
  1104. *
  1105. * Both vectors are assumed to be unit length.
  1106. */
  1107. const rotTmpVec3 = Vec3.zero();
  1108. const rotTmpVec3UnitX = Vec3.create(1, 0, 0);
  1109. const rotTmpVec3UnitY = Vec3.create(0, 1, 0);
  1110. export function rotationTo(out: Quat, a: Vec3, b: Vec3) {
  1111. let dot = Vec3.dot(a, b);
  1112. if (dot < -0.999999) {
  1113. Vec3.cross(rotTmpVec3, rotTmpVec3UnitX, a);
  1114. if (Vec3.magnitude(rotTmpVec3) < 0.000001)
  1115. Vec3.cross(rotTmpVec3, rotTmpVec3UnitY, a);
  1116. Vec3.normalize(rotTmpVec3, rotTmpVec3);
  1117. setAxisAngle(out, rotTmpVec3, Math.PI);
  1118. return out;
  1119. } else if (dot > 0.999999) {
  1120. out[0] = 0;
  1121. out[1] = 0;
  1122. out[2] = 0;
  1123. out[3] = 1;
  1124. return out;
  1125. } else {
  1126. Vec3.cross(rotTmpVec3, a, b);
  1127. out[0] = rotTmpVec3[0];
  1128. out[1] = rotTmpVec3[1];
  1129. out[2] = rotTmpVec3[2];
  1130. out[3] = 1 + dot;
  1131. return normalize(out, out);
  1132. }
  1133. }
  1134. /**
  1135. * Performs a spherical linear interpolation with two control points
  1136. */
  1137. let sqlerpTemp1 = Quat.zero();
  1138. let sqlerpTemp2 = Quat.zero();
  1139. export function sqlerp(out: Quat, a: Quat, b: Quat, c: Quat, d: Quat, t: number) {
  1140. slerp(sqlerpTemp1, a, d, t);
  1141. slerp(sqlerpTemp2, b, c, t);
  1142. slerp(out, sqlerpTemp1, sqlerpTemp2, 2 * t * (1 - t));
  1143. return out;
  1144. }
  1145. /**
  1146. * Sets the specified quaternion with values corresponding to the given
  1147. * axes. Each axis is a vec3 and is expected to be unit length and
  1148. * perpendicular to all other specified axes.
  1149. */
  1150. const axesTmpMat = Mat3.zero();
  1151. export function setAxes(out: Quat, view: Vec3, right: Vec3, up: Vec3) {
  1152. axesTmpMat[0] = right[0];
  1153. axesTmpMat[3] = right[1];
  1154. axesTmpMat[6] = right[2];
  1155. axesTmpMat[1] = up[0];
  1156. axesTmpMat[4] = up[1];
  1157. axesTmpMat[7] = up[2];
  1158. axesTmpMat[2] = -view[0];
  1159. axesTmpMat[5] = -view[1];
  1160. axesTmpMat[8] = -view[2];
  1161. return normalize(out, Quat.fromMat3(out, axesTmpMat));
  1162. }
  1163. }