mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
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.
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <span>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
namespace Cubed {
|
||||
class Renderer;
|
||||
class Camera;
|
||||
@@ -32,8 +34,9 @@ public:
|
||||
|
||||
ModelRender(Renderer& renderer);
|
||||
|
||||
void render_instance(ModelID id, std::span<const InstanceData> 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<const InstanceData> instances);
|
||||
|
||||
private:
|
||||
Renderer& m_renderer;
|
||||
|
||||
@@ -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 <glm/glm.hpp>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
namespace Cubed {
|
||||
class Renderer;
|
||||
class ClientWorld;
|
||||
@@ -12,6 +16,8 @@ class TextureManager;
|
||||
class Camera;
|
||||
class WorldRenderer {
|
||||
public:
|
||||
using InstanceDataMap =
|
||||
std::unordered_map<ModelID, std::vector<ModelRender::InstanceData>>;
|
||||
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
|
||||
@@ -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<const InstanceData> instances,
|
||||
const Camera& camera, bool shadow) {
|
||||
void ModelRender::build_vertices(ModelID id,
|
||||
std::span<const InstanceData> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
namespace Cubed {
|
||||
|
||||
namespace {
|
||||
std::unordered_map<ModelID, std::vector<ModelRender::InstanceData>>
|
||||
get_instances_data_map(ClientWorld& world) {
|
||||
WorldRenderer::InstanceDataMap get_instances_data_map(ClientWorld& world) {
|
||||
std::unordered_map<ModelID, std::vector<ModelRender::InstanceData>>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user