Merge pull request #3789 from supertuxkart/feature/auto-LoD-computation
Feature/auto LoD computation
This commit is contained in:
commit
7ff6f291d2
@ -202,11 +202,17 @@ void DrawCalls::prepareDrawCalls(scene::ICameraSceneNode *camnode)
|
||||
{
|
||||
CPUParticleManager::getInstance()->reset();
|
||||
TextBillboardDrawer::reset();
|
||||
PROFILER_PUSH_CPU_MARKER("- culling", 0xFF, 0xFF, 0x0);
|
||||
PROFILER_PUSH_CPU_MARKER("- prepare draw call", 0xFF, 0xFF, 0x0);
|
||||
SP::prepareDrawCalls();
|
||||
PROFILER_POP_CPU_MARKER();
|
||||
|
||||
PROFILER_PUSH_CPU_MARKER("-- parse scene manager", 0x00, 0xFF, 0x0);
|
||||
parseSceneManager(
|
||||
irr_driver->getSceneManager()->getRootSceneNode()->getChildren(),
|
||||
camnode);
|
||||
PROFILER_POP_CPU_MARKER();
|
||||
|
||||
PROFILER_PUSH_CPU_MARKER("-- handle dynamic draw", 0x00, 0xFF, 0x0);
|
||||
SP::handleDynamicDrawCall();
|
||||
SP::updateModelMatrix();
|
||||
PROFILER_POP_CPU_MARKER();
|
||||
@ -233,21 +239,6 @@ void DrawCalls::prepareDrawCalls(scene::ICameraSceneNode *camnode)
|
||||
PROFILER_POP_CPU_MARKER();
|
||||
}
|
||||
|
||||
/* switch (reason)
|
||||
{
|
||||
case GL_ALREADY_SIGNALED:
|
||||
printf("Already Signaled\n");
|
||||
break;
|
||||
case GL_TIMEOUT_EXPIRED:
|
||||
printf("Timeout Expired\n");
|
||||
break;
|
||||
case GL_CONDITION_SATISFIED:
|
||||
printf("Condition Satisfied\n");
|
||||
break;
|
||||
case GL_WAIT_FAILED:
|
||||
printf("Wait Failed\n");
|
||||
break;
|
||||
}*/
|
||||
|
||||
PROFILER_PUSH_CPU_MARKER("- particle and text billboard upload", 0x3F,
|
||||
0x03, 0x61);
|
||||
|
@ -172,6 +172,7 @@ IrrDriver::IrrDriver()
|
||||
m_skinning_joint = 0;
|
||||
m_recording = false;
|
||||
m_sun_interposer = NULL;
|
||||
m_scene_complexity = 0;
|
||||
|
||||
#ifndef SERVER_ONLY
|
||||
for (unsigned i = 0; i < Q_LAST; i++)
|
||||
@ -1718,7 +1719,7 @@ void IrrDriver::displayFPS()
|
||||
core::rect<s32> position;
|
||||
|
||||
if (UserConfigParams::m_artist_debug_mode)
|
||||
position = core::rect<s32>(75, 0, 1100, 40);
|
||||
position = core::rect<s32>(51, 0, 1100, 80);
|
||||
else
|
||||
position = core::rect<s32>(75, 0, 900, 40);
|
||||
GL32_draw2DRectangle(video::SColor(150, 96, 74, 196), position, NULL);
|
||||
@ -1777,10 +1778,10 @@ void IrrDriver::displayFPS()
|
||||
{
|
||||
fps_string = StringUtils::insertValues
|
||||
(L"FPS: %d/%d/%d - PolyCount: %d Solid, "
|
||||
"%d Shadows - LightDist : %d, Total skinning joints: %d, "
|
||||
"%d Shadows - LightDist : %d\nComplexity %d, Total skinning joints: %d, "
|
||||
"Ping: %dms",
|
||||
min, fps, max, SP::sp_solid_poly_count,
|
||||
SP::sp_shadow_poly_count, m_last_light_bucket_distance,
|
||||
SP::sp_shadow_poly_count, m_last_light_bucket_distance, irr_driver->getSceneComplexity(),
|
||||
m_skinning_joint, ping);
|
||||
}
|
||||
else
|
||||
|
@ -150,6 +150,9 @@ private:
|
||||
/** Whether the mouse cursor is currently shown */
|
||||
bool m_pointer_shown;
|
||||
|
||||
/** Store if the scene is complex (based on polycount, etc) */
|
||||
int m_scene_complexity;
|
||||
|
||||
/** Internal method that applies the resolution in user settings. */
|
||||
void applyResolutionSettings();
|
||||
void createListOfVideoModes();
|
||||
@ -369,6 +372,13 @@ 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.0);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
bool isRecording() const { return m_recording; }
|
||||
// ------------------------------------------------------------------------
|
||||
void setRecording(bool val);
|
||||
|
@ -40,8 +40,6 @@ LODNode::LODNode(std::string group_name, scene::ISceneNode* parent,
|
||||
|
||||
m_group_name = group_name;
|
||||
|
||||
m_previous_visibility = FIRST_PASS;
|
||||
|
||||
// At this stage refcount is two: one because of the object being
|
||||
// created, and once because it is a child of the parent. Drop once,
|
||||
// so that only the reference from the parent is active, causing this
|
||||
@ -50,6 +48,17 @@ LODNode::LODNode(std::string group_name, scene::ISceneNode* parent,
|
||||
|
||||
m_forced_lod = -1;
|
||||
m_last_tick = 0;
|
||||
m_area = 0;
|
||||
|
||||
m_previous_level = 0;
|
||||
m_current_level = 0;
|
||||
|
||||
m_timer = 0;
|
||||
|
||||
is_in_transition = false;
|
||||
|
||||
//m_node_to_fade_out = 0;
|
||||
//m_node_to_fade_in = 0;
|
||||
}
|
||||
|
||||
LODNode::~LODNode()
|
||||
@ -78,14 +87,34 @@ int LODNode::getLevel()
|
||||
return (int)m_detail.size() - 1;
|
||||
const Vec3 &pos = camera->getCameraSceneNode()->getAbsolutePosition();
|
||||
|
||||
const int dist =
|
||||
int dist =
|
||||
(int)((m_nodes[0]->getAbsolutePosition()).getDistanceFromSQ(pos.toIrrVector() ));
|
||||
|
||||
// Based on the complexity of the track we are more or less aggressive with culling
|
||||
int complexity = irr_driver->getSceneComplexity();
|
||||
// The track has high complexity so we decrease the draw distance by 10%
|
||||
if (complexity > 3000 )
|
||||
{
|
||||
dist += (dist/10);
|
||||
}
|
||||
// The track has medium complexity, we can increase slightly the draw distance
|
||||
else if(complexity > 1500 )
|
||||
{
|
||||
dist -= (dist/100);
|
||||
}
|
||||
// The track has low complexity we can increase a lot the draw distance
|
||||
else
|
||||
{
|
||||
dist -= (dist/10);
|
||||
}
|
||||
|
||||
for (unsigned int n=0; n<m_detail.size(); n++)
|
||||
{
|
||||
if (dist < m_detail[n])
|
||||
{
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
} // getLevel
|
||||
@ -144,24 +173,53 @@ 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 = getLevel();
|
||||
// Don't need to run the computation of the level everytime
|
||||
if ((int)(rand()%10) == 1)
|
||||
{
|
||||
m_current_level = getLevel();
|
||||
}
|
||||
|
||||
if (m_previous_level != m_current_level && !is_in_transition)
|
||||
{
|
||||
is_in_transition = true;
|
||||
m_timer = 0;
|
||||
}
|
||||
|
||||
if (is_in_transition)
|
||||
{
|
||||
// Initially we display the previous one along the new one
|
||||
for (size_t i = 0; i < m_nodes.size(); i++)
|
||||
{
|
||||
m_nodes[i]->setVisible(i == level);
|
||||
if (i == level && shown != NULL)
|
||||
*shown = (i > 0);
|
||||
if (m_current_level == i || m_previous_level == i)
|
||||
m_nodes[i]->setVisible(true);
|
||||
}
|
||||
|
||||
// We reset counting
|
||||
if (m_timer > 20)
|
||||
{
|
||||
is_in_transition = false;
|
||||
m_previous_level = m_current_level;
|
||||
}
|
||||
m_timer ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < m_nodes.size(); i++)
|
||||
{
|
||||
m_nodes[i]->setVisible(i == m_current_level);
|
||||
}
|
||||
}
|
||||
|
||||
//const u32 now = irr_driver->getDevice()->getTimer()->getTime();
|
||||
}
|
||||
|
||||
void LODNode::OnRegisterSceneNode()
|
||||
{
|
||||
bool shown = false;
|
||||
updateVisibility(&shown);
|
||||
|
||||
#ifndef SERVER_ONLY
|
||||
if (CVS->isGLSL())
|
||||
@ -173,69 +231,7 @@ void LODNode::OnRegisterSceneNode()
|
||||
const u32 now = irr_driver->getDevice()->getTimer()->getTime();
|
||||
|
||||
// support an optional, mostly hard-coded fade-in/out effect for objects with a single level
|
||||
if (m_nodes.size() == 1 && (m_nodes[0]->getType() == scene::ESNT_MESH ||
|
||||
m_nodes[0]->getType() == scene::ESNT_ANIMATED_MESH) &&
|
||||
now > m_last_tick)
|
||||
{
|
||||
if (m_previous_visibility == WAS_HIDDEN && shown)
|
||||
{
|
||||
scene::IMesh* mesh;
|
||||
|
||||
if (m_nodes[0]->getType() == scene::ESNT_MESH)
|
||||
{
|
||||
scene::IMeshSceneNode* node = (scene::IMeshSceneNode*)(m_nodes[0]);
|
||||
mesh = node->getMesh();
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(m_nodes[0]->getType() == scene::ESNT_ANIMATED_MESH);
|
||||
scene::IAnimatedMeshSceneNode* node =
|
||||
(scene::IAnimatedMeshSceneNode*)(m_nodes[0]);
|
||||
assert(node != NULL);
|
||||
mesh = node->getMesh();
|
||||
}
|
||||
}
|
||||
else if (m_previous_visibility == WAS_SHOWN && !shown)
|
||||
{
|
||||
scene::IMesh* mesh;
|
||||
|
||||
if (m_nodes[0]->getType() == scene::ESNT_MESH)
|
||||
{
|
||||
scene::IMeshSceneNode* node = (scene::IMeshSceneNode*)(m_nodes[0]);
|
||||
mesh = node->getMesh();
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(m_nodes[0]->getType() == scene::ESNT_ANIMATED_MESH);
|
||||
scene::IAnimatedMeshSceneNode* node =
|
||||
(scene::IAnimatedMeshSceneNode*)(m_nodes[0]);
|
||||
assert(node != NULL);
|
||||
mesh = node->getMesh();
|
||||
}
|
||||
|
||||
}
|
||||
else if (m_previous_visibility == FIRST_PASS && !shown)
|
||||
{
|
||||
scene::IMesh* mesh;
|
||||
|
||||
if (m_nodes[0]->getType() == scene::ESNT_MESH)
|
||||
{
|
||||
scene::IMeshSceneNode* node = (scene::IMeshSceneNode*)(m_nodes[0]);
|
||||
mesh = node->getMesh();
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(m_nodes[0]->getType() == scene::ESNT_ANIMATED_MESH);
|
||||
scene::IAnimatedMeshSceneNode* node =
|
||||
(scene::IAnimatedMeshSceneNode*)(m_nodes[0]);
|
||||
assert(node != NULL);
|
||||
mesh = node->getMesh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_previous_visibility = (shown ? WAS_SHOWN : WAS_HIDDEN);
|
||||
m_last_tick = now;
|
||||
#ifndef SERVER_ONLY
|
||||
if (!CVS->isGLSL())
|
||||
{
|
||||
@ -249,8 +245,43 @@ void LODNode::OnRegisterSceneNode()
|
||||
scene::ISceneNode::OnRegisterSceneNode();
|
||||
}
|
||||
|
||||
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.25;
|
||||
if(UserConfigParams::m_geometry_level == 1) agressivity = 1.0;
|
||||
if(UserConfigParams::m_geometry_level == 2) agressivity = 0.75;
|
||||
|
||||
// First we try to estimate how far away we need to draw
|
||||
float max_draw = 0.0;
|
||||
max_draw = sqrtf((0.5 * m_area + 10) * 200) - 10;
|
||||
// If the draw distance is too big we artificially reduce it
|
||||
if(max_draw > 250)
|
||||
{
|
||||
max_draw = 250 + (max_draw * 0.06);
|
||||
}
|
||||
|
||||
max_draw *= agressivity;
|
||||
|
||||
int step = (int) (max_draw * max_draw) / m_detail.size();
|
||||
|
||||
// Then we recompute the level of detail culling distance
|
||||
int biais = m_detail.size();
|
||||
for(int i = 0; i < m_detail.size(); i++)
|
||||
{
|
||||
m_detail[i] = ((step / biais) * (i + 1));
|
||||
biais--;
|
||||
}
|
||||
}
|
||||
|
||||
void LODNode::add(int level, scene::ISceneNode* node, bool reparent)
|
||||
{
|
||||
Box = node->getBoundingBox();
|
||||
m_area = Box.getArea();
|
||||
|
||||
// samuncle suggested to put a slight randomisation in LOD
|
||||
// I'm not convinced (Auria) but he's the artist pro, so I listen ;P
|
||||
// The last level should not be randomized because after that the object disappears,
|
||||
@ -266,6 +297,7 @@ void LODNode::add(int level, scene::ISceneNode* node, bool reparent)
|
||||
node->grab();
|
||||
node->remove();
|
||||
node->setPosition(core::vector3df(0,0,0));
|
||||
node->setVisible(false);
|
||||
m_detail.push_back(level*level);
|
||||
m_nodes.push_back(node);
|
||||
m_nodes_set.insert(node);
|
||||
|
@ -62,14 +62,18 @@ private:
|
||||
* m_forced_lod is >=0, only this level is be used. */
|
||||
int m_forced_lod;
|
||||
|
||||
enum PreviousVisibility
|
||||
{
|
||||
FIRST_PASS,
|
||||
WAS_SHOWN,
|
||||
WAS_HIDDEN
|
||||
};
|
||||
// Area of the bounding box (for autoLOD computation)
|
||||
float m_area;
|
||||
|
||||
// Previous level for the smooth transitions
|
||||
int m_previous_level;
|
||||
int m_current_level;
|
||||
|
||||
int m_timer;
|
||||
|
||||
bool is_in_transition;
|
||||
|
||||
|
||||
PreviousVisibility m_previous_visibility;
|
||||
|
||||
u32 m_last_tick;
|
||||
|
||||
@ -83,7 +87,7 @@ public:
|
||||
|
||||
int getLevel();
|
||||
|
||||
void updateVisibility(bool* shown = NULL);
|
||||
void updateVisibility();
|
||||
|
||||
/*
|
||||
//! Returns a reference to the current relative transformation matrix.
|
||||
@ -104,6 +108,11 @@ public:
|
||||
*/
|
||||
void add(int level, scene::ISceneNode* node, bool reparent);
|
||||
|
||||
/**
|
||||
* This method can be used to automatically compute LoD level
|
||||
*/
|
||||
void autoComputeLevel(float scale);
|
||||
|
||||
void forceLevelOfDetail(int n);
|
||||
|
||||
/** Get the highest level of detail node */
|
||||
|
@ -235,7 +235,7 @@ void ShaderBasedRenderer::renderSceneDeferred(scene::ICameraSceneNode * const ca
|
||||
}
|
||||
irr_driver->getSceneManager()->setActiveCamera(camnode);
|
||||
|
||||
PROFILER_PUSH_CPU_MARKER("- Draw Call Generation", 0xFF, 0xFF, 0xFF);
|
||||
PROFILER_PUSH_CPU_MARKER("- Draw Call Generation xxx", 0xFF, 0xFF, 0xFF);
|
||||
m_draw_calls.prepareDrawCalls(camnode);
|
||||
PROFILER_POP_CPU_MARKER();
|
||||
PROFILER_PUSH_CPU_MARKER("Update Light Info", 0xFF, 0x0, 0x0);
|
||||
|
@ -142,6 +142,9 @@ LODNode* ModelDefinitionLoader::instanciateAsLOD(const XMLNode* node, scene::ISc
|
||||
lod_node->add(group[m].m_distance, scene_node, true);
|
||||
}
|
||||
}
|
||||
vector3df scale = vector3df(1.f, 1.f, 1.f);
|
||||
node->get("scale", &scale);
|
||||
lod_node->autoComputeLevel(scale.getLength());
|
||||
|
||||
#ifdef DEBUG
|
||||
std::string debug_name = groupname+" (LOD track-object)";
|
||||
|
@ -302,6 +302,7 @@ void Track::reset()
|
||||
*/
|
||||
void Track::cleanup()
|
||||
{
|
||||
irr_driver->resetSceneComplexity();
|
||||
m_physical_object_uid = 0;
|
||||
#ifdef USE_RESIZE_CACHE
|
||||
if (!UserConfigParams::m_high_definition_textures)
|
||||
@ -2018,6 +2019,7 @@ 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());
|
||||
// Correct the parenting of meta library
|
||||
for (auto& p : m_meta_library)
|
||||
{
|
||||
@ -2258,6 +2260,8 @@ void Track::loadObjects(const XMLNode* root, const std::string& path,
|
||||
const bool is_mode_ctf = m_is_ctf && race_manager->getMinorMode() ==
|
||||
RaceManager::MINOR_MODE_CAPTURE_THE_FLAG;
|
||||
|
||||
// We keep track of the complexity of the scene (amount of objects loaded, etc)
|
||||
irr_driver->addSceneComplexity(node_count);
|
||||
for (unsigned int i = 0; i < node_count; i++)
|
||||
{
|
||||
main_loop->renderGUI(4950, i, node_count);
|
||||
|
Loading…
Reference in New Issue
Block a user