refactor: prevent desert from generation adjacent to mountain in biome generation

This commit is contained in:
2026-04-17 22:22:18 +08:00
parent e69d38ad94
commit f2328d19fd
5 changed files with 38 additions and 28 deletions

View File

@@ -4,13 +4,13 @@ constexpr int MAX_BLOCK_NUM = 5;
constexpr int MAX_UI_NUM = 1; constexpr int MAX_UI_NUM = 1;
constexpr int CHUCK_SIZE = 16; constexpr int CHUCK_SIZE = 16;
constexpr int DISTANCE = 16; constexpr int DISTANCE = 24;
constexpr int MAX_BLOCK_STATUS = 1; constexpr int MAX_BLOCK_STATUS = 1;
constexpr int MAX_CHARACTER = 128; constexpr int MAX_CHARACTER = 128;
constexpr float NORMAL_FOV = 70.0f; constexpr float NORMAL_FOV = 70.0f;
constexpr int MAX_BIOME_SUM = 4; constexpr int MAX_BIOME_SUM = 4;
constexpr float BIOME_NOISE_FREQUENCY = 0.005f; constexpr float BIOME_NOISE_FREQUENCY = 0.003f;
constexpr float VERTICES_POS[6][6][3] = { constexpr float VERTICES_POS[6][6][3] = {
// ===== front (z = +1) ===== // ===== front (z = +1) =====

View File

@@ -1,4 +1,5 @@
#pragma once #pragma once
#include <cmath>
#include <array> #include <array>
#include <functional> #include <functional>
#include <string> #include <string>
@@ -29,6 +30,11 @@ struct ChunkPos {
}; };
}; };
constexpr float PLAIN_FREQ = 0.5f;
constexpr float FOREST_FREQ = 1.0f;
constexpr float DESERT_FREQ = 1.0f;
constexpr float MOUNTAIN_FREQ = 2.0f;
enum class Biome { enum class Biome {
PLAIN = 0, PLAIN = 0,
FOREST, FOREST,
@@ -62,9 +68,20 @@ constexpr inline std::string get_biome_str(Biome biome) {
}; };
inline Biome get_biome_from_noise(float temp, float humid) { inline Biome get_biome_from_noise(float temp, float humid) {
if (temp < 0.5f && humid < 0.5f) return Biome::MOUNTAIN; auto weight = [](float t, float h, float ct, float ch) -> float {
if (temp < 0.5f && humid >= 0.5f) return Biome::PLAIN; float dt = t - ct;
if (temp >= 0.5f && humid < 0.5f) return Biome::DESERT; float dh = h - ch;
float dist = std::sqrt(dt*dt + dh*dh);
return std::max(0.0f, 0.5f - dist);
};
float w_m = weight(temp, humid, 0.25f, 0.15f);
float w_p = weight(temp, humid, 0.50f, 0.40f);
float w_d = weight(temp, humid, 0.75f, 0.15f);
float w_f = weight(temp, humid, 0.75f, 0.75f);
w_m = pow(w_m, 8); w_p = pow(w_p, 8); w_d = pow(w_d, 8); w_f = pow(w_f, 8);
if (w_m >= w_p && w_m >= w_d && w_m >= w_f) return Biome::MOUNTAIN;
if (w_p >= w_m && w_p >= w_d && w_p >= w_f) return Biome::PLAIN;
if (w_d >= w_m && w_d >= w_p && w_d >= w_f) return Biome::DESERT;
return Biome::FOREST; return Biome::FOREST;
} }
@@ -72,13 +89,13 @@ inline std::array<float, 3> get_noise_frequencies_for_biome(Biome biome) {
using enum Biome; using enum Biome;
switch (biome) { switch (biome) {
case PLAIN: case PLAIN:
return {0.003f, 0.008f, 0.018f}; return {0.003f, 0.010f, 0.020f};
case FOREST: case FOREST:
return {0.004f, 0.012f, 0.022f}; return {0.004f, 0.012f, 0.022f};
case DESERT: case DESERT:
return {0.003f, 0.008f, 0.018f}; return {0.003f, 0.010f, 0.020f};
case MOUNTAIN: case MOUNTAIN:
return {0.006f, 0.015f, 0.03f}; return {0.006f, 0.015f, 0.030f};
} }
Logger::warn("Unknown Biome"); Logger::warn("Unknown Biome");
return {0.003f, 0.015f, 0.06f}; return {0.003f, 0.015f, 0.06f};
@@ -88,11 +105,11 @@ inline BiomeHeightRange get_biome_height_range(Biome biome) {
using enum Biome; using enum Biome;
switch (biome) { switch (biome) {
case PLAIN: case PLAIN:
return {62, 4}; return {62, 8};
case FOREST: case FOREST:
return {64, 8}; return {64, 12};
case DESERT: case DESERT:
return {61, 8}; return {61, 12};
case MOUNTAIN: case MOUNTAIN:
return {70, 70}; return {70, 70};
} }

View File

@@ -2,5 +2,5 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
namespace Math { namespace Math {
void extract_frustum_planes(const glm::mat4& mvp_matrix, std::vector<glm::vec4>& planes); void extract_frustum_planes(const glm::mat4& mvp_matrix, std::vector<glm::vec4>& planes);
int get_interpolated_height(float world_x, float world_z, float biome_noise, float temp, float humid); int get_interpolated_height(float world_x, float world_z, float temp, float humid);
} }

View File

@@ -280,16 +280,10 @@ void Chunk::resolve_blocks() {
float world_x = static_cast<float>(x + m_chunk_pos.x * CHUCK_SIZE); float world_x = static_cast<float>(x + m_chunk_pos.x * CHUCK_SIZE);
float world_z = static_cast<float>(z + m_chunk_pos.z * CHUCK_SIZE); float world_z = static_cast<float>(z + m_chunk_pos.z * CHUCK_SIZE);
float biome_noise = PerlinNoise::noise(
world_x * BIOME_NOISE_FREQUENCY,
0.5f,
world_z * BIOME_NOISE_FREQUENCY
);
float temp = PerlinNoise::noise(world_x * BIOME_NOISE_FREQUENCY, 0.0f, world_z * BIOME_NOISE_FREQUENCY); float temp = PerlinNoise::noise(world_x * BIOME_NOISE_FREQUENCY, 0.0f, world_z * BIOME_NOISE_FREQUENCY);
float humid = PerlinNoise::noise(world_x * BIOME_NOISE_FREQUENCY, 1.0f, world_z * BIOME_NOISE_FREQUENCY); float humid = PerlinNoise::noise(world_x * BIOME_NOISE_FREQUENCY, 1.0f, world_z * BIOME_NOISE_FREQUENCY);
int height = Math::get_interpolated_height(world_x, world_z, biome_noise, temp, humid); int height = Math::get_interpolated_height(world_x, world_z, temp, humid);
auto biome = get_biome_from_noise(temp, humid); auto biome = get_biome_from_noise(temp, humid);
for (int y = 5; y < height - 5; y++) { for (int y = 5; y < height - 5; y++) {
m_blocks[get_index(x, y, z)] = 3; m_blocks[get_index(x, y, z)] = 3;

View File

@@ -34,9 +34,8 @@ namespace Math {
} }
} }
int get_interpolated_height(float world_x, float world_z, float biome_noise, float temp, float humid) { int get_interpolated_height(float world_x, float world_z, float temp, float humid) {
auto weight = [](float t, float h, float ct, float ch) -> float { auto weight = [](float t, float h, float ct, float ch) -> float {
float dt = t - ct; float dt = t - ct;
float dh = h - ch; float dh = h - ch;
@@ -44,16 +43,16 @@ namespace Math {
return std::max(0.0f, 0.5f - dist); return std::max(0.0f, 0.5f - dist);
}; };
float w_mountain = weight(temp, humid, 0.25f, 0.25f); float w_mountain = weight(temp, humid, 0.25f, 0.15f);
float w_plain = weight(temp, humid, 0.25f, 0.75f); float w_plain = weight(temp, humid, 0.50f, 0.40f);
float w_desert = weight(temp, humid, 0.75f, 0.25f); float w_desert = weight(temp, humid, 0.75f, 0.15f);
float w_forest = weight(temp, humid, 0.75f, 0.75f); float w_forest = weight(temp, humid, 0.75f, 0.75f);
// adjust transitions between chunks // adjust transitions between chunks
float pow_n = 8.0f; // the larger n is, the purer the biome float pow_n = 8.0f; // the larger n is, the purer the biome
w_mountain = std::pow(w_mountain, pow_n); w_mountain = std::pow(w_mountain, pow_n) * MOUNTAIN_FREQ;
w_plain = std::pow(w_plain, pow_n); w_plain = std::pow(w_plain, pow_n) * PLAIN_FREQ;
w_desert = std::pow(w_desert, pow_n); w_desert = std::pow(w_desert, pow_n) * DESERT_FREQ;
w_forest = std::pow(w_forest, pow_n); w_forest = std::pow(w_forest, pow_n) * FOREST_FREQ;
float total = w_mountain + w_plain + w_desert + w_forest; float total = w_mountain + w_plain + w_desert + w_forest;
w_mountain /= total; w_plain /= total; w_desert /= total; w_forest /= total; w_mountain /= total; w_plain /= total; w_desert /= total; w_forest /= total;