// V.1.0 // Noise / Simplex2 export class Grad { public x: number public y: number public z: number constructor(x: number, y: number, z: number) { this.x = x this.y = y this.z = z return this } public dot2(x: number, y: number): number { return this.x * x + this.y * y } public dot3(x: number, y: number, z: number): number { return this.x * x + this.y * y + this.z + z } } // Main export class Noise { constructor(seed: number) { this.seed(seed) return this } public fade(t: number): number { return t * t * t * (t * (t * 6 - 15) + 10) } // Linear interpolation. public lerp(a: number, b: number, t: number): number { return (1 - t) * a + t * b } // 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. public seed(seed: number): number { let i: number, l: number, results, v: number if (seed > 0 && seed < 1) { // Scale the seed out seed *= 65536 } seed = Math.floor(seed) if (seed < 256) { seed |= seed << 8 } results = [] for (i = l = 0; l <= 255; i = ++l) { v = void 0 if (i & 1) { v = Noise.p[i] ^ (seed & 255) } else { v = Noise.p[i] ^ ((seed >> 8) & 255) } Noise.perm[i] = Noise.perm[i + 256] = v results.push(Noise.gradP[i] = Noise.gradP[i + 256] = Noise.grad3[v % 12]) } return results } // 2D simplex noise simplex2(xin: number | undefined, yin: number | undefined): number { var gi0, gi1, gi2, i, i1, j, j1, n0, n1, n2, s, t, t0, t1, t2, x0, x1, x2, y0, y1, y2 xin = typeof xin === "undefined" ? 0 : xin yin = typeof yin === "undefined" ? 0 : yin n0 = void 0 n1 = void 0 n2 = void 0 // Noise contributions from the three corners // Skew the input space to determine which simplex cell we're in s = (xin + yin) * Noise.F2 // Hairy factor for 2D i = Math.floor(xin + s) j = Math.floor(yin + s) t = (i + j) * Noise.G2 x0 = xin - i + t // The x,y distances from the cell origin, unskewed. y0 = yin - j + t // For the 2D case, the simplex shape is an equilateral triangle. // Determine which simplex we are in. i1 = void 0 j1 = void 0 // Offsets for second (middle) corner of simplex in (i,j) coords if (x0 > y0) { // lower triangle, XY order: (0,0)->(1,0)->(1,1) i1 = 1 j1 = 0 // upper triangle, YX order: (0,0)->(0,1)->(1,1) } else { 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 x1 = x0 - i1 + Noise.G2 // Offsets for middle corner in (x,y) unskewed coords y1 = y0 - j1 + Noise.G2 x2 = x0 - 1 + 2 * Noise.G2 // Offsets for last corner in (x,y) unskewed coords y2 = y0 - 1 + 2 * Noise.G2 // Work out the hashed gradient indices of the three simplex corners i &= 255 j &= 255 gi0 = Noise.gradP[i + Noise.perm[j]] gi1 = Noise.gradP[i + i1 + Noise.perm[j + j1]] gi2 = Noise.gradP[i + 1 + Noise.perm[j + 1]] // Calculate the contribution from the three corners 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 } t1 = 0.5 - x1 * x1 - y1 * y1 if (t1 < 0) { n1 = 0 } else { t1 *= t1 n1 = t1 * t1 * gi1.dot2(x1, y1) } 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 simplex3(xin, yin, zin) { var gi0, gi1, gi2, gi3, i, i1, i2, j, j1, j2, k, k1, k2, n0, n1, n2, n3, s, t, t0, t1, t2, t3, x0, x1, x2, x3, y0, y1, y2, y3, z0, z1, z2, z3 // Noise contributions from the four corners n0 = void 0 n1 = void 0 n2 = void 0 n3 = void 0 // Skew the input space to determine which simplex cell we're in s = (xin + yin + zin) * Noise.F3 // Hairy factor for 2D i = Math.floor(xin + s) j = Math.floor(yin + s) k = Math.floor(zin + s) t = (i + j + k) * Noise.G3 x0 = xin - i + t // The x, y distances from the cell origin, unskewed. y0 = yin - j + t z0 = zin - k + t // For the 3D case, the simplex shape is a slightly irregular tetrahedron. // Determine which simplex we are in. i1 = void 0 j1 = void 0 k1 = void 0 // Offsets for second corner of simplex in (i,j,k) coords i2 = void 0 j2 = void 0 k2 = void 0 // Offsets for third corner of simplex in (i,j,k) coords 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. x1 = x0 - i1 + Noise.G3 // Offsets for second corner y1 = y0 - j1 + Noise.G3 z1 = z0 - k1 + Noise.G3 x2 = x0 - i2 + 2 * Noise.G3 // Offsets for third corner y2 = y0 - j2 + 2 * Noise.G3 z2 = z0 - k2 + 2 * Noise.G3 x3 = x0 - 1 + 3 * Noise.G3 // Offsets for fourth corner y3 = y0 - 1 + 3 * Noise.G3 z3 = z0 - 1 + 3 * Noise.G3 // Work out the hashed gradient indices of the four simplex corners i &= 255 j &= 255 k &= 255 gi0 = Noise.gradP[i + Noise.perm[j + Noise.perm[k]]] gi1 = Noise.gradP[i + i1 + Noise.perm[j + j1 + Noise.perm[k + k1]]] gi2 = Noise.gradP[i + i2 + Noise.perm[j + j2 + Noise.perm[k + k2]]] gi3 = Noise.gradP[i + 1 + Noise.perm[j + 1 + Noise.perm[k + 1]]] // Calculate the contribution from the four corners t0 = 0.6 - 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 } t1 = 0.6 - x1 * x1 - y1 * y1 - z1 * z1 if (t1 < 0) { n1 = 0 } else { t1 *= t1 n1 = t1 * t1 * gi1.dot3(x1, y1, z1) } t2 = 0.6 - x2 * x2 - y2 * y2 - z2 * z2 if (t2 < 0) { n2 = 0 } else { t2 *= t2 n2 = t2 * t2 * gi2.dot3(x2, y2, z2) } t3 = 0.6 - 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) } perlin2(x, y) { var X, Y, n00, n01, n10, n11, u // Find unit grid cell containing point X = Math.floor(x) Y = Math.floor(y) // Get relative xy coordinates of point within that cell x = x - X y = y - Y // Wrap the integer cells at 255 (smaller integer period can be introduced here) X = X & 255 Y = Y & 255 // Calculate noise contributions from each of the four corners n00 = Noise.gradP[X + Noise.perm[Y]].dot2(x, y) n01 = Noise.gradP[X + Noise.perm[Y + 1]].dot2(x, y - 1) n10 = Noise.gradP[X + 1 + Noise.perm[Y]].dot2(x - 1, y) n11 = Noise.gradP[X + 1 + Noise.perm[Y + 1]].dot2(x - 1, y - 1) // Compute the fade curve value for x u = this.fade(x) // Interpolate the four results return this.lerp(this.lerp(n00, n10, u), this.lerp(n01, n11, u), this.fade(y)) } // 3D Perlin Noise perlin3(x, y, z) { var X, Y, Z, n000, n001, n010, n011, n100, n101, n110, n111, u, v, w // Find unit grid cell containing point X = Math.floor(x) Y = Math.floor(y) Z = Math.floor(z) // Get relative xyz coordinates of point within that cell x = x - X y = y - Y z = z - Z // Wrap the integer cells at 255 (smaller integer period can be introduced here) X = X & 255 Y = Y & 255 Z = Z & 255 // Calculate noise contributions from each of the eight corners n000 = Noise.gradP[X + Noise.perm[Y + Noise.perm[Z]]].dot3(x, y, z) n001 = Noise.gradP[X + Noise.perm[Y + Noise.perm[Z + 1]]].dot3(x, y, z - 1) n010 = Noise.gradP[X + Noise.perm[Y + 1 + Noise.perm[Z]]].dot3(x, y - 1, z) n011 = Noise.gradP[X + Noise.perm[Y + 1 + Noise.perm[Z + 1]]].dot3(x, y - 1, z - 1) n100 = Noise.gradP[X + 1 + Noise.perm[Y + Noise.perm[Z]]].dot3(x - 1, y, z) n101 = Noise.gradP[X + 1 + Noise.perm[Y + Noise.perm[Z + 1]]].dot3(x - 1, y, z - 1) n110 = Noise.gradP[X + 1 + Noise.perm[Y + 1 + Noise.perm[Z]]].dot3(x - 1, y - 1, z) n111 = Noise.gradP[X + 1 + Noise.perm[Y + 1 + Noise.perm[Z + 1]]].dot3(x - 1, y - 1, z - 1) // Compute the fade curve value for x, y, z u = this.fade(x) v = this.fade(y) 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) } public static 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)] // Init. public static 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. public static perm = new Array(512) public static gradP = new Array(512) // Skewing and unskewing factors for 2, 3, and 4 dimensions public static F2 = 0.5 * (Math.sqrt(3) - 1) public static G2 = (3 - Math.sqrt(3)) / 6 public static F3 = 1 / 3 public static G3 = 1 / 6 } // Ported from: https://github.com/josephg/noisejs/blob/master/perlin.js