occlusion culling fix, a little reshaping of map rendering for more useful profiler output and dynamic profiler text size

This commit is contained in:
Perttu Ahola 2011-11-02 18:13:56 +02:00
parent 03db16d55b
commit 1726b82a16
4 changed files with 157 additions and 100 deletions

@ -46,6 +46,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("keymap_screenshot", "KEY_F12"); settings->setDefault("keymap_screenshot", "KEY_F12");
settings->setDefault("keymap_toggle_profiler", "KEY_F2"); settings->setDefault("keymap_toggle_profiler", "KEY_F2");
settings->setDefault("keymap_toggle_force_fog_off", "KEY_F3"); settings->setDefault("keymap_toggle_force_fog_off", "KEY_F3");
settings->setDefault("keymap_toggle_update_camera", "KEY_F4");
// Some (temporary) keys for debugging // Some (temporary) keys for debugging
settings->setDefault("keymap_print_debug_stacks", "KEY_KEY_P"); settings->setDefault("keymap_print_debug_stacks", "KEY_KEY_P");

@ -888,11 +888,11 @@ void the_game(
//guitext_chat->setBackgroundColor(video::SColor(96,0,0,0)); //guitext_chat->setBackgroundColor(video::SColor(96,0,0,0));
core::list<ChatLine> chat_lines; core::list<ChatLine> chat_lines;
// Profiler text // Profiler text (size is updated when text is updated)
gui::IGUIStaticText *guitext_profiler = guienv->addStaticText( gui::IGUIStaticText *guitext_profiler = guienv->addStaticText(
L"<Profiler>", L"<Profiler>",
core::rect<s32>(6, 4+(text_height+5)*3, 400, core::rect<s32>(6, 4+(text_height+5)*2, 400,
(text_height+5)*3 + text_height*35), (text_height+5)*2 + text_height*35),
false, false); false, false);
guitext_profiler->setBackgroundColor(video::SColor(80,0,0,0)); guitext_profiler->setBackgroundColor(video::SColor(80,0,0,0));
guitext_profiler->setVisible(false); guitext_profiler->setVisible(false);
@ -951,8 +951,8 @@ void the_game(
bool respawn_menu_active = false; bool respawn_menu_active = false;
bool show_profiler = false; bool show_profiler = false;
bool force_fog_off = false; bool force_fog_off = false;
bool disable_camera_update = false;
/* /*
Main loop Main loop
@ -1188,9 +1188,18 @@ void the_game(
std::ostringstream os(std::ios_base::binary); std::ostringstream os(std::ios_base::binary);
g_profiler->print(os); g_profiler->print(os);
guitext_profiler->setText(narrow_to_wide(os.str()).c_str()); std::wstring text = narrow_to_wide(os.str());
guitext_profiler->setText(text.c_str());
g_profiler->clear(); g_profiler->clear();
s32 w = font->getDimension(text.c_str()).Width;
if(w < 400)
w = 400;
core::rect<s32> rect(6, 4+(text_height+5)*2, 12+w,
8+(text_height+5)*2 +
font->getDimension(text.c_str()).Height);
guitext_profiler->setRelativePosition(rect);
} }
/* /*
@ -1324,10 +1333,26 @@ void the_game(
{ {
show_profiler = !show_profiler; show_profiler = !show_profiler;
guitext_profiler->setVisible(show_profiler); guitext_profiler->setVisible(show_profiler);
if(show_profiler)
chat_lines.push_back(ChatLine(L"Profiler disabled"));
else
chat_lines.push_back(ChatLine(L"Profiler enabled"));
} }
else if(input->wasKeyDown(getKeySetting("keymap_toggle_force_fog_off"))) else if(input->wasKeyDown(getKeySetting("keymap_toggle_force_fog_off")))
{ {
force_fog_off = !force_fog_off; force_fog_off = !force_fog_off;
if(force_fog_off)
chat_lines.push_back(ChatLine(L"Fog disabled"));
else
chat_lines.push_back(ChatLine(L"Fog enabled"));
}
else if(input->wasKeyDown(getKeySetting("keymap_toggle_update_camera")))
{
disable_camera_update = !disable_camera_update;
if(disable_camera_update)
chat_lines.push_back(ChatLine(L"Camera update disabled"));
else
chat_lines.push_back(ChatLine(L"Camera update enabled"));
} }
// Item selection with mouse wheel // Item selection with mouse wheel
@ -1573,11 +1598,10 @@ void the_game(
v3f camera_direction = camera.getDirection(); v3f camera_direction = camera.getDirection();
f32 camera_fov = camera.getFovMax(); f32 camera_fov = camera.getFovMax();
if(FIELD_OF_VIEW_TEST) if(!disable_camera_update){
client.updateCamera(v3f(0,0,0), v3f(0,0,1), camera_fov);
else
client.updateCamera(camera_position, client.updateCamera(camera_position,
camera_direction, camera_fov); camera_direction, camera_fov);
}
//timer2.stop(); //timer2.stop();
//TimeTaker //timer3("//timer3"); //TimeTaker //timer3("//timer3");

@ -3620,6 +3620,12 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT; bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
std::string prefix;
if(pass == scene::ESNRP_SOLID)
prefix = "CM: solid: ";
else
prefix = "CM: transparent: ";
/* /*
This is called two times per frame, reset on the non-transparent one This is called two times per frame, reset on the non-transparent one
*/ */
@ -3689,27 +3695,19 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
// Blocks from which stuff was actually drawn // Blocks from which stuff was actually drawn
u32 blocks_without_stuff = 0; u32 blocks_without_stuff = 0;
int timecheck_counter = 0; /*
core::map<v2s16, MapSector*>::Iterator si; Collect a set of blocks for drawing
si = m_sectors.getIterator(); */
for(; si.atEnd() == false; si++)
{
{
timecheck_counter++;
if(timecheck_counter > 50)
{
timecheck_counter = 0;
int time2 = time(0);
if(time2 > time1 + 4)
{
infostream<<"ClientMap::renderMap(): "
"Rendering takes ages, returning."
<<std::endl;
return;
}
}
}
core::map<v3s16, MapBlock*> drawset;
{
ScopeProfiler sp(g_profiler, prefix+"collecting blocks for drawing", SPT_AVG);
for(core::map<v2s16, MapSector*>::Iterator
si = m_sectors.getIterator();
si.atEnd() == false; si++)
{
MapSector *sector = si.getNode()->getValue(); MapSector *sector = si.getNode()->getValue();
v2s16 sp = sector->getPos(); v2s16 sp = sector->getPos();
@ -3726,7 +3724,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
sector->getBlocks(sectorblocks); sector->getBlocks(sectorblocks);
/* /*
Draw blocks Loop through blocks in sector
*/ */
u32 sector_blocks_drawn = 0; u32 sector_blocks_drawn = 0;
@ -3753,14 +3751,14 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
continue; continue;
} }
// Okay, this block will be drawn. Reset usage timer.
block->resetUsageTimer();
// This is ugly (spherical distance limit?) // This is ugly (spherical distance limit?)
/*if(m_control.range_all == false && /*if(m_control.range_all == false &&
d - 0.5*BS*MAP_BLOCKSIZE > range) d - 0.5*BS*MAP_BLOCKSIZE > range)
continue;*/ continue;*/
// This block is in range. Reset usage timer.
block->resetUsageTimer();
blocks_in_range++; blocks_in_range++;
#if 1 #if 1
@ -3812,11 +3810,8 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
mesh_expired = false; mesh_expired = false;
} }
#endif #endif
/*
Draw the faces of the block
*/
{ {
JMutexAutoLock lock(block->mesh_mutex); JMutexAutoLock lock(block->mesh_mutex);
@ -3832,66 +3827,103 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
&& m_control.range_all == false && m_control.range_all == false
&& d > m_control.wanted_min_range * BS) && d > m_control.wanted_min_range * BS)
continue; continue;
blocks_drawn++;
sector_blocks_drawn++;
u32 c = mesh->getMeshBufferCount();
bool stuff_actually_drawn = false;
for(u32 i=0; i<c; i++)
{
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
const video::SMaterial& material = buf->getMaterial();
video::IMaterialRenderer* rnd =
driver->getMaterialRenderer(material.MaterialType);
bool transparent = (rnd && rnd->isTransparent());
// Render transparent on transparent pass and likewise.
if(transparent == is_transparent_pass)
{
if(buf->getVertexCount() == 0)
errorstream<<"Block ["<<analyze_block(block)
<<"] contains an empty meshbuf"<<std::endl;
/*
This *shouldn't* hurt too much because Irrlicht
doesn't change opengl textures if the old
material has the same texture.
*/
driver->setMaterial(buf->getMaterial());
driver->drawMeshBuffer(buf);
vertex_count += buf->getVertexCount();
meshbuffer_count++;
stuff_actually_drawn = true;
}
}
if(stuff_actually_drawn)
blocks_had_pass_meshbuf++;
else
blocks_without_stuff++;
} }
drawset[block->getPos()] = block;
sector_blocks_drawn++;
blocks_drawn++;
} // foreach sectorblocks } // foreach sectorblocks
if(sector_blocks_drawn != 0) if(sector_blocks_drawn != 0)
{
m_last_drawn_sectors[sp] = true; m_last_drawn_sectors[sp] = true;
}
} // ScopeProfiler
/*
Draw the selected MapBlocks
*/
{
ScopeProfiler sp(g_profiler, prefix+"drawing blocks", SPT_AVG);
int timecheck_counter = 0;
for(core::map<v3s16, MapBlock*>::Iterator
i = drawset.getIterator();
i.atEnd() == false; i++)
{
{
timecheck_counter++;
if(timecheck_counter > 50)
{
timecheck_counter = 0;
int time2 = time(0);
if(time2 > time1 + 4)
{
infostream<<"ClientMap::renderMap(): "
"Rendering takes ages, returning."
<<std::endl;
return;
}
}
}
MapBlock *block = i.getNode()->getValue();
/*
Draw the faces of the block
*/
{
JMutexAutoLock lock(block->mesh_mutex);
scene::SMesh *mesh = block->mesh;
assert(mesh);
u32 c = mesh->getMeshBufferCount();
bool stuff_actually_drawn = false;
for(u32 i=0; i<c; i++)
{
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
const video::SMaterial& material = buf->getMaterial();
video::IMaterialRenderer* rnd =
driver->getMaterialRenderer(material.MaterialType);
bool transparent = (rnd && rnd->isTransparent());
// Render transparent on transparent pass and likewise.
if(transparent == is_transparent_pass)
{
if(buf->getVertexCount() == 0)
errorstream<<"Block ["<<analyze_block(block)
<<"] contains an empty meshbuf"<<std::endl;
/*
This *shouldn't* hurt too much because Irrlicht
doesn't change opengl textures if the old
material has the same texture.
*/
driver->setMaterial(buf->getMaterial());
driver->drawMeshBuffer(buf);
vertex_count += buf->getVertexCount();
meshbuffer_count++;
stuff_actually_drawn = true;
}
}
if(stuff_actually_drawn)
blocks_had_pass_meshbuf++;
else
blocks_without_stuff++;
} }
} }
} // ScopeProfiler
std::string prefix = "CM: ";
// Log only on solid pass because values are the same // Log only on solid pass because values are the same
if(pass == scene::ESNRP_SOLID){ if(pass == scene::ESNRP_SOLID){
g_profiler->avg(prefix+"blocks in range", blocks_in_range); g_profiler->avg("CM: blocks in range", blocks_in_range);
if(blocks_in_range != 0) if(blocks_in_range != 0)
g_profiler->avg(prefix+"blocks in range without mesh (frac)", g_profiler->avg("CM: blocks in range without mesh (frac)",
(float)blocks_in_range_without_mesh/blocks_in_range); (float)blocks_in_range_without_mesh/blocks_in_range);
g_profiler->avg(prefix+"blocks drawn", blocks_drawn); g_profiler->avg("CM: blocks drawn", blocks_drawn);
} }
if(pass == scene::ESNRP_SOLID)
prefix = "CM: solid: ";
else
prefix = "CM: transparent: ";
g_profiler->avg(prefix+"vertices drawn", vertex_count); g_profiler->avg(prefix+"vertices drawn", vertex_count);
if(blocks_had_pass_meshbuf != 0) if(blocks_had_pass_meshbuf != 0)
g_profiler->avg(prefix+"meshbuffers per block", g_profiler->avg(prefix+"meshbuffers per block",

@ -236,21 +236,21 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
// If block is (nearly) touching the camera, don't // If block is (nearly) touching the camera, don't
// bother validating further (that is, render it anyway) // bother validating further (that is, render it anyway)
if(d > block_max_radius) if(d < block_max_radius)
{ return true;
// Cosine of the angle between the camera direction
// and the block direction (camera_dir is an unit vector)
f32 cosangle = dforward / d;
// Compensate for the size of the block // Cosine of the angle between the camera direction
// (as the block has to be shown even if it's a bit off FOV) // and the block direction (camera_dir is an unit vector)
// This is an estimate. f32 cosangle = dforward / d;
cosangle += block_max_radius / dforward;
// If block is not in the field of view, skip it // Compensate for the size of the block
if(cosangle < cos(camera_fov / 2)) // (as the block has to be shown even if it's a bit off FOV)
return false; // This is an estimate, plus an arbitary factor
} cosangle += block_max_radius / d * 0.5;
// If block is not in the field of view, skip it
if(cosangle < cos(camera_fov / 2))
return false;
return true; return true;
} }