From f3ff209823854629917a9180a2ccc24476c0cc2d Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Sun, 8 Mar 2026 11:27:37 +0800 Subject: [PATCH] perf: optmize world rendering performance --- include/Cubed/texture_manager.hpp | 15 ++-- include/Cubed/tools/shader_tools.hpp | 5 +- src/main.cpp | 114 ++++++++++++++++----------- src/shaders/fShader.glsl | 5 +- src/shaders/vShader.glsl | 6 +- src/texture_manager.cpp | 92 ++++++++++++--------- src/tools/shader_tools.cpp | 25 +++--- 7 files changed, 149 insertions(+), 113 deletions(-) diff --git a/include/Cubed/texture_manager.hpp b/include/Cubed/texture_manager.hpp index 0a0adca..7af1397 100644 --- a/include/Cubed/texture_manager.hpp +++ b/include/Cubed/texture_manager.hpp @@ -1,24 +1,21 @@ #pragma once #include -#include -#include #include #include class TextureManager { private: - std::vector m_block_textures; + GLuint m_texture_array; + + void load_block_texture(unsigned block_id); public: TextureManager(); ~TextureManager(); - const BlockTexture& get_block_texture(const std::string& block_name); - const BlockTexture& get_block_texture(unsigned block_id); - void delet_texture(); - - void load_block_texture(const std::string& block_name); - void load_block_texture(unsigned block_id); + + void delet_texture(); + GLuint get_texture_array(); // Must call after MapTable::init_map() and glfwMakeContextCurrent(window); void init_texture(); }; \ No newline at end of file diff --git a/include/Cubed/tools/shader_tools.hpp b/include/Cubed/tools/shader_tools.hpp index 3db813b..63a0f42 100644 --- a/include/Cubed/tools/shader_tools.hpp +++ b/include/Cubed/tools/shader_tools.hpp @@ -9,6 +9,7 @@ namespace Shader { void print_program_info(int prog); bool check_opengl_error(); std::string read_shader_source(const char* file_path); - GLuint load_texture(const std::string& tex_image_path); - GLuint load_texture(const char* tex_image_path); + void delete_image_data(unsigned char* data); + unsigned char* load_image_data(const std::string& tex_image_path); + } diff --git a/src/main.cpp b/src/main.cpp index 7a4a22c..4478b47 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,7 +18,13 @@ #include constexpr int NUM_VAO = 1; -constexpr int NUM_VBO = 3; +constexpr int NUM_VBO = 1; + +struct Vertex { + float x, y, z; + float s, t; + float layer; +}; GLuint rendering_program; GLuint vao[NUM_VAO]; @@ -31,13 +37,16 @@ float inc = 0.01f; float tf = 0.0f; double last_time = 0.0f; double delta_time = 0.0f; - +GLuint texture_array; Player player; Camera camera; TextureManager texture_manager; World world; +std::vector vertex_data; + + void setup_vertices(void) { - float vertices_pos[108] = { + float vertices_pos[6][6][3] = { // ===== front (z = +1) ===== -0.5f, -0.5f, 0.5f, // bottom left -0.5f, 0.5f, 0.5f, // top left @@ -82,7 +91,7 @@ void setup_vertices(void) { -0.5f, -0.5f, 0.5f // front left }; - float tex_coords[72] { + float tex_coords[6][6][2] = { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, @@ -92,18 +101,46 @@ void setup_vertices(void) { }; + // every block + for (int x = 0; x < DISTANCE * CHUCK_SIZE; x++) { + for (int z = 0; z < DISTANCE * CHUCK_SIZE; z++) { + for (int y = 0; y < CHUCK_SIZE; y++) { + const auto& block_render_data = world.get_block_render_data(x, y, z); + // air + if (block_render_data.block_id == 0) { + continue; + } + for (int face = 0; face < 6; face++) { + if (!block_render_data.draw_face[face]) { + continue; + } + for (int i = 0; i < 6; i++) { + Vertex vex = { + vertices_pos[face][i][0] + (float)x * 1.0f, + vertices_pos[face][i][1] + (float)y * 1.0f, + vertices_pos[face][i][2] + (float)z * 1.0f, + tex_coords[face][i][0], + tex_coords[face][i][1], + static_cast(block_render_data.block_id * 6 + face) + + }; + vertex_data.emplace_back(vex); + } + } + } + + } + } + glGenVertexArrays(NUM_VAO, vao); glBindVertexArray(vao[0]); glGenBuffers(NUM_VBO, vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices_pos), vertices_pos, GL_STATIC_DRAW); - - glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); - glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_STATIC_DRAW); - + glBufferData(GL_ARRAY_BUFFER, vertex_data.size() * sizeof(Vertex), vertex_data.data(), GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); } @@ -167,7 +204,14 @@ void init(GLFWwindow* window) { p_mat = glm::perspective(glm::radians(60.0f), aspect, 0.1f, 1000.0f); glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); + glDepthFunc(GL_LEQUAL); + + #ifndef NDEBUG + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback([](GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* user_param) { + LOG::info("GL Debug: {}", reinterpret_cast(message)); + }, nullptr); + #endif setup_vertices(); @@ -205,47 +249,24 @@ void display(GLFWwindow* window, double current_time) { glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); - glEnableVertexAttribArray(0); + 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)); - glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); glActiveTexture(GL_TEXTURE0); - for (int x = 0; x < DISTANCE * CHUCK_SIZE; x++) { - for (int z = 0; z < DISTANCE * CHUCK_SIZE; z++) { - for (int y = 0; y < CHUCK_SIZE; y++) { - - m_mat = glm::translate(glm::mat4(1.0f), glm::vec3((float)x, y, (float)z)); - v_mat = camera.get_camera_lookat(); - 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)); - - const auto& block_render_data = world.get_block_render_data(x, y, z); - // air - if (block_render_data.block_id == 0) { - continue; - } - for (int face = 0; face < 6; face++) { - if (!block_render_data.draw_face[face]) { - continue; - } - glBindTexture(GL_TEXTURE_2D, - texture_manager.get_block_texture( - block_render_data - .block_id) - .texture[face] - ); - - glDrawArrays(GL_TRIANGLES, face * 6, 6); - } - } - - } - } + glBindTexture(GL_TEXTURE_2D_ARRAY, texture_array); + + m_mat = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f)); + v_mat = camera.get_camera_lookat(); + 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)); + glDrawArrays(GL_TRIANGLES, 0, vertex_data.size() * 3); } @@ -293,6 +314,7 @@ int main() { MapTable::init_map(); texture_manager.init_texture(); world.init_world(); + texture_array = texture_manager.get_texture_array(); init(window); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); diff --git a/src/shaders/fShader.glsl b/src/shaders/fShader.glsl index a45ba36..f0249c6 100644 --- a/src/shaders/fShader.glsl +++ b/src/shaders/fShader.glsl @@ -1,11 +1,12 @@ #version 430 in vec2 tc; +flat in int tex_layer; out vec4 color; -layout (binding = 0) uniform sampler2D samp; +layout (binding = 0) uniform sampler2DArray samp; void main(void) { - color = texture(samp, tc); + color = texture(samp, vec3(tc, tex_layer)); //color = varyingColor; } diff --git a/src/shaders/vShader.glsl b/src/shaders/vShader.glsl index cd74ca1..19ab747 100644 --- a/src/shaders/vShader.glsl +++ b/src/shaders/vShader.glsl @@ -2,8 +2,9 @@ layout (location = 0) in vec3 pos; layout (location = 1) in vec2 texCoord; +layout (location = 2) in float layer; out vec2 tc; - +flat out int tex_layer; mat4 buildRotateX(float rad); mat4 buildRotateY(float rad); @@ -13,11 +14,12 @@ mat4 buildTranslate(float x, float y, float z); uniform mat4 mv_matrix; uniform mat4 proj_matrix; -layout (binding = 0) uniform sampler2D samp; + void main(void) { gl_Position = proj_matrix * mv_matrix * vec4(pos, 1.0); tc = texCoord; + tex_layer = int(layer); } mat4 buildTranslate(float x, float y, float z) { diff --git a/src/texture_manager.cpp b/src/texture_manager.cpp index 9fb7418..6d0557b 100644 --- a/src/texture_manager.cpp +++ b/src/texture_manager.cpp @@ -11,61 +11,75 @@ TextureManager::~TextureManager() { delet_texture(); } -const BlockTexture& TextureManager::get_block_texture(const std::string& name) { - - - load_block_texture(name); - return m_block_textures[MapTable::get_id_from_name(name)]; - -} - -const BlockTexture& TextureManager::get_block_texture(unsigned id) { - - - load_block_texture(id); - return m_block_textures[id]; - -} - - void TextureManager::delet_texture() { - for (const auto& block_texture : m_block_textures) { - for (const auto& id : block_texture.texture) { - glDeleteTextures(1, &id); - } - } + glDeleteTextures(1, &m_texture_array); LOG::info("Successfully delete all texture"); } -void TextureManager::load_block_texture(const std::string& block_name) { +GLuint TextureManager::get_texture_array() { + return m_texture_array; +} - auto id = MapTable::get_id_from_name(block_name); - m_block_textures[id].name = block_name; - m_block_textures[id].id = id; +void TextureManager::load_block_texture(unsigned id) { + CUBED_ASSERT_MSG(id < MAX_BLOCK_NUM, "Exceed the max block sum limit"); + const std::string& name = MapTable::get_name_from_id(id); // air don`t need texture if (id == 0) { return; } - std::string block_texture_path = "assets/texture/block/" + block_name; - m_block_textures[id].texture.emplace_back(Shader::load_texture(block_texture_path + "/front.png")); - m_block_textures[id].texture.emplace_back(Shader::load_texture(block_texture_path + "/right.png")); - m_block_textures[id].texture.emplace_back(Shader::load_texture(block_texture_path + "/back.png")); - m_block_textures[id].texture.emplace_back(Shader::load_texture(block_texture_path + "/left.png")); - m_block_textures[id].texture.emplace_back(Shader::load_texture(block_texture_path + "/top.png")); - m_block_textures[id].texture.emplace_back(Shader::load_texture(block_texture_path + "/base.png")); -} + unsigned char * image_data[6]; + + std::string block_texture_path = "assets/texture/block/" + name; + image_data[0] = (Shader::load_image_data(block_texture_path + "/front.png")); + image_data[1] = (Shader::load_image_data(block_texture_path + "/right.png")); + image_data[2] = (Shader::load_image_data(block_texture_path + "/back.png")); + image_data[3] = (Shader::load_image_data(block_texture_path + "/left.png")); + image_data[4] = (Shader::load_image_data(block_texture_path + "/top.png")); + image_data[5] = (Shader::load_image_data(block_texture_path + "/base.png")); + + glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_array); + Shader::check_opengl_error(); + for (int i = 0; i < 6; i++) { + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, + 0, 0, id * 6 + i, + 16, 16, 1, + GL_RGBA, GL_UNSIGNED_BYTE, + image_data[i] + ); + Shader::check_opengl_error(); + Shader::delete_image_data(image_data[i]); + } -void TextureManager::load_block_texture(unsigned block_id) { - CUBED_ASSERT_MSG(block_id < MAX_BLOCK_NUM, "Exceed the max block sum limit"); - load_block_texture(MapTable::get_name_from_id(block_id)); } void TextureManager::init_texture() { - MapTable::init_map(); - m_block_textures.resize(MAX_BLOCK_NUM); + MapTable::init_map(); + + glGenTextures(1, &m_texture_array); + Shader::check_opengl_error(); + glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_array); + Shader::check_opengl_error(); + glTexImage3D(GL_TEXTURE_2D_ARRAY, + 0, GL_RGBA, + 16, 16, + MAX_BLOCK_NUM * 6, + 0, GL_RGBA, + GL_UNSIGNED_BYTE, nullptr); + Shader::check_opengl_error(); for (int i = 0; i < MAX_BLOCK_NUM; i++) { load_block_texture(i); } + glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_array); + Shader::check_opengl_error(); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + Shader::check_opengl_error(); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + Shader::check_opengl_error(); + glGenerateMipmap(GL_TEXTURE_2D_ARRAY); + Shader::check_opengl_error(); + + + } \ No newline at end of file diff --git a/src/tools/shader_tools.cpp b/src/tools/shader_tools.cpp index 05f6999..622de95 100644 --- a/src/tools/shader_tools.cpp +++ b/src/tools/shader_tools.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -65,20 +66,18 @@ namespace Shader { return content; } - GLuint load_texture(const std::string& tex_image_path) { - return load_texture(tex_image_path.c_str()); + void delete_image_data(unsigned char* data) { + SOIL_free_image_data(data); } - GLuint load_texture(const char* tex_image_path) { - GLuint texture_id; - texture_id = SOIL_load_OGL_texture(tex_image_path, SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y); - std::string error_info = std::string("Could not load texture ") + tex_image_path; - CUBED_ASSERT_MSG(texture_id, error_info.c_str()); - // generate mipmap - glBindTexture(GL_TEXTURE_2D, texture_id); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glGenerateMipmap(GL_TEXTURE_2D); - return texture_id; + unsigned char* load_image_data(const std::string& tex_image_path) { + unsigned char* data; + int width, height, channels; + data = SOIL_load_image(tex_image_path.c_str(), &width, &height, &channels, SOIL_LOAD_AUTO); + std::string error_info = "Could not load texture " + tex_image_path; + CUBED_ASSERT_MSG(data, error_info.c_str()); + + return data; } + }