Skip to content
{{ message }}

Instantly share code, notes, and snippets.

# Flafla2/Perlin_Tiled.cs

Last active May 22, 2021
A slightly modified implementation of Ken Perlin's improved noise that allows for tiling the noise arbitrarily.
 public class Perlin { public int repeat; public Perlin(int repeat = -1) { this.repeat = repeat; } public double OctavePerlin(double x, double y, double z, int octaves, double persistence) { double total = 0; double frequency = 1; double amplitude = 1; double maxValue = 0; // Used for normalizing result to 0.0 - 1.0 for(int i=0;i 0) { // If we have any repeat on, change the coordinates to their "local" repetitions x = x%repeat; y = y%repeat; z = z%repeat; } int xi = (int)x & 255; // Calculate the "unit cube" that the point asked will be located in int yi = (int)y & 255; // The left bound is ( |_x_|,|_y_|,|_z_| ) and the right bound is that int zi = (int)z & 255; // plus 1. Next we calculate the location (from 0.0 to 1.0) in that cube. double xf = x-(int)x; // We also fade the location to smooth the result. double yf = y-(int)y;i double zf = z-(int)z; double u = fade(xf); double v = fade(yf); double w = fade(zf); int 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)]; double 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 int inc(int num) { num++; if (repeat > 0) num %= repeat; return num; } public static double grad(int hash, double x, double y, double z) { int h = hash & 15; // Take the hashed value and take the first 4 bits of it (15 == 0b1111) double u = h < 8 /* 0b1000 */ ? x : y; // If the most significant bit (MSB) of the hash is 0 then set u = x. Otherwise y. double v; // 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 double fade(double t) { // 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 double lerp(double a, double b, double x) { return a + x * (b - a); } }

### eAi commented Apr 1, 2016

 Line 61 has a typo - the extra 'i' at the end.

### ghost commented May 1, 2017

 Good catch @eAi

### WouterVanmulken commented Oct 5, 2017

 I liked this a lot, so i made a js implementation of it, which can be found here .

### DerDu commented Dec 28, 2020 • edited

 PHP Version ``````repeat= \$repeat; for (\$x = 0; \$x < 512; \$x++) { \$this->p[\$x] = \$this->permutation[\$x % 256]; } } public function noise(float \$x, float \$y, float \$z, int \$octaves, float \$persistence): float { \$total = 0.0; \$frequency = 1.0; \$amplitude = 1.0; \$maxValue = 0.0; for (\$i = 0; \$i < \$octaves; \$i++) { \$total += \$this->perlin(\$x * \$frequency, \$y * \$frequency, \$z * \$frequency) * \$amplitude; \$maxValue += \$amplitude; \$amplitude *= \$persistence; \$frequency *= 2; } return \$total / \$maxValue; } private function perlin(float \$x, float \$y, float \$z): float { if (\$this->seed > 0) { \$x = \$x % \$this->repeat; \$y = \$y % \$this->repeat; \$z = \$z % \$this->repeat; } \$xi = (int)\$x & 255; \$yi = (int)\$y & 255; \$zi = (int)\$z & 255; \$xf = \$x - (int)\$x; \$yf = \$y - (int)\$y; \$zf = \$z - (int)\$z; \$u = \$this->fade(\$xf); \$v = \$this->fade(\$yf); \$w = \$this->fade(\$zf); \$aaa = \$this->p[\$this->p[\$this->p[\$xi] + \$yi] + \$zi]; \$aba = \$this->p[\$this->p[\$this->p[\$xi] + \$this->inc(\$yi)] + \$zi]; \$aab = \$this->p[\$this->p[\$this->p[\$xi] + \$yi] + \$this->inc(\$zi)]; \$abb = \$this->p[\$this->p[\$this->p[\$xi] + \$this->inc(\$yi)] + \$this->inc(\$zi)]; \$baa = \$this->p[\$this->p[\$this->p[\$this->inc(\$xi)] + \$yi] + \$zi]; \$bba = \$this->p[\$this->p[\$this->p[\$this->inc(\$xi)] + \$this->inc(\$yi)] + \$zi]; \$bab = \$this->p[\$this->p[\$this->p[\$this->inc(\$xi)] + \$yi] + \$this->inc(\$zi)]; \$bbb = \$this->p[\$this->p[\$this->p[\$this->inc(\$xi)] + \$this->inc(\$yi)] + \$this->inc(\$zi)]; \$x1 = \$this->lerp(\$this->grad(\$aaa, \$xf, \$yf, \$zf), \$this->grad(\$baa, \$xf - 1, \$yf, \$zf), \$u); \$x2 = \$this->lerp(\$this->grad(\$aba, \$xf, \$yf - 1, \$zf), \$this->grad(\$bba, \$xf - 1, \$yf - 1, \$zf), \$u); \$y1 = \$this->lerp(\$x1, \$x2, \$v); \$x1 = \$this->lerp(\$this->grad(\$aab, \$xf, \$yf, \$zf - 1), \$this->grad(\$bab, \$xf - 1, \$yf, \$zf - 1), \$u); \$x2 = \$this->lerp(\$this->grad(\$abb, \$xf, \$yf - 1, \$zf - 1), \$this->grad(\$bbb, \$xf - 1, \$yf - 1, \$zf - 1), \$u); \$y2 = \$this->lerp(\$x1, \$x2, \$v); return (\$this->lerp(\$y1, \$y2, \$w) + 1) / 2; } private function fade(float \$t): float { return \$t * \$t * \$t * (\$t * (\$t * 6 - 15) + 10);// 6t^5 - 15t^4 + 10t^3 } private function inc(int \$num): int { \$num++; if (\$this->repeat > 0) { \$num %= \$this->repeat; } return \$num; } private function lerp(float \$a, float \$b, float \$x): float { return \$a + \$x * (\$b - \$a); } private function grad(int \$hash, float \$x, float \$y, float \$z): float { \$h = \$hash & 15; \$u = (\$h < 8 ? \$x : \$y); if (\$h < 4) { \$v = \$y; } elseif (\$h == 12 || \$h == 14) { \$v = \$x; } else { \$v = \$z; } return ((\$h & 1) == 0 ? \$u : -\$u) + ((\$h & 2) == 0 ? \$v : -\$v); } } ``````
to join this conversation on GitHub. Already have an account? Sign in to comment