#include #include #include #include #include "worleynoise.h" #include "common/vector3d.h" void WorleyNoise::generateNoise() { auto start = std::chrono::high_resolution_clock::now(); // Generate random points points.clear(); points.reserve(pow(numberOfPoints, 3)); for (int x = 0; x < numberOfPoints; x++) { for (int y = 0; y < numberOfPoints; y++) { for (int z = 0; z < numberOfPoints; z++) { Vector3d point = getRandomPoint(); // Scale and translate into subcell point /= (float) numberOfPoints; Vector3d offset = Vector3d(x, y, z); offset /= (float) numberOfPoints; point += offset; points[x + y * numberOfPoints + z * numberOfPoints * numberOfPoints] = point; } } } // Generate getNoise map noiseMap.clear(); noiseMap.resize(size * size * size); for (int x = 0; x < size; x++) { for (int y = 0; y < size; y++) { for (int z = 0; z < size; z++) { Vector3d point = Vector3d(x, y, z); point /= (float) size; setNoise(x, y, z, distanceToClosestPoint(point)); } } } // Normalize getNoise map to [0, 1] float min = *std::min_element(noiseMap.begin(), noiseMap.end()); float max = *std::max_element(noiseMap.begin(), noiseMap.end()); for (int i = 0; i < noiseMap.size(); i++) { noiseMap[i] = (noiseMap[i] - min) / (max - min); } // Duration of computation auto stop = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast(stop - start); std::cout << "Finished computing Worley getNoise for size " << size << " and " << numberOfPoints << " points in " << duration.count() << " seconds" << std::endl; } WorleyNoise::WorleyNoise(int size, int numberOfPoints) : numberOfPoints(numberOfPoints), Noise(size) { // Init random std::random_device rd; this->generator = std::mt19937(rd()); this->distribution = std::uniform_real_distribution(0.0f, 1.0f); generateNoise(); } Vector3d WorleyNoise::getRandomPoint() { return Vector3d(distribution(generator), distribution(generator), distribution(generator)); } float WorleyNoise::distanceToClosestPoint(Vector3d point) { std::vector closePoints = getSubcellPoints(point); // Iterate over all subcells float minDistance = INFINITY; for (Vector3d p: closePoints) { float distance = length(p - point); if (distance < minDistance) { minDistance = distance; } } return minDistance; } std::vector WorleyNoise::getSubcellPoints(Vector3d point) { std::vector closePoints; point *= numberOfPoints; point.x = std::floor(point.x); point.y = std::floor(point.y); point.z = std::floor(point.z); // Iterate over all subcells for (int x = -1; x <= 1; x++) { for (int y = -1; y <= 1; y++) { for (int z = -1; z <= 1; z++) { Vector3d offset = Vector3d(x, y, z); Vector3d subcell = point + offset; Vector3d cellOffsets = Vector3d(0, 0, 0); if (subcell.x < 0) { cellOffsets.x = -1; } if (subcell.y < 0) { cellOffsets.y = -1; } if (subcell.z < 0) { cellOffsets.z = -1; } if (subcell.x >= numberOfPoints) { cellOffsets.x = 1; } if (subcell.y >= numberOfPoints) { cellOffsets.y = 1; } if (subcell.z >= numberOfPoints) { cellOffsets.z = 1; } // Wrap around subcell.x = std::fmod(subcell.x + numberOfPoints, numberOfPoints); subcell.y = std::fmod(subcell.y + numberOfPoints, numberOfPoints); subcell.z = std::fmod(subcell.z + numberOfPoints, numberOfPoints); // Get points in subcell int index = subcell.x + subcell.y * numberOfPoints + subcell.z * numberOfPoints * numberOfPoints; closePoints.push_back(points[index] + cellOffsets); } } } return closePoints; }