Quaternion.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918
  1. import { clamp } from './MathUtils.js';
  2. import { warn } from '../utils.js';
  3. /**
  4. * Class for representing a Quaternion. Quaternions are used in three.js to represent rotations.
  5. *
  6. * Iterating through a vector instance will yield its components `(x, y, z, w)` in
  7. * the corresponding order.
  8. *
  9. * Note that three.js expects Quaternions to be normalized.
  10. * ```js
  11. * const quaternion = new THREE.Quaternion();
  12. * quaternion.setFromAxisAngle( new THREE.Vector3( 0, 1, 0 ), Math.PI / 2 );
  13. *
  14. * const vector = new THREE.Vector3( 1, 0, 0 );
  15. * vector.applyQuaternion( quaternion );
  16. * ```
  17. */
  18. class Quaternion {
  19. /**
  20. * Constructs a new quaternion.
  21. *
  22. * @param {number} [x=0] - The x value of this quaternion.
  23. * @param {number} [y=0] - The y value of this quaternion.
  24. * @param {number} [z=0] - The z value of this quaternion.
  25. * @param {number} [w=1] - The w value of this quaternion.
  26. */
  27. constructor( x = 0, y = 0, z = 0, w = 1 ) {
  28. /**
  29. * This flag can be used for type testing.
  30. *
  31. * @type {boolean}
  32. * @readonly
  33. * @default true
  34. */
  35. this.isQuaternion = true;
  36. this._x = x;
  37. this._y = y;
  38. this._z = z;
  39. this._w = w;
  40. }
  41. /**
  42. * Interpolates between two quaternions via SLERP. This implementation assumes the
  43. * quaternion data are managed in flat arrays.
  44. *
  45. * @param {Array<number>} dst - The destination array.
  46. * @param {number} dstOffset - An offset into the destination array.
  47. * @param {Array<number>} src0 - The source array of the first quaternion.
  48. * @param {number} srcOffset0 - An offset into the first source array.
  49. * @param {Array<number>} src1 - The source array of the second quaternion.
  50. * @param {number} srcOffset1 - An offset into the second source array.
  51. * @param {number} t - The interpolation factor. A value in the range `[0,1]` will interpolate. A value outside the range `[0,1]` will extrapolate.
  52. * @see {@link Quaternion#slerp}
  53. */
  54. static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {
  55. let x0 = src0[ srcOffset0 + 0 ],
  56. y0 = src0[ srcOffset0 + 1 ],
  57. z0 = src0[ srcOffset0 + 2 ],
  58. w0 = src0[ srcOffset0 + 3 ];
  59. let x1 = src1[ srcOffset1 + 0 ],
  60. y1 = src1[ srcOffset1 + 1 ],
  61. z1 = src1[ srcOffset1 + 2 ],
  62. w1 = src1[ srcOffset1 + 3 ];
  63. if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
  64. let dot = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1;
  65. if ( dot < 0 ) {
  66. x1 = - x1;
  67. y1 = - y1;
  68. z1 = - z1;
  69. w1 = - w1;
  70. dot = - dot;
  71. }
  72. let s = 1 - t;
  73. if ( dot < 0.9995 ) {
  74. // slerp
  75. const theta = Math.acos( dot );
  76. const sin = Math.sin( theta );
  77. s = Math.sin( s * theta ) / sin;
  78. t = Math.sin( t * theta ) / sin;
  79. x0 = x0 * s + x1 * t;
  80. y0 = y0 * s + y1 * t;
  81. z0 = z0 * s + z1 * t;
  82. w0 = w0 * s + w1 * t;
  83. } else {
  84. // for small angles, lerp then normalize
  85. x0 = x0 * s + x1 * t;
  86. y0 = y0 * s + y1 * t;
  87. z0 = z0 * s + z1 * t;
  88. w0 = w0 * s + w1 * t;
  89. const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );
  90. x0 *= f;
  91. y0 *= f;
  92. z0 *= f;
  93. w0 *= f;
  94. }
  95. }
  96. dst[ dstOffset ] = x0;
  97. dst[ dstOffset + 1 ] = y0;
  98. dst[ dstOffset + 2 ] = z0;
  99. dst[ dstOffset + 3 ] = w0;
  100. }
  101. /**
  102. * Multiplies two quaternions. This implementation assumes the quaternion data are managed
  103. * in flat arrays.
  104. *
  105. * @param {Array<number>} dst - The destination array.
  106. * @param {number} dstOffset - An offset into the destination array.
  107. * @param {Array<number>} src0 - The source array of the first quaternion.
  108. * @param {number} srcOffset0 - An offset into the first source array.
  109. * @param {Array<number>} src1 - The source array of the second quaternion.
  110. * @param {number} srcOffset1 - An offset into the second source array.
  111. * @return {Array<number>} The destination array.
  112. * @see {@link Quaternion#multiplyQuaternions}.
  113. */
  114. static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) {
  115. const x0 = src0[ srcOffset0 ];
  116. const y0 = src0[ srcOffset0 + 1 ];
  117. const z0 = src0[ srcOffset0 + 2 ];
  118. const w0 = src0[ srcOffset0 + 3 ];
  119. const x1 = src1[ srcOffset1 ];
  120. const y1 = src1[ srcOffset1 + 1 ];
  121. const z1 = src1[ srcOffset1 + 2 ];
  122. const w1 = src1[ srcOffset1 + 3 ];
  123. dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1;
  124. dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1;
  125. dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1;
  126. dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1;
  127. return dst;
  128. }
  129. /**
  130. * The x value of this quaternion.
  131. *
  132. * @type {number}
  133. * @default 0
  134. */
  135. get x() {
  136. return this._x;
  137. }
  138. set x( value ) {
  139. this._x = value;
  140. this._onChangeCallback();
  141. }
  142. /**
  143. * The y value of this quaternion.
  144. *
  145. * @type {number}
  146. * @default 0
  147. */
  148. get y() {
  149. return this._y;
  150. }
  151. set y( value ) {
  152. this._y = value;
  153. this._onChangeCallback();
  154. }
  155. /**
  156. * The z value of this quaternion.
  157. *
  158. * @type {number}
  159. * @default 0
  160. */
  161. get z() {
  162. return this._z;
  163. }
  164. set z( value ) {
  165. this._z = value;
  166. this._onChangeCallback();
  167. }
  168. /**
  169. * The w value of this quaternion.
  170. *
  171. * @type {number}
  172. * @default 1
  173. */
  174. get w() {
  175. return this._w;
  176. }
  177. set w( value ) {
  178. this._w = value;
  179. this._onChangeCallback();
  180. }
  181. /**
  182. * Sets the quaternion components.
  183. *
  184. * @param {number} x - The x value of this quaternion.
  185. * @param {number} y - The y value of this quaternion.
  186. * @param {number} z - The z value of this quaternion.
  187. * @param {number} w - The w value of this quaternion.
  188. * @return {Quaternion} A reference to this quaternion.
  189. */
  190. set( x, y, z, w ) {
  191. this._x = x;
  192. this._y = y;
  193. this._z = z;
  194. this._w = w;
  195. this._onChangeCallback();
  196. return this;
  197. }
  198. /**
  199. * Returns a new quaternion with copied values from this instance.
  200. *
  201. * @return {Quaternion} A clone of this instance.
  202. */
  203. clone() {
  204. return new this.constructor( this._x, this._y, this._z, this._w );
  205. }
  206. /**
  207. * Copies the values of the given quaternion to this instance.
  208. *
  209. * @param {Quaternion} quaternion - The quaternion to copy.
  210. * @return {Quaternion} A reference to this quaternion.
  211. */
  212. copy( quaternion ) {
  213. this._x = quaternion.x;
  214. this._y = quaternion.y;
  215. this._z = quaternion.z;
  216. this._w = quaternion.w;
  217. this._onChangeCallback();
  218. return this;
  219. }
  220. /**
  221. * Sets this quaternion from the rotation specified by the given
  222. * Euler angles.
  223. *
  224. * @param {Euler} euler - The Euler angles.
  225. * @param {boolean} [update=true] - Whether the internal `onChange` callback should be executed or not.
  226. * @return {Quaternion} A reference to this quaternion.
  227. */
  228. setFromEuler( euler, update = true ) {
  229. const x = euler._x, y = euler._y, z = euler._z, order = euler._order;
  230. // http://www.mathworks.com/matlabcentral/fileexchange/
  231. // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
  232. // content/SpinCalc.m
  233. const cos = Math.cos;
  234. const sin = Math.sin;
  235. const c1 = cos( x / 2 );
  236. const c2 = cos( y / 2 );
  237. const c3 = cos( z / 2 );
  238. const s1 = sin( x / 2 );
  239. const s2 = sin( y / 2 );
  240. const s3 = sin( z / 2 );
  241. switch ( order ) {
  242. case 'XYZ':
  243. this._x = s1 * c2 * c3 + c1 * s2 * s3;
  244. this._y = c1 * s2 * c3 - s1 * c2 * s3;
  245. this._z = c1 * c2 * s3 + s1 * s2 * c3;
  246. this._w = c1 * c2 * c3 - s1 * s2 * s3;
  247. break;
  248. case 'YXZ':
  249. this._x = s1 * c2 * c3 + c1 * s2 * s3;
  250. this._y = c1 * s2 * c3 - s1 * c2 * s3;
  251. this._z = c1 * c2 * s3 - s1 * s2 * c3;
  252. this._w = c1 * c2 * c3 + s1 * s2 * s3;
  253. break;
  254. case 'ZXY':
  255. this._x = s1 * c2 * c3 - c1 * s2 * s3;
  256. this._y = c1 * s2 * c3 + s1 * c2 * s3;
  257. this._z = c1 * c2 * s3 + s1 * s2 * c3;
  258. this._w = c1 * c2 * c3 - s1 * s2 * s3;
  259. break;
  260. case 'ZYX':
  261. this._x = s1 * c2 * c3 - c1 * s2 * s3;
  262. this._y = c1 * s2 * c3 + s1 * c2 * s3;
  263. this._z = c1 * c2 * s3 - s1 * s2 * c3;
  264. this._w = c1 * c2 * c3 + s1 * s2 * s3;
  265. break;
  266. case 'YZX':
  267. this._x = s1 * c2 * c3 + c1 * s2 * s3;
  268. this._y = c1 * s2 * c3 + s1 * c2 * s3;
  269. this._z = c1 * c2 * s3 - s1 * s2 * c3;
  270. this._w = c1 * c2 * c3 - s1 * s2 * s3;
  271. break;
  272. case 'XZY':
  273. this._x = s1 * c2 * c3 - c1 * s2 * s3;
  274. this._y = c1 * s2 * c3 - s1 * c2 * s3;
  275. this._z = c1 * c2 * s3 + s1 * s2 * c3;
  276. this._w = c1 * c2 * c3 + s1 * s2 * s3;
  277. break;
  278. default:
  279. warn( 'Quaternion: .setFromEuler() encountered an unknown order: ' + order );
  280. }
  281. if ( update === true ) this._onChangeCallback();
  282. return this;
  283. }
  284. /**
  285. * Sets this quaternion from the given axis and angle.
  286. *
  287. * @param {Vector3} axis - The normalized axis.
  288. * @param {number} angle - The angle in radians.
  289. * @return {Quaternion} A reference to this quaternion.
  290. */
  291. setFromAxisAngle( axis, angle ) {
  292. // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
  293. const halfAngle = angle / 2, s = Math.sin( halfAngle );
  294. this._x = axis.x * s;
  295. this._y = axis.y * s;
  296. this._z = axis.z * s;
  297. this._w = Math.cos( halfAngle );
  298. this._onChangeCallback();
  299. return this;
  300. }
  301. /**
  302. * Sets this quaternion from the given rotation matrix.
  303. *
  304. * @param {Matrix4} m - A 4x4 matrix of which the upper 3x3 of matrix is a pure rotation matrix (i.e. unscaled).
  305. * @return {Quaternion} A reference to this quaternion.
  306. */
  307. setFromRotationMatrix( m ) {
  308. // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
  309. // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
  310. const te = m.elements,
  311. m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
  312. m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
  313. m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],
  314. trace = m11 + m22 + m33;
  315. if ( trace > 0 ) {
  316. const s = 0.5 / Math.sqrt( trace + 1.0 );
  317. this._w = 0.25 / s;
  318. this._x = ( m32 - m23 ) * s;
  319. this._y = ( m13 - m31 ) * s;
  320. this._z = ( m21 - m12 ) * s;
  321. } else if ( m11 > m22 && m11 > m33 ) {
  322. const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
  323. this._w = ( m32 - m23 ) / s;
  324. this._x = 0.25 * s;
  325. this._y = ( m12 + m21 ) / s;
  326. this._z = ( m13 + m31 ) / s;
  327. } else if ( m22 > m33 ) {
  328. const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
  329. this._w = ( m13 - m31 ) / s;
  330. this._x = ( m12 + m21 ) / s;
  331. this._y = 0.25 * s;
  332. this._z = ( m23 + m32 ) / s;
  333. } else {
  334. const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
  335. this._w = ( m21 - m12 ) / s;
  336. this._x = ( m13 + m31 ) / s;
  337. this._y = ( m23 + m32 ) / s;
  338. this._z = 0.25 * s;
  339. }
  340. this._onChangeCallback();
  341. return this;
  342. }
  343. /**
  344. * Sets this quaternion to the rotation required to rotate the direction vector
  345. * `vFrom` to the direction vector `vTo`.
  346. *
  347. * @param {Vector3} vFrom - The first (normalized) direction vector.
  348. * @param {Vector3} vTo - The second (normalized) direction vector.
  349. * @return {Quaternion} A reference to this quaternion.
  350. */
  351. setFromUnitVectors( vFrom, vTo ) {
  352. // assumes direction vectors vFrom and vTo are normalized
  353. let r = vFrom.dot( vTo ) + 1;
  354. if ( r < 1e-8 ) { // the epsilon value has been discussed in #31286
  355. // vFrom and vTo point in opposite directions
  356. r = 0;
  357. if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {
  358. this._x = - vFrom.y;
  359. this._y = vFrom.x;
  360. this._z = 0;
  361. this._w = r;
  362. } else {
  363. this._x = 0;
  364. this._y = - vFrom.z;
  365. this._z = vFrom.y;
  366. this._w = r;
  367. }
  368. } else {
  369. // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3
  370. this._x = vFrom.y * vTo.z - vFrom.z * vTo.y;
  371. this._y = vFrom.z * vTo.x - vFrom.x * vTo.z;
  372. this._z = vFrom.x * vTo.y - vFrom.y * vTo.x;
  373. this._w = r;
  374. }
  375. return this.normalize();
  376. }
  377. /**
  378. * Returns the angle between this quaternion and the given one in radians.
  379. *
  380. * @param {Quaternion} q - The quaternion to compute the angle with.
  381. * @return {number} The angle in radians.
  382. */
  383. angleTo( q ) {
  384. return 2 * Math.acos( Math.abs( clamp( this.dot( q ), - 1, 1 ) ) );
  385. }
  386. /**
  387. * Rotates this quaternion by a given angular step to the given quaternion.
  388. * The method ensures that the final quaternion will not overshoot `q`.
  389. *
  390. * @param {Quaternion} q - The target quaternion.
  391. * @param {number} step - The angular step in radians.
  392. * @return {Quaternion} A reference to this quaternion.
  393. */
  394. rotateTowards( q, step ) {
  395. const angle = this.angleTo( q );
  396. if ( angle === 0 ) return this;
  397. const t = Math.min( 1, step / angle );
  398. this.slerp( q, t );
  399. return this;
  400. }
  401. /**
  402. * Sets this quaternion to the identity quaternion; that is, to the
  403. * quaternion that represents "no rotation".
  404. *
  405. * @return {Quaternion} A reference to this quaternion.
  406. */
  407. identity() {
  408. return this.set( 0, 0, 0, 1 );
  409. }
  410. /**
  411. * Inverts this quaternion via {@link Quaternion#conjugate}. The
  412. * quaternion is assumed to have unit length.
  413. *
  414. * @return {Quaternion} A reference to this quaternion.
  415. */
  416. invert() {
  417. return this.conjugate();
  418. }
  419. /**
  420. * Returns the rotational conjugate of this quaternion. The conjugate of a
  421. * quaternion represents the same rotation in the opposite direction about
  422. * the rotational axis.
  423. *
  424. * @return {Quaternion} A reference to this quaternion.
  425. */
  426. conjugate() {
  427. this._x *= - 1;
  428. this._y *= - 1;
  429. this._z *= - 1;
  430. this._onChangeCallback();
  431. return this;
  432. }
  433. /**
  434. * Calculates the dot product of this quaternion and the given one.
  435. *
  436. * @param {Quaternion} v - The quaternion to compute the dot product with.
  437. * @return {number} The result of the dot product.
  438. */
  439. dot( v ) {
  440. return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
  441. }
  442. /**
  443. * Computes the squared Euclidean length (straight-line length) of this quaternion,
  444. * considered as a 4 dimensional vector. This can be useful if you are comparing the
  445. * lengths of two quaternions, as this is a slightly more efficient calculation than
  446. * {@link Quaternion#length}.
  447. *
  448. * @return {number} The squared Euclidean length.
  449. */
  450. lengthSq() {
  451. return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
  452. }
  453. /**
  454. * Computes the Euclidean length (straight-line length) of this quaternion,
  455. * considered as a 4 dimensional vector.
  456. *
  457. * @return {number} The Euclidean length.
  458. */
  459. length() {
  460. return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
  461. }
  462. /**
  463. * Normalizes this quaternion - that is, calculated the quaternion that performs
  464. * the same rotation as this one, but has a length equal to `1`.
  465. *
  466. * @return {Quaternion} A reference to this quaternion.
  467. */
  468. normalize() {
  469. let l = this.length();
  470. if ( l === 0 ) {
  471. this._x = 0;
  472. this._y = 0;
  473. this._z = 0;
  474. this._w = 1;
  475. } else {
  476. l = 1 / l;
  477. this._x = this._x * l;
  478. this._y = this._y * l;
  479. this._z = this._z * l;
  480. this._w = this._w * l;
  481. }
  482. this._onChangeCallback();
  483. return this;
  484. }
  485. /**
  486. * Multiplies this quaternion by the given one.
  487. *
  488. * @param {Quaternion} q - The quaternion.
  489. * @return {Quaternion} A reference to this quaternion.
  490. */
  491. multiply( q ) {
  492. return this.multiplyQuaternions( this, q );
  493. }
  494. /**
  495. * Pre-multiplies this quaternion by the given one.
  496. *
  497. * @param {Quaternion} q - The quaternion.
  498. * @return {Quaternion} A reference to this quaternion.
  499. */
  500. premultiply( q ) {
  501. return this.multiplyQuaternions( q, this );
  502. }
  503. /**
  504. * Multiplies the given quaternions and stores the result in this instance.
  505. *
  506. * @param {Quaternion} a - The first quaternion.
  507. * @param {Quaternion} b - The second quaternion.
  508. * @return {Quaternion} A reference to this quaternion.
  509. */
  510. multiplyQuaternions( a, b ) {
  511. // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
  512. const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
  513. const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
  514. this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
  515. this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
  516. this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
  517. this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
  518. this._onChangeCallback();
  519. return this;
  520. }
  521. /**
  522. * Performs a spherical linear interpolation between this quaternion and the target quaternion.
  523. *
  524. * @param {Quaternion} qb - The target quaternion.
  525. * @param {number} t - The interpolation factor. A value in the range `[0,1]` will interpolate. A value outside the range `[0,1]` will extrapolate.
  526. * @return {Quaternion} A reference to this quaternion.
  527. */
  528. slerp( qb, t ) {
  529. let x = qb._x, y = qb._y, z = qb._z, w = qb._w;
  530. let dot = this.dot( qb );
  531. if ( dot < 0 ) {
  532. x = - x;
  533. y = - y;
  534. z = - z;
  535. w = - w;
  536. dot = - dot;
  537. }
  538. let s = 1 - t;
  539. if ( dot < 0.9995 ) {
  540. // slerp
  541. const theta = Math.acos( dot );
  542. const sin = Math.sin( theta );
  543. s = Math.sin( s * theta ) / sin;
  544. t = Math.sin( t * theta ) / sin;
  545. this._x = this._x * s + x * t;
  546. this._y = this._y * s + y * t;
  547. this._z = this._z * s + z * t;
  548. this._w = this._w * s + w * t;
  549. this._onChangeCallback();
  550. } else {
  551. // for small angles, lerp then normalize
  552. this._x = this._x * s + x * t;
  553. this._y = this._y * s + y * t;
  554. this._z = this._z * s + z * t;
  555. this._w = this._w * s + w * t;
  556. this.normalize(); // normalize calls _onChangeCallback()
  557. }
  558. return this;
  559. }
  560. /**
  561. * Performs a spherical linear interpolation between the given quaternions
  562. * and stores the result in this quaternion.
  563. *
  564. * @param {Quaternion} qa - The source quaternion.
  565. * @param {Quaternion} qb - The target quaternion.
  566. * @param {number} t - The interpolation factor in the closed interval `[0, 1]`.
  567. * @return {Quaternion} A reference to this quaternion.
  568. */
  569. slerpQuaternions( qa, qb, t ) {
  570. return this.copy( qa ).slerp( qb, t );
  571. }
  572. /**
  573. * Sets this quaternion to a uniformly random, normalized quaternion.
  574. *
  575. * @return {Quaternion} A reference to this quaternion.
  576. */
  577. random() {
  578. // Ken Shoemake
  579. // Uniform random rotations
  580. // D. Kirk, editor, Graphics Gems III, pages 124-132. Academic Press, New York, 1992.
  581. const theta1 = 2 * Math.PI * Math.random();
  582. const theta2 = 2 * Math.PI * Math.random();
  583. const x0 = Math.random();
  584. const r1 = Math.sqrt( 1 - x0 );
  585. const r2 = Math.sqrt( x0 );
  586. return this.set(
  587. r1 * Math.sin( theta1 ),
  588. r1 * Math.cos( theta1 ),
  589. r2 * Math.sin( theta2 ),
  590. r2 * Math.cos( theta2 ),
  591. );
  592. }
  593. /**
  594. * Returns `true` if this quaternion is equal with the given one.
  595. *
  596. * @param {Quaternion} quaternion - The quaternion to test for equality.
  597. * @return {boolean} Whether this quaternion is equal with the given one.
  598. */
  599. equals( quaternion ) {
  600. return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
  601. }
  602. /**
  603. * Sets this quaternion's components from the given array.
  604. *
  605. * @param {Array<number>} array - An array holding the quaternion component values.
  606. * @param {number} [offset=0] - The offset into the array.
  607. * @return {Quaternion} A reference to this quaternion.
  608. */
  609. fromArray( array, offset = 0 ) {
  610. this._x = array[ offset ];
  611. this._y = array[ offset + 1 ];
  612. this._z = array[ offset + 2 ];
  613. this._w = array[ offset + 3 ];
  614. this._onChangeCallback();
  615. return this;
  616. }
  617. /**
  618. * Writes the components of this quaternion to the given array. If no array is provided,
  619. * the method returns a new instance.
  620. *
  621. * @param {Array<number>} [array=[]] - The target array holding the quaternion components.
  622. * @param {number} [offset=0] - Index of the first element in the array.
  623. * @return {Array<number>} The quaternion components.
  624. */
  625. toArray( array = [], offset = 0 ) {
  626. array[ offset ] = this._x;
  627. array[ offset + 1 ] = this._y;
  628. array[ offset + 2 ] = this._z;
  629. array[ offset + 3 ] = this._w;
  630. return array;
  631. }
  632. /**
  633. * Sets the components of this quaternion from the given buffer attribute.
  634. *
  635. * @param {BufferAttribute} attribute - The buffer attribute holding quaternion data.
  636. * @param {number} index - The index into the attribute.
  637. * @return {Quaternion} A reference to this quaternion.
  638. */
  639. fromBufferAttribute( attribute, index ) {
  640. this._x = attribute.getX( index );
  641. this._y = attribute.getY( index );
  642. this._z = attribute.getZ( index );
  643. this._w = attribute.getW( index );
  644. this._onChangeCallback();
  645. return this;
  646. }
  647. /**
  648. * This methods defines the serialization result of this class. Returns the
  649. * numerical elements of this quaternion in an array of format `[x, y, z, w]`.
  650. *
  651. * @return {Array<number>} The serialized quaternion.
  652. */
  653. toJSON() {
  654. return this.toArray();
  655. }
  656. _onChange( callback ) {
  657. this._onChangeCallback = callback;
  658. return this;
  659. }
  660. _onChangeCallback() {}
  661. *[ Symbol.iterator ]() {
  662. yield this._x;
  663. yield this._y;
  664. yield this._z;
  665. yield this._w;
  666. }
  667. }
  668. export { Quaternion };
粤ICP备19079148号