From 1726b82a16a9778c2c9d34f3676ebed7500cc45a Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Wed, 2 Nov 2011 18:13:56 +0200 Subject: [PATCH] occlusion culling fix, a little reshaping of map rendering for more useful profiler output and dynamic profiler text size --- src/defaultsettings.cpp | 1 + src/game.cpp | 40 +++++++-- src/map.cpp | 188 +++++++++++++++++++++++----------------- src/utility.cpp | 28 +++--- 4 files changed, 157 insertions(+), 100 deletions(-) diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index fea000804..74c9af1c3 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -46,6 +46,7 @@ void set_default_settings(Settings *settings) settings->setDefault("keymap_screenshot", "KEY_F12"); settings->setDefault("keymap_toggle_profiler", "KEY_F2"); settings->setDefault("keymap_toggle_force_fog_off", "KEY_F3"); + settings->setDefault("keymap_toggle_update_camera", "KEY_F4"); // Some (temporary) keys for debugging settings->setDefault("keymap_print_debug_stacks", "KEY_KEY_P"); diff --git a/src/game.cpp b/src/game.cpp index c67660ec8..d666dbcdf 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -888,11 +888,11 @@ void the_game( //guitext_chat->setBackgroundColor(video::SColor(96,0,0,0)); core::list chat_lines; - // Profiler text + // Profiler text (size is updated when text is updated) gui::IGUIStaticText *guitext_profiler = guienv->addStaticText( L"", - core::rect(6, 4+(text_height+5)*3, 400, - (text_height+5)*3 + text_height*35), + core::rect(6, 4+(text_height+5)*2, 400, + (text_height+5)*2 + text_height*35), false, false); guitext_profiler->setBackgroundColor(video::SColor(80,0,0,0)); guitext_profiler->setVisible(false); @@ -951,8 +951,8 @@ void the_game( bool respawn_menu_active = false; bool show_profiler = false; - bool force_fog_off = false; + bool disable_camera_update = false; /* Main loop @@ -1188,9 +1188,18 @@ void the_game( std::ostringstream os(std::ios_base::binary); 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(); + + s32 w = font->getDimension(text.c_str()).Width; + if(w < 400) + w = 400; + core::rect 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; 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"))) { 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 @@ -1573,11 +1598,10 @@ void the_game( v3f camera_direction = camera.getDirection(); f32 camera_fov = camera.getFovMax(); - if(FIELD_OF_VIEW_TEST) - client.updateCamera(v3f(0,0,0), v3f(0,0,1), camera_fov); - else + if(!disable_camera_update){ client.updateCamera(camera_position, camera_direction, camera_fov); + } //timer2.stop(); //TimeTaker //timer3("//timer3"); diff --git a/src/map.cpp b/src/map.cpp index 8aad4e539..1eb8ac2fc 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -3620,6 +3620,12 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) 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 */ @@ -3689,27 +3695,19 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) // Blocks from which stuff was actually drawn u32 blocks_without_stuff = 0; - int timecheck_counter = 0; - core::map::Iterator si; - 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." - < drawset; + { + ScopeProfiler sp(g_profiler, prefix+"collecting blocks for drawing", SPT_AVG); + + for(core::map::Iterator + si = m_sectors.getIterator(); + si.atEnd() == false; si++) + { MapSector *sector = si.getNode()->getValue(); v2s16 sp = sector->getPos(); @@ -3726,11 +3724,11 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) sector->getBlocks(sectorblocks); /* - Draw blocks + Loop through blocks in sector */ - - u32 sector_blocks_drawn = 0; + u32 sector_blocks_drawn = 0; + core::list< MapBlock * >::Iterator i; for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++) { @@ -3744,7 +3742,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) float range = 100000 * BS; if(m_control.range_all == false) range = m_control.wanted_range * BS; - + float d = 0.0; if(isBlockInSight(block->getPos(), camera_position, camera_direction, camera_fov, @@ -3753,16 +3751,16 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) continue; } - // Okay, this block will be drawn. Reset usage timer. - block->resetUsageTimer(); - // This is ugly (spherical distance limit?) /*if(m_control.range_all == false && d - 0.5*BS*MAP_BLOCKSIZE > range) continue;*/ - blocks_in_range++; + // This block is in range. Reset usage timer. + block->resetUsageTimer(); + blocks_in_range++; + #if 1 /* Update expired mesh (used for day/night change) @@ -3812,11 +3810,8 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) mesh_expired = false; } - #endif - /* - Draw the faces of the block - */ + { JMutexAutoLock lock(block->mesh_mutex); @@ -3832,66 +3827,103 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) && m_control.range_all == false && d > m_control.wanted_min_range * BS) continue; - - blocks_drawn++; - sector_blocks_drawn++; - - u32 c = mesh->getMeshBufferCount(); - bool stuff_actually_drawn = false; - for(u32 i=0; igetMeshBuffer(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 ["<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 if(sector_blocks_drawn != 0) - { 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::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." + <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; igetMeshBuffer(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 ["<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 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) - 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); - 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); if(blocks_had_pass_meshbuf != 0) g_profiler->avg(prefix+"meshbuffers per block", diff --git a/src/utility.cpp b/src/utility.cpp index 0139281fa..7ffbe7160 100644 --- a/src/utility.cpp +++ b/src/utility.cpp @@ -236,21 +236,21 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, // If block is (nearly) touching the camera, don't // bother validating further (that is, render it anyway) - if(d > block_max_radius) - { - // 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 - // (as the block has to be shown even if it's a bit off FOV) - // This is an estimate. - cosangle += block_max_radius / dforward; + 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 + // (as the block has to be shown even if it's a bit off FOV) + // 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; - } + // If block is not in the field of view, skip it + if(cosangle < cos(camera_fov / 2)) + return false; return true; }