3d.ts 40 KB

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