From 8577408cec947baeafe3e114f07e482e3ad50da3 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Mon, 15 Apr 2024 22:30:08 +0800 Subject: [PATCH] LOD improvements (#5038) * Quick cull invisible LOD nodes * Reduce dynamic cast * Fix for Vulkan Maintainer's comment: Helps only in select tracks and more in already fast frames than in the more problematic slow frames, but an improvement nonetheless. --- src/graphics/draw_calls.cpp | 42 +++++++++++++++++---------- src/graphics/lod_node.cpp | 58 +++++++++++++++++++------------------ src/graphics/lod_node.hpp | 6 ++-- 3 files changed, 60 insertions(+), 46 deletions(-) diff --git a/src/graphics/draw_calls.cpp b/src/graphics/draw_calls.cpp index a642a720bbb..c8acf2f2e53 100644 --- a/src/graphics/draw_calls.cpp +++ b/src/graphics/draw_calls.cpp @@ -145,42 +145,52 @@ void DrawCalls::parseSceneManager(core::array &List, { for (unsigned i = 0; i < List.size(); ++i) { - if (LODNode *node = dynamic_cast(List[i])) - { - node->updateVisibility(); - } - List[i]->updateAbsolutePosition(); if (!List[i]->isVisible()) continue; - if (STKParticle *node = dynamic_cast(List[i])) + if (List[i]->getType() == ESNT_LOD_NODE) { + LODNode *node = static_cast(List[i]); + + core::array child; + if (node->getLevel() >= 0) + child.push_back(node->getAllNodes()[node->getLevel()]); + for (int i = 0; i < node->getChildren().size(); i++) + { + if (node->getNodesSet().find(node->getChildren()[i]) == node->getNodesSet().end()) + child.push_back(node->getChildren()[i]); + } + parseSceneManager(child, cam); + continue; + } + else if (List[i]->getType() == ESNT_ANIMATED_MESH) + { + SP::SPMeshNode* node = static_cast(List[i]); + SP::addObject(node); + } + else if (STKParticle *node = dynamic_cast(List[i])) + { + node->updateAbsolutePosition(); if (!isCulledPrecise(cam, List[i], irr_driver->getBoundingBoxesViz())) CPUParticleManager::getInstance()->addParticleNode(node); continue; } - - if (scene::IBillboardSceneNode *node = + else if (scene::IBillboardSceneNode *node = dynamic_cast(List[i])) { + node->updateAbsolutePosition(); if (!isCulledPrecise(cam, List[i])) CPUParticleManager::getInstance()->addBillboardNode(node); continue; } - - if (STKTextBillboard *tb = + else if (STKTextBillboard *tb = dynamic_cast(List[i])) { + node->updateAbsolutePosition(); if (!isCulledPrecise(cam, List[i], irr_driver->getBoundingBoxesViz())) TextBillboardDrawer::addTextBillboard(tb); continue; } - - SP::SPMeshNode* node = dynamic_cast(List[i]); - if (node) - { - SP::addObject(node); - } parseSceneManager(List[i]->getChildren(), cam); } } diff --git a/src/graphics/lod_node.cpp b/src/graphics/lod_node.cpp index 7bf1b767245..997faa0fc47 100644 --- a/src/graphics/lod_node.cpp +++ b/src/graphics/lod_node.cpp @@ -49,13 +49,8 @@ LODNode::LODNode(std::string group_name, scene::ISceneNode* parent, m_forced_lod = -1; m_area = 0; -#ifndef SERVER_ONLY - if (!CVS->isGLSL()) - { - m_current_level.reset(new int); - *m_current_level = -1; - } -#endif + m_current_level = -1; + m_current_level_dirty = true; } LODNode::~LODNode() @@ -76,8 +71,12 @@ int LODNode::getLevel() return -1; // If a level is forced, use it - if(m_forced_lod>-1) + if (m_forced_lod >- 1) return m_forced_lod; + + if (!m_current_level_dirty) + return m_current_level; + m_current_level_dirty = false; Camera* camera = Camera::getActiveCamera(); if (camera == NULL) @@ -90,9 +89,12 @@ int LODNode::getLevel() for (unsigned int n=0; n 0) { // update absolute position @@ -126,9 +130,8 @@ void LODNode::OnAnimate(u32 timeMs) #endif { int level = getLevel(); - *m_current_level = level; // Assume all the scene node have the same bouding box - if(level>=0) + if(level >= 0) { m_nodes[level]->setVisible(true); m_nodes[level]->OnAnimate(timeMs); @@ -154,29 +157,22 @@ void LODNode::OnAnimate(u32 timeMs) } } -void LODNode::updateVisibility(bool* shown) +void LODNode::updateVisibility() { if (!isVisible()) return; if (m_nodes.size() == 0) return; - unsigned int level = 0; - if (m_current_level) - level = *m_current_level; - else - level = getLevel(); + m_current_level_dirty = true; + unsigned int level = getLevel(); + for (size_t i = 0; i < m_nodes.size(); i++) { m_nodes[i]->setVisible(i == level); - if (i == level && shown != NULL) - *shown = (i > 0); } } void LODNode::OnRegisterSceneNode() { - bool shown = false; - updateVisibility(&shown); - #ifndef SERVER_ONLY if (CVS->isGLSL()) { @@ -184,14 +180,20 @@ void LODNode::OnRegisterSceneNode() } #endif -#ifndef SERVER_ONLY - if (!CVS->isGLSL()) + if (isVisible() && m_nodes.size() > 0) { - for (unsigned i = 0; i < Children.size(); ++i) - Children[i]->updateAbsolutePosition(); + int level = getLevel(); + + if (level >= 0) + { + m_nodes[level]->OnRegisterSceneNode(); + } + for (int i = 0; i < Children.size(); i++) + { + if (m_nodes_set.find(Children[i]) == m_nodes_set.end()) + Children[i]->OnRegisterSceneNode(); + } } -#endif - scene::ISceneNode::OnRegisterSceneNode(); } /* Each model with LoD has specific distances beyond which it is rendered at a lower diff --git a/src/graphics/lod_node.hpp b/src/graphics/lod_node.hpp index 174a0badce6..fe52253de79 100644 --- a/src/graphics/lod_node.hpp +++ b/src/graphics/lod_node.hpp @@ -63,7 +63,8 @@ class LODNode : public scene::ISceneNode * m_forced_lod is >=0, only this level is be used. */ int m_forced_lod; - std::unique_ptr m_current_level; + int m_current_level; + bool m_current_level_dirty; // Area of the bounding box (for autoLOD computation) float m_area; @@ -79,7 +80,7 @@ class LODNode : public scene::ISceneNode int getLevel(); - void updateVisibility(bool* shown = NULL); + void updateVisibility(); /* //! Returns a reference to the current relative transformation matrix. @@ -115,6 +116,7 @@ class LODNode : public scene::ISceneNode } std::vector& getAllNodes() { return m_nodes; } + std::set& getNodesSet() { return m_nodes_set; } //! OnAnimate() is called just before rendering the whole scene. /** This method will be called once per frame, independent