Skip to content

Instantly share code, notes, and snippets.

@Kakusakov
Forked from Flafla2/Perlin.cs
Last active October 15, 2023 07:52
Show Gist options
  • Save Kakusakov/c2706dc3ab3c11427606159ef6dd724b to your computer and use it in GitHub Desktop.
Save Kakusakov/c2706dc3ab3c11427606159ef6dd724b to your computer and use it in GitHub Desktop.
Improved Perlin Noise Implementation in C#
// Clone of https://gist.github.com/Flafla2/1a0b9ebef678bbce3215 with more dimensions and seed generation.
public class PerlinGen
{
private readonly int[] p; // Randomly shuffled array of values from 0 to 255.
// Values are repeated twice to get performance boost
// from avoiding the use of modulo operator.
public PerlinGen(int seed)
{
// Generate p.
p = new int[512];
System.Random rng = new(seed);
for (int i = 0; i < 256; ++i) p[i] = i;
int n = 256;
while (n > 1)
{
int k = rng.Next(n--);
(p[k], p[n]) = (p[n], p[k]);
}
for (int i = 0; i < 256; ++i) p[i + 256] = p[i];
}
public PerlinGen(PerlinGen copy)
{
p = copy.p;
}
public float Perlin3(float x, float y, float z)
{
int xi = (int)x & 255;
int yi = (int)y & 255;
int zi = (int)z & 255;
x -= (int)x;
y -= (int)y;
z -= (int)z;
float u = Fade(x);
float v = Fade(y);
float w = Fade(z);
int A = p[xi] + yi;
int AA = p[A] + zi;
int AB = p[A + 1] + zi;
int B = p[xi + 1] + yi;
int BA = p[B] + zi;
int BB = p[B + 1] + zi;
return Lerp(w,
Lerp(v,
Lerp(u, Grad3(p[AA], x, y, z), Grad3(p[BA], x - 1, y, z)),
Lerp(u, Grad3(p[AB], x, y - 1, z), Grad3(p[BB], x - 1, y - 1, z))
),
Lerp(v,
Lerp(u, Grad3(p[AA + 1], x, y, z - 1), Grad3(p[BA + 1], x - 1, y, z - 1)),
Lerp(u, Grad3(p[AB + 1], x, y - 1, z - 1), Grad3(p[BB + 1], x - 1, y - 1, z - 1))
)
);
}
public float Perlin2(float x, float y)
{
int xi = (int)x & 255;
int yi = (int)y & 255;
x -= (int)x;
y -= (int)y;
float u = Fade(x);
float v = Fade(y);
int A = p[xi] + yi;
int B = p[xi + 1] + yi;
return Lerp(v,
Lerp(u, Grad2(p[A], x, y), Grad2(p[B], x - 1, y)),
Lerp(u, Grad2(p[A + 1], x, y - 1), Grad2(p[B + 1], x - 1, y - 1))
);
}
public float Perlin1(float x)
{
int xi = (int)x & 255;
x -= (int)x;
float u = Fade(x);
return Lerp(u, Grad1(p[xi], x), Grad1(p[xi + 1], x - 1));
}
public static float Fade(float t) => t * t * t * (t * (t * 6 - 15) + 10);
public static float Grad3(int hash, float x, float y, float z)
{
int h = hash & 15;
float u = h < 8 ? x : y;
float v = h < 4 ? y : h == 12 || h == 14 ? x : z;
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
public static float Grad2(int hash, float x, float y)
{
return ((hash & 1) == 0 ? x : -x) + ((hash & 2) == 0 ? y : -y);
}
public static float Grad1(int hash, float x)
{
return (hash & 1) == 0 ? x : -x;
}
public static float Lerp(float t, float a, float b) => a + t * (b - a);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment