MathUtils.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. let _seed = 1234567;
  2. const DEG2RAD = Math.PI / 180;
  3. const RAD2DEG = 180 / Math.PI;
  4. //
  5. const _lut = [];
  6. for ( let i = 0; i < 256; i ++ ) {
  7. _lut[ i ] = ( i < 16 ? '0' : '' ) + ( i ).toString( 16 );
  8. }
  9. const hasRandomUUID = typeof crypto !== 'undefined' && 'randomUUID' in crypto;
  10. function generateUUID() {
  11. if ( hasRandomUUID ) {
  12. return crypto.randomUUID().toUpperCase();
  13. }
  14. // TODO Remove this code when crypto.randomUUID() is available everywhere
  15. // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
  16. const d0 = Math.random() * 0xffffffff | 0;
  17. const d1 = Math.random() * 0xffffffff | 0;
  18. const d2 = Math.random() * 0xffffffff | 0;
  19. const d3 = Math.random() * 0xffffffff | 0;
  20. const uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' +
  21. _lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' +
  22. _lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] +
  23. _lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ];
  24. // .toUpperCase() here flattens concatenated strings to save heap memory space.
  25. return uuid.toUpperCase();
  26. }
  27. function clamp( value, min, max ) {
  28. return Math.max( min, Math.min( max, value ) );
  29. }
  30. // compute euclidian modulo of m % n
  31. // https://en.wikipedia.org/wiki/Modulo_operation
  32. function euclideanModulo( n, m ) {
  33. return ( ( n % m ) + m ) % m;
  34. }
  35. // Linear mapping from range <a1, a2> to range <b1, b2>
  36. function mapLinear( x, a1, a2, b1, b2 ) {
  37. return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
  38. }
  39. // https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/
  40. function inverseLerp( x, y, value ) {
  41. if ( x !== y ) {
  42. return ( value - x ) / ( y - x );
  43. } else {
  44. return 0;
  45. }
  46. }
  47. // https://en.wikipedia.org/wiki/Linear_interpolation
  48. function lerp( x, y, t ) {
  49. return ( 1 - t ) * x + t * y;
  50. }
  51. // http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/
  52. function damp( x, y, lambda, dt ) {
  53. return lerp( x, y, 1 - Math.exp( - lambda * dt ) );
  54. }
  55. // https://www.desmos.com/calculator/vcsjnyz7x4
  56. function pingpong( x, length = 1 ) {
  57. return length - Math.abs( euclideanModulo( x, length * 2 ) - length );
  58. }
  59. // http://en.wikipedia.org/wiki/Smoothstep
  60. function smoothstep( x, min, max ) {
  61. if ( x <= min ) return 0;
  62. if ( x >= max ) return 1;
  63. x = ( x - min ) / ( max - min );
  64. return x * x * ( 3 - 2 * x );
  65. }
  66. function smootherstep( x, min, max ) {
  67. if ( x <= min ) return 0;
  68. if ( x >= max ) return 1;
  69. x = ( x - min ) / ( max - min );
  70. return x * x * x * ( x * ( x * 6 - 15 ) + 10 );
  71. }
  72. // Random integer from <low, high> interval
  73. function randInt( low, high ) {
  74. return low + Math.floor( Math.random() * ( high - low + 1 ) );
  75. }
  76. // Random float from <low, high> interval
  77. function randFloat( low, high ) {
  78. return low + Math.random() * ( high - low );
  79. }
  80. // Random float from <-range/2, range/2> interval
  81. function randFloatSpread( range ) {
  82. return range * ( 0.5 - Math.random() );
  83. }
  84. // Deterministic pseudo-random float in the interval [ 0, 1 ]
  85. function seededRandom( s ) {
  86. if ( s !== undefined ) _seed = s % 2147483647;
  87. // Park-Miller algorithm
  88. _seed = _seed * 16807 % 2147483647;
  89. return ( _seed - 1 ) / 2147483646;
  90. }
  91. function degToRad( degrees ) {
  92. return degrees * DEG2RAD;
  93. }
  94. function radToDeg( radians ) {
  95. return radians * RAD2DEG;
  96. }
  97. function isPowerOfTwo( value ) {
  98. return ( value & ( value - 1 ) ) === 0 && value !== 0;
  99. }
  100. function ceilPowerOfTwo( value ) {
  101. return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) );
  102. }
  103. function floorPowerOfTwo( value ) {
  104. return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) );
  105. }
  106. function setQuaternionFromProperEuler( q, a, b, c, order ) {
  107. // Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles
  108. // rotations are applied to the axes in the order specified by 'order'
  109. // rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c'
  110. // angles are in radians
  111. const cos = Math.cos;
  112. const sin = Math.sin;
  113. const c2 = cos( b / 2 );
  114. const s2 = sin( b / 2 );
  115. const c13 = cos( ( a + c ) / 2 );
  116. const s13 = sin( ( a + c ) / 2 );
  117. const c1_3 = cos( ( a - c ) / 2 );
  118. const s1_3 = sin( ( a - c ) / 2 );
  119. const c3_1 = cos( ( c - a ) / 2 );
  120. const s3_1 = sin( ( c - a ) / 2 );
  121. switch ( order ) {
  122. case 'XYX':
  123. q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 );
  124. break;
  125. case 'YZY':
  126. q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 );
  127. break;
  128. case 'ZXZ':
  129. q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 );
  130. break;
  131. case 'XZX':
  132. q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 );
  133. break;
  134. case 'YXY':
  135. q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 );
  136. break;
  137. case 'ZYZ':
  138. q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 );
  139. break;
  140. default:
  141. console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order );
  142. }
  143. }
  144. export {
  145. DEG2RAD,
  146. RAD2DEG,
  147. generateUUID,
  148. clamp,
  149. euclideanModulo,
  150. mapLinear,
  151. inverseLerp,
  152. lerp,
  153. damp,
  154. pingpong,
  155. smoothstep,
  156. smootherstep,
  157. randInt,
  158. randFloat,
  159. randFloatSpread,
  160. seededRandom,
  161. degToRad,
  162. radToDeg,
  163. isPowerOfTwo,
  164. ceilPowerOfTwo,
  165. floorPowerOfTwo,
  166. setQuaternionFromProperEuler,
  167. };