Improve Auto-LoD

- Increase the Auto-LoD distance on tracks with a low scene complexity (fix #5065)
- Increase the Auto-LoD distance when the old formula gives a too low base distance (small objects). This helps with some of the worst popping issues for comparatively little performance cost.
- Make the LoD distance auto-compute code clearer by moving the settings-related multiplier after the squaring step
- Also fix a couple of unrelated warnings about comparison between signed and unsigned integers
This commit is contained in:
Alayan 2024-04-29 21:47:17 +02:00
parent ec4f4065f5
commit 0716965df7
No known key found for this signature in database
6 changed files with 67 additions and 17 deletions

View File

@ -156,7 +156,7 @@ void DrawCalls::parseSceneManager(core::array<scene::ISceneNode*> &List,
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++)
for (unsigned int i = 0; i < node->getChildren().size(); i++)
{
if (node->getNodesSet().find(node->getChildren()[i]) == node->getNodesSet().end())
child.push_back(node->getChildren()[i]);

View File

@ -210,6 +210,7 @@ IrrDriver::IrrDriver()
m_recording = false;
m_sun_interposer = NULL;
m_scene_complexity = 0;
m_lod_multiplier = 1.0f;
#ifndef SERVER_ONLY
for (unsigned i = 0; i < Q_LAST; i++)

View File

@ -155,6 +155,8 @@ private:
/** Store if the scene is complex (based on polycount, etc) */
int m_scene_complexity;
/** Used for auto-LoD adjustment in low-complexity scenes */
float m_lod_multiplier;
/** Internal method that applies the resolution in user settings. */
void applyResolutionSettings(bool recreate_device);
@ -368,12 +370,18 @@ public:
bool getBoundingBoxesViz() { return m_boundingboxesviz; }
// ------------------------------------------------------------------------
int getSceneComplexity() { return m_scene_complexity; }
// ------------------------------------------------------------------------
void resetSceneComplexity() { m_scene_complexity = 0; }
// ------------------------------------------------------------------------
void addSceneComplexity(int complexity)
{
if (complexity > 1) m_scene_complexity += (complexity - 1);
}
// ------------------------------------------------------------------------
float getLODMultiplier() { return m_lod_multiplier; }
// ------------------------------------------------------------------------
void setLODMultiplier(float multiplier) { m_lod_multiplier = multiplier; }
// ------------------------------------------------------------------------
bool isRecording() const { return m_recording; }
// ------------------------------------------------------------------------
void setRecording(bool val);

View File

@ -51,6 +51,7 @@ LODNode::LODNode(std::string group_name, scene::ISceneNode* parent,
m_area = 0;
m_current_level = -1;
m_current_level_dirty = true;
m_lod_distances_updated = false;
}
LODNode::~LODNode()
@ -86,6 +87,15 @@ int LODNode::getLevel()
const int dist =
(int)((m_nodes[0]->getAbsolutePosition()).getDistanceFromSQ(pos.toIrrVector() ));
if (!m_lod_distances_updated)
{
for (unsigned int n=0; n<m_detail.size(); n++)
{
m_detail[n] = (int)((float)m_detail[n] * irr_driver->getLODMultiplier());
}
m_lod_distances_updated = true;
}
for (unsigned int n=0; n<m_detail.size(); n++)
{
if (dist < m_detail[n])
@ -136,8 +146,7 @@ void LODNode::OnAnimate(u32 timeMs)
}
}
}
}
} // if isVisible() && m_nodes.size() > 0
}
void LODNode::updateVisibility()
@ -173,12 +182,12 @@ void LODNode::OnRegisterSceneNode()
{
m_nodes[level]->OnRegisterSceneNode();
}
for (int i = 0; i < Children.size(); i++)
for (unsigned i = 0; i < Children.size(); i++)
{
if (m_nodes_set.find(Children[i]) == m_nodes_set.end())
Children[i]->OnRegisterSceneNode();
}
}
} // if isVisible() && m_nodes.size() > 0
}
/* Each model with LoD has specific distances beyond which it is rendered at a lower
@ -189,18 +198,14 @@ void LODNode::autoComputeLevel(float scale)
{
m_area *= scale;
// Amount of details based on user's input
float agressivity = 1.0;
if( UserConfigParams::m_geometry_level == 0) agressivity = 1.3;
else if(UserConfigParams::m_geometry_level == 1) agressivity = 0.8;
else if(UserConfigParams::m_geometry_level == 2) agressivity = 0.8; // Also removes many objects
else if(UserConfigParams::m_geometry_level == 3) agressivity = 1.8;
else if(UserConfigParams::m_geometry_level == 4) agressivity = 2.4;
else if(UserConfigParams::m_geometry_level == 5) agressivity = 3.2;
// First we try to estimate how far away we need to draw
// This first formula is equivalent to the one used up to STK 1.4
float max_draw = 10*(sqrtf(m_area + 20) - 1);
// At really short distances, popping is more annoying even if
// the object is small, so we limit how small the distance can be
if (max_draw < 80)
max_draw = 30 + (max_draw * 0.625);
// If the draw distance is too big we artificially reduce it
// The formulas are still experimental and improvable.
if(max_draw > 250)
@ -209,9 +214,23 @@ void LODNode::autoComputeLevel(float scale)
if (max_draw > 500)
max_draw = 200 + (max_draw * 0.6);
max_draw *= agressivity;
// As it is faster to compute the squared distance than distance, at runtime
// we compare the distance saved in the LoD node with the square of the distance
// between the camera and the object. Therefore, we apply squaring here.
max_draw *= max_draw;
int step = (int) (max_draw * max_draw) / m_detail.size();
// Amount of details based on the user's input
float aggressivity = 1.0;
if( UserConfigParams::m_geometry_level == 0) aggressivity = 1.5;
else if(UserConfigParams::m_geometry_level == 1) aggressivity = 0.65;
else if(UserConfigParams::m_geometry_level == 2) aggressivity = 0.65; // Also removes many objects
else if(UserConfigParams::m_geometry_level == 3) aggressivity = 4.5;
else if(UserConfigParams::m_geometry_level == 4) aggressivity = 5.75;
else if(UserConfigParams::m_geometry_level == 5) aggressivity = 15.0;
max_draw *= aggressivity;
int step = (int) (max_draw) / m_detail.size();
// Then we recompute the level of detail culling distance
int biais = m_detail.size();

View File

@ -70,6 +70,7 @@ private:
float m_area;
bool m_update_box_every_frame;
bool m_lod_distances_updated;
public:
LODNode(std::string group_name, scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id=-1);

View File

@ -2090,7 +2090,28 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id)
loadObjects(root, path, model_def_loader, true, NULL, NULL);
main_loop->renderGUI(5000);
Log::info("Track", "Overall scene complexity estimated at %d", irr_driver->getSceneComplexity());
// If the track is low complexity, increase distances for LoD nodes
// Scene complexity is not computed before LoD nodes are loaded, so
// instead we set a variable that will be used to update the distances
// later on.
float squared_multiplier = 1.0f;
if (irr_driver->getSceneComplexity() < 1500)
{
float ratio = 1.0f;
// Cap the potential effect
if (irr_driver->getSceneComplexity() < 100)
ratio = 15.0f;
else
ratio = 1500.0f / (float)(irr_driver->getSceneComplexity());
squared_multiplier = 0.3f + 0.7f * ratio;
}
irr_driver->setLODMultiplier(squared_multiplier);
// The LoD distances are stored squared in the node, therefore the real multiplier
// is the square root of the one that gets applied
Log::info("Track", "Overall scene complexity estimated at %d, Auto-LoD multiplier is %f",
irr_driver->getSceneComplexity(), sqrtf(squared_multiplier));
// Correct the parenting of meta library
for (auto& p : m_meta_library)
{