#include #include #include "perlinnoise.h" Vector3d PerlinNoise::randomGradient() { Vector3d v; v.x = distribution(generator); v.y = distribution(generator); v.z = distribution(generator); return normalized(v); } float PerlinNoise::getGradientValue(int x, int y, int z) { Vector3d position = Vector3d(x, y, z); // Translate position to grid position /= (float) size; position *= (float) gridSize; // Get the grid coordinates int x_min = floor(position.x); int y_min = floor(position.y); int z_min = floor(position.z); // Get the grid coordinates of the next grid point int x_max = x_min + 1; int y_max = y_min + 1; int z_max = z_min + 1; // Get the fractional part of the position Vector3d delta = position - Vector3d(x_min, y_min, z_min); // Interpolate the gradient values float n000 = getCornerValue(position, Vector3d(x_min, y_min, z_min)); float n100 = getCornerValue(position, Vector3d(x_max, y_min, z_min)); float n010 = getCornerValue(position, Vector3d(x_min, y_max, z_min)); float n110 = getCornerValue(position, Vector3d(x_max, y_max, z_min)); float n001 = getCornerValue(position, Vector3d(x_min, y_min, z_max)); float n101 = getCornerValue(position, Vector3d(x_max, y_min, z_max)); float n011 = getCornerValue(position, Vector3d(x_min, y_max, z_max)); float n111 = getCornerValue(position, Vector3d(x_max, y_max, z_max)); // Smooth the interpolation float ix0 = interpolate(n000, n100, delta.x); float ix1 = interpolate(n010, n110, delta.x); float ix2 = interpolate(n001, n101, delta.x); float ix3 = interpolate(n011, n111, delta.x); float iy0 = interpolate(ix0, ix1, delta.y); float iy1 = interpolate(ix2, ix3, delta.y); float noise = interpolate(iy0, iy1, delta.z); return noise; } PerlinNoise::PerlinNoise(int size, int gridSize) : Noise(size), gridSize(gridSize) { // Init random std::random_device rd; this->generator = std::mt19937(rd()); this->distribution = std::normal_distribution(0.0f, 1.0f); generateNoise(); } void PerlinNoise::generateNoise() { // Generate gradients gradients.clear(); gradients.resize(pow(gridSize, 3)); for (int i = 0; i < gradients.size(); i++) { gradients[i] = randomGradient(); } // Generate each pixel for (int x = 0; x < size; x++) { for (int y = 0; y < size; y++) { for (int z = 0; z < size; z++) { setNoise(x, y, z, getGradientValue(x, y, z)); } } } // Normalize cloudNoise map to [0, 1] float min = *std::min_element(noiseMap.begin(), noiseMap.end()); float max = *std::max_element(noiseMap.begin(), noiseMap.end()); std::for_each(noiseMap.begin(), noiseMap.end(), [min, max](float &value) { value = (value - min) / (max - min); }); } float PerlinNoise::getCornerValue(Vector3d position, Vector3d corner) { int x = (int) corner.x % gridSize; int y = (int) corner.y % gridSize; int z = (int) corner.z % gridSize; Vector3d gradient = gradients[x + y * gridSize + z * gridSize * gridSize]; return dotProduct(gradient, position - corner); }