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 <glm/glm.hpp>
|
||||||
#include <span>
|
#include <span>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
class Renderer;
|
class Renderer;
|
||||||
class Camera;
|
class Camera;
|
||||||
@@ -32,8 +34,9 @@ public:
|
|||||||
|
|
||||||
ModelRender(Renderer& renderer);
|
ModelRender(Renderer& renderer);
|
||||||
|
|
||||||
void render_instance(ModelID id, std::span<const InstanceData> instances,
|
void render_instance(ModelID id, size_t sum, const Camera& camera,
|
||||||
const Camera& camera, bool shadow);
|
bool shadow);
|
||||||
|
void build_vertices(ModelID id, std::span<const InstanceData> instances);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Renderer& m_renderer;
|
Renderer& m_renderer;
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "Cubed/gameplay/model.hpp"
|
||||||
#include "Cubed/render/frame_buffer.hpp"
|
#include "Cubed/render/frame_buffer.hpp"
|
||||||
|
#include "Cubed/render/model_renderer.hpp"
|
||||||
#include "Cubed/render/player_renderer.hpp"
|
#include "Cubed/render/player_renderer.hpp"
|
||||||
#include "Cubed/render/texture.hpp"
|
#include "Cubed/render/texture.hpp"
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
class Renderer;
|
class Renderer;
|
||||||
class ClientWorld;
|
class ClientWorld;
|
||||||
@@ -12,6 +16,8 @@ class TextureManager;
|
|||||||
class Camera;
|
class Camera;
|
||||||
class WorldRenderer {
|
class WorldRenderer {
|
||||||
public:
|
public:
|
||||||
|
using InstanceDataMap =
|
||||||
|
std::unordered_map<ModelID, std::vector<ModelRender::InstanceData>>;
|
||||||
struct ParallelLight {
|
struct ParallelLight {
|
||||||
glm::vec3 sundir; // direction from sun to vertex
|
glm::vec3 sundir; // direction from sun to vertex
|
||||||
glm::vec3 lightdir;
|
glm::vec3 lightdir;
|
||||||
@@ -128,12 +134,13 @@ private:
|
|||||||
|
|
||||||
void render_world(ClientWorld& world);
|
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_underwater(ClientWorld& world);
|
||||||
void render_outline(ClientWorld& world);
|
void render_outline(ClientWorld& world);
|
||||||
void shadow_entity(ClientWorld& world, const glm::mat4& light_matrix);
|
void shadow_entity(ClientWorld& world, const glm::mat4& light_matrix,
|
||||||
void render_entity(ClientWorld& world);
|
const InstanceDataMap& map);
|
||||||
|
void render_entity(ClientWorld& world, const InstanceDataMap& map);
|
||||||
|
|
||||||
void render_normal_block(const glm::mat4& model_mat,
|
void render_normal_block(const glm::mat4& model_mat,
|
||||||
const glm::mat4& mv_mat, const glm::mat4& norm_mat,
|
const glm::mat4& mv_mat, const glm::mat4& norm_mat,
|
||||||
@@ -147,5 +154,6 @@ private:
|
|||||||
float angle_step_deg) const;
|
float angle_step_deg) const;
|
||||||
glm::vec3 get_smoothed_shadow_lightdir(const glm::vec3& raw_shadow_sundir,
|
glm::vec3 get_smoothed_shadow_lightdir(const glm::vec3& raw_shadow_sundir,
|
||||||
float dt);
|
float dt);
|
||||||
|
InstanceDataMap entity_build(ClientWorld& world);
|
||||||
};
|
};
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -17,10 +17,8 @@ float swing_angle(const WalkPose& pose, float speed, float amp_deg) {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
ModelRender::ModelRender(Renderer& renderer) : m_renderer(renderer) {}
|
ModelRender::ModelRender(Renderer& renderer) : m_renderer(renderer) {}
|
||||||
|
void ModelRender::build_vertices(ModelID id,
|
||||||
void ModelRender::render_instance(ModelID id,
|
std::span<const InstanceData> instances) {
|
||||||
std::span<const InstanceData> instances,
|
|
||||||
const Camera& camera, bool shadow) {
|
|
||||||
if (instances.empty()) {
|
if (instances.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -68,6 +66,12 @@ void ModelRender::render_instance(ModelID id,
|
|||||||
batch.instance_vbo->buffer_sub_data(
|
batch.instance_vbo->buffer_sub_data(
|
||||||
batch.instance_matrices.data(),
|
batch.instance_matrices.data(),
|
||||||
instances.size() * batch.node_count * sizeof(glm::mat4), 0);
|
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")
|
auto& shader = shadow ? m_renderer.get_shader("depth_model_instance")
|
||||||
: m_renderer.get_shader("model_instance");
|
: m_renderer.get_shader("model_instance");
|
||||||
@@ -83,7 +87,7 @@ void ModelRender::render_instance(ModelID id,
|
|||||||
}
|
}
|
||||||
entry.mesh->vao->bind();
|
entry.mesh->vao->bind();
|
||||||
glDrawElementsInstanced(GL_TRIANGLES, entry.mesh->indices.size(),
|
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 Cubed {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
std::unordered_map<ModelID, std::vector<ModelRender::InstanceData>>
|
WorldRenderer::InstanceDataMap get_instances_data_map(ClientWorld& world) {
|
||||||
get_instances_data_map(ClientWorld& world) {
|
|
||||||
std::unordered_map<ModelID, std::vector<ModelRender::InstanceData>>
|
std::unordered_map<ModelID, std::vector<ModelRender::InstanceData>>
|
||||||
instances_data_map;
|
instances_data_map;
|
||||||
auto& registry = world.entity_manager().get_registry();
|
auto& registry = world.entity_manager().get_registry();
|
||||||
@@ -40,6 +39,7 @@ get_instances_data_map(ClientWorld& world) {
|
|||||||
}
|
}
|
||||||
return instances_data_map;
|
return instances_data_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
WorldRenderer::WorldRenderer(Renderer& renderer)
|
WorldRenderer::WorldRenderer(Renderer& renderer)
|
||||||
@@ -74,13 +74,15 @@ void WorldRenderer::render(ClientWorld& world) {
|
|||||||
|
|
||||||
day_night_calculation(world);
|
day_night_calculation(world);
|
||||||
|
|
||||||
|
auto map = entity_build(world);
|
||||||
|
|
||||||
render_sky(world);
|
render_sky(world);
|
||||||
if (m_shader_on) {
|
if (m_shader_on) {
|
||||||
shadow_map_generate(world);
|
shadow_map_generate(world, map);
|
||||||
}
|
}
|
||||||
render_world(world);
|
render_world(world);
|
||||||
render_outline(world);
|
render_outline(world);
|
||||||
render_entity(world);
|
render_entity(world, map);
|
||||||
|
|
||||||
FrameBuffer::unbind();
|
FrameBuffer::unbind();
|
||||||
|
|
||||||
@@ -128,6 +130,14 @@ void WorldRenderer::day_night_calculation(ClientWorld& world) {
|
|||||||
m_ambient_strength = glm::mix(0.45f, 0.25f, day_factor);
|
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) {
|
void WorldRenderer::render_sky(ClientWorld& world) {
|
||||||
|
|
||||||
auto& camera = world.world_scene().camera();
|
auto& camera = world.world_scene().camera();
|
||||||
@@ -321,16 +331,16 @@ void WorldRenderer::render_outline(ClientWorld& world) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WorldRenderer::shadow_entity(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);
|
glEnable(GL_DEPTH_TEST);
|
||||||
{
|
{
|
||||||
auto& shader = m_renderer.get_shader("depth_model_instance");
|
auto& shader = m_renderer.get_shader("depth_model_instance");
|
||||||
shader.use();
|
shader.use();
|
||||||
shader.set_loc("lightSpaceMatrix", light_matrix);
|
shader.set_loc("lightSpaceMatrix", light_matrix);
|
||||||
auto instances_data_map = get_instances_data_map(world);
|
for (auto& [id, data] : map) {
|
||||||
for (auto& [id, data] : instances_data_map) {
|
|
||||||
m_renderer.model_renderer().render_instance(
|
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;
|
float texels_per_unit = 0.0f;
|
||||||
const auto& lightdir = m_parallel_light.lightdir;
|
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) {
|
void WorldRenderer::render_underwater(ClientWorld& world) {
|
||||||
@@ -727,7 +738,8 @@ void WorldRenderer::render_transparent_block(const glm::mat4& mv_mat,
|
|||||||
glBindVertexArray(0);
|
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("renderDistance", m_world.rendering_distance());
|
||||||
// shader.set_loc("skyColor", m_sky_uniform.sky_top);
|
// 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);
|
model.set_loc("samples", m_samples);
|
||||||
m_depth_map_texture->bind(0);
|
m_depth_map_texture->bind(0);
|
||||||
|
|
||||||
auto instances_data_map = get_instances_data_map(world);
|
for (auto& [id, data] : map) {
|
||||||
for (auto& [id, data] : instances_data_map) {
|
|
||||||
m_renderer.model_renderer().render_instance(
|
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