mirror of
https://github.com/minetest/minetest.git
synced 2024-11-27 18:13:46 +01:00
occlusion culling fix, a little reshaping of map rendering for more useful profiler output and dynamic profiler text size
This commit is contained in:
parent
03db16d55b
commit
1726b82a16
@ -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");
|
||||||
|
|
||||||
|
40
src/game.cpp
40
src/game.cpp
@ -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");
|
||||||
|
180
src/map.cpp
180
src/map.cpp
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user