refactor: terrain generation (#9)

* feat: add BlockType

* refactor: use fBM for heightmap generation

* feat: improve mountain realism

* refactor: adjust mountain spawn probability

* feat: add biome boundary blending

* refactor: remove resolve_biome_adjacency_conflict function

* feat: add snowy plain

* perf: speed up world generation

* refactor: lower overall terrain height
This commit is contained in:
zhenyan121
2026-05-23 10:33:52 +08:00
committed by GitHub
parent 1a26474a05
commit a54e87dbc6
28 changed files with 455 additions and 155 deletions

View File

@@ -8,7 +8,7 @@ constexpr int WORLD_SIZE_Y = 256;
constexpr int CHUNK_SIZE = 16;
constexpr int SEA_LEVEL = 64;
constexpr int MAX_BLOCK_NUM = 8;
constexpr int MAX_BLOCK_NUM = 9;
constexpr int MAX_UI_NUM = 1;
constexpr int MAX_BLOCK_STATUS = 1;
constexpr int MAX_BIOME_SUM = 4;

View File

@@ -5,9 +5,24 @@
namespace Cubed {
constexpr float BIOME_NOISE_FREQUENCY = 0.03f;
constexpr float BIOME_NOISE_FREQUENCY = 0.06f;
constexpr float HEIGHTMAP_NOISE_FREQUENCY = 0.001f;
constexpr float MOUNTAINOUS_NOISE_FREQUENCY = 0.003f;
enum class BiomeType {
PLAIN = 0,
FOREST,
DESERT,
MOUNTAIN,
RIVER,
SNOWY_PLAIN,
NONE
};
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;
@@ -47,13 +62,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<float, 3> get_noise_frequencies_for_biome(BiomeType biome);
BiomeHeightRange get_biome_height_range(BiomeType biome);
// std::array<float, 3> 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();

View File

@@ -10,6 +10,8 @@
namespace Cubed {
using BlockType = uint8_t;
struct BlockTexture {
std::string name;
unsigned id;
@@ -39,10 +41,11 @@ struct LookBlock {
};
constexpr std::array<std::string_view, MAX_BLOCK_NUM> BLOCK_REISTER{
"air", "grass_block", "dirt", "stone", "sand", "log", "leaf", "water"};
"air", "grass_block", "dirt", "stone", "sand", "log", "leaf",
"water", "snowy_grass_block"};
const std::array<bool, MAX_BLOCK_NUM> TRANSPARENT_MAP{
true, false, false, false, false, false, true};
true, false, false, false, false, false, true, false, false};
inline bool is_in_transparent_map(unsigned id) {
ASSERT_MSG(id < MAX_BLOCK_NUM, "ID is invaild");

View File

@@ -0,0 +1,21 @@
#pragma once
#include "Cubed/gameplay/builders/biome_builder.hpp"
namespace Cubed {
class ChunkGenerator;
class SnowyPlainBuilder : public BiomeBuilder {
public:
SnowyPlainBuilder(ChunkGenerator& chunk_generator);
void build_biome() override;
ChunkGenerator& get_chunk_generator() override;
void build_vegetation() override;
private:
ChunkGenerator& m_chunk_generator;
void build_blocks();
};
} // namespace Cubed

View File

@@ -7,7 +7,6 @@
#include "Cubed/primitive_data.hpp"
#include <atomic>
#include <cstdint>
namespace Cubed {
@@ -32,13 +31,16 @@ private:
World& m_world;
HeightMapArray m_heightmap;
// the index is a array of block id
std::vector<uint8_t> m_blocks;
std::vector<BlockType> m_blocks;
GLuint m_vbo = 0;
std::vector<Vertex> m_vertexs_data;
float frequency = 0.01f;
float height = 80;
unsigned m_seed = 0;
BiomeConditions m_conditions;
void clear_dirty();
public:
@@ -49,12 +51,21 @@ public:
Chunk(Chunk&&) noexcept;
Chunk& operator=(Chunk&&) noexcept;
static std::tuple<int, int, int> world_to_block(int world_x, int world_y,
int world_z, int chunk_x,
int chunk_z);
static std::tuple<int, int, int> world_to_block(const glm::ivec3& block_pos,
ChunkPos chunk_pos);
static std::tuple<int, int, int> block_to_world(int x, int y, int z,
int chunk_x, int chunk_z);
static std::tuple<int, int, int> block_to_world(const glm::ivec3& block_pos,
ChunkPos chunk_pos);
BiomeType get_biome() const;
ChunkPos get_chunk_pos() const;
const std::vector<uint8_t>& get_chunk_blocks() const;
const std::vector<BlockType>& get_chunk_blocks() const;
HeightMapArray get_heightmap() const;
static int get_index(int x, int y, int z);
static int get_index(const glm::vec3& pos);
static int index(int x, int y, int z);
static int index(const glm::vec3& pos);
// Init Chunk
// Determine biome from temperature and humidity noise
void gen_phase_one();
@@ -69,8 +80,8 @@ public:
// Generate terrain blocks from heightmap and biome
void gen_phase_five();
// Blend surface blocks at chunk borders with neighbors
void gen_phase_six(const std::array<std::optional<std::vector<uint8_t>>, 4>&
neighbor_block);
void gen_phase_six(const std::array<std::optional<std::vector<BlockType>>,
4>& neighbor_block);
// Generate biome-specific vegetation/structures
void gen_phase_seven();
// void gen_vertex_data();
@@ -79,7 +90,7 @@ public:
// 2 : (0, 1)
// 3 : (0, -1)
void gen_vertex_data(
const std::array<const std::vector<uint8_t>*, 4>& neighbor_block);
const std::array<const std::vector<BlockType>*, 4>& neighbor_block);
void upload_to_gpu();
GLuint get_vbo() const;
@@ -97,9 +108,10 @@ public:
BiomeType biome() const;
void biome(BiomeType b);
HeightMapArray& heightmap();
std::vector<uint8_t>& blocks();
std::vector<BlockType>& blocks();
World& world();
unsigned seed() const;
BiomeConditions& conditions();
};
} // namespace Cubed

View File

@@ -2,6 +2,7 @@
#include "Cubed/constants.hpp"
#include "Cubed/gameplay/biome.hpp"
#include "Cubed/gameplay/block.hpp"
#include "Cubed/gameplay/builders/biome_builder.hpp"
#include "Cubed/tools/cubed_random.hpp"
@@ -36,7 +37,7 @@ public:
void generate_terrain_blocks();
// Adjust Block;
void blend_surface_blocks_borders(
const std::array<std::optional<std::vector<uint8_t>>, 4>&
const std::array<std::optional<std::vector<BlockType>>, 4>&
neighbor_block);
// Generate Structure
void generate_vegetation();
@@ -44,6 +45,7 @@ public:
Chunk& chunk();
Random& random();
const std::array<BiomeType, 8>& neighbor_biome() const;
void generate_cave();
private:
static inline std::atomic<bool> is_init{false};
@@ -57,7 +59,6 @@ private:
unsigned m_chunk_seed = 0;
void make_biome_builder();
void generate_cave();
};
} // namespace Cubed

View File

@@ -4,7 +4,7 @@
namespace Cubed {
class PerlinNoise {
class PerlinNoise3D {
public:
static void init(unsigned seed);
static float noise(float x, float y, float z);
@@ -18,4 +18,19 @@ private:
static float grad(int hash, float x, float y, float z);
};
class PerlinNoise2D {
public:
static void init(unsigned seed);
static float noise(float x, float y);
static void reload(unsigned seed);
private:
static inline std::atomic<bool> is_init = false;
static inline std::vector<int> p;
static float fade(float t);
static float lerp(float t, float a, float b);
static float grad(int hash, float x, float y);
};
} // namespace Cubed