Add perlin noise implementation.

This commit is contained in:
Kyle Isom 2019-02-16 16:50:56 -08:00
parent 0f5a237b10
commit bb0620f3aa
6 changed files with 164 additions and 0 deletions

8
misc/noise/Makefile Normal file
View File

@ -0,0 +1,8 @@
SOURCES := noise.cc test.cc util.cc
noise: $(SOURCES)
g++ -o $@ $(SOURCES)
.PHONY: clean
clean:
rm -f noise

93
misc/noise/noise.cc Normal file
View File

@ -0,0 +1,93 @@
#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))));
}

16
misc/noise/noise.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef __NOISE_H
#define __NOISE_H
class NoiseGenerator {
public:
NoiseGenerator();
double sample(double x, double y, double z);
void randomise();
private:
uint8_t p[512];
uint8_t perm[256];
};
#endif // __NOISE_H

15
misc/noise/test.cc Normal file
View File

@ -0,0 +1,15 @@
#include <iostream>
#include "noise.h"
using namespace std;
int
main(void)
{
NoiseGenerator noise;
for (double t = 0; t < 5; t += 0.01) {
cout << t << "\t" << noise.sample(t, t, t) << endl;
}
}

20
misc/noise/util.cc Normal file
View File

@ -0,0 +1,20 @@
#include "util.h"
#include <stdint.h>
void
swap_u8(uint8_t &a, uint8_t &b)
{
a ^= b;
b ^= a;
a ^= b;
}
void
swap_ul(unsigned long &a, unsigned long &b)
{
a ^= b;
b ^= a;
a ^= b;
}

12
misc/noise/util.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef __UTIL_H
#define __UTIL_H
#include <stdint.h>
void swap_u8(uint8_t &a, uint8_t &b);
void swap_ul(unsigned long &a, unsigned long &b);
#endif // __UTIL_H