From 3534acd90f4dbc90f0ecdd135abd3ebbc349c60c Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Thu, 6 Aug 2026 15:11:51 +0800 Subject: [PATCH] refactor(render): build entity instance buffers once per frame Move instance matrix upload into build_vertices and use a precomputed instance data map for both shadow and color passes, avoiding duplicate GPU buffer updates. --- include/Cubed/render/model_renderer.hpp | 7 +++-- include/Cubed/render/world_renderer.hpp | 14 +++++++-- src/render/model_renderer.cpp | 14 +++++---- src/render/world_renderer.cpp | 39 ++++++++++++++++--------- 4 files changed, 50 insertions(+), 24 deletions(-) diff --git a/include/Cubed/render/model_renderer.hpp b/include/Cubed/render/model_renderer.hpp index b590a8e..53c852a 100644 --- a/include/Cubed/render/model_renderer.hpp +++ b/include/Cubed/render/model_renderer.hpp @@ -6,6 +6,8 @@ #include #include +#include +#include namespace Cubed { class Renderer; class Camera; @@ -32,8 +34,9 @@ public: ModelRender(Renderer& renderer); - void render_instance(ModelID id, std::span instances, - const Camera& camera, bool shadow); + void render_instance(ModelID id, size_t sum, const Camera& camera, + bool shadow); + void build_vertices(ModelID id, std::span instances); private: Renderer& m_renderer; diff --git a/include/Cubed/render/world_renderer.hpp b/include/Cubed/render/world_renderer.hpp index 10af50b..51a2c1f 100644 --- a/include/Cubed/render/world_renderer.hpp +++ b/include/Cubed/render/world_renderer.hpp @@ -1,10 +1,14 @@ #pragma once +#include "Cubed/gameplay/model.hpp" #include "Cubed/render/frame_buffer.hpp" +#include "Cubed/render/model_renderer.hpp" #include "Cubed/render/player_renderer.hpp" #include "Cubed/render/texture.hpp" #include #include +#include +#include namespace Cubed { class Renderer; class ClientWorld; @@ -12,6 +16,8 @@ class TextureManager; class Camera; class WorldRenderer { public: + using InstanceDataMap = + std::unordered_map>; struct ParallelLight { glm::vec3 sundir; // direction from sun to vertex glm::vec3 lightdir; @@ -128,12 +134,13 @@ private: void render_world(ClientWorld& world); - void shadow_map_generate(ClientWorld& world); + void shadow_map_generate(ClientWorld& world, const InstanceDataMap& map); void render_underwater(ClientWorld& world); void render_outline(ClientWorld& world); - void shadow_entity(ClientWorld& world, const glm::mat4& light_matrix); - void render_entity(ClientWorld& world); + void shadow_entity(ClientWorld& world, const glm::mat4& light_matrix, + const InstanceDataMap& map); + void render_entity(ClientWorld& world, const InstanceDataMap& map); void render_normal_block(const glm::mat4& model_mat, const glm::mat4& mv_mat, const glm::mat4& norm_mat, @@ -147,5 +154,6 @@ private: float angle_step_deg) const; glm::vec3 get_smoothed_shadow_lightdir(const glm::vec3& raw_shadow_sundir, float dt); + InstanceDataMap entity_build(ClientWorld& world); }; } // namespace Cubed \ No newline at end of file diff --git a/src/render/model_renderer.cpp b/src/render/model_renderer.cpp index 5b042cb..851e139 100644 --- a/src/render/model_renderer.cpp +++ b/src/render/model_renderer.cpp @@ -17,10 +17,8 @@ float swing_angle(const WalkPose& pose, float speed, float amp_deg) { } // namespace ModelRender::ModelRender(Renderer& renderer) : m_renderer(renderer) {} - -void ModelRender::render_instance(ModelID id, - std::span instances, - const Camera& camera, bool shadow) { +void ModelRender::build_vertices(ModelID id, + std::span instances) { if (instances.empty()) { return; } @@ -68,6 +66,12 @@ void ModelRender::render_instance(ModelID id, batch.instance_vbo->buffer_sub_data( batch.instance_matrices.data(), instances.size() * batch.node_count * sizeof(glm::mat4), 0); +} +void ModelRender::render_instance(ModelID id, size_t sum, const Camera& camera, + bool shadow) { + + auto& root = ModelManager::model(id).node; + auto& batch = get_batch(id, root); auto& shader = shadow ? m_renderer.get_shader("depth_model_instance") : m_renderer.get_shader("model_instance"); @@ -83,7 +87,7 @@ void ModelRender::render_instance(ModelID id, } entry.mesh->vao->bind(); glDrawElementsInstanced(GL_TRIANGLES, entry.mesh->indices.size(), - GL_UNSIGNED_INT, 0, instances.size()); + GL_UNSIGNED_INT, 0, sum); } } diff --git a/src/render/world_renderer.cpp b/src/render/world_renderer.cpp index 63f8d43..e62df6f 100644 --- a/src/render/world_renderer.cpp +++ b/src/render/world_renderer.cpp @@ -15,8 +15,7 @@ namespace Cubed { namespace { -std::unordered_map> -get_instances_data_map(ClientWorld& world) { +WorldRenderer::InstanceDataMap get_instances_data_map(ClientWorld& world) { std::unordered_map> instances_data_map; auto& registry = world.entity_manager().get_registry(); @@ -40,6 +39,7 @@ get_instances_data_map(ClientWorld& world) { } return instances_data_map; }; + } // namespace WorldRenderer::WorldRenderer(Renderer& renderer) @@ -74,13 +74,15 @@ void WorldRenderer::render(ClientWorld& world) { day_night_calculation(world); + auto map = entity_build(world); + render_sky(world); if (m_shader_on) { - shadow_map_generate(world); + shadow_map_generate(world, map); } render_world(world); render_outline(world); - render_entity(world); + render_entity(world, map); FrameBuffer::unbind(); @@ -128,6 +130,14 @@ void WorldRenderer::day_night_calculation(ClientWorld& world) { m_ambient_strength = glm::mix(0.45f, 0.25f, day_factor); } +WorldRenderer::InstanceDataMap WorldRenderer::entity_build(ClientWorld& world) { + auto instances_data_map = get_instances_data_map(world); + for (auto& [id, data] : instances_data_map) { + m_renderer.model_renderer().build_vertices(id, data); + } + return instances_data_map; +} + void WorldRenderer::render_sky(ClientWorld& world) { auto& camera = world.world_scene().camera(); @@ -321,16 +331,16 @@ void WorldRenderer::render_outline(ClientWorld& world) { } void WorldRenderer::shadow_entity(ClientWorld& world, - const glm::mat4& light_matrix) { + const glm::mat4& light_matrix, + const InstanceDataMap& map) { glEnable(GL_DEPTH_TEST); { auto& shader = m_renderer.get_shader("depth_model_instance"); shader.use(); shader.set_loc("lightSpaceMatrix", light_matrix); - auto instances_data_map = get_instances_data_map(world); - for (auto& [id, data] : instances_data_map) { + for (auto& [id, data] : map) { m_renderer.model_renderer().render_instance( - id, data, world.world_scene().camera(), true); + id, data.size(), world.world_scene().camera(), true); } } @@ -342,7 +352,8 @@ void WorldRenderer::shadow_entity(ClientWorld& world, } } -void WorldRenderer::shadow_map_generate(ClientWorld& world) { +void WorldRenderer::shadow_map_generate(ClientWorld& world, + const InstanceDataMap& map) { float texels_per_unit = 0.0f; const auto& lightdir = m_parallel_light.lightdir; @@ -445,7 +456,7 @@ void WorldRenderer::shadow_map_generate(ClientWorld& world) { } } - shadow_entity(world, light_space_matrix); + shadow_entity(world, light_space_matrix, map); } void WorldRenderer::render_underwater(ClientWorld& world) { @@ -727,7 +738,8 @@ void WorldRenderer::render_transparent_block(const glm::mat4& mv_mat, glBindVertexArray(0); } -void WorldRenderer::render_entity(ClientWorld& world) { +void WorldRenderer::render_entity(ClientWorld& world, + const InstanceDataMap& map) { // shader.set_loc("renderDistance", m_world.rendering_distance()); // shader.set_loc("skyColor", m_sky_uniform.sky_top); @@ -752,10 +764,9 @@ void WorldRenderer::render_entity(ClientWorld& world) { model.set_loc("samples", m_samples); m_depth_map_texture->bind(0); - auto instances_data_map = get_instances_data_map(world); - for (auto& [id, data] : instances_data_map) { + for (auto& [id, data] : map) { m_renderer.model_renderer().render_instance( - id, data, world.world_scene().camera(), false); + id, data.size(), world.world_scene().camera(), false); } }