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.
This commit is contained in:
CodingJellyfish 2024-04-15 22:30:08 +08:00 committed by GitHub
parent 6cf094ab78
commit 8577408cec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 60 additions and 46 deletions

View File

@ -145,42 +145,52 @@ void DrawCalls::parseSceneManager(core::array<scene::ISceneNode*> &List,
{ {
for (unsigned i = 0; i < List.size(); ++i) for (unsigned i = 0; i < List.size(); ++i)
{ {
if (LODNode *node = dynamic_cast<LODNode *>(List[i]))
{
node->updateVisibility();
}
List[i]->updateAbsolutePosition();
if (!List[i]->isVisible()) if (!List[i]->isVisible())
continue; continue;
if (STKParticle *node = dynamic_cast<STKParticle*>(List[i])) if (List[i]->getType() == ESNT_LOD_NODE)
{ {
LODNode *node = static_cast<LODNode *>(List[i]);
core::array<scene::ISceneNode*> 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<SP::SPMeshNode*>(List[i]);
SP::addObject(node);
}
else if (STKParticle *node = dynamic_cast<STKParticle*>(List[i]))
{
node->updateAbsolutePosition();
if (!isCulledPrecise(cam, List[i], irr_driver->getBoundingBoxesViz())) if (!isCulledPrecise(cam, List[i], irr_driver->getBoundingBoxesViz()))
CPUParticleManager::getInstance()->addParticleNode(node); CPUParticleManager::getInstance()->addParticleNode(node);
continue; continue;
} }
else if (scene::IBillboardSceneNode *node =
if (scene::IBillboardSceneNode *node =
dynamic_cast<scene::IBillboardSceneNode*>(List[i])) dynamic_cast<scene::IBillboardSceneNode*>(List[i]))
{ {
node->updateAbsolutePosition();
if (!isCulledPrecise(cam, List[i])) if (!isCulledPrecise(cam, List[i]))
CPUParticleManager::getInstance()->addBillboardNode(node); CPUParticleManager::getInstance()->addBillboardNode(node);
continue; continue;
} }
else if (STKTextBillboard *tb =
if (STKTextBillboard *tb =
dynamic_cast<STKTextBillboard*>(List[i])) dynamic_cast<STKTextBillboard*>(List[i]))
{ {
node->updateAbsolutePosition();
if (!isCulledPrecise(cam, List[i], irr_driver->getBoundingBoxesViz())) if (!isCulledPrecise(cam, List[i], irr_driver->getBoundingBoxesViz()))
TextBillboardDrawer::addTextBillboard(tb); TextBillboardDrawer::addTextBillboard(tb);
continue; continue;
} }
SP::SPMeshNode* node = dynamic_cast<SP::SPMeshNode*>(List[i]);
if (node)
{
SP::addObject(node);
}
parseSceneManager(List[i]->getChildren(), cam); parseSceneManager(List[i]->getChildren(), cam);
} }
} }

View File

@ -49,13 +49,8 @@ LODNode::LODNode(std::string group_name, scene::ISceneNode* parent,
m_forced_lod = -1; m_forced_lod = -1;
m_area = 0; m_area = 0;
#ifndef SERVER_ONLY m_current_level = -1;
if (!CVS->isGLSL()) m_current_level_dirty = true;
{
m_current_level.reset(new int);
*m_current_level = -1;
}
#endif
} }
LODNode::~LODNode() LODNode::~LODNode()
@ -79,6 +74,10 @@ int LODNode::getLevel()
if (m_forced_lod >- 1) if (m_forced_lod >- 1)
return m_forced_lod; return m_forced_lod;
if (!m_current_level_dirty)
return m_current_level;
m_current_level_dirty = false;
Camera* camera = Camera::getActiveCamera(); Camera* camera = Camera::getActiveCamera();
if (camera == NULL) if (camera == NULL)
return (int)m_detail.size() - 1; return (int)m_detail.size() - 1;
@ -90,9 +89,12 @@ int LODNode::getLevel()
for (unsigned int n=0; n<m_detail.size(); n++) for (unsigned int n=0; n<m_detail.size(); n++)
{ {
if (dist < m_detail[n]) if (dist < m_detail[n])
{
m_current_level = n;
return n; return n;
} }
}
m_current_level = -1;
return -1; return -1;
} // getLevel } // getLevel
@ -108,6 +110,8 @@ void LODNode::forceLevelOfDetail(int n)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void LODNode::OnAnimate(u32 timeMs) void LODNode::OnAnimate(u32 timeMs)
{ {
updateVisibility();
if (isVisible() && m_nodes.size() > 0) if (isVisible() && m_nodes.size() > 0)
{ {
// update absolute position // update absolute position
@ -126,7 +130,6 @@ void LODNode::OnAnimate(u32 timeMs)
#endif #endif
{ {
int level = getLevel(); int level = getLevel();
*m_current_level = level;
// Assume all the scene node have the same bouding box // Assume all the scene node have the same bouding box
if(level >= 0) if(level >= 0)
{ {
@ -154,29 +157,22 @@ void LODNode::OnAnimate(u32 timeMs)
} }
} }
void LODNode::updateVisibility(bool* shown) void LODNode::updateVisibility()
{ {
if (!isVisible()) return; if (!isVisible()) return;
if (m_nodes.size() == 0) return; if (m_nodes.size() == 0) return;
unsigned int level = 0; m_current_level_dirty = true;
if (m_current_level) unsigned int level = getLevel();
level = *m_current_level;
else
level = getLevel();
for (size_t i = 0; i < m_nodes.size(); i++) for (size_t i = 0; i < m_nodes.size(); i++)
{ {
m_nodes[i]->setVisible(i == level); m_nodes[i]->setVisible(i == level);
if (i == level && shown != NULL)
*shown = (i > 0);
} }
} }
void LODNode::OnRegisterSceneNode() void LODNode::OnRegisterSceneNode()
{ {
bool shown = false;
updateVisibility(&shown);
#ifndef SERVER_ONLY #ifndef SERVER_ONLY
if (CVS->isGLSL()) if (CVS->isGLSL())
{ {
@ -184,14 +180,20 @@ void LODNode::OnRegisterSceneNode()
} }
#endif #endif
#ifndef SERVER_ONLY if (isVisible() && m_nodes.size() > 0)
if (!CVS->isGLSL())
{ {
for (unsigned i = 0; i < Children.size(); ++i) int level = getLevel();
Children[i]->updateAbsolutePosition();
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 /* Each model with LoD has specific distances beyond which it is rendered at a lower

View File

@ -63,7 +63,8 @@ private:
* m_forced_lod is >=0, only this level is be used. */ * m_forced_lod is >=0, only this level is be used. */
int m_forced_lod; int m_forced_lod;
std::unique_ptr<int> m_current_level; int m_current_level;
bool m_current_level_dirty;
// Area of the bounding box (for autoLOD computation) // Area of the bounding box (for autoLOD computation)
float m_area; float m_area;
@ -79,7 +80,7 @@ public:
int getLevel(); int getLevel();
void updateVisibility(bool* shown = NULL); void updateVisibility();
/* /*
//! Returns a reference to the current relative transformation matrix. //! Returns a reference to the current relative transformation matrix.
@ -115,6 +116,7 @@ public:
} }
std::vector<scene::ISceneNode*>& getAllNodes() { return m_nodes; } std::vector<scene::ISceneNode*>& getAllNodes() { return m_nodes; }
std::set<scene::ISceneNode*>& getNodesSet() { return m_nodes_set; }
//! OnAnimate() is called just before rendering the whole scene. //! OnAnimate() is called just before rendering the whole scene.
/** This method will be called once per frame, independent /** This method will be called once per frame, independent