Skip to content

Instantly share code, notes, and snippets.

@anissen
Last active March 5, 2017 18:16
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save anissen/fae4fa40a41e08430ae2 to your computer and use it in GitHub Desktop.
Save anissen/fae4fa40a41e08430ae2 to your computer and use it in GitHub Desktop.
Perlin noise test
// Haxe implementation ported from https://gist.github.com/Flafla2/f0260a861be0ebdeef76
// Related article: http://flafla2.github.io/2014/08/09/perlinnoise.html
class Perlin {
public var repeat :Int;
public function new(repeat :Int = -1) {
this.repeat = repeat;
}
public function OctavePerlin(x :Float, y :Float, z :Float, octaves :Int, persistence :Float) {
var total :Float = 0;
var frequency :Float = 1;
var amplitude :Float = 1;
var maxValue :Float = 0; // Used for normalizing result to 0.0 - 1.0
for (i in 0 ... octaves) {
total += perlin(x * frequency, y * frequency, z * frequency) * amplitude;
maxValue += amplitude;
amplitude *= persistence;
frequency *= 2;
}
return total / maxValue;
}
static var permutation :Array<Int> = [ 151,160,137,91,90,15, // Hash lookup table as defined by Ken Perlin. This is a randomly
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, // arranged array of all numbers from 0-255 inclusive.
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
];
static var p :Array<Int>; // Doubled permutation to avoid overflow
static public function init() {
p = [ for (x in 0 ... 512) permutation[x % 256] ];
}
public function perlin(x :Float, y :Float, z :Float) :Float {
if(repeat > 0) { // If we have any repeat on, change the coordinates to their "local" repetitions
x = x % repeat;
y = y % repeat;
z = z % repeat;
}
var xi :Int = Math.floor(x) & 255; // Calculate the "unit cube" that the point asked will be located in
var yi :Int = Math.floor(y) & 255; // The left bound is ( |_x_|,|_y_|,|_z_| ) and the right bound is that
var zi :Int = Math.floor(z) & 255; // plus 1. Next we calculate the location (from 0.0 to 1.0) in that cube.
var xf :Float = x - Math.floor(x); // We also fade the location to smooth the result.
var yf :Float = y - Math.floor(y);
var zf :Float = z - Math.floor(z);
var u :Float = fade(xf);
var v :Float = fade(yf);
var w :Float = fade(zf);
var aaa, aba, aab, abb, baa, bba, bab, bbb;
aaa = p[p[p[ xi ]+ yi ]+ zi ];
aba = p[p[p[ xi ]+inc(yi)]+ zi ];
aab = p[p[p[ xi ]+ yi ]+inc(zi)];
abb = p[p[p[ xi ]+inc(yi)]+inc(zi)];
baa = p[p[p[inc(xi)]+ yi ]+ zi ];
bba = p[p[p[inc(xi)]+inc(yi)]+ zi ];
bab = p[p[p[inc(xi)]+ yi ]+inc(zi)];
bbb = p[p[p[inc(xi)]+inc(yi)]+inc(zi)];
var x1, x2, y1, y2;
x1 = lerp( grad (aaa, xf , yf , zf), // The gradient function calculates the dot product between a pseudorandom
grad (baa, xf-1, yf , zf), // gradient vector and the vector from the input coordinate to the 8
u); // surrounding points in its unit cube.
x2 = lerp( grad (aba, xf , yf-1, zf), // This is all then lerped together as a sort of weighted average based on the faded (u,v,w)
grad (bba, xf-1, yf-1, zf), // values we made earlier.
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);
return (lerp (y1, y2, w)+1)/2; // For convenience we bound it to 0 - 1 (theoretical min/max before is -1 - 1)
}
public function inc(num :Int) :Int {
num++;
if (repeat > 0) num %= repeat;
return num;
}
public static function grad(hash :Int, x :Float, y :Float, z :Float) :Float {
var h :Int = hash & 15; // Take the hashed value and take the first 4 bits of it (15 == 0b1111)
var u :Float = h < 8 /* 0b1000 */ ? x : y; // If the most significant bit (MSB) of the hash is 0 then set u = x. Otherwise y.
var v :Float; // In Ken Perlin's original implementation this was another conditional operator (?:). I
// expanded it for readability.
if(h < 4 /* 0b0100 */) // If the first and second significant bits are 0 set v = y
v = y;
else if(h == 12 /* 0b1100 */ || h == 14 /* 0b1110*/)// If the first and second significant bits are 1 set v = x
v = x;
else // If the first and second significant bits are not equal (0/1, 1/0) set v = z
v = z;
return ((h&1) == 0 ? u : -u)+((h&2) == 0 ? v : -v); // Use the last 2 bits to decide if u and v are positive or negative. Then return their addition.
}
public static function fade(t :Float) :Float {
// 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.
return t * t * t * (t * (t * 6 - 15) + 10); // 6t^5 - 15t^4 + 10t^3
}
public static function lerp(a :Float, b :Float, x :Float) :Float {
return a + x * (b - a);
}
}
class Test {
static function main() {
Perlin.init();
var perlin = new Perlin();
var document = js.Browser.document;
var canvas = document.createCanvasElement();
canvas.id = "CursorLayer";
canvas.width = 256;
canvas.height = 256;
canvas.style.border = "1px solid";
var body = document.getElementsByTagName("body")[0];
body.appendChild(canvas);
var context = canvas.getContext2d();
for (y in 0 ... 64) {
for (x in 0 ... 64) {
var c = Math.round(perlin.perlin(x / 8, y / 8, 0.1) * 255);
//trace('$x, $y: $c');
context.fillStyle = 'rgb($c, $c, $c)';
context.fillRect(x * 4, y * 4, 4, 4);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment