From 295188971da0217501450bb6a7e88a384760df44 Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Sun, 12 Apr 2026 20:52:57 +0800 Subject: [PATCH] perf: fast chunk generation --- include/Cubed/gameplay/chunk.hpp | 9 ++++++ include/Cubed/gameplay/chunk_status.hpp | 4 +++ include/Cubed/gameplay/player.hpp | 6 ++++ include/Cubed/gameplay/world.hpp | 13 ++++---- src/gameplay/chunk.cpp | 41 +++++++++++++++++++------ src/gameplay/player.cpp | 9 ++++++ src/gameplay/world.cpp | 16 +++++----- 7 files changed, 73 insertions(+), 25 deletions(-) diff --git a/include/Cubed/gameplay/chunk.hpp b/include/Cubed/gameplay/chunk.hpp index 554b35d..21385da 100644 --- a/include/Cubed/gameplay/chunk.hpp +++ b/include/Cubed/gameplay/chunk.hpp @@ -13,6 +13,11 @@ private: bool m_is_gened = false; bool m_dirty = false; + + static constexpr int SIZE_X = CHUCK_SIZE; + static constexpr int SIZE_Y = WORLD_SIZE_Y; + static constexpr int SIZE_Z = CHUCK_SIZE; + ChunkPos m_chunk_pos; World& m_world; // the index is a array of block id @@ -26,6 +31,10 @@ private: public: Chunk(World& world, ChunkPos chunk_pos); ~Chunk(); + Chunk(const Chunk&) = delete; + Chunk& operator=(const Chunk&) = delete; + Chunk(Chunk&&) = default; + Chunk& operator=(Chunk&&) = delete; const std::vector& get_chunk_blocks() const; static int get_index(int x, int y, int z); diff --git a/include/Cubed/gameplay/chunk_status.hpp b/include/Cubed/gameplay/chunk_status.hpp index 2e8e3ee..1a3cbd3 100644 --- a/include/Cubed/gameplay/chunk_status.hpp +++ b/include/Cubed/gameplay/chunk_status.hpp @@ -3,6 +3,7 @@ struct ChunkPos { int x; int z; + bool operator==(const ChunkPos&) const = default; struct Hash { std::size_t operator()(const ChunkPos& pos) const{ @@ -24,3 +25,6 @@ struct ChunkPos { }; + + + diff --git a/include/Cubed/gameplay/player.hpp b/include/Cubed/gameplay/player.hpp index 886c5b4..476560b 100644 --- a/include/Cubed/gameplay/player.hpp +++ b/include/Cubed/gameplay/player.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -43,10 +44,14 @@ private: glm::vec3 direction = glm::vec3(0.0f, 0.0f, 0.0f); glm::vec3 move_distance {0.0f, 0.0f, 0.0f}; // player is tow block tall, the pos is the lower pos + glm::vec3 m_player_pos {0.0f, 120.0f, 0.0f}; + ChunkPos m_player_chunk_pos {0, 0}; + glm::vec3 m_front {0, 0, -1}; glm::vec3 m_right {0, 0, 0}; glm::vec3 m_size {0.6f, 1.8f, 0.6f}; + Gait m_gait = Gait::WALK; MoveState m_move_state {}; @@ -56,6 +61,7 @@ private: bool ray_cast(const glm::vec3& start, const glm::vec3& dir, glm::ivec3& block_pos, glm::vec3& normal, float distance = 4.0f); + void check_player_chunk_transition(); void update_direction(); void update_lookup_block(); void update_move(float delta_time); diff --git a/include/Cubed/gameplay/world.hpp b/include/Cubed/gameplay/world.hpp index 1ed500c..eb7a6d1 100644 --- a/include/Cubed/gameplay/world.hpp +++ b/include/Cubed/gameplay/world.hpp @@ -8,24 +8,21 @@ class Player; class World { -private: - bool need_gen_chunk = false; - - BlockRenderData m_block_render_data; +private: + bool m_need_gen_chunk; std::unordered_map m_chunks; std::unordered_map m_players; std::vector m_planes; - std::pair chunk_pos(int world_x, int world_z) const; void gen_chunks(); - public: World(); ~World(); + bool can_move(const AABB& player_box) const; - const BlockRenderData& get_block_render_data(int x, int y ,int z); + //const BlockRenderData& get_block_render_data(int x, int y ,int z); const std::optional& get_look_block_pos(const std::string& name) const; Player& get_player(const std::string& name); void init_world(); @@ -34,6 +31,8 @@ public: int get_block(const glm::ivec3& block_pos) const; bool is_block(const glm::ivec3& block_pos) const; + ChunkPos chunk_pos(int world_x, int world_z) const; + void need_gen(); void render(const glm::mat4& mvp_matrix); diff --git a/src/gameplay/chunk.cpp b/src/gameplay/chunk.cpp index b938a56..38ac19f 100644 --- a/src/gameplay/chunk.cpp +++ b/src/gameplay/chunk.cpp @@ -11,9 +11,14 @@ Chunk::Chunk(World& world, ChunkPos chunk_pos) : } Chunk::~Chunk() { - glDeleteBuffers(1, &m_vbo); + if (m_vbo != 0) { + glDeleteBuffers(1, &m_vbo); + } + } + + const std::vector& Chunk::get_chunk_blocks() const{ return m_blocks; } @@ -30,20 +35,36 @@ int Chunk::get_index(int x, int y, int z) { void Chunk::gen_vertex_data() { m_vertexs_data.clear(); - - for (int x = 0; x < CHUCK_SIZE; x++) { - for (int y = 0; y < WORLD_SIZE_Y; y++) { - for (int z = 0; z < CHUCK_SIZE; z++) { + static const glm::ivec3 DIR[6] = { + {0,0,1},{1,0,0},{0,0,-1},{-1,0,0},{0,1,0},{0,-1,0} + }; + + for (int x = 0; x < SIZE_X; x++) { + for (int y = 0; y < SIZE_Y; y++) { + for (int z = 0; z < SIZE_Z; z++) { int world_x = x + m_chunk_pos.x * CHUCK_SIZE; int world_z = z + m_chunk_pos.z * CHUCK_SIZE; int world_y = y; - const auto& block_render_data = m_world.get_block_render_data(world_x, world_y, world_z); + int id = m_blocks[get_index(x, y, z)]; // air - if (m_blocks[get_index(x, y, z)] == 0) { + if (id == 0) { continue; } for (int face = 0; face < 6; face++) { - if (!block_render_data.draw_face[face]) { + int nx = x + DIR[face].x; + int ny = y + DIR[face].y; + int nz = z + DIR[face].z; + bool neighbor_soild = false; + + if (nx < 0 || nx >= SIZE_X || ny < 0 || ny >= SIZE_Y || nz < 0 || nz>= SIZE_Z) { + neighbor_soild = m_world.is_block(glm::ivec3(world_x, world_y, world_z) + DIR[face]); + } else { + if (m_blocks[get_index(nx, ny, nz)] != 0) { + neighbor_soild = true; + } + } + + if (neighbor_soild) { continue; } for (int i = 0; i < 6; i++) { @@ -53,7 +74,7 @@ void Chunk::gen_vertex_data() { VERTICES_POS[face][i][2] + (float)world_z * 1.0f, TEX_COORDS[face][i][0], TEX_COORDS[face][i][1], - static_cast(block_render_data.block_id * 6 + face) + static_cast(id * 6 + face) }; m_vertexs_data.emplace_back(vex); @@ -70,7 +91,7 @@ void Chunk::gen_vertex_data() { } glBindBuffer(GL_ARRAY_BUFFER, m_vbo); - glBufferData(GL_ARRAY_BUFFER, m_vertexs_data.size() * sizeof(Vertex), m_vertexs_data.data(), GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, m_vertexs_data.size() * sizeof(Vertex), m_vertexs_data.data(), GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); diff --git a/src/gameplay/player.cpp b/src/gameplay/player.cpp index b653422..1bc5d0a 100644 --- a/src/gameplay/player.cpp +++ b/src/gameplay/player.cpp @@ -137,6 +137,7 @@ void Player::set_player_pos(const glm::vec3& pos) { void Player::update(float delta_time) { update_move(delta_time); update_lookup_block(); + check_player_chunk_transition(); } void Player::update_player_move_state(int key, int action) { @@ -223,6 +224,14 @@ void Player::update_front_vec(float offset_x, float offset_y) { m_front = glm::normalize(m_front); } +void Player::check_player_chunk_transition() { + ChunkPos cur_pos = m_world.chunk_pos(m_player_pos.x, m_player_pos.z); + if (cur_pos != m_player_chunk_pos) { + m_world.need_gen(); + m_player_chunk_pos = cur_pos; + } +} + void Player::update_direction() { m_right = glm::normalize(glm::cross(m_front, glm::vec3(0.0f, 1.0f, 0.0f))); diff --git a/src/gameplay/world.cpp b/src/gameplay/world.cpp index da2879f..a3a65eb 100644 --- a/src/gameplay/world.cpp +++ b/src/gameplay/world.cpp @@ -16,12 +16,10 @@ World::~World() { } bool World::can_move(const AABB& player_box) const{ - - return true; } - +/* const BlockRenderData& World::get_block_render_data(int world_x, int world_y ,int world_z) { auto [chunk_x, chunk_z] = chunk_pos(world_x, world_z); //Logger::info("Chunk PosX : {} Chuch PosZ : {}", chunk_x, chunk_z); @@ -58,7 +56,7 @@ const BlockRenderData& World::get_block_render_data(int world_x, int world_y ,in return m_block_render_data; } - +*/ const std::optional& World::get_look_block_pos(const std::string& name) const{ static std::optional null_look_block = std::nullopt; auto it = m_players.find(HASH::str(name)); @@ -141,7 +139,7 @@ void World::render(const glm::mat4& mvp_matrix) { } -std::pair World::chunk_pos(int world_x, int world_z) const{ +ChunkPos World::chunk_pos(int world_x, int world_z) const{ int chunk_x, chunk_z; if (world_x < 0) { chunk_x = (world_x + 1) / CHUCK_SIZE - 1; @@ -191,6 +189,8 @@ void World::gen_chunks() { pre_gen_chunks.push_back(pos); } } + + Logger::info("New Gen Chunks Sum: {}", pre_gen_chunks.size()); if (pre_gen_chunks.empty()) { return; } @@ -214,7 +214,7 @@ void World::gen_chunks() { } void World::need_gen() { - need_gen_chunk = true; + m_need_gen_chunk = true; } bool World::is_aabb_in_frustum(const glm::vec3& center, const glm::vec3& half_extents) { @@ -324,9 +324,9 @@ void World::update(float delta_time) { for (auto& player : m_players) { player.second.update(delta_time); } - if (need_gen_chunk) { + if (m_need_gen_chunk) { gen_chunks(); - need_gen_chunk = false; + m_need_gen_chunk = false; } // unified compute vertex data before rendering