-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMathUtils.js
258 lines (161 loc) · 5.14 KB
/
MathUtils.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
const _lut = [];
for ( let i = 0; i < 256; i ++ ) {
_lut[ i ] = ( i < 16 ? '0' : '' ) + ( i ).toString( 16 );
}
let _seed = 1234567;
const DEG2RAD = Math.PI / 180;
const RAD2DEG = 180 / Math.PI;
// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
function generateUUID() {
const d0 = Math.random() * 0xffffffff | 0;
const d1 = Math.random() * 0xffffffff | 0;
const d2 = Math.random() * 0xffffffff | 0;
const d3 = Math.random() * 0xffffffff | 0;
const uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' +
_lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' +
_lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] +
_lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ];
// .toUpperCase() here flattens concatenated strings to save heap memory space.
return uuid.toUpperCase();
}
function clamp( value, min, max ) {
return Math.max( min, Math.min( max, value ) );
}
// compute euclidian modulo of m % n
// https://en.wikipedia.org/wiki/Modulo_operation
function euclideanModulo( n, m ) {
return ( ( n % m ) + m ) % m;
}
// Linear mapping from range <a1, a2> to range <b1, b2>
function mapLinear( x, a1, a2, b1, b2 ) {
return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
}
// https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/
function inverseLerp( x, y, value ) {
if ( x !== y ) {
return ( value - x ) / ( y - x );
} else {
return 0;
}
}
// https://en.wikipedia.org/wiki/Linear_interpolation
function lerp( x, y, t ) {
return ( 1 - t ) * x + t * y;
}
// http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/
function damp( x, y, lambda, dt ) {
return lerp( x, y, 1 - Math.exp( - lambda * dt ) );
}
// https://www.desmos.com/calculator/vcsjnyz7x4
function pingpong( x, length = 1 ) {
return length - Math.abs( euclideanModulo( x, length * 2 ) - length );
}
// http://en.wikipedia.org/wiki/Smoothstep
function smoothstep( x, min, max ) {
if ( x <= min ) return 0;
if ( x >= max ) return 1;
x = ( x - min ) / ( max - min );
return x * x * ( 3 - 2 * x );
}
function smootherstep( x, min, max ) {
if ( x <= min ) return 0;
if ( x >= max ) return 1;
x = ( x - min ) / ( max - min );
return x * x * x * ( x * ( x * 6 - 15 ) + 10 );
}
// Random integer from <low, high> interval
function randInt( low, high ) {
return low + Math.floor( Math.random() * ( high - low + 1 ) );
}
// Random float from <low, high> interval
function randFloat( low, high ) {
return low + Math.random() * ( high - low );
}
// Random float from <-range/2, range/2> interval
function randFloatSpread( range ) {
return range * ( 0.5 - Math.random() );
}
// Deterministic pseudo-random float in the interval [ 0, 1 ]
function seededRandom( s ) {
if ( s !== undefined ) _seed = s % 2147483647;
// Park-Miller algorithm
_seed = _seed * 16807 % 2147483647;
return ( _seed - 1 ) / 2147483646;
}
function degToRad( degrees ) {
return degrees * DEG2RAD;
}
function radToDeg( radians ) {
return radians * RAD2DEG;
}
function isPowerOfTwo( value ) {
return ( value & ( value - 1 ) ) === 0 && value !== 0;
}
function ceilPowerOfTwo( value ) {
return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) );
}
function floorPowerOfTwo( value ) {
return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) );
}
function setQuaternionFromProperEuler( q, a, b, c, order ) {
// Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles
// rotations are applied to the axes in the order specified by 'order'
// rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c'
// angles are in radians
const cos = Math.cos;
const sin = Math.sin;
const c2 = cos( b / 2 );
const s2 = sin( b / 2 );
const c13 = cos( ( a + c ) / 2 );
const s13 = sin( ( a + c ) / 2 );
const c1_3 = cos( ( a - c ) / 2 );
const s1_3 = sin( ( a - c ) / 2 );
const c3_1 = cos( ( c - a ) / 2 );
const s3_1 = sin( ( c - a ) / 2 );
switch ( order ) {
case 'XYX':
q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 );
break;
case 'YZY':
q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 );
break;
case 'ZXZ':
q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 );
break;
case 'XZX':
q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 );
break;
case 'YXY':
q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 );
break;
case 'ZYZ':
q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 );
break;
default:
console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order );
}
}
export {
DEG2RAD,
RAD2DEG,
generateUUID,
clamp,
euclideanModulo,
mapLinear,
inverseLerp,
lerp,
damp,
pingpong,
smoothstep,
smootherstep,
randInt,
randFloat,
randFloatSpread,
seededRandom,
degToRad,
radToDeg,
isPowerOfTwo,
ceilPowerOfTwo,
floorPowerOfTwo,
setQuaternionFromProperEuler,
};