Created
April 9, 2018 06:43
-
-
Save stackdumper/5c8f652cf2fb2a6950176b571e45ccbc to your computer and use it in GitHub Desktop.
Noise.js for WebWorkers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* A speed-improved perlin and simplex noise algorithms for 2D. | |
* | |
* Based on example code by Stefan Gustavson ([email protected]). | |
* Optimisations by Peter Eastman ([email protected]). | |
* Better rank ordering method by Stefan Gustavson in 2012. | |
* Converted to Javascript by Joseph Gentle. | |
* | |
* Version 2012-03-09 | |
* | |
* This code was placed in the public domain by its original author, | |
* Stefan Gustavson. You may use it as you see fit, but | |
* attribution is appreciated. | |
* | |
*/ | |
// Passing in seed will seed this Noise instance | |
class Noise { | |
constructor(seed) { | |
class Grad { | |
constructor(x, y, z) { | |
this.x = x | |
this.y = y | |
this.z = z | |
} | |
dot2(x, y) { | |
return this.x * x + this.y * y | |
} | |
dot3(x, y, z) { | |
return this.x * x + this.y * y + this.z * z | |
} | |
} | |
this.grad3 = [ | |
new Grad(1, 1, 0), | |
new Grad(-1, 1, 0), | |
new Grad(1, -1, 0), | |
new Grad(-1, -1, 0), | |
new Grad(1, 0, 1), | |
new Grad(-1, 0, 1), | |
new Grad(1, 0, -1), | |
new Grad(-1, 0, -1), | |
new Grad(0, 1, 1), | |
new Grad(0, -1, 1), | |
new Grad(0, 1, -1), | |
new Grad(0, -1, -1), | |
] | |
this.p = [ | |
151, | |
160, | |
137, | |
91, | |
90, | |
15, | |
131, | |
13, | |
201, | |
95, | |
96, | |
53, | |
194, | |
233, | |
7, | |
225, | |
140, | |
36, | |
103, | |
30, | |
69, | |
142, | |
8, | |
99, | |
37, | |
240, | |
21, | |
10, | |
23, | |
190, | |
6, | |
148, | |
247, | |
120, | |
234, | |
75, | |
0, | |
26, | |
197, | |
62, | |
94, | |
252, | |
219, | |
203, | |
117, | |
35, | |
11, | |
32, | |
57, | |
177, | |
33, | |
88, | |
237, | |
149, | |
56, | |
87, | |
174, | |
20, | |
125, | |
136, | |
171, | |
168, | |
68, | |
175, | |
74, | |
165, | |
71, | |
134, | |
139, | |
48, | |
27, | |
166, | |
77, | |
146, | |
158, | |
231, | |
83, | |
111, | |
229, | |
122, | |
60, | |
211, | |
133, | |
230, | |
220, | |
105, | |
92, | |
41, | |
55, | |
46, | |
245, | |
40, | |
244, | |
102, | |
143, | |
54, | |
65, | |
25, | |
63, | |
161, | |
1, | |
216, | |
80, | |
73, | |
209, | |
76, | |
132, | |
187, | |
208, | |
89, | |
18, | |
169, | |
200, | |
196, | |
135, | |
130, | |
116, | |
188, | |
159, | |
86, | |
164, | |
100, | |
109, | |
198, | |
173, | |
186, | |
3, | |
64, | |
52, | |
217, | |
226, | |
250, | |
124, | |
123, | |
5, | |
202, | |
38, | |
147, | |
118, | |
126, | |
255, | |
82, | |
85, | |
212, | |
207, | |
206, | |
59, | |
227, | |
47, | |
16, | |
58, | |
17, | |
182, | |
189, | |
28, | |
42, | |
223, | |
183, | |
170, | |
213, | |
119, | |
248, | |
152, | |
2, | |
44, | |
154, | |
163, | |
70, | |
221, | |
153, | |
101, | |
155, | |
167, | |
43, | |
172, | |
9, | |
129, | |
22, | |
39, | |
253, | |
19, | |
98, | |
108, | |
110, | |
79, | |
113, | |
224, | |
232, | |
178, | |
185, | |
112, | |
104, | |
218, | |
246, | |
97, | |
228, | |
251, | |
34, | |
242, | |
193, | |
238, | |
210, | |
144, | |
12, | |
191, | |
179, | |
162, | |
241, | |
81, | |
51, | |
145, | |
235, | |
249, | |
14, | |
239, | |
107, | |
49, | |
192, | |
214, | |
31, | |
181, | |
199, | |
106, | |
157, | |
184, | |
84, | |
204, | |
176, | |
115, | |
121, | |
50, | |
45, | |
127, | |
4, | |
150, | |
254, | |
138, | |
236, | |
205, | |
93, | |
222, | |
114, | |
67, | |
29, | |
24, | |
72, | |
243, | |
141, | |
128, | |
195, | |
78, | |
66, | |
215, | |
61, | |
156, | |
180, | |
] | |
// To remove the need for index wrapping, double the permutation table length | |
this.perm = new Array(512) | |
this.gradP = new Array(512) | |
// Skewing and unskewing factors for 2, 3, and 4 dimensions | |
this.F2 = 0.5 * (Math.sqrt(3) - 1) | |
this.G2 = (3 - Math.sqrt(3)) / 6 | |
this.F3 = 1 / 3 | |
this.G3 = 1 / 6 | |
this.seed(seed || 0) | |
} | |
// This isn't a very good seeding function, but it works ok. It supports 2^16 | |
// different seed values. Write something better if you need more seeds. | |
seed(seed) { | |
if (seed > 0 && seed < 1) { | |
// Scale the seed out | |
seed *= 65536 | |
} | |
seed = Math.floor(seed) | |
if (seed < 256) { | |
seed |= seed << 8 | |
} | |
const p = this.p | |
for (let i = 0; i < 256; i++) { | |
let v | |
if (i & 1) { | |
v = p[i] ^ (seed & 255) | |
} | |
else { | |
v = p[i] ^ ((seed >> 8) & 255) | |
} | |
const perm = this.perm | |
const gradP = this.gradP | |
perm[i] = perm[i + 256] = v | |
gradP[i] = gradP[i + 256] = this.grad3[v % 12] | |
} | |
} | |
// 2D simplex noise | |
simplex2(xin, yin) { | |
let n0 // Noise contributions from the three corners | |
let n1 | |
let n2 | |
// Skew the input space to determine which simplex cell we're in | |
const s = (xin + yin) * this.F2 // Hairy factor for 2D | |
let i = Math.floor(xin + s) | |
let j = Math.floor(yin + s) | |
const t = (i + j) * this.G2 | |
const x0 = xin - i + t // The x,y distances from the cell origin, unskewed. | |
const y0 = yin - j + t | |
// For the 2D case, the simplex shape is an equilateral triangle. | |
// Determine which simplex we are in. | |
let i1 // Offsets for second (middle) corner of simplex in (i,j) coords | |
let j1 | |
if (x0 > y0) { | |
// lower triangle, XY order: (0,0)->(1,0)->(1,1) | |
i1 = 1 | |
j1 = 0 | |
} | |
else { | |
// upper triangle, YX order: (0,0)->(0,1)->(1,1) | |
i1 = 0 | |
j1 = 1 | |
} | |
// A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and | |
// a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where | |
// c = (3-sqrt(3))/6 | |
const x1 = x0 - i1 + this.G2 // Offsets for middle corner in (x,y) unskewed coords | |
const y1 = y0 - j1 + this.G2 | |
const x2 = x0 - 1 + 2 * this.G2 // Offsets for last corner in (x,y) unskewed coords | |
const y2 = y0 - 1 + 2 * this.G2 | |
// Work out the hashed gradient indices of the three simplex corners | |
i &= 255 | |
j &= 255 | |
const perm = this.perm | |
const gradP = this.gradP | |
const gi0 = gradP[i + perm[j]] | |
const gi1 = gradP[i + i1 + perm[j + j1]] | |
const gi2 = gradP[i + 1 + perm[j + 1]] | |
// Calculate the contribution from the three corners | |
let t0 = 0.5 - x0 * x0 - y0 * y0 | |
if (t0 < 0) { | |
n0 = 0 | |
} | |
else { | |
t0 *= t0 | |
n0 = t0 * t0 * gi0.dot2(x0, y0) // (x,y) of grad3 used for 2D gradient | |
} | |
let t1 = 0.5 - x1 * x1 - y1 * y1 | |
if (t1 < 0) { | |
n1 = 0 | |
} | |
else { | |
t1 *= t1 | |
n1 = t1 * t1 * gi1.dot2(x1, y1) | |
} | |
let t2 = 0.5 - x2 * x2 - y2 * y2 | |
if (t2 < 0) { | |
n2 = 0 | |
} | |
else { | |
t2 *= t2 | |
n2 = t2 * t2 * gi2.dot2(x2, y2) | |
} | |
// Add contributions from each corner to get the final noise value. | |
// The result is scaled to return values in the interval [-1,1]. | |
return 70 * (n0 + n1 + n2) | |
} | |
// 3D simplex noise | |
simplex3(xin, yin, zin) { | |
let n0 // Noise contributions from the four corners | |
let n1 | |
let n2 | |
let n3 | |
// Skew the input space to determine which simplex cell we're in | |
const s = (xin + yin + zin) * this.F3 // Hairy factor for 2D | |
let i = Math.floor(xin + s) | |
let j = Math.floor(yin + s) | |
let k = Math.floor(zin + s) | |
const t = (i + j + k) * this.G3 | |
const x0 = xin - i + t // The x,y distances from the cell origin, unskewed. | |
const y0 = yin - j + t | |
const z0 = zin - k + t | |
// For the 3D case, the simplex shape is a slightly irregular tetrahedron. | |
// Determine which simplex we are in. | |
let i1 // Offsets for second corner of simplex in (i,j,k) coords | |
let j1 | |
let k1 | |
let i2 // Offsets for third corner of simplex in (i,j,k) coords | |
let j2 | |
let k2 | |
if (x0 >= y0) { | |
if (y0 >= z0) { | |
i1 = 1 | |
j1 = 0 | |
k1 = 0 | |
i2 = 1 | |
j2 = 1 | |
k2 = 0 | |
} | |
else if (x0 >= z0) { | |
i1 = 1 | |
j1 = 0 | |
k1 = 0 | |
i2 = 1 | |
j2 = 0 | |
k2 = 1 | |
} | |
else { | |
i1 = 0 | |
j1 = 0 | |
k1 = 1 | |
i2 = 1 | |
j2 = 0 | |
k2 = 1 | |
} | |
} | |
else if (y0 < z0) { | |
i1 = 0 | |
j1 = 0 | |
k1 = 1 | |
i2 = 0 | |
j2 = 1 | |
k2 = 1 | |
} | |
else if (x0 < z0) { | |
i1 = 0 | |
j1 = 1 | |
k1 = 0 | |
i2 = 0 | |
j2 = 1 | |
k2 = 1 | |
} | |
else { | |
i1 = 0 | |
j1 = 1 | |
k1 = 0 | |
i2 = 1 | |
j2 = 1 | |
k2 = 0 | |
} | |
// A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z), | |
// a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and | |
// a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where | |
// c = 1/6. | |
const x1 = x0 - i1 + G3 // Offsets for second corner | |
const y1 = y0 - j1 + G3 | |
const z1 = z0 - k1 + G3 | |
const x2 = x0 - i2 + 2 * G3 // Offsets for third corner | |
const y2 = y0 - j2 + 2 * G3 | |
const z2 = z0 - k2 + 2 * G3 | |
const x3 = x0 - 1 + 3 * G3 // Offsets for fourth corner | |
const y3 = y0 - 1 + 3 * G3 | |
const z3 = z0 - 1 + 3 * G3 | |
// Work out the hashed gradient indices of the four simplex corners | |
i &= 255 | |
j &= 255 | |
k &= 255 | |
const perm = this.perm | |
const gradP = this.gradP | |
const gi0 = gradP[i + perm[j + perm[k]]] | |
const gi1 = gradP[i + i1 + perm[j + j1 + perm[k + k1]]] | |
const gi2 = gradP[i + i2 + perm[j + j2 + perm[k + k2]]] | |
const gi3 = gradP[i + 1 + perm[j + 1 + perm[k + 1]]] | |
// Calculate the contribution from the four corners | |
let t0 = 0.5 - x0 * x0 - y0 * y0 - z0 * z0 | |
if (t0 < 0) { | |
n0 = 0 | |
} | |
else { | |
t0 *= t0 | |
n0 = t0 * t0 * gi0.dot3(x0, y0, z0) // (x,y) of grad3 used for 2D gradient | |
} | |
let t1 = 0.5 - x1 * x1 - y1 * y1 - z1 * z1 | |
if (t1 < 0) { | |
n1 = 0 | |
} | |
else { | |
t1 *= t1 | |
n1 = t1 * t1 * gi1.dot3(x1, y1, z1) | |
} | |
let t2 = 0.5 - x2 * x2 - y2 * y2 - z2 * z2 | |
if (t2 < 0) { | |
n2 = 0 | |
} | |
else { | |
t2 *= t2 | |
n2 = t2 * t2 * gi2.dot3(x2, y2, z2) | |
} | |
let t3 = 0.5 - x3 * x3 - y3 * y3 - z3 * z3 | |
if (t3 < 0) { | |
n3 = 0 | |
} | |
else { | |
t3 *= t3 | |
n3 = t3 * t3 * gi3.dot3(x3, y3, z3) | |
} | |
// Add contributions from each corner to get the final noise value. | |
// The result is scaled to return values in the interval [-1,1]. | |
return 32 * (n0 + n1 + n2 + n3) | |
} | |
// 2D Perlin Noise | |
perlin2(x, y) { | |
// Find unit grid cell containing point | |
let X = Math.floor(x) | |
let Y = Math.floor(y) | |
// Get relative xy coordinates of point within that cell | |
x -= X | |
y -= Y | |
// Wrap the integer cells at 255 (smaller integer period can be introduced here) | |
X &= 255 | |
Y &= 255 | |
// Calculate noise contributions from each of the four corners | |
const perm = this.perm | |
const gradP = this.gradP | |
const n00 = gradP[X + perm[Y]].dot2(x, y) | |
const n01 = gradP[X + perm[Y + 1]].dot2(x, y - 1) | |
const n10 = gradP[X + 1 + perm[Y]].dot2(x - 1, y) | |
const n11 = gradP[X + 1 + perm[Y + 1]].dot2(x - 1, y - 1) | |
// Compute the fade curve value for x | |
const u = this.fade(x) | |
// Interpolate the four results | |
return this.lerp(this.lerp(n00, n10, u), this.lerp(n01, n11, u), this.fade(y)) | |
} | |
fade(t) { | |
return t * t * t * (t * (t * 6 - 15) + 10) | |
} | |
lerp(a, b, t) { | |
return (1 - t) * a + t * b | |
} | |
// 3D Perlin Noise | |
perlin3(x, y, z) { | |
// Find unit grid cell containing point | |
let X = Math.floor(x) | |
let Y = Math.floor(y) | |
let Z = Math.floor(z) | |
// Get relative xyz coordinates of point within that cell | |
x -= X | |
y -= Y | |
z -= Z | |
// Wrap the integer cells at 255 (smaller integer period can be introduced here) | |
X &= 255 | |
Y &= 255 | |
Z &= 255 | |
// Calculate noise contributions from each of the eight corners | |
const perm = this.perm | |
const gradP = this.gradP | |
const n000 = gradP[X + perm[Y + perm[Z]]].dot3(x, y, z) | |
const n001 = gradP[X + perm[Y + perm[Z + 1]]].dot3(x, y, z - 1) | |
const n010 = gradP[X + perm[Y + 1 + perm[Z]]].dot3(x, y - 1, z) | |
const n011 = gradP[X + perm[Y + 1 + perm[Z + 1]]].dot3(x, y - 1, z - 1) | |
const n100 = gradP[X + 1 + perm[Y + perm[Z]]].dot3(x - 1, y, z) | |
const n101 = gradP[X + 1 + perm[Y + perm[Z + 1]]].dot3(x - 1, y, z - 1) | |
const n110 = gradP[X + 1 + perm[Y + 1 + perm[Z]]].dot3(x - 1, y - 1, z) | |
const n111 = gradP[X + 1 + perm[Y + 1 + perm[Z + 1]]].dot3(x - 1, y - 1, z - 1) | |
// Compute the fade curve value for x, y, z | |
const u = this.fade(x) | |
const v = this.fade(y) | |
const w = this.fade(z) | |
// Interpolate | |
return this.lerp( | |
this.lerp(this.lerp(n000, n100, u), this.lerp(n001, n101, u), w), | |
this.lerp(this.lerp(n010, n110, u), this.lerp(n011, n111, u), w), | |
v | |
) | |
} | |
} | |
/* | |
for(var i=0; i<256; i++) { | |
perm[i] = perm[i + 256] = p[i]; | |
gradP[i] = gradP[i + 256] = grad3[perm[i] % 12]; | |
} */ | |
global.Noise = Noise |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment