Matrix3.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. /**
  2. * Represents a 3x3 matrix.
  3. *
  4. * A Note on Row-Major and Column-Major Ordering:
  5. *
  6. * The constructor and {@link Matrix3#set} method take arguments in
  7. * [row-major](https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order)
  8. * order, while internally they are stored in the {@link Matrix3#elements} array in column-major order.
  9. * This means that calling:
  10. * ```js
  11. * const m = new THREE.Matrix();
  12. * m.set( 11, 12, 13,
  13. * 21, 22, 23,
  14. * 31, 32, 33 );
  15. * ```
  16. * will result in the elements array containing:
  17. * ```js
  18. * m.elements = [ 11, 21, 31,
  19. * 12, 22, 32,
  20. * 13, 23, 33 ];
  21. * ```
  22. * and internally all calculations are performed using column-major ordering.
  23. * However, as the actual ordering makes no difference mathematically and
  24. * most people are used to thinking about matrices in row-major order, the
  25. * three.js documentation shows matrices in row-major order. Just bear in
  26. * mind that if you are reading the source code, you'll have to take the
  27. * transpose of any matrices outlined here to make sense of the calculations.
  28. */
  29. class Matrix3 {
  30. /**
  31. * Constructs a new 3x3 matrix. The arguments are supposed to be
  32. * in row-major order. If no arguments are provided, the constructor
  33. * initializes the matrix as an identity matrix.
  34. *
  35. * @param {number} [n11] - 1-1 matrix element.
  36. * @param {number} [n12] - 1-2 matrix element.
  37. * @param {number} [n13] - 1-3 matrix element.
  38. * @param {number} [n21] - 2-1 matrix element.
  39. * @param {number} [n22] - 2-2 matrix element.
  40. * @param {number} [n23] - 2-3 matrix element.
  41. * @param {number} [n31] - 3-1 matrix element.
  42. * @param {number} [n32] - 3-2 matrix element.
  43. * @param {number} [n33] - 3-3 matrix element.
  44. */
  45. constructor( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
  46. /**
  47. * This flag can be used for type testing.
  48. *
  49. * @type {boolean}
  50. * @readonly
  51. * @default true
  52. */
  53. Matrix3.prototype.isMatrix3 = true;
  54. /**
  55. * A column-major list of matrix values.
  56. *
  57. * @type {Array<number>}
  58. */
  59. this.elements = [
  60. 1, 0, 0,
  61. 0, 1, 0,
  62. 0, 0, 1
  63. ];
  64. if ( n11 !== undefined ) {
  65. this.set( n11, n12, n13, n21, n22, n23, n31, n32, n33 );
  66. }
  67. }
  68. /**
  69. * Sets the elements of the matrix.The arguments are supposed to be
  70. * in row-major order.
  71. *
  72. * @param {number} [n11] - 1-1 matrix element.
  73. * @param {number} [n12] - 1-2 matrix element.
  74. * @param {number} [n13] - 1-3 matrix element.
  75. * @param {number} [n21] - 2-1 matrix element.
  76. * @param {number} [n22] - 2-2 matrix element.
  77. * @param {number} [n23] - 2-3 matrix element.
  78. * @param {number} [n31] - 3-1 matrix element.
  79. * @param {number} [n32] - 3-2 matrix element.
  80. * @param {number} [n33] - 3-3 matrix element.
  81. * @return {Matrix3} A reference to this matrix.
  82. */
  83. set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
  84. const te = this.elements;
  85. te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;
  86. te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;
  87. te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;
  88. return this;
  89. }
  90. /**
  91. * Sets this matrix to the 3x3 identity matrix.
  92. *
  93. * @return {Matrix3} A reference to this matrix.
  94. */
  95. identity() {
  96. this.set(
  97. 1, 0, 0,
  98. 0, 1, 0,
  99. 0, 0, 1
  100. );
  101. return this;
  102. }
  103. /**
  104. * Copies the values of the given matrix to this instance.
  105. *
  106. * @param {Matrix3} m - The matrix to copy.
  107. * @return {Matrix3} A reference to this matrix.
  108. */
  109. copy( m ) {
  110. const te = this.elements;
  111. const me = m.elements;
  112. te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ];
  113. te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ];
  114. te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ];
  115. return this;
  116. }
  117. /**
  118. * Extracts the basis of this matrix into the three axis vectors provided.
  119. *
  120. * @param {Vector3} xAxis - The basis's x axis.
  121. * @param {Vector3} yAxis - The basis's y axis.
  122. * @param {Vector3} zAxis - The basis's z axis.
  123. * @return {Matrix3} A reference to this matrix.
  124. */
  125. extractBasis( xAxis, yAxis, zAxis ) {
  126. xAxis.setFromMatrix3Column( this, 0 );
  127. yAxis.setFromMatrix3Column( this, 1 );
  128. zAxis.setFromMatrix3Column( this, 2 );
  129. return this;
  130. }
  131. /**
  132. * Set this matrix to the upper 3x3 matrix of the given 4x4 matrix.
  133. *
  134. * @param {Matrix4} m - The 4x4 matrix.
  135. * @return {Matrix3} A reference to this matrix.
  136. */
  137. setFromMatrix4( m ) {
  138. const me = m.elements;
  139. this.set(
  140. me[ 0 ], me[ 4 ], me[ 8 ],
  141. me[ 1 ], me[ 5 ], me[ 9 ],
  142. me[ 2 ], me[ 6 ], me[ 10 ]
  143. );
  144. return this;
  145. }
  146. /**
  147. * Post-multiplies this matrix by the given 3x3 matrix.
  148. *
  149. * @param {Matrix3} m - The matrix to multiply with.
  150. * @return {Matrix3} A reference to this matrix.
  151. */
  152. multiply( m ) {
  153. return this.multiplyMatrices( this, m );
  154. }
  155. /**
  156. * Pre-multiplies this matrix by the given 3x3 matrix.
  157. *
  158. * @param {Matrix3} m - The matrix to multiply with.
  159. * @return {Matrix3} A reference to this matrix.
  160. */
  161. premultiply( m ) {
  162. return this.multiplyMatrices( m, this );
  163. }
  164. /**
  165. * Multiples the given 3x3 matrices and stores the result
  166. * in this matrix.
  167. *
  168. * @param {Matrix3} a - The first matrix.
  169. * @param {Matrix3} b - The second matrix.
  170. * @return {Matrix3} A reference to this matrix.
  171. */
  172. multiplyMatrices( a, b ) {
  173. const ae = a.elements;
  174. const be = b.elements;
  175. const te = this.elements;
  176. const a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];
  177. const a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];
  178. const a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];
  179. const b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];
  180. const b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];
  181. const b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];
  182. te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;
  183. te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32;
  184. te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33;
  185. te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31;
  186. te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32;
  187. te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33;
  188. te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31;
  189. te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32;
  190. te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33;
  191. return this;
  192. }
  193. /**
  194. * Multiplies every component of the matrix by the given scalar.
  195. *
  196. * @param {number} s - The scalar.
  197. * @return {Matrix3} A reference to this matrix.
  198. */
  199. multiplyScalar( s ) {
  200. const te = this.elements;
  201. te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;
  202. te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;
  203. te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;
  204. return this;
  205. }
  206. /**
  207. * Computes and returns the determinant of this matrix.
  208. *
  209. * @return {number} The determinant.
  210. */
  211. determinant() {
  212. const te = this.elements;
  213. const a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],
  214. d = te[ 3 ], e = te[ 4 ], f = te[ 5 ],
  215. g = te[ 6 ], h = te[ 7 ], i = te[ 8 ];
  216. return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;
  217. }
  218. /**
  219. * Inverts this matrix, using the [analytic method](https://en.wikipedia.org/wiki/Invertible_matrix#Analytic_solution).
  220. * You can not invert with a determinant of zero. If you attempt this, the method produces
  221. * a zero matrix instead.
  222. *
  223. * @return {Matrix3} A reference to this matrix.
  224. */
  225. invert() {
  226. const te = this.elements,
  227. n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ],
  228. n12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ],
  229. n13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ],
  230. t11 = n33 * n22 - n32 * n23,
  231. t12 = n32 * n13 - n33 * n12,
  232. t13 = n23 * n12 - n22 * n13,
  233. det = n11 * t11 + n21 * t12 + n31 * t13;
  234. if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 );
  235. const detInv = 1 / det;
  236. te[ 0 ] = t11 * detInv;
  237. te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;
  238. te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;
  239. te[ 3 ] = t12 * detInv;
  240. te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;
  241. te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;
  242. te[ 6 ] = t13 * detInv;
  243. te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;
  244. te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;
  245. return this;
  246. }
  247. /**
  248. * Transposes this matrix in place.
  249. *
  250. * @return {Matrix3} A reference to this matrix.
  251. */
  252. transpose() {
  253. let tmp;
  254. const m = this.elements;
  255. tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;
  256. tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;
  257. tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;
  258. return this;
  259. }
  260. /**
  261. * Computes the normal matrix which is the inverse transpose of the upper
  262. * left 3x3 portion of the given 4x4 matrix.
  263. *
  264. * @param {Matrix4} matrix4 - The 4x4 matrix.
  265. * @return {Matrix3} A reference to this matrix.
  266. */
  267. getNormalMatrix( matrix4 ) {
  268. return this.setFromMatrix4( matrix4 ).invert().transpose();
  269. }
  270. /**
  271. * Transposes this matrix into the supplied array, and returns itself unchanged.
  272. *
  273. * @param {Array<number>} r - An array to store the transposed matrix elements.
  274. * @return {Matrix3} A reference to this matrix.
  275. */
  276. transposeIntoArray( r ) {
  277. const m = this.elements;
  278. r[ 0 ] = m[ 0 ];
  279. r[ 1 ] = m[ 3 ];
  280. r[ 2 ] = m[ 6 ];
  281. r[ 3 ] = m[ 1 ];
  282. r[ 4 ] = m[ 4 ];
  283. r[ 5 ] = m[ 7 ];
  284. r[ 6 ] = m[ 2 ];
  285. r[ 7 ] = m[ 5 ];
  286. r[ 8 ] = m[ 8 ];
  287. return this;
  288. }
  289. /**
  290. * Sets the UV transform matrix from offset, repeat, rotation, and center.
  291. *
  292. * @param {number} tx - Offset x.
  293. * @param {number} ty - Offset y.
  294. * @param {number} sx - Repeat x.
  295. * @param {number} sy - Repeat y.
  296. * @param {number} rotation - Rotation, in radians. Positive values rotate counterclockwise.
  297. * @param {number} cx - Center x of rotation.
  298. * @param {number} cy - Center y of rotation
  299. * @return {Matrix3} A reference to this matrix.
  300. */
  301. setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) {
  302. const c = Math.cos( rotation );
  303. const s = Math.sin( rotation );
  304. this.set(
  305. sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx,
  306. - sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty,
  307. 0, 0, 1
  308. );
  309. return this;
  310. }
  311. /**
  312. * Scales this matrix with the given scalar values.
  313. *
  314. * @param {number} sx - The amount to scale in the X axis.
  315. * @param {number} sy - The amount to scale in the Y axis.
  316. * @return {Matrix3} A reference to this matrix.
  317. */
  318. scale( sx, sy ) {
  319. this.premultiply( _m3.makeScale( sx, sy ) );
  320. return this;
  321. }
  322. /**
  323. * Rotates this matrix by the given angle.
  324. *
  325. * @param {number} theta - The rotation in radians.
  326. * @return {Matrix3} A reference to this matrix.
  327. */
  328. rotate( theta ) {
  329. this.premultiply( _m3.makeRotation( - theta ) );
  330. return this;
  331. }
  332. /**
  333. * Translates this matrix by the given scalar values.
  334. *
  335. * @param {number} tx - The amount to translate in the X axis.
  336. * @param {number} ty - The amount to translate in the Y axis.
  337. * @return {Matrix3} A reference to this matrix.
  338. */
  339. translate( tx, ty ) {
  340. this.premultiply( _m3.makeTranslation( tx, ty ) );
  341. return this;
  342. }
  343. // for 2D Transforms
  344. /**
  345. * Sets this matrix as a 2D translation transform.
  346. *
  347. * @param {number|Vector2} x - The amount to translate in the X axis or alternatively a translation vector.
  348. * @param {number} y - The amount to translate in the Y axis.
  349. * @return {Matrix3} A reference to this matrix.
  350. */
  351. makeTranslation( x, y ) {
  352. if ( x.isVector2 ) {
  353. this.set(
  354. 1, 0, x.x,
  355. 0, 1, x.y,
  356. 0, 0, 1
  357. );
  358. } else {
  359. this.set(
  360. 1, 0, x,
  361. 0, 1, y,
  362. 0, 0, 1
  363. );
  364. }
  365. return this;
  366. }
  367. /**
  368. * Sets this matrix as a 2D rotational transformation.
  369. *
  370. * @param {number} theta - The rotation in radians.
  371. * @return {Matrix3} A reference to this matrix.
  372. */
  373. makeRotation( theta ) {
  374. // counterclockwise
  375. const c = Math.cos( theta );
  376. const s = Math.sin( theta );
  377. this.set(
  378. c, - s, 0,
  379. s, c, 0,
  380. 0, 0, 1
  381. );
  382. return this;
  383. }
  384. /**
  385. * Sets this matrix as a 2D scale transform.
  386. *
  387. * @param {number} x - The amount to scale in the X axis.
  388. * @param {number} y - The amount to scale in the Y axis.
  389. * @return {Matrix3} A reference to this matrix.
  390. */
  391. makeScale( x, y ) {
  392. this.set(
  393. x, 0, 0,
  394. 0, y, 0,
  395. 0, 0, 1
  396. );
  397. return this;
  398. }
  399. /**
  400. * Returns `true` if this matrix is equal with the given one.
  401. *
  402. * @param {Matrix3} matrix - The matrix to test for equality.
  403. * @return {boolean} Whether this matrix is equal with the given one.
  404. */
  405. equals( matrix ) {
  406. const te = this.elements;
  407. const me = matrix.elements;
  408. for ( let i = 0; i < 9; i ++ ) {
  409. if ( te[ i ] !== me[ i ] ) return false;
  410. }
  411. return true;
  412. }
  413. /**
  414. * Sets the elements of the matrix from the given array.
  415. *
  416. * @param {Array<number>} array - The matrix elements in column-major order.
  417. * @param {number} [offset=0] - Index of the first element in the array.
  418. * @return {Matrix3} A reference to this matrix.
  419. */
  420. fromArray( array, offset = 0 ) {
  421. for ( let i = 0; i < 9; i ++ ) {
  422. this.elements[ i ] = array[ i + offset ];
  423. }
  424. return this;
  425. }
  426. /**
  427. * Writes the elements of this matrix to the given array. If no array is provided,
  428. * the method returns a new instance.
  429. *
  430. * @param {Array<number>} [array=[]] - The target array holding the matrix elements in column-major order.
  431. * @param {number} [offset=0] - Index of the first element in the array.
  432. * @return {Array<number>} The matrix elements in column-major order.
  433. */
  434. toArray( array = [], offset = 0 ) {
  435. const te = this.elements;
  436. array[ offset ] = te[ 0 ];
  437. array[ offset + 1 ] = te[ 1 ];
  438. array[ offset + 2 ] = te[ 2 ];
  439. array[ offset + 3 ] = te[ 3 ];
  440. array[ offset + 4 ] = te[ 4 ];
  441. array[ offset + 5 ] = te[ 5 ];
  442. array[ offset + 6 ] = te[ 6 ];
  443. array[ offset + 7 ] = te[ 7 ];
  444. array[ offset + 8 ] = te[ 8 ];
  445. return array;
  446. }
  447. /**
  448. * Returns a matrix with copied values from this instance.
  449. *
  450. * @return {Matrix3} A clone of this instance.
  451. */
  452. clone() {
  453. return new this.constructor().fromArray( this.elements );
  454. }
  455. }
  456. const _m3 = /*@__PURE__*/ new Matrix3();
  457. export { Matrix3 };
粤ICP备19079148号