@@ -34,7 +34,30 @@ const G3 = 1.0 / 6.0;
3434const F4 = ( Math . sqrt ( 5.0 ) - 1.0 ) / 4.0 ;
3535const G4 = ( 5.0 - Math . sqrt ( 5.0 ) ) / 20.0 ;
3636
37- const grad3 = new Float32Array ( [ 1 , 1 , 0 ,
37+ // I'm really not sure why this | 0 (basically a coercion to int)
38+ // is making this faster but I get ~5 million ops/sec more on the
39+ // benchmarks across the board or a ~10% speedup.
40+ const fastFloor = ( x : number ) => Math . floor ( x ) | 0 ;
41+
42+ const grad2 = new Float64Array ( [ 1 , 1 ,
43+ - 1 , 1 ,
44+ 1 , - 1 ,
45+
46+ - 1 , - 1 ,
47+ 1 , 0 ,
48+ - 1 , 0 ,
49+
50+ 1 , 0 ,
51+ - 1 , 0 ,
52+ 0 , 1 ,
53+
54+ 0 , - 1 ,
55+ 0 , 1 ,
56+ 0 , - 1 ] ) ;
57+
58+ // double seems to be faster than single or int's
59+ // probably because most operations are in double precision
60+ const grad3 = new Float64Array ( [ 1 , 1 , 0 ,
3861 - 1 , 1 , 0 ,
3962 1 , - 1 , 0 ,
4063
@@ -50,7 +73,8 @@ const grad3 = new Float32Array([1, 1, 0,
5073 0 , 1 , - 1 ,
5174 0 , - 1 , - 1 ] ) ;
5275
53- const grad4 = new Float32Array ( [ 0 , 1 , 1 , 1 , 0 , 1 , 1 , - 1 , 0 , 1 , - 1 , 1 , 0 , 1 , - 1 , - 1 ,
76+ // double is a bit quicker here as well
77+ const grad4 = new Float64Array ( [ 0 , 1 , 1 , 1 , 0 , 1 , 1 , - 1 , 0 , 1 , - 1 , 1 , 0 , 1 , - 1 , - 1 ,
5478 0 , - 1 , 1 , 1 , 0 , - 1 , 1 , - 1 , 0 , - 1 , - 1 , 1 , 0 , - 1 , - 1 , - 1 ,
5579 1 , 0 , 1 , 1 , 1 , 0 , 1 , - 1 , 1 , 0 , - 1 , 1 , 1 , 0 , - 1 , - 1 ,
5680 - 1 , 0 , 1 , 1 , - 1 , 0 , 1 , - 1 , - 1 , 0 , - 1 , 1 , - 1 , 0 , - 1 , - 1 ,
@@ -79,15 +103,18 @@ export type NoiseFunction2D = (x: number, y: number) => number;
79103 */
80104export function createNoise2D ( random : RandomFn = Math . random ) : NoiseFunction2D {
81105 const perm = buildPermutationTable ( random ) ;
82- const permMod12 = perm . map ( v => v % 12 ) ;
106+ // precalculating this yields a little ~3% performance improvement.
107+ const permGrad2x = new Float64Array ( perm ) . map ( v => grad2 [ ( v % 12 ) * 2 ] ) ;
108+ const permGrad2y = new Float64Array ( perm ) . map ( v => grad2 [ ( v % 12 ) * 2 + 1 ] ) ;
83109 return function noise2D ( x : number , y : number ) : number {
110+ // if(!isFinite(x) || !isFinite(y)) return 0;
84111 let n0 = 0 ; // Noise contributions from the three corners
85112 let n1 = 0 ;
86113 let n2 = 0 ;
87114 // Skew the input space to determine which simplex cell we're in
88115 const s = ( x + y ) * F2 ; // Hairy factor for 2D
89- const i = Math . floor ( x + s ) ;
90- const j = Math . floor ( y + s ) ;
116+ const i = fastFloor ( x + s ) ;
117+ const j = fastFloor ( y + s ) ;
91118 const t = ( i + j ) * G2 ;
92119 const X0 = i - t ; // Unskew the cell origin back to (x,y) space
93120 const Y0 = j - t ;
@@ -117,21 +144,30 @@ export function createNoise2D(random: RandomFn = Math.random): NoiseFunction2D {
117144 // Calculate the contribution from the three corners
118145 let t0 = 0.5 - x0 * x0 - y0 * y0 ;
119146 if ( t0 >= 0 ) {
120- const gi0 = permMod12 [ ii + perm [ jj ] ] * 3 ;
147+ const gi0 = ii + perm [ jj ] ;
148+ const g0x = permGrad2x [ gi0 ] ;
149+ const g0y = permGrad2y [ gi0 ] ;
121150 t0 *= t0 ;
122- n0 = t0 * t0 * ( grad3 [ gi0 ] * x0 + grad3 [ gi0 + 1 ] * y0 ) ; // (x,y) of grad3 used for 2D gradient
151+ // n0 = t0 * t0 * (grad2[gi0] * x0 + grad2[gi0 + 1] * y0); // (x,y) of grad3 used for 2D gradient
152+ n0 = t0 * t0 * ( g0x * x0 + g0y * y0 ) ;
123153 }
124154 let t1 = 0.5 - x1 * x1 - y1 * y1 ;
125155 if ( t1 >= 0 ) {
126- const gi1 = permMod12 [ ii + i1 + perm [ jj + j1 ] ] * 3 ;
156+ const gi1 = ii + i1 + perm [ jj + j1 ] ;
157+ const g1x = permGrad2x [ gi1 ] ;
158+ const g1y = permGrad2y [ gi1 ] ;
127159 t1 *= t1 ;
128- n1 = t1 * t1 * ( grad3 [ gi1 ] * x1 + grad3 [ gi1 + 1 ] * y1 ) ;
160+ // n1 = t1 * t1 * (grad2[gi1] * x1 + grad2[gi1 + 1] * y1);
161+ n1 = t1 * t1 * ( g1x * x1 + g1y * y1 ) ;
129162 }
130163 let t2 = 0.5 - x2 * x2 - y2 * y2 ;
131164 if ( t2 >= 0 ) {
132- const gi2 = permMod12 [ ii + 1 + perm [ jj + 1 ] ] * 3 ;
165+ const gi2 = ii + 1 + perm [ jj + 1 ] ;
166+ const g2x = permGrad2x [ gi2 ] ;
167+ const g2y = permGrad2y [ gi2 ] ;
133168 t2 *= t2 ;
134- n2 = t2 * t2 * ( grad3 [ gi2 ] * x2 + grad3 [ gi2 + 1 ] * y2 ) ;
169+ // n2 = t2 * t2 * (grad2[gi2] * x2 + grad2[gi2 + 1] * y2);
170+ n2 = t2 * t2 * ( g2x * x2 + g2y * y2 ) ;
135171 }
136172 // Add contributions from each corner to get the final noise value.
137173 // The result is scaled to return values in the interval [-1,1].
@@ -155,15 +191,13 @@ export type NoiseFunction3D = (x: number, y: number, z: number) => number;
155191 */
156192export function createNoise3D ( random : RandomFn = Math . random ) : NoiseFunction3D {
157193 const perm = buildPermutationTable ( random ) ;
158- const permMod12 = perm . map ( v => v % 12 ) ;
159-
160194 return function noise3D ( x : number , y : number , z : number ) : number {
161195 let n0 , n1 , n2 , n3 ; // Noise contributions from the four corners
162196 // Skew the input space to determine which simplex cell we're in
163197 const s = ( x + y + z ) * F3 ; // Very nice and simple skew factor for 3D
164- const i = Math . floor ( x + s ) ;
165- const j = Math . floor ( y + s ) ;
166- const k = Math . floor ( z + s ) ;
198+ const i = fastFloor ( x + s ) ;
199+ const j = fastFloor ( y + s ) ;
200+ const k = fastFloor ( z + s ) ;
167201 const t = ( i + j + k ) * G3 ;
168202 const X0 = i - t ; // Unskew the cell origin back to (x,y,z) space
169203 const Y0 = j - t ;
@@ -248,28 +282,28 @@ export function createNoise3D(random: RandomFn = Math.random): NoiseFunction3D {
248282 let t0 = 0.6 - x0 * x0 - y0 * y0 - z0 * z0 ;
249283 if ( t0 < 0 ) n0 = 0.0 ;
250284 else {
251- const gi0 = permMod12 [ ii + perm [ jj + perm [ kk ] ] ] * 3 ;
285+ const gi0 = ( perm [ ii + perm [ jj + perm [ kk ] ] ] % 12 ) * 3 ;
252286 t0 *= t0 ;
253287 n0 = t0 * t0 * ( grad3 [ gi0 ] * x0 + grad3 [ gi0 + 1 ] * y0 + grad3 [ gi0 + 2 ] * z0 ) ;
254288 }
255289 let t1 = 0.6 - x1 * x1 - y1 * y1 - z1 * z1 ;
256290 if ( t1 < 0 ) n1 = 0.0 ;
257291 else {
258- const gi1 = permMod12 [ ii + i1 + perm [ jj + j1 + perm [ kk + k1 ] ] ] * 3 ;
292+ const gi1 = ( perm [ ii + i1 + perm [ jj + j1 + perm [ kk + k1 ] ] ] % 12 ) * 3 ;
259293 t1 *= t1 ;
260294 n1 = t1 * t1 * ( grad3 [ gi1 ] * x1 + grad3 [ gi1 + 1 ] * y1 + grad3 [ gi1 + 2 ] * z1 ) ;
261295 }
262296 let t2 = 0.6 - x2 * x2 - y2 * y2 - z2 * z2 ;
263297 if ( t2 < 0 ) n2 = 0.0 ;
264298 else {
265- const gi2 = permMod12 [ ii + i2 + perm [ jj + j2 + perm [ kk + k2 ] ] ] * 3 ;
299+ const gi2 = ( perm [ ii + i2 + perm [ jj + j2 + perm [ kk + k2 ] ] ] % 12 ) * 3 ;
266300 t2 *= t2 ;
267301 n2 = t2 * t2 * ( grad3 [ gi2 ] * x2 + grad3 [ gi2 + 1 ] * y2 + grad3 [ gi2 + 2 ] * z2 ) ;
268302 }
269303 let t3 = 0.6 - x3 * x3 - y3 * y3 - z3 * z3 ;
270304 if ( t3 < 0 ) n3 = 0.0 ;
271305 else {
272- const gi3 = permMod12 [ ii + 1 + perm [ jj + 1 + perm [ kk + 1 ] ] ] * 3 ;
306+ const gi3 = ( perm [ ii + 1 + perm [ jj + 1 + perm [ kk + 1 ] ] ] % 12 ) * 3 ;
273307 t3 *= t3 ;
274308 n3 = t3 * t3 * ( grad3 [ gi3 ] * x3 + grad3 [ gi3 + 1 ] * y3 + grad3 [ gi3 + 2 ] * z3 ) ;
275309 }
@@ -300,10 +334,10 @@ export function createNoise4D(random: RandomFn = Math.random) {
300334 let n0 , n1 , n2 , n3 , n4 ; // Noise contributions from the five corners
301335 // Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in
302336 const s = ( x + y + z + w ) * F4 ; // Factor for 4D skewing
303- const i = Math . floor ( x + s ) ;
304- const j = Math . floor ( y + s ) ;
305- const k = Math . floor ( z + s ) ;
306- const l = Math . floor ( w + s ) ;
337+ const i = fastFloor ( x + s ) ;
338+ const j = fastFloor ( y + s ) ;
339+ const k = fastFloor ( z + s ) ;
340+ const l = fastFloor ( w + s ) ;
307341 const t = ( i + j + k + l ) * G4 ; // Factor for 4D unskewing
308342 const X0 = i - t ; // Unskew the cell origin back to (x,y,z,w) space
309343 const Y0 = j - t ;
0 commit comments