Skip to content

Commit

Permalink
Improve Auto-LoD
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
Alayan-stk-2 committed Apr 29, 2024
1 parent ec4f406 commit 0716965
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 17 deletions.
2 changes: 1 addition & 1 deletion src/graphics/draw_calls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand Down
1 change: 1 addition & 0 deletions src/graphics/irr_driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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++)
Expand Down
8 changes: 8 additions & 0 deletions src/graphics/irr_driver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ class IrrDriver : public IEventReceiver, public NoCopy

/** 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);
Expand Down Expand Up @@ -368,12 +370,18 @@ class IrrDriver : public IEventReceiver, public NoCopy
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);
Expand Down
49 changes: 34 additions & 15 deletions src/graphics/lod_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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])
Expand Down Expand Up @@ -136,8 +146,7 @@ void LODNode::OnAnimate(u32 timeMs)
}
}
}

}
} // if isVisible() && m_nodes.size() > 0
}

void LODNode::updateVisibility()
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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;

// 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 * max_draw) / m_detail.size();
int step = (int) (max_draw) / m_detail.size();

// Then we recompute the level of detail culling distance
int biais = m_detail.size();
Expand Down
1 change: 1 addition & 0 deletions src/graphics/lod_node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class LODNode : public scene::ISceneNode
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);
Expand Down
23 changes: 22 additions & 1 deletion src/tracks/track.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down

0 comments on commit 0716965

Please sign in to comment.