Created
July 13, 2016 18:41
-
-
Save jessestricker/0688dbc21bd398a8369c22f34922e29a to your computer and use it in GitHub Desktop.
[C++] OpenSimplexNoise
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "OpenSimplexNoise.hpp" | |
#include <iostream> | |
#include <string> | |
int main() | |
{ | |
OpenSimplexNoise noise(1234); | |
// check for persistance | |
std::cout << noise(0, 0) << std::endl; | |
std::cout << noise(0, 0) << std::endl; | |
// print other values | |
std::cout << noise(0, 1) << std::endl; | |
std::cout << noise(1, 0) << std::endl; | |
std::cout << noise(1, 1) << std::endl; | |
// wait for enter key | |
std::string s; | |
std::getline(std::cin, s); | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "OpenSimplexNoise.hpp" | |
#include <cmath> // sqrt | |
#include <numeric> // std::iota | |
#include <algorithm> // std::shuffle | |
const OpenSimplexNoise::value_t | |
OpenSimplexNoise::STRETCH_CONST = (sqrt(3) - 3) / 6, | |
OpenSimplexNoise::SQUISH_CONST = (sqrt(3) - 1) / 2; | |
const std::array<OpenSimplexNoise::gradient, 8> OpenSimplexNoise::GRADIENTS = | |
{ | |
gradient{ 5,2 },{ 2,5 }, | |
{ -5,2 },{ -2,5 }, | |
{ 5, -2 },{ 2, -5 }, | |
{ -5, -2 },{ -2, -5 }, | |
}; | |
OpenSimplexNoise::OpenSimplexNoise(seed_t seed) : | |
_seed(seed), _perm{} | |
{ | |
// fill perm with numbers from 0 to UINT8_MAX | |
std::iota(_perm.begin(), _perm.end(), 0); | |
// shuffle all values using a seeded mersenne twister | |
std::mt19937 randEngine(seed); | |
std::shuffle(_perm.begin(), _perm.end(), randEngine); | |
} | |
OpenSimplexNoise::seed_t OpenSimplexNoise::seed() const { return _seed; } | |
OpenSimplexNoise::value_t OpenSimplexNoise::operator()(value_t x, value_t y) const | |
{ | |
value_t xsb, ysb; | |
value_t xins, yins; | |
{ | |
// place input coordinates onto grid. | |
auto stretchOffset = (x + y) * STRETCH_CONST; | |
auto xs = x + stretchOffset; | |
auto ys = y + stretchOffset; | |
// floor to get grid coordinates of rhombus (stretched square) super-cell origin. | |
xsb = static_cast<value_t>(fast_floor(xs)); | |
ysb = static_cast<value_t>(fast_floor(ys)); | |
// compute grid coordinates relative to rhombus origin. | |
xins = xs - xsb; | |
yins = ys - ysb; | |
} | |
auto inSum = xins + yins; | |
value_t dx0, dy0; | |
{ | |
// skew out to get actual coordinates of rhombus origin | |
auto squishOffset = (xsb + ysb) * SQUISH_CONST; | |
auto xb = xsb + squishOffset; | |
auto yb = ysb + squishOffset; | |
// positions relative to origin point. | |
dx0 = x - xb; | |
dy0 = y - yb; | |
} | |
value_t value = 0; | |
// contribution (1,0) | |
{ | |
auto dx1 = dx0 - 1 - SQUISH_CONST; | |
auto dy1 = dy0 - 0 - SQUISH_CONST; | |
auto attn1 = 2 - dx1 * dx1 - dy1 * dy1; | |
if (attn1 > 0) { | |
attn1 *= attn1; | |
value += attn1 * attn1 * extrapolate(xsb + 1, ysb + 0, dx1, dy1); | |
} | |
} | |
// contribution (0,1) | |
{ | |
auto dx2 = dx0 - 0 - SQUISH_CONST; | |
auto dy2 = dy0 - 1 - SQUISH_CONST; | |
auto attn2 = 2 - dx2 * dx2 - dy2 * dy2; | |
if (attn2 > 0) { | |
attn2 *= attn2; | |
value += attn2 * attn2 * extrapolate(xsb + 0, ysb + 1, dx2, dy2); | |
} | |
} | |
value_t dx_ext, dy_ext; | |
int xsv_ext, ysv_ext; | |
{ | |
if (inSum <= 1) { // we're inside the triangle (2-simplex) at (0,0) | |
auto zins = 1 - inSum; | |
if (zins > xins || zins > yins) { // (0,0) is one of the closest two triangular vertices | |
if (xins > yins) { | |
xsv_ext = xsb + 1; | |
ysv_ext = ysb - 1; | |
dx_ext = dx0 - 1; | |
dy_ext = dy0 + 1; | |
} | |
else { | |
xsv_ext = xsb - 1; | |
ysv_ext = ysb + 1; | |
dx_ext = dx0 + 1; | |
dy_ext = dy0 - 1; | |
} | |
} | |
else { // (1,0) and (0,1) are the closest two vertices. | |
xsv_ext = xsb + 1; | |
ysv_ext = ysb + 1; | |
dx_ext = dx0 - 1 - 2 * SQUISH_CONST; | |
dy_ext = dy0 - 1 - 2 * SQUISH_CONST; | |
} | |
} | |
else { // we're inside the triangle (2-simplex) at (1,1) | |
auto zins = 2 - inSum; | |
if (zins < xins || zins < yins) { // (0,0) is one of the closest two triangular vertices | |
if (xins > yins) { | |
xsv_ext = xsb + 2; | |
ysv_ext = ysb + 0; | |
dx_ext = dx0 - 2 - 2 * SQUISH_CONST; | |
dy_ext = dy0 + 0 - 2 * SQUISH_CONST; | |
} | |
else { | |
xsv_ext = xsb + 0; | |
ysv_ext = ysb + 2; | |
dx_ext = dx0 + 0 - 2 * SQUISH_CONST; | |
dy_ext = dy0 - 2 - 2 * SQUISH_CONST; | |
} | |
} | |
else { // (1,0) and (0,1) are the closest two vertices. | |
dx_ext = dx0; | |
dy_ext = dy0; | |
xsv_ext = xsb; | |
ysv_ext = ysb; | |
} | |
xsb += 1; | |
ysb += 1; | |
dx0 = dx0 - 1 - 2 * SQUISH_CONST; | |
dy0 = dy0 - 1 - 2 * SQUISH_CONST; | |
} | |
} | |
// contribution (0,0) or (1,1) | |
{ | |
auto attn0 = 2 - dx0 * dx0 - dy0 * dy0; | |
if (attn0 > 0) { | |
attn0 *= attn0; | |
value += attn0 * attn0 * extrapolate(xsb, ysb, dx0, dy0); | |
} | |
} | |
// extra vertex | |
{ | |
auto attn_ext = 2 - dx_ext * dx_ext - dy_ext * dy_ext; | |
if (attn_ext > 0) { | |
attn_ext *= attn_ext; | |
value += attn_ext * attn_ext * extrapolate(xsv_ext, ysv_ext, dx_ext, dy_ext); | |
} | |
} | |
return value / NORM_CONST; | |
} | |
OpenSimplexNoise::value_t OpenSimplexNoise::extrapolate(uint8_t xsb, uint8_t ysb, value_t dx, value_t dy) const | |
{ | |
uint8_t index = _perm[(_perm[xsb & 0xFF] + ysb) & 0xFF]; | |
index &= 0x0E; | |
index /= 2; | |
auto& gradient = GRADIENTS[index]; | |
return gradient.x * dx + gradient.y * dy; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <array> // std::array | |
#include <cstdint> // int8_t, ... | |
#include <limits> // std::numeric_limits<> | |
#include <random> // std::mt19937 | |
class OpenSimplexNoise | |
{ | |
public: | |
typedef std::mt19937::result_type seed_t; | |
typedef double value_t; | |
static constexpr seed_t DEFAULT_SEED = 0; | |
static constexpr value_t NORM_CONST = 47; | |
static const value_t STRETCH_CONST, SQUISH_CONST; | |
OpenSimplexNoise(seed_t seed = DEFAULT_SEED); | |
seed_t seed() const; | |
value_t operator()(value_t x, value_t y) const; | |
private: | |
struct gradient | |
{ | |
int8_t x, y; | |
gradient(int8_t x, int8_t y) : x(x), y(y) {} | |
}; | |
static const std::array<gradient, 8> GRADIENTS; | |
seed_t _seed; | |
std::array<uint8_t, std::numeric_limits<uint8_t>::max() + 1> _perm; | |
value_t extrapolate(uint8_t xsb, uint8_t ysb, value_t dx, value_t dy) const; | |
}; | |
// | |
// utility functions | |
inline int32_t fast_floor(float v) | |
{ | |
auto vi = static_cast<int32_t>(v); | |
return v < vi ? vi - 1 : vi; | |
} | |
inline int64_t fast_floor(double v) | |
{ | |
auto vi = static_cast<int64_t>(v); | |
return v < vi ? vi - 1 : vi; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment