Skip to content

Commit 7bd1fc1

Browse files
committed
Applied optimizations from the 2d to the 3d and 4d
1 parent 5e4db82 commit 7bd1fc1

File tree

2 files changed

+34
-34
lines changed

2 files changed

+34
-34
lines changed

README.md

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -85,23 +85,13 @@ The ALEA PRNG used in the example above can be found in the [alea](https://npmjs
8585
## Benchmarks
8686

8787
simplex-noise.js is reasonably quick.
88-
According to `perf/benchmark.js` I can perform about 50 million `noise2D()` calls/second on a single thread on my desktop (Ryzen 5950X).
89-
So ~20 nanoseconds per call.
88+
According to `perf/index.js` I can perform about 70 million `noise2D()` calls/second on a single thread on my desktop (Ryzen 5950X).
9089

9190
```
9291
$ node perf/index.js
93-
noise2D: 66,608,762 ops/sec ±0%
94-
noise3D: 41,059,121 ops/sec ±0%
95-
noise4D: 33,406,638 ops/sec ±0%
96-
```
97-
98-
At least at a glance it also seems to be faster than 'fast-simplex-noise':
99-
```
100-
simplex-noise noise2D: 53,429,815 ops/sec ±0%
101-
fast-simplex-noise noise2D: 6,239,845 ops/sec ±0%
102-
103-
simplex-noise noise4D: 22,578,593 ops/sec ±0%
104-
fast-simplex-noise noise4D: 5,292,975 ops/sec ±0%
92+
noise2D: 72,916,215 ops/sec ±1%
93+
noise3D: 47,855,199 ops/sec ±0%
94+
noise4D: 35,564,111 ops/sec ±0%
10595
```
10696

10797
## Migrating from 3.x to 4.x
@@ -157,10 +147,11 @@ const simplex = {
157147
When combined with tree-shaking this helps with build sizes.
158148
- Removed the built in version of the alea PRNG to focus the library to do only one thing.
159149
If you want to continue to use it you'll have to install and import it separately.
160-
- Noise functions are a bit faster (~ 10-20%) due to using integers in some places
150+
- Noise functions are a bit faster (~ 20 - 30%).
161151
- Noise values can be different from previous versions
162152
- Inputs coordinates bigger than 2^31 may not result in a noisy output anymore.
163-
- Test coverage is now at 100%
153+
If you have a usecase that is affected this please file an issue.
154+
- Test coverage is now at 100%.
164155

165156
### 3.0.1
166157
- Include simplex-noise.ts as source file, fixes sourcemap warnings.

simplex-noise.ts

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ export type NoiseFunction3D = (x: number, y: number, z: number) => number;
195195
*/
196196
export function createNoise3D(random: RandomFn = Math.random): NoiseFunction3D {
197197
const perm = buildPermutationTable(random);
198+
// precalculating these seems to yield a speedup of over 15%
199+
const permGrad3x = new Float64Array(perm).map(v => grad3[(v % 12) * 3]);
200+
const permGrad3y = new Float64Array(perm).map(v => grad3[(v % 12) * 3 + 1]);
201+
const permGrad3z = new Float64Array(perm).map(v => grad3[(v % 12) * 3 + 2]);
198202
return function noise3D(x: number, y: number, z: number): number {
199203
let n0, n1, n2, n3; // Noise contributions from the four corners
200204
// Skew the input space to determine which simplex cell we're in
@@ -286,30 +290,30 @@ export function createNoise3D(random: RandomFn = Math.random): NoiseFunction3D {
286290
let t0 = 0.6 - x0 * x0 - y0 * y0 - z0 * z0;
287291
if (t0 < 0) n0 = 0.0;
288292
else {
289-
const gi0 = (perm[ii + perm[jj + perm[kk]]] % 12) * 3;
293+
const gi0 = ii + perm[jj + perm[kk]];
290294
t0 *= t0;
291-
n0 = t0 * t0 * (grad3[gi0] * x0 + grad3[gi0 + 1] * y0 + grad3[gi0 + 2] * z0);
295+
n0 = t0 * t0 * (permGrad3x[gi0] * x0 + permGrad3y[gi0] * y0 + permGrad3z[gi0] * z0);
292296
}
293297
let t1 = 0.6 - x1 * x1 - y1 * y1 - z1 * z1;
294298
if (t1 < 0) n1 = 0.0;
295299
else {
296-
const gi1 = (perm[ii + i1 + perm[jj + j1 + perm[kk + k1]]] % 12) * 3;
300+
const gi1 = ii + i1 + perm[jj + j1 + perm[kk + k1]];
297301
t1 *= t1;
298-
n1 = t1 * t1 * (grad3[gi1] * x1 + grad3[gi1 + 1] * y1 + grad3[gi1 + 2] * z1);
302+
n1 = t1 * t1 * (permGrad3x[gi1] * x1 + permGrad3y[gi1] * y1 + permGrad3z[gi1] * z1);
299303
}
300304
let t2 = 0.6 - x2 * x2 - y2 * y2 - z2 * z2;
301305
if (t2 < 0) n2 = 0.0;
302306
else {
303-
const gi2 = (perm[ii + i2 + perm[jj + j2 + perm[kk + k2]]] % 12) * 3;
307+
const gi2 = ii + i2 + perm[jj + j2 + perm[kk + k2]];
304308
t2 *= t2;
305-
n2 = t2 * t2 * (grad3[gi2] * x2 + grad3[gi2 + 1] * y2 + grad3[gi2 + 2] * z2);
309+
n2 = t2 * t2 * (permGrad3x[gi2] * x2 + permGrad3y[gi2] * y2 + permGrad3z[gi2] * z2);
306310
}
307311
let t3 = 0.6 - x3 * x3 - y3 * y3 - z3 * z3;
308312
if (t3 < 0) n3 = 0.0;
309313
else {
310-
const gi3 = (perm[ii + 1 + perm[jj + 1 + perm[kk + 1]]] % 12) * 3;
314+
const gi3 = ii + 1 + perm[jj + 1 + perm[kk + 1]];
311315
t3 *= t3;
312-
n3 = t3 * t3 * (grad3[gi3] * x3 + grad3[gi3 + 1] * y3 + grad3[gi3 + 2] * z3);
316+
n3 = t3 * t3 * (permGrad3x[gi3] * x3 + permGrad3y[gi3] * y3 + permGrad3z[gi3] * z3);
313317
}
314318
// Add contributions from each corner to get the final noise value.
315319
// The result is scaled to stay just inside [-1,1]
@@ -336,6 +340,11 @@ export type NoiseFunction4D = (x: number, y: number, z: number, w: number) => nu
336340
*/
337341
export function createNoise4D(random: RandomFn = Math.random) {
338342
const perm = buildPermutationTable(random);
343+
// precalculating these leads to a ~10% speedup
344+
const permGrad4x = new Float64Array(perm).map(v => grad4[(v % 32) * 4]);
345+
const permGrad4y = new Float64Array(perm).map(v => grad4[(v % 32) * 4 + 1]);
346+
const permGrad4z = new Float64Array(perm).map(v => grad4[(v % 32) * 4 + 2]);
347+
const permGrad4w = new Float64Array(perm).map(v => grad4[(v % 32) * 4 + 3]);
339348
return function noise4D(x: number, y: number, z: number, w: number): number {
340349
let n0, n1, n2, n3, n4; // Noise contributions from the five corners
341350
// Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in
@@ -424,37 +433,37 @@ export function createNoise4D(random: RandomFn = Math.random) {
424433
let t0 = 0.6 - x0 * x0 - y0 * y0 - z0 * z0 - w0 * w0;
425434
if (t0 < 0) n0 = 0.0;
426435
else {
427-
const gi0 = (perm[ii + perm[jj + perm[kk + perm[ll]]]] % 32) * 4;
436+
const gi0 = ii + perm[jj + perm[kk + perm[ll]]];
428437
t0 *= t0;
429-
n0 = t0 * t0 * (grad4[gi0] * x0 + grad4[gi0 + 1] * y0 + grad4[gi0 + 2] * z0 + grad4[gi0 + 3] * w0);
438+
n0 = t0 * t0 * (permGrad4x[gi0] * x0 + permGrad4y[gi0] * y0 + permGrad4z[gi0] * z0 + permGrad4w[gi0] * w0);
430439
}
431440
let t1 = 0.6 - x1 * x1 - y1 * y1 - z1 * z1 - w1 * w1;
432441
if (t1 < 0) n1 = 0.0;
433442
else {
434-
const gi1 = (perm[ii + i1 + perm[jj + j1 + perm[kk + k1 + perm[ll + l1]]]] % 32) * 4;
443+
const gi1 = ii + i1 + perm[jj + j1 + perm[kk + k1 + perm[ll + l1]]];
435444
t1 *= t1;
436-
n1 = t1 * t1 * (grad4[gi1] * x1 + grad4[gi1 + 1] * y1 + grad4[gi1 + 2] * z1 + grad4[gi1 + 3] * w1);
445+
n1 = t1 * t1 * (permGrad4x[gi1] * x1 + permGrad4y[gi1] * y1 + permGrad4z[gi1] * z1 + permGrad4w[gi1] * w1);
437446
}
438447
let t2 = 0.6 - x2 * x2 - y2 * y2 - z2 * z2 - w2 * w2;
439448
if (t2 < 0) n2 = 0.0;
440449
else {
441-
const gi2 = (perm[ii + i2 + perm[jj + j2 + perm[kk + k2 + perm[ll + l2]]]] % 32) * 4;
450+
const gi2 = ii + i2 + perm[jj + j2 + perm[kk + k2 + perm[ll + l2]]];
442451
t2 *= t2;
443-
n2 = t2 * t2 * (grad4[gi2] * x2 + grad4[gi2 + 1] * y2 + grad4[gi2 + 2] * z2 + grad4[gi2 + 3] * w2);
452+
n2 = t2 * t2 * (permGrad4x[gi2] * x2 + permGrad4y[gi2] * y2 + permGrad4z[gi2] * z2 + permGrad4w[gi2] * w2);
444453
}
445454
let t3 = 0.6 - x3 * x3 - y3 * y3 - z3 * z3 - w3 * w3;
446455
if (t3 < 0) n3 = 0.0;
447456
else {
448-
const gi3 = (perm[ii + i3 + perm[jj + j3 + perm[kk + k3 + perm[ll + l3]]]] % 32) * 4;
457+
const gi3 = ii + i3 + perm[jj + j3 + perm[kk + k3 + perm[ll + l3]]];
449458
t3 *= t3;
450-
n3 = t3 * t3 * (grad4[gi3] * x3 + grad4[gi3 + 1] * y3 + grad4[gi3 + 2] * z3 + grad4[gi3 + 3] * w3);
459+
n3 = t3 * t3 * (permGrad4x[gi3] * x3 + permGrad4y[gi3] * y3 + permGrad4z[gi3] * z3 + permGrad4w[gi3] * w3);
451460
}
452461
let t4 = 0.6 - x4 * x4 - y4 * y4 - z4 * z4 - w4 * w4;
453462
if (t4 < 0) n4 = 0.0;
454463
else {
455-
const gi4 = (perm[ii + 1 + perm[jj + 1 + perm[kk + 1 + perm[ll + 1]]]] % 32) * 4;
464+
const gi4 = ii + 1 + perm[jj + 1 + perm[kk + 1 + perm[ll + 1]]];
456465
t4 *= t4;
457-
n4 = t4 * t4 * (grad4[gi4] * x4 + grad4[gi4 + 1] * y4 + grad4[gi4 + 2] * z4 + grad4[gi4 + 3] * w4);
466+
n4 = t4 * t4 * (permGrad4x[gi4] * x4 + permGrad4y[gi4] * y4 + permGrad4z[gi4] * z4 + permGrad4w[gi4] * w4);
458467
}
459468
// Sum up and scale the result to cover the range [-1,1]
460469
return 27.0 * (n0 + n1 + n2 + n3 + n4);

0 commit comments

Comments
 (0)