perf(render): frustum cull entities before instance building

Add frustum culling to entity instance data collection using AABB vs camera frustum planes. Pass renderer into get_instances_data_map to compute MVP and extract planes. Also add "Rendered Entities" debug counter for visibility.
This commit is contained in:
2026-08-06 20:40:01 +08:00
parent 94d92f2159
commit 9745ccc7d6
2 changed files with 27 additions and 3 deletions

View File

@@ -68,6 +68,9 @@ void DebugCollector::init(int, int) {
// rendered_chunk // rendered_chunk
add_label("Rendered Chunk: 0", "rendered_chunk"); add_label("Rendered Chunk: 0", "rendered_chunk");
// rendered_entities
add_label("Rendered Entities: 0", "rendered_entities");
// rss // rss
add_label("RSS: 0mb", "rss"); add_label("RSS: 0mb", "rss");

View File

@@ -4,6 +4,7 @@
#include "Cubed/debug_collector.hpp" #include "Cubed/debug_collector.hpp"
#include "Cubed/gameplay/client_world.hpp" #include "Cubed/gameplay/client_world.hpp"
#include "Cubed/gameplay/ecs/client_entity.hpp" #include "Cubed/gameplay/ecs/client_entity.hpp"
#include "Cubed/gameplay/hitbox_manager.hpp"
#include "Cubed/render/renderer.hpp" #include "Cubed/render/renderer.hpp"
#include "Cubed/render/renderer_constants.hpp" #include "Cubed/render/renderer_constants.hpp"
#include "Cubed/scene/world_scene.hpp" #include "Cubed/scene/world_scene.hpp"
@@ -15,28 +16,48 @@
namespace Cubed { namespace Cubed {
namespace { namespace {
WorldRenderer::InstanceDataMap get_instances_data_map(ClientWorld& world) { WorldRenderer::InstanceDataMap get_instances_data_map(ClientWorld& world,
Renderer& renderer) {
glm::mat4 mvp_mat =
renderer.p_mat() * world.world_scene().camera().get_camera_lookat();
auto& m_planes = world.planes();
Math::extract_frustum_planes(mvp_mat, m_planes);
size_t cnt = 0;
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();
auto view = registry.view<BaseClientCreature, RenderTransform>(); auto view =
registry.view<BaseClientCreature, RenderTransform, EntityInfo>();
for (auto entity : view) { for (auto entity : view) {
auto& creature = view.get<BaseClientCreature>(entity); auto& creature = view.get<BaseClientCreature>(entity);
auto pos = creature.transform.position.value; auto pos = creature.transform.position.value;
if (!world.is_render(pos)) { if (!world.is_render(pos)) {
continue; continue;
} }
auto& info = view.get<EntityInfo>(entity);
auto& t = view.get<RenderTransform>(entity); auto& t = view.get<RenderTransform>(entity);
auto aabb = HitboxManager::hitbox(info.name);
aabb.box.center += t.position.value;
if (!Math::is_aabb_in_frustum(aabb.box.center, aabb.box.half + 1.0f,
m_planes)) {
continue;
}
float yaw = std::atan2(t.direction.value.x, t.direction.value.z); float yaw = std::atan2(t.direction.value.x, t.direction.value.z);
ModelRender::InstanceData data; ModelRender::InstanceData data;
data.pos = t.position.value; data.pos = t.position.value;
data.yaw = yaw; data.yaw = yaw;
data.pose = creature.pose; data.pose = creature.pose;
instances_data_map[creature.model].emplace_back(std::move(data)); instances_data_map[creature.model].emplace_back(std::move(data));
++cnt;
// m_renderer.model_renderer().shadow_pass( // m_renderer.model_renderer().shadow_pass(
// creature.model, t.position.value, yaw, // creature.model, t.position.value, yaw,
// world.world_scene().camera(), creature.pose); // world.world_scene().camera(), creature.pose);
} }
d_rep("rendered_entities", "Rendered Entities: {}", cnt);
return instances_data_map; return instances_data_map;
}; };
@@ -131,7 +152,7 @@ void WorldRenderer::day_night_calculation(ClientWorld& world) {
} }
WorldRenderer::InstanceDataMap WorldRenderer::entity_build(ClientWorld& world) { WorldRenderer::InstanceDataMap WorldRenderer::entity_build(ClientWorld& world) {
auto instances_data_map = get_instances_data_map(world); auto instances_data_map = get_instances_data_map(world, m_renderer);
for (auto& [id, data] : instances_data_map) { for (auto& [id, data] : instances_data_map) {
m_renderer.model_renderer().build_vertices(id, data); m_renderer.model_renderer().build_vertices(id, data);
} }