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:
parent
ec4f4065f5
commit
0716965df7
@ -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]);
|
||||
|
@ -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++)
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user