From ca4d767a525fbe5d327e5995ff69ff91e61cb41f Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Fri, 22 May 2026 20:33:38 +0800 Subject: [PATCH] feat: improve mountain realism --- include/Cubed/gameplay/biome.hpp | 10 ++++- include/Cubed/gameplay/chunk.hpp | 4 ++ src/gameplay/biome.cpp | 47 ++++++++++++---------- src/gameplay/builders/mountain_builder.cpp | 14 +------ src/gameplay/chunk.cpp | 7 +++- src/gameplay/chunk_generator.cpp | 42 +++++++++++++++++-- 6 files changed, 85 insertions(+), 39 deletions(-) diff --git a/include/Cubed/gameplay/biome.hpp b/include/Cubed/gameplay/biome.hpp index 8e1fcb7..8142e9d 100644 --- a/include/Cubed/gameplay/biome.hpp +++ b/include/Cubed/gameplay/biome.hpp @@ -7,8 +7,15 @@ namespace Cubed { constexpr float BIOME_NOISE_FREQUENCY = 0.03f; constexpr float HEIGHTMAP_NOISE_FREQUENCY = 0.001f; +constexpr float MOUNTAINOUS_NOISE_FREQUENCY = 0.003f; enum class BiomeType { PLAIN = 0, FOREST, DESERT, MOUNTAIN, RIVER, NONE }; +struct BiomeConditions { + float temp = 0.0f; + float humid = 0.0f; + float mountainous = 0.0f; +}; + struct BiomeHeightRange { int base_y; int amplitude; @@ -47,13 +54,14 @@ struct MountainParams : public BaseBiomeParams {}; struct RiverParams : public BaseBiomeParams {}; std::string get_biome_str(BiomeType biome); -BiomeType get_biome_from_noise(float temp, float humid); std::array get_noise_frequencies_for_biome(BiomeType biome); BiomeHeightRange get_biome_height_range(BiomeType biome); BiomeType safe_int_to_biome(int x); int get_interpolated_height(float world_x, float world_z, float temp, float humid); +BiomeType determine_biome(const BiomeConditions& conditions); + PlainParams& plain_params(); ForestParams& forest_params(); DesertParams& desert_params(); diff --git a/include/Cubed/gameplay/chunk.hpp b/include/Cubed/gameplay/chunk.hpp index 197122b..f4b464c 100644 --- a/include/Cubed/gameplay/chunk.hpp +++ b/include/Cubed/gameplay/chunk.hpp @@ -38,6 +38,9 @@ private: float frequency = 0.01f; float height = 80; unsigned m_seed = 0; + + BiomeConditions m_conditions; + void clear_dirty(); public: @@ -108,6 +111,7 @@ public: std::vector& blocks(); World& world(); unsigned seed() const; + BiomeConditions& conditions(); }; } // namespace Cubed \ No newline at end of file diff --git a/src/gameplay/biome.cpp b/src/gameplay/biome.cpp index f9736f1..51b4361 100644 --- a/src/gameplay/biome.cpp +++ b/src/gameplay/biome.cpp @@ -7,6 +7,8 @@ namespace Cubed { +using enum BiomeType; + static PlainParams plain{{BiomeType::PLAIN, {0.0f, 0.5f}, {0.0f, 0.5f}, @@ -84,27 +86,7 @@ Biome get_biome_from_noise(float temp, float humid) { return Biome::FOREST; } */ -BiomeType get_biome_from_noise(float temp, float humid) { - using enum BiomeType; - if (plain.temp.first <= temp && temp < plain.temp.second && - plain.humid.first <= humid && humid < plain.humid.second) { - return PLAIN; - } - if (forest.temp.first <= temp && temp < forest.temp.second && - forest.humid.first <= humid && humid < forest.humid.second) { - return FOREST; - } - if (desert.temp.first <= temp && temp < desert.temp.second && - desert.humid.first <= humid && humid < desert.humid.second) { - return DESERT; - } - if (mountain.temp.first <= temp && temp <= mountain.temp.second && - mountain.humid.first <= humid && humid <= mountain.humid.second) { - return MOUNTAIN; - } - Logger::warn("Invail Temp {} or Humid {}", temp, humid); - return PLAIN; -} + std::array get_noise_frequencies_for_biome(BiomeType biome) { using enum BiomeType; switch (biome) { @@ -201,6 +183,29 @@ int get_interpolated_height(float world_x, float world_z, float temp, return static_cast(h); } */ + +BiomeType determine_biome(const BiomeConditions& conditions) { + if (conditions.mountainous > 0.85) { + return MOUNTAIN; + } + auto temp = conditions.temp; + auto humid = conditions.humid; + if (plain.temp.first <= temp && temp < plain.temp.second && + plain.humid.first <= humid && humid < plain.humid.second) { + return PLAIN; + } + if (forest.temp.first <= temp && temp < forest.temp.second && + forest.humid.first <= humid && humid < forest.humid.second) { + return FOREST; + } + if (desert.temp.first <= temp && temp < desert.temp.second && + desert.humid.first <= humid && humid < desert.humid.second) { + return DESERT; + } + + return PLAIN; +} + PlainParams& plain_params() { return plain; } ForestParams& forest_params() { return forest; } DesertParams& desert_params() { return desert; } diff --git a/src/gameplay/builders/mountain_builder.cpp b/src/gameplay/builders/mountain_builder.cpp index 9ec08d8..1af20c5 100644 --- a/src/gameplay/builders/mountain_builder.cpp +++ b/src/gameplay/builders/mountain_builder.cpp @@ -18,21 +18,9 @@ void MountainBuilder::build_blocks() { for (int x = 0; x < CHUNK_SIZE; x++) { for (int z = 0; z < CHUNK_SIZE; z++) { int height = static_cast(m_heightmap[x][z]); - for (int y = 5; y < height - 5; y++) { + for (int y = 5; y <= height; y++) { m_blocks[Chunk::index(x, y, z)] = 3; } - for (int y = height - 5; y <= height - 1; y++) { - if (y > 110) { - m_blocks[Chunk::index(x, y, z)] = 3; - } else { - m_blocks[Chunk::index(x, y, z)] = 2; - } - } - if (height > 110) { - m_blocks[Chunk::index(x, height, z)] = 3; - } else { - m_blocks[Chunk::index(x, height, z)] = 1; - } } } } diff --git a/src/gameplay/chunk.cpp b/src/gameplay/chunk.cpp index 0b406bc..8b5daf9 100644 --- a/src/gameplay/chunk.cpp +++ b/src/gameplay/chunk.cpp @@ -24,7 +24,8 @@ Chunk::Chunk(Chunk&& other) noexcept m_chunk_pos(std::move(other.m_chunk_pos)), m_world(other.m_world), m_heightmap(std::move(other.m_heightmap)), m_blocks(std::move(other.m_blocks)), m_vbo(other.m_vbo), - m_vertexs_data(std::move(other.m_vertexs_data)), m_seed(other.m_seed) { + m_vertexs_data(std::move(other.m_vertexs_data)), m_seed(other.m_seed), + m_conditions(other.m_conditions) { other.m_vbo = 0; } @@ -44,6 +45,7 @@ Chunk& Chunk::operator=(Chunk&& other) noexcept { m_need_upload = other.m_need_upload.load(); m_vertex_sum = other.m_vertex_sum.load(); m_seed = other.m_seed; + m_conditions = other.m_conditions; return *this; } @@ -349,4 +351,7 @@ unsigned Chunk::seed() const { } return m_seed; } + +BiomeConditions& Chunk::conditions() { return m_conditions; } + } // namespace Cubed diff --git a/src/gameplay/chunk_generator.cpp b/src/gameplay/chunk_generator.cpp index e56b238..3c1cab6 100644 --- a/src/gameplay/chunk_generator.cpp +++ b/src/gameplay/chunk_generator.cpp @@ -9,6 +9,7 @@ #include "Cubed/gameplay/tree.hpp" #include "Cubed/gameplay/world.hpp" #include "Cubed/tools/cubed_hash.hpp" +#include "Cubed/tools/math_tools.hpp" #include "Cubed/tools/perlin_noise.hpp" namespace Cubed { @@ -59,7 +60,16 @@ void ChunkGenerator::assign_chunk_biome() { z * BIOME_NOISE_FREQUENCY); float humid = PerlinNoise3D::noise(x * BIOME_NOISE_FREQUENCY, 1.0f, z * BIOME_NOISE_FREQUENCY); - auto biome = get_biome_from_noise(temp, humid); + float center_x = static_cast(SIZE_X / 2) + x * CHUNK_SIZE + 0.5f; + float center_z = static_cast(SIZE_Z / 2) + z * CHUNK_SIZE + 0.5f; + float mountainous = + PerlinNoise2D::noise(center_x * MOUNTAINOUS_NOISE_FREQUENCY, + center_z * MOUNTAINOUS_NOISE_FREQUENCY); + auto& conditions = m_chunk.conditions(); + conditions.mountainous = mountainous; + conditions.humid = humid; + conditions.temp = temp; + auto biome = determine_biome(conditions); m_chunk.biome(biome); } @@ -139,11 +149,37 @@ void ChunkGenerator::generate_heightmap() { } return value; }; + int octaves = 4; float lacunarity = 2.0f; float gain = 0.5f; - heightmap[x][z] = 64 + fbm_height(world_x, world_z, octaves, - lacunarity, gain, 40, 0.005f); + float base_y = 64; + float amplitude = 40.0f; + float mountainous = + PerlinNoise2D::noise(world_x * MOUNTAINOUS_NOISE_FREQUENCY, + world_z * MOUNTAINOUS_NOISE_FREQUENCY); + /* + float t = Math::smootherstep(0.6, 0.7, mountainous); + base_y = std::lerp(64, 85, t); + amplitude = std::lerp(10, 40, t); + */ + float t; + if (mountainous >= 0.8f) { + t = Math::smootherstep(0.80f, 0.85, mountainous); + base_y = std::lerp(72, 88, t); + amplitude = std::lerp(28, 48, t); + } else if (mountainous >= 0.75f) { + t = Math::smootherstep(0.75f, 0.80f, mountainous); + base_y = std::lerp(68, 72, t); + amplitude = std::lerp(18, 28, t); + } else { + t = Math::smootherstep(0.5, 0.75, mountainous); + base_y = std::lerp(60, 68, t); + amplitude = std::lerp(8, 18, t); + } + heightmap[x][z] = + base_y + fbm_height(world_x, world_z, octaves, lacunarity, gain, + amplitude, 0.005f); } } }