MathUtils.js 6.0 KB

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