From 4d4bbe82ecdc2f7beed46dd00c70fefe402c6ecc Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Thu, 19 Mar 2026 10:54:13 +0800 Subject: [PATCH] feat: add frustum culling --- CMakeLists.txt | 1 + include/Cubed/gameplay/world.hpp | 5 +++- include/Cubed/tools/math_tools.hpp | 5 ++++ src/gameplay/world.cpp | 46 +++++++++++++++++++++--------- src/main.cpp | 6 ++-- src/tools/math_tools.cpp | 29 +++++++++++++++++++ 6 files changed, 74 insertions(+), 18 deletions(-) create mode 100644 include/Cubed/tools/math_tools.hpp create mode 100644 src/tools/math_tools.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c2257d5..408ca6f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,7 @@ add_executable(${PROJECT_NAME} src/input.cpp src/map_table.cpp src/texture_manager.cpp + src/tools/math_tools.cpp src/tools/shader_tools.cpp src/tools/log.cpp ) diff --git a/include/Cubed/gameplay/world.hpp b/include/Cubed/gameplay/world.hpp index 5ccc5a0..70983be 100644 --- a/include/Cubed/gameplay/world.hpp +++ b/include/Cubed/gameplay/world.hpp @@ -11,6 +11,7 @@ private: BlockRenderData m_block_render_data; std::unordered_map m_chunks; std::unordered_map m_players; + std::vector m_planes; public: World(); @@ -20,8 +21,10 @@ public: const std::optional& get_look_block_pos(const std::string& name) const; Player& get_player(const std::string& name); void init_world(); + bool is_aabb_in_frustum(const glm::vec3& center, const glm::vec3& half_extents); bool is_block(const glm::ivec3& block_pos) const; - void render(); + + void render(const glm::mat4& mvp_matrix); void set_block(const glm::ivec3& pos, unsigned id); void update(float delta_time); diff --git a/include/Cubed/tools/math_tools.hpp b/include/Cubed/tools/math_tools.hpp new file mode 100644 index 0000000..9935d70 --- /dev/null +++ b/include/Cubed/tools/math_tools.hpp @@ -0,0 +1,5 @@ +#pragma once +#include +namespace Math { + void extract_frustum_planes(const glm::mat4& mvp_matrix, std::vector& planes); +} \ No newline at end of file diff --git a/src/gameplay/world.cpp b/src/gameplay/world.cpp index 09dc845..349af20 100644 --- a/src/gameplay/world.cpp +++ b/src/gameplay/world.cpp @@ -3,6 +3,7 @@ #include #include #include +#include World::World() { } @@ -123,26 +124,43 @@ void World::init_world() { m_players.emplace(HASH::str("TestPlayer"), Player(*this, "TestPlayer")); } -void World::render() { - +void World::render(const glm::mat4& mvp_matrix) { + Math::extract_frustum_planes(mvp_matrix, m_planes); for (const auto& chunk_map : m_chunks) { const auto& [pos, chunk] = chunk_map; + glm::vec3 center = glm::vec3(static_cast(pos.x * CHUCK_SIZE) + static_cast(CHUCK_SIZE / 2), static_cast(CHUCK_SIZE / 2), static_cast(pos.z * CHUCK_SIZE) + static_cast(CHUCK_SIZE / 2)); + if (is_aabb_in_frustum(center, glm::vec3(static_cast(CHUCK_SIZE / 2), static_cast(CHUCK_SIZE / 2), static_cast(CHUCK_SIZE / 2)))) { + glBindBuffer(GL_ARRAY_BUFFER, chunk.get_vbo()); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, s)); + glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, layer)); + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); + + glDrawArrays(GL_TRIANGLES, 0, chunk.get_vertex_data().size() * 3); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + } - glBindBuffer(GL_ARRAY_BUFFER, chunk.get_vbo()); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, s)); - glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, layer)); - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - - glDrawArrays(GL_TRIANGLES, 0, chunk.get_vertex_data().size() * 3); - glBindBuffer(GL_ARRAY_BUFFER, 0); } -} +} +bool World::is_aabb_in_frustum(const glm::vec3& center, const glm::vec3& half_extents) { + for (const auto& plane : m_planes) { + // distance + float d = glm::dot(glm::vec3(plane), center) + plane.w; + float r = half_extents.x * std::abs(plane.x) + + half_extents.y * std::abs(plane.y) + + half_extents.z * std::abs(plane.z); + if (d + r < 0) { + return false; + } + } + return true; +} bool World::is_block(const glm::ivec3& block_pos) const{ int chunk_x, chunk_z; int world_x, world_y, world_z; diff --git a/src/main.cpp b/src/main.cpp index 2810e69..a527bfe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,7 +24,7 @@ GLuint vao[NUM_VAO]; GLuint mv_loc, proj_loc; int width ,height; float aspect; -glm::mat4 p_mat, v_mat, m_mat, mv_mat; +glm::mat4 p_mat, v_mat, m_mat, mv_mat, mvp_mat; float inc = 0.01f; float tf = 0.0f; double last_time = glfwGetTime(); @@ -183,8 +183,8 @@ void display(GLFWwindow* window, double current_time) { mv_mat = v_mat * m_mat; glUniformMatrix4fv(mv_loc, 1, GL_FALSE, glm::value_ptr(mv_mat)); glUniformMatrix4fv(proj_loc, 1 ,GL_FALSE, glm::value_ptr(p_mat)); - - world.render(); + mvp_mat = p_mat * mv_mat; + world.render(mvp_mat); render_outline(); diff --git a/src/tools/math_tools.cpp b/src/tools/math_tools.cpp new file mode 100644 index 0000000..e6e5ed3 --- /dev/null +++ b/src/tools/math_tools.cpp @@ -0,0 +1,29 @@ +#include + +#include +namespace Math { + void extract_frustum_planes(const glm::mat4& mvp_matrix, std::vector& planes) { + if (planes.size() != 6) { + planes.resize(6); + } + + const float* m = glm::value_ptr(mvp_matrix); + + // left plane + planes[0] = glm::vec4(m[3] + m[0], m[7] + m[4], m[11] + m[8], m[15] + m[12]); + // right plane + planes[1] = glm::vec4(m[3] - m[0], m[7] - m[4], m[11] - m[8], m[15] - m[12]); + // bottom plane + planes[2] = glm::vec4(m[3] + m[1], m[7] + m[5], m[11] + m[9], m[15] + m[13]); + // top plane + planes[3] = glm::vec4(m[3] - m[1], m[7] - m[5], m[11] - m[9], m[15] - m[13]); + // near plane + planes[4] = glm::vec4(m[3] + m[2], m[7] + m[6], m[11] + m[10], m[15] + m[14]); + // far plane + planes[5] = glm::vec4(m[3] - m[2], m[7] - m[6], m[11] - m[10], m[15] - m[14]); + + for (auto& p : planes) { + p = glm::normalize(p); + } + } +} \ No newline at end of file