Refactor & better parameters for noise generation

This commit is contained in:
Namonay
2025-05-30 21:13:15 +02:00
parent 1fcf111e43
commit d58fbe0bb7
2 changed files with 34 additions and 33 deletions

View File

@@ -8,11 +8,11 @@ constexpr float HEIGHT_COEFF = 255.0f;
constexpr std::uint32_t WATER_LEVEL = 20; constexpr std::uint32_t WATER_LEVEL = 20;
Noise::Noise(const std::uint32_t seed, float frequency, float amplitude, int octaves, float lacunarity, float persistance, int redistribution): seed(std::mt19937(seed)), frequency(frequency), amplitude(amplitude), octaves(octaves), lacunarity(lacunarity), persistance(persistance), redistribution(redistribution) Noise::Noise(const std::uint32_t seed, float frequency, float amplitude, int octaves, float lacunarity, float persistance, int redistribution, float compensatory_factor): m_seed(std::mt19937(seed)), c_frequency(frequency), c_amplitude(amplitude), c_octaves(octaves), c_lacunarity(lacunarity), c_persistance(persistance), c_redistribution(redistribution), c_compensatory_factor(compensatory_factor)
{ {
if(amplitude > 1.0f || amplitude < -1.0f) if(c_amplitude > 1.0f || c_amplitude < -1.0f)
Scop::FatalError("Amplitude value must be in [-1;1]"); Scop::FatalError("Amplitude value must be in [-1;1]");
if(redistribution <= 0) if(c_redistribution <= 0)
Scop::FatalError("Redistribution cannot be a negative integer"); Scop::FatalError("Redistribution cannot be a negative integer");
InitPermutation(); InitPermutation();
} }
@@ -23,7 +23,7 @@ void Noise::InitPermutation()
for(int i = 0; i < 256; ++i) for(int i = 0; i < 256; ++i)
permutations[i] = i; permutations[i] = i;
std::shuffle(permutations.begin(), permutations.end(), seed); std::shuffle(permutations.begin(), permutations.end(), m_seed);
for(int i = 0; i < 256; ++i) for(int i = 0; i < 256; ++i)
{ {
this->perms[i] = permutations[i]; this->perms[i] = permutations[i];
@@ -63,27 +63,27 @@ const float Noise::Perlin2D(float x, float y) noexcept
const int Noise::ApplyPerlin2DParameters(float x, float y) noexcept // Wrapper to apply various mumbo jumbo to get a very worldlike generation const int Noise::ApplyPerlin2DParameters(float x, float y) noexcept // Wrapper to apply various mumbo jumbo to get a very worldlike generation
{ {
float total = 0.0f; float total = 0.0f;
float tmp_freq = frequency; float tmp_freq = c_frequency;
float tmp_amp = amplitude; float tmp_amp = c_amplitude;
float maxValue = 0.0f; float maxValue = 0.0f;
for(int i = 0; i < this->octaves; ++i) for(int i = 0; i < this->c_octaves; ++i)
{ {
total += Perlin2D(x * tmp_freq, y * tmp_freq) * tmp_amp; total += Perlin2D(x * tmp_freq, y * tmp_freq) * tmp_amp;
maxValue += tmp_amp; maxValue += tmp_amp;
tmp_amp *= persistance; tmp_amp *= c_persistance;
tmp_freq *= lacunarity; tmp_freq *= c_lacunarity;
} }
float normalized = total / maxValue; float normalized = total / maxValue;
normalized = std::clamp(normalized, 0.0f, 1.0f); normalized = std::clamp(normalized, 0.0f, 1.0f);
normalized = std::pow(normalized, redistribution); normalized = std::pow(normalized * c_compensatory_factor, c_redistribution);
return static_cast<int>(normalized * HEIGHT_COEFF); return static_cast<int>(normalized * HEIGHT_COEFF);
} }
[[nodiscard]] const int Noise::Perlin2D(int x, int y) noexcept [[nodiscard]] const int Noise::Perlin2D(int x, int y) noexcept
{ // Wrapper to unnormalise input and output { // Wrapper to unnormalise input and output
float scaledX = static_cast<float>(x) * frequency; float scaledX = static_cast<float>(x) * c_frequency;
float scaledY = static_cast<float>(y) * frequency; float scaledY = static_cast<float>(y) * c_frequency;
return floor(ApplyPerlin2DParameters(scaledX, scaledY)); return floor(ApplyPerlin2DParameters(scaledX, scaledY));
} }
@@ -107,17 +107,17 @@ const int Noise::ApplyPerlin2DParameters(float x, float y) noexcept // Wrapper t
[[nodiscard]] const int Noise::Perlin3D(int x, int y, int z) noexcept [[nodiscard]] const int Noise::Perlin3D(int x, int y, int z) noexcept
{ {
float scaledX = static_cast<float>(x) * frequency; float scaledX = static_cast<float>(x) * c_frequency;
float scaledY = static_cast<float>(y) * frequency; float scaledY = static_cast<float>(y) * c_frequency;
float scaledZ = static_cast<float>(z) * frequency; float scaledZ = static_cast<float>(z) * c_frequency;
return floor(ApplyPerlin3DParameters(scaledX, scaledY, scaledZ)); return static_cast<int>(ApplyPerlin3DParameters(scaledX, scaledY, scaledZ));
} }
[[nodiscard]] const float Noise::Perlin3D(float x, float y, float z) noexcept [[nodiscard]] const float Noise::Perlin3D(float x, float y, float z) noexcept
{ {
int xi = (int)floor(x) & 255; int xi = static_cast<int>(x) & 255;
int yi = (int)floor(y) & 255; int yi = static_cast<int>(y) & 255;
int zi = (int)floor(z) & 255; int zi = static_cast<int>(z) & 255;
float xf = x - floor(x); float xf = x - floor(x);
float yf = y - floor(y); float yf = y - floor(y);
@@ -149,22 +149,22 @@ const int Noise::ApplyPerlin2DParameters(float x, float y) noexcept // Wrapper t
grad(bbb, xf - 1, yf - 1, zf - 1), u); grad(bbb, xf - 1, yf - 1, zf - 1), u);
y2 = std::lerp(x1, x2, v); y2 = std::lerp(x1, x2, v);
return ((std::lerp(y1, y2, w) + 1.0f) / 2.0f) * amplitude; return ((std::lerp(y1, y2, w) + 1.0f) / 2.0f) * c_amplitude;
} }
[[nodiscard]] const int Noise::ApplyPerlin3DParameters(float x, float y, float z) noexcept [[nodiscard]] const int Noise::ApplyPerlin3DParameters(float x, float y, float z) noexcept
{ {
float total = 0.0f; float total = 0.0f;
float tmp_freq = frequency; float tmp_freq = c_frequency;
float tmp_amp = amplitude; float tmp_amp = c_amplitude;
float maxValue = 0.0f; float maxValue = 0.0f;
for(int i = 0; i < this->octaves; ++i) for(int i = 0; i < this->c_octaves; ++i)
{ {
total += Perlin3D(x * tmp_freq, y * tmp_freq, z * tmp_freq) * tmp_amp; total += Perlin3D(x * tmp_freq, y * tmp_freq, z * tmp_freq) * tmp_amp;
maxValue += tmp_amp; maxValue += tmp_amp;
tmp_amp *= persistance; tmp_amp *= c_persistance;
tmp_freq *= lacunarity; tmp_freq *= c_lacunarity;
} }
float normalized = total / maxValue; float normalized = total / maxValue;
normalized = std::clamp(normalized, 0.0f, 1.0f); normalized = std::clamp(normalized, 0.0f, 1.0f);

View File

@@ -11,7 +11,7 @@
class Noise class Noise
{ {
public: public:
Noise(const std::uint32_t seed = 42, float frequency = 0.05f, float amplitude = 0.95f, int octaves = 4, float lacunarity = 2.4f, float persistance = 0.8f, int redistribution = 3); Noise(const std::uint32_t seed = 42, float frequency = 0.045f, float amplitude = 0.80f, int octaves = 4, float lacunarity = 2.0f, float persistance = 0.7f, int redistribution = 4, float compensatory_factor = 1.3f);
[[nodiscard]] std::array<std::uint32_t, CHUNK_SIZE.y> GetHeight(Scop::Vec2i pos); [[nodiscard]] std::array<std::uint32_t, CHUNK_SIZE.y> GetHeight(Scop::Vec2i pos);
[[nodiscard]] const int Perlin2D(int x, int y) noexcept; [[nodiscard]] const int Perlin2D(int x, int y) noexcept;
@@ -19,14 +19,15 @@ class Noise
~Noise() = default; ~Noise() = default;
private: private:
std::mt19937 seed; std::mt19937 m_seed;
std::array<int, NOISE_SIZE> perms; std::array<int, NOISE_SIZE> perms;
const float frequency; const float c_frequency;
const float amplitude; const float c_amplitude;
const int octaves; const int c_octaves;
const float lacunarity; const float c_lacunarity;
const float persistance; const float c_persistance;
const int redistribution; const int c_redistribution;
const float c_compensatory_factor;
void InitPermutation(void); void InitPermutation(void);
[[nodiscard]] const float Perlin2D(float x, float y) noexcept; [[nodiscard]] const float Perlin2D(float x, float y) noexcept;