2023-01-24 05:22:40 +01:00
|
|
|
#include <chrono>
|
|
|
|
#include <iostream>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <set>
|
|
|
|
#include "worleynoise.h"
|
|
|
|
#include "common/vector3d.h"
|
|
|
|
|
|
|
|
void WorleyNoise::generateNoise()
|
|
|
|
{
|
|
|
|
auto start = std::chrono::high_resolution_clock::now();
|
|
|
|
|
|
|
|
// Generate random points
|
|
|
|
points.clear();
|
2023-01-24 07:04:58 +01:00
|
|
|
points.reserve(pow(numberOfPoints, 3));
|
|
|
|
for (int x = 0; x < numberOfPoints; x++)
|
2023-01-24 05:22:40 +01:00
|
|
|
{
|
2023-01-24 07:04:58 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2023-01-24 05:22:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
2023-01-24 07:04:58 +01:00
|
|
|
setNoise(x, y, z, distanceToClosestPoint(point));
|
2023-01-24 05:22:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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<std::chrono::seconds>(stop - start);
|
|
|
|
|
|
|
|
std::cout << "Finished computing Worley getNoise for size " << size << " and " << numberOfPoints << " points in "
|
|
|
|
<< duration.count() << " seconds" << std::endl;
|
|
|
|
}
|
|
|
|
|
2023-01-24 07:04:58 +01:00
|
|
|
WorleyNoise::WorleyNoise(int size, int numberOfPoints) : numberOfPoints(numberOfPoints), Noise(size)
|
2023-01-24 05:22:40 +01:00
|
|
|
{
|
2023-01-24 06:26:24 +01:00
|
|
|
// Init random
|
|
|
|
std::random_device rd;
|
|
|
|
this->generator = std::mt19937(rd());
|
|
|
|
this->distribution = std::uniform_real_distribution<float>(0.0f, 1.0f);
|
|
|
|
|
2023-01-24 05:22:40 +01:00
|
|
|
generateNoise();
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3d WorleyNoise::getRandomPoint()
|
|
|
|
{
|
|
|
|
return Vector3d(distribution(generator), distribution(generator), distribution(generator));
|
|
|
|
}
|
|
|
|
|
|
|
|
float WorleyNoise::distanceToClosestPoint(Vector3d point)
|
|
|
|
{
|
2023-01-24 07:04:58 +01:00
|
|
|
std::vector<Vector3d> closePoints = getSubcellPoints(point);
|
|
|
|
|
|
|
|
// Iterate over all subcells
|
2023-01-24 05:22:40 +01:00
|
|
|
float minDistance = INFINITY;
|
2023-01-24 07:04:58 +01:00
|
|
|
for (Vector3d p: closePoints)
|
2023-01-24 05:22:40 +01:00
|
|
|
{
|
|
|
|
float distance = length(p - point);
|
|
|
|
if (distance < minDistance)
|
|
|
|
{
|
|
|
|
minDistance = distance;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return minDistance;
|
|
|
|
}
|
|
|
|
|
2023-01-24 07:04:58 +01:00
|
|
|
std::vector<Vector3d> WorleyNoise::getSubcellPoints(Vector3d point)
|
2023-01-24 05:22:40 +01:00
|
|
|
{
|
2023-01-24 07:04:58 +01:00
|
|
|
std::vector<Vector3d> closePoints;
|
|
|
|
|
2023-01-24 07:52:55 +01:00
|
|
|
point *= numberOfPoints;
|
|
|
|
point.x = std::floor(point.x);
|
|
|
|
point.y = std::floor(point.y);
|
|
|
|
point.z = std::floor(point.z);
|
2023-01-24 05:22:40 +01:00
|
|
|
|
2023-01-24 07:04:58 +01:00
|
|
|
// Iterate over all subcells
|
2023-01-24 05:22:40 +01:00
|
|
|
for (int x = -1; x <= 1; x++)
|
|
|
|
{
|
|
|
|
for (int y = -1; y <= 1; y++)
|
|
|
|
{
|
|
|
|
for (int z = -1; z <= 1; z++)
|
|
|
|
{
|
2023-01-24 07:04:58 +01:00
|
|
|
Vector3d offset = Vector3d(x, y, z);
|
|
|
|
Vector3d subcell = point + offset;
|
|
|
|
|
2023-01-24 07:52:55 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-01-24 07:04:58 +01:00
|
|
|
// 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;
|
2023-01-24 07:52:55 +01:00
|
|
|
closePoints.push_back(points[index] + cellOffsets);
|
2023-01-24 05:22:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-01-24 07:04:58 +01:00
|
|
|
return closePoints;
|
2023-01-24 05:22:40 +01:00
|
|
|
}
|