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)
{
if (LODNode *node = dynamic_cast<LODNode *>(List[i]))
{
node->updateVisibility();
}
List[i]->updateAbsolutePosition();
if (!List[i]->isVisible())
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()))
CPUParticleManager::getInstance()->addParticleNode(node);
continue;
}
if (scene::IBillboardSceneNode *node =
else if (scene::IBillboardSceneNode *node =
dynamic_cast<scene::IBillboardSceneNode*>(List[i]))
{
node->updateAbsolutePosition();
if (!isCulledPrecise(cam, List[i]))
CPUParticleManager::getInstance()->addBillboardNode(node);
continue;
}
if (STKTextBillboard *tb =
else if (STKTextBillboard *tb =
dynamic_cast<STKTextBillboard*>(List[i]))
{
node->updateAbsolutePosition();
if (!isCulledPrecise(cam, List[i], irr_driver->getBoundingBoxesViz()))
TextBillboardDrawer::addTextBillboard(tb);
continue;
}
SP::SPMeshNode* node = dynamic_cast<SP::SPMeshNode*>(List[i]);
if (node)
{
SP::addObject(node);
}
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_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,9 +71,13 @@ 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)
return (int)m_detail.size() - 1;
@ -90,9 +89,12 @@ int LODNode::getLevel()
for (unsigned int n=0; n<m_detail.size(); n++)
{
if (dist < m_detail[n])
{
m_current_level = n;
return n;
}
}
m_current_level = -1;
return -1;
} // getLevel
@ -108,6 +110,8 @@ void LODNode::forceLevelOfDetail(int n)
// ----------------------------------------------------------------------------
void LODNode::OnAnimate(u32 timeMs)
{
updateVisibility();
if (isVisible() && m_nodes.size() > 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

View File

@ -63,7 +63,8 @@ private:
* m_forced_lod is >=0, only this level is be used. */
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)
float m_area;
@ -79,7 +80,7 @@ public:
int getLevel();
void updateVisibility(bool* shown = NULL);
void updateVisibility();
/*
//! Returns a reference to the current relative transformation matrix.
@ -115,6 +116,7 @@ public:
}
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.
/** This method will be called once per frame, independent