From bb0620f3aa466355ac2d76ae2c80f996685a31ad Mon Sep 17 00:00:00 2001 From: Kyle Isom Date: Sat, 16 Feb 2019 16:50:56 -0800 Subject: [PATCH] Add perlin noise implementation. --- misc/noise/Makefile | 8 ++++ misc/noise/noise.cc | 93 +++++++++++++++++++++++++++++++++++++++++++++ misc/noise/noise.h | 16 ++++++++ misc/noise/test.cc | 15 ++++++++ misc/noise/util.cc | 20 ++++++++++ misc/noise/util.h | 12 ++++++ 6 files changed, 164 insertions(+) create mode 100644 misc/noise/Makefile create mode 100644 misc/noise/noise.cc create mode 100644 misc/noise/noise.h create mode 100644 misc/noise/test.cc create mode 100644 misc/noise/util.cc create mode 100644 misc/noise/util.h diff --git a/misc/noise/Makefile b/misc/noise/Makefile new file mode 100644 index 0000000..cdf21de --- /dev/null +++ b/misc/noise/Makefile @@ -0,0 +1,8 @@ +SOURCES := noise.cc test.cc util.cc + +noise: $(SOURCES) + g++ -o $@ $(SOURCES) + +.PHONY: clean +clean: + rm -f noise diff --git a/misc/noise/noise.cc b/misc/noise/noise.cc new file mode 100644 index 0000000..2505b04 --- /dev/null +++ b/misc/noise/noise.cc @@ -0,0 +1,93 @@ +#include +#include + +#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)))); +} diff --git a/misc/noise/noise.h b/misc/noise/noise.h new file mode 100644 index 0000000..f1cb248 --- /dev/null +++ b/misc/noise/noise.h @@ -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 diff --git a/misc/noise/test.cc b/misc/noise/test.cc new file mode 100644 index 0000000..f83e4b9 --- /dev/null +++ b/misc/noise/test.cc @@ -0,0 +1,15 @@ +#include +#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; + } +} diff --git a/misc/noise/util.cc b/misc/noise/util.cc new file mode 100644 index 0000000..1cf5461 --- /dev/null +++ b/misc/noise/util.cc @@ -0,0 +1,20 @@ +#include "util.h" +#include + + +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; +} diff --git a/misc/noise/util.h b/misc/noise/util.h new file mode 100644 index 0000000..e134f99 --- /dev/null +++ b/misc/noise/util.h @@ -0,0 +1,12 @@ +#ifndef __UTIL_H +#define __UTIL_H + + +#include + + +void swap_u8(uint8_t &a, uint8_t &b); +void swap_ul(unsigned long &a, unsigned long &b); + + +#endif // __UTIL_H