Last active
March 5, 2018 03:31
-
-
Save kirbysayshi/915d4671aa7467ec96a24fedcb531eaf to your computer and use it in GitHub Desktop.
Code adapted and cleaned up from the C# implementation here http://flafla2.github.io/2014/08/09/perlinnoise.html. Specific changes: conversion to JS, removal of classes and stateful classes.
This file contains 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
// Hash lookup table as defined by Ken Perlin. This is a randomly | |
// arranged array of all numbers from 0-255 inclusive. | |
const permutation = [ 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 | |
]; | |
const pp = []; | |
for (let i = 0; i < 512; i++) { | |
pp[i] = permutation[i % 256]; | |
} | |
// Source: http://riven8192.blogspot.com/2010/08/calculate-perlinnoise-twice-as-fast.html | |
function grad(hash, x, y, z) { | |
switch(hash & 0xF) { | |
case 0x0: return x + y; | |
case 0x1: return -x + y; | |
case 0x2: return x - y; | |
case 0x3: return -x - y; | |
case 0x4: return x + z; | |
case 0x5: return -x + z; | |
case 0x6: return x - z; | |
case 0x7: return -x - z; | |
case 0x8: return y + z; | |
case 0x9: return -y + z; | |
case 0xA: return y - z; | |
case 0xB: return -y - z; | |
case 0xC: return y + x; | |
case 0xD: return -y + z; | |
case 0xE: return y - x; | |
case 0xF: return -y - z; | |
default: return 0; // never happens | |
} | |
} | |
// Fade function as defined by Ken Perlin. This eases coordinate values | |
// so that they will "ease" towards integral values. This ends up smoothing | |
// the final output. | |
function fade(t) { | |
// 6t^5 - 15t^4 + 10t^3 | |
return t * t * t * (t * (t * 6 - 15) + 10); | |
} | |
function inc(num, repeat) { | |
num++; | |
if (repeat > 0) num %= repeat; | |
return num; | |
} | |
function lerp(a, b, x) { | |
return a + x * (b - a); | |
} | |
// Make sure that x, y, z are within 0-1! Otherwise you will just see 0.5. | |
export function Perlin(x, y, z, repeat = 0) { | |
// If we have any repeat on, change the coordinates to their "local" repetitions | |
if (repeat > 0) { | |
x = x % repeat; | |
y = y % repeat; | |
z = z % repeat; | |
} | |
// Calculate the "unit cube" that the point asked will be located in | |
// The left bound is ( |_x_|,|_y_|,|_z_| ) and the right bound is that | |
// plus 1. Next we calculate the location (from 0.0 to 1.0) in that cube. | |
// We also fade the location to smooth the result. | |
const xi = Math.floor(x) & 255; | |
const yi = Math.floor(y) & 255; | |
const zi = Math.floor(z) & 255; | |
const xf = x - Math.floor(x); | |
const yf = y - Math.floor(y); | |
const zf = z - Math.floor(z); | |
const u = fade(xf); | |
const v = fade(yf); | |
const w = fade(zf); | |
const aaa = pp[pp[pp[xi] + yi] + zi]; | |
const aba = pp[pp[pp[xi] + inc(yi, repeat)] + zi]; | |
const aab = pp[pp[pp[xi] + yi] + inc(zi, repeat)]; | |
const abb = pp[pp[pp[xi] + inc(yi, repeat)] + inc(zi, repeat)]; | |
const baa = pp[pp[pp[inc(xi, repeat)] + yi] + zi]; | |
const bba = pp[pp[pp[inc(xi, repeat)] + inc(yi, repeat)] + zi]; | |
const bab = pp[pp[pp[inc(xi, repeat)] + yi] + inc(zi, repeat)]; | |
const bbb = pp[pp[pp[inc(xi, repeat)] + inc(yi, repeat)] + inc(zi, repeat)]; | |
// The gradient function calculates the dot product between a pseudorandom | |
// gradient vector and the vector from the input coordinate to the 8 | |
// surrounding points in its unit cube. | |
// This is all then lerped together as a sort of weighted average based on the faded (u,v,w) | |
// values we made earlier. | |
let x1, x2, y1, y2; | |
x1 = lerp(grad(aaa, xf, yf, zf), grad(baa, xf - 1, yf, zf), u); | |
x2 = lerp(grad(aba, xf, yf - 1, zf), grad(bba, xf - 1, yf - 1, zf), u); | |
y1 = lerp(x1, x2, v); | |
x1 = lerp(grad(aab, xf, yf, zf - 1), grad(bab, xf - 1, yf, zf - 1), u); | |
x2 = lerp(grad(abb, xf, yf - 1, zf - 1), grad(bbb, xf - 1, yf - 1, zf - 1), u); | |
y2 = lerp(x1, x2, v); | |
// For convenience we bound it to 0 - 1 (theoretical min/max before is -1 - 1) | |
return (lerp (y1, y2, w)+1)/2; | |
} | |
// Make sure that x, y, z are within 0-1! Otherwise you will just see 0.5. | |
export function OctavePerlin(x, y, z, octaves, persistence, repeat=0) { | |
let total = 0; | |
let frequency = 1; | |
let amplitude = 1; | |
// Used for normalizing result to 0.0 - 1.0 | |
let maxValue = 0; | |
for(let i = 0; i < octaves; i++) { | |
total += Perlin(x * frequency, y * frequency, z * frequency, repeat) * amplitude; | |
maxValue += amplitude; | |
amplitude *= persistence; | |
frequency *= 2; | |
} | |
return total/maxValue; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment