sandbox/misc/noise/noise.cc

94 lines
1.8 KiB
C++
Raw Normal View History

2019-02-17 00:50:56 +00:00
#include <math.h>
#include <stdint.h>
#include "noise.h"
#include "util.h"
// C++ conversion of Ken Perlin's improved noise generator from
// https://mrl.nyu.edu/~perlin/noise/
static double
grad(int hash, double x, double y, double z)
{
int h = hash & 15;
double u = h < 8 ? x : y;
double v = h < 4 ? y : h == 12 || h == 14 ? x : z;
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
static double
lerp(double t, double a, double b)
{
return a + t * (b - a);
}
static double
fade(double t)
{
return t * t * t * (t * (t * 6 - 15) + 10);
}
NoiseGenerator::NoiseGenerator()
{
// Generate a random permutation of 256 values from 0 to 255
// inclusive. This is generated by setting each value in the
// array to its index value, then putting it through a
// Fisher-Yates shuffle.
for (int i = 0; i < 256; i++) {
perm[i] = i;
}
for (int i = 255; i > 0; i--) {
int j = random() % (i + 1);
swap_u8(perm[i], perm[j]);
}
for (int i = 0; i < 256; i++) {
p[i] = perm[i];
p[i+256] = perm[i];
}
}
double
NoiseGenerator::sample(double x, double y, double z)
{
uint16_t ux = (uint16_t)floor(x) & 255;
uint16_t uy = (uint16_t)floor(y) & 255;
uint16_t uz = (uint16_t)floor(z) & 255;
double u, v, w;
uint16_t a, aa, ab, b, ba, bb;
x -= floor(x);
u = fade(x);
y -= floor(y);
v = fade(y);
z -= floor(z);
w = fade(z);
a = p[ux] + uy;
aa = p[a] + uz;
ab = p[a + 1] + uz;
b = p[ux + 1] + uy;
ba = p[b] + uz;
bb = p[b + 1] + uz;
return lerp(w, lerp(v, lerp(u, grad(p[aa], x, y, z),
grad(p[ba], x-1, y, z)),
lerp(u, grad(p[ab], x, y-1, z),
grad(p[bb], x-1, y-1, z))),
lerp(v, lerp(u, grad(p[aa+1], x, y, z-1),
grad(p[ba+1], x-1, y, z-1)),
lerp(u, grad(p[ab+1], x, y-1, z-1),
grad(p[bb+1], x-1, y-1, z-1))));
}