void ClientMap::updateDrawList(video::IVideoDriver* driver) { ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG); g_profiler->add("CM::updateDrawList() count", 1); INodeDefManager *nodemgr = m_gamedef->ndef(); for (std::map<v3s16, MapBlock*>::iterator i = m_drawlist.begin(); i != m_drawlist.end(); ++i) { MapBlock *block = i->second; block->refDrop(); } m_drawlist.clear(); v3f camera_position = m_camera_position; v3f camera_direction = m_camera_direction; f32 camera_fov = m_camera_fov; // Use a higher fov to accomodate faster camera movements. // Blocks are cropped better when they are drawn. // Or maybe they aren't? Well whatever. camera_fov *= 1.2; v3s16 cam_pos_nodes = floatToInt(camera_position, BS); v3s16 p_blocks_min; v3s16 p_blocks_max; getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max); // Number of blocks in rendering range u32 blocks_in_range = 0; // Number of blocks occlusion culled u32 blocks_occlusion_culled = 0; // Number of blocks in rendering range but don't have a mesh u32 blocks_in_range_without_mesh = 0; // Blocks that had mesh that would have been drawn according to // rendering range (if max blocks limit didn't kick in) u32 blocks_would_have_drawn = 0; // Blocks that were drawn and had a mesh u32 blocks_drawn = 0; // Blocks which had a corresponding meshbuffer for this pass //u32 blocks_had_pass_meshbuf = 0; // Blocks from which stuff was actually drawn //u32 blocks_without_stuff = 0; // Distance to farthest drawn block float farthest_drawn = 0; for (std::map<v2s16, MapSector*>::iterator si = m_sectors.begin(); si != m_sectors.end(); ++si) { MapSector *sector = si->second; v2s16 sp = sector->getPos(); if (m_control.range_all == false) { if (sp.X < p_blocks_min.X || sp.X > p_blocks_max.X || sp.Y < p_blocks_min.Z || sp.Y > p_blocks_max.Z) continue; } MapBlockVect sectorblocks; sector->getBlocks(sectorblocks); /* Loop through blocks in sector */ u32 sector_blocks_drawn = 0; for (MapBlockVect::iterator i = sectorblocks.begin(); i != sectorblocks.end(); ++i) { MapBlock *block = *i; /* Compare block position to camera position, skip if not seen on display */ if (block->mesh != NULL) block->mesh->updateCameraOffset(m_camera_offset); 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, range, &d)) continue; // This is ugly (spherical distance limit?) /*if(m_control.range_all == false && d - 0.5*BS*MAP_BLOCKSIZE > range) continue;*/ blocks_in_range++; /* Ignore if mesh doesn't exist */ { //MutexAutoLock lock(block->mesh_mutex); if (block->mesh == NULL) { blocks_in_range_without_mesh++; continue; } } /* Occlusion culling */ // No occlusion culling when free_move is on and camera is // inside ground bool occlusion_culling_enabled = true; if (g_settings->getBool("free_move")) { MapNode n = getNodeNoEx(cam_pos_nodes); if (n.getContent() == CONTENT_IGNORE || nodemgr->get(n).solidness == 2) occlusion_culling_enabled = false; } v3s16 cpn = block->getPos() * MAP_BLOCKSIZE; cpn += v3s16(MAP_BLOCKSIZE / 2, MAP_BLOCKSIZE / 2, MAP_BLOCKSIZE / 2); float step = BS * 1; float stepfac = 1.1; float startoff = BS * 1; // The occlusion search of 'isOccluded()' must stop short of the target // point by distance 'endoff' (end offset) to not enter the target mapblock. // For the 8 mapblock corners 'endoff' must therefore be the maximum diagonal // of a mapblock, because we must consider all view angles. // sqrt(1^2 + 1^2 + 1^2) = 1.732 float endoff = -BS * MAP_BLOCKSIZE * 1.732050807569; v3s16 spn = cam_pos_nodes; s16 bs2 = MAP_BLOCKSIZE / 2 + 1; // to reduce the likelihood of falsely occluded blocks // require at least two solid blocks // this is a HACK, we should think of a more precise algorithm u32 needed_count = 2; if (occlusion_culling_enabled && // For the central point of the mapblock 'endoff' can be halved isOccluded(this, spn, cpn, step, stepfac, startoff, endoff / 2.0f, needed_count, nodemgr) && isOccluded(this, spn, cpn + v3s16(bs2,bs2,bs2), step, stepfac, startoff, endoff, needed_count, nodemgr) && isOccluded(this, spn, cpn + v3s16(bs2,bs2,-bs2), step, stepfac, startoff, endoff, needed_count, nodemgr) && isOccluded(this, spn, cpn + v3s16(bs2,-bs2,bs2), step, stepfac, startoff, endoff, needed_count, nodemgr) && isOccluded(this, spn, cpn + v3s16(bs2,-bs2,-bs2), step, stepfac, startoff, endoff, needed_count, nodemgr) && isOccluded(this, spn, cpn + v3s16(-bs2,bs2,bs2), step, stepfac, startoff, endoff, needed_count, nodemgr) && isOccluded(this, spn, cpn + v3s16(-bs2,bs2,-bs2), step, stepfac, startoff, endoff, needed_count, nodemgr) && isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,bs2), step, stepfac, startoff, endoff, needed_count, nodemgr) && isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,-bs2), step, stepfac, startoff, endoff, needed_count, nodemgr)) { blocks_occlusion_culled++; continue; } // This block is in range. Reset usage timer. block->resetUsageTimer(); // Limit block count in case of a sudden increase blocks_would_have_drawn++; if (blocks_drawn >= m_control.wanted_max_blocks && !m_control.range_all && d > m_control.wanted_range * BS) continue; // Add to set block->refGrab(); m_drawlist[block->getPos()] = block; sector_blocks_drawn++; blocks_drawn++; if (d / BS > farthest_drawn) farthest_drawn = d / BS; } // foreach sectorblocks if (sector_blocks_drawn != 0) m_last_drawn_sectors.insert(sp); } m_control.blocks_would_have_drawn = blocks_would_have_drawn; m_control.blocks_drawn = blocks_drawn; m_control.farthest_drawn = farthest_drawn; g_profiler->avg("CM: blocks in range", blocks_in_range); g_profiler->avg("CM: blocks occlusion culled", blocks_occlusion_culled); if (blocks_in_range != 0) g_profiler->avg("CM: blocks in range without mesh (frac)", (float)blocks_in_range_without_mesh / blocks_in_range); g_profiler->avg("CM: blocks drawn", blocks_drawn); g_profiler->avg("CM: farthest drawn", farthest_drawn); g_profiler->avg("CM: wanted max blocks", m_control.wanted_max_blocks); }
void ClientMap::updateDrawList(video::IVideoDriver* driver) { ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG); g_profiler->add("CM::updateDrawList() count", 1); INodeDefManager *nodemgr = m_gamedef->ndef(); for(std::map<v3s16, MapBlock*>::iterator i = m_drawlist.begin(); i != m_drawlist.end(); ++i) { MapBlock *block = i->second; block->refDrop(); } m_drawlist.clear(); m_camera_mutex.Lock(); v3f camera_position = m_camera_position; v3f camera_direction = m_camera_direction; f32 camera_fov = m_camera_fov; m_camera_mutex.Unlock(); // Use a higher fov to accomodate faster camera movements. // Blocks are cropped better when they are drawn. // Or maybe they aren't? Well whatever. camera_fov *= 1.2; v3s16 cam_pos_nodes = floatToInt(camera_position, BS); v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1); v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d; v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d; // Take a fair amount as we will be dropping more out later // Umm... these additions are a bit strange but they are needed. v3s16 p_blocks_min( p_nodes_min.X / MAP_BLOCKSIZE - 3, p_nodes_min.Y / MAP_BLOCKSIZE - 3, p_nodes_min.Z / MAP_BLOCKSIZE - 3); v3s16 p_blocks_max( p_nodes_max.X / MAP_BLOCKSIZE + 1, p_nodes_max.Y / MAP_BLOCKSIZE + 1, p_nodes_max.Z / MAP_BLOCKSIZE + 1); // Number of blocks in rendering range u32 blocks_in_range = 0; // Number of blocks occlusion culled u32 blocks_occlusion_culled = 0; // Number of blocks in rendering range but don't have a mesh u32 blocks_in_range_without_mesh = 0; // Blocks that had mesh that would have been drawn according to // rendering range (if max blocks limit didn't kick in) u32 blocks_would_have_drawn = 0; // Blocks that were drawn and had a mesh u32 blocks_drawn = 0; // Blocks which had a corresponding meshbuffer for this pass //u32 blocks_had_pass_meshbuf = 0; // Blocks from which stuff was actually drawn //u32 blocks_without_stuff = 0; for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin(); si != m_sectors.end(); ++si) { MapSector *sector = si->second; v2s16 sp = sector->getPos(); if(m_control.range_all == false) { if(sp.X < p_blocks_min.X || sp.X > p_blocks_max.X || sp.Y < p_blocks_min.Z || sp.Y > p_blocks_max.Z) continue; } std::list< MapBlock * > sectorblocks; sector->getBlocks(sectorblocks); /* Loop through blocks in sector */ u32 sector_blocks_drawn = 0; std::list< MapBlock * >::iterator i; for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++) { MapBlock *block = *i; /* Compare block position to camera position, skip if not seen on display */ 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, range, &d) == false) { continue; } // This is ugly (spherical distance limit?) /*if(m_control.range_all == false && d - 0.5*BS*MAP_BLOCKSIZE > range) continue;*/ blocks_in_range++; /* Ignore if mesh doesn't exist */ { //JMutexAutoLock lock(block->mesh_mutex); if(block->mesh == NULL){ blocks_in_range_without_mesh++; continue; } } /* Occlusion culling */ // No occlusion culling when free_move is on and camera is // inside ground bool occlusion_culling_enabled = true; if(g_settings->getBool("free_move")){ MapNode n = getNodeNoEx(cam_pos_nodes); if(n.getContent() == CONTENT_IGNORE || nodemgr->get(n).solidness == 2) occlusion_culling_enabled = false; } v3s16 cpn = block->getPos() * MAP_BLOCKSIZE; cpn += v3s16(MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2); float step = BS*1; float stepfac = 1.1; float startoff = BS*1; float endoff = -BS*MAP_BLOCKSIZE*1.42*1.42; v3s16 spn = cam_pos_nodes + v3s16(0,0,0); s16 bs2 = MAP_BLOCKSIZE/2 + 1; u32 needed_count = 1; if( occlusion_culling_enabled && isOccluded(this, spn, cpn + v3s16(0,0,0), step, stepfac, startoff, endoff, needed_count, nodemgr) && isOccluded(this, spn, cpn + v3s16(bs2,bs2,bs2), step, stepfac, startoff, endoff, needed_count, nodemgr) && isOccluded(this, spn, cpn + v3s16(bs2,bs2,-bs2), step, stepfac, startoff, endoff, needed_count, nodemgr) && isOccluded(this, spn, cpn + v3s16(bs2,-bs2,bs2), step, stepfac, startoff, endoff, needed_count, nodemgr) && isOccluded(this, spn, cpn + v3s16(bs2,-bs2,-bs2), step, stepfac, startoff, endoff, needed_count, nodemgr) && isOccluded(this, spn, cpn + v3s16(-bs2,bs2,bs2), step, stepfac, startoff, endoff, needed_count, nodemgr) && isOccluded(this, spn, cpn + v3s16(-bs2,bs2,-bs2), step, stepfac, startoff, endoff, needed_count, nodemgr) && isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,bs2), step, stepfac, startoff, endoff, needed_count, nodemgr) && isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,-bs2), step, stepfac, startoff, endoff, needed_count, nodemgr) ) { blocks_occlusion_culled++; continue; } // This block is in range. Reset usage timer. block->resetUsageTimer(); // Limit block count in case of a sudden increase blocks_would_have_drawn++; if(blocks_drawn >= m_control.wanted_max_blocks && m_control.range_all == false && d > m_control.wanted_min_range * BS) continue; // Add to set block->refGrab(); m_drawlist[block->getPos()] = block; sector_blocks_drawn++; blocks_drawn++; } // foreach sectorblocks if(sector_blocks_drawn != 0) m_last_drawn_sectors.insert(sp); } m_control.blocks_would_have_drawn = blocks_would_have_drawn; m_control.blocks_drawn = blocks_drawn; g_profiler->avg("CM: blocks in range", blocks_in_range); g_profiler->avg("CM: blocks occlusion culled", blocks_occlusion_culled); if(blocks_in_range != 0) g_profiler->avg("CM: blocks in range without mesh (frac)", (float)blocks_in_range_without_mesh/blocks_in_range); g_profiler->avg("CM: blocks drawn", blocks_drawn); g_profiler->avg("CM: wanted max blocks", m_control.wanted_max_blocks); }
void ClientMap::updateDrawList(video::IVideoDriver* driver) { ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG); g_profiler->add("CM::updateDrawList() count", 1); for (std::map<v3s16, MapBlock*>::iterator i = m_drawlist.begin(); i != m_drawlist.end(); ++i) { MapBlock *block = i->second; block->refDrop(); } m_drawlist.clear(); v3f camera_position = m_camera_position; v3f camera_direction = m_camera_direction; f32 camera_fov = m_camera_fov; // Use a higher fov to accomodate faster camera movements. // Blocks are cropped better when they are drawn. // Or maybe they aren't? Well whatever. camera_fov *= 1.2; v3s16 cam_pos_nodes = floatToInt(camera_position, BS); v3s16 p_blocks_min; v3s16 p_blocks_max; getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max); // Number of blocks in rendering range u32 blocks_in_range = 0; // Number of blocks occlusion culled u32 blocks_occlusion_culled = 0; // Number of blocks in rendering range but don't have a mesh u32 blocks_in_range_without_mesh = 0; // Blocks that had mesh that would have been drawn according to // rendering range (if max blocks limit didn't kick in) u32 blocks_would_have_drawn = 0; // Blocks that were drawn and had a mesh u32 blocks_drawn = 0; // Blocks which had a corresponding meshbuffer for this pass //u32 blocks_had_pass_meshbuf = 0; // Blocks from which stuff was actually drawn //u32 blocks_without_stuff = 0; // Distance to farthest drawn block float farthest_drawn = 0; // No occlusion culling when free_move is on and camera is // inside ground bool occlusion_culling_enabled = true; if (g_settings->getBool("free_move")) { MapNode n = getNodeNoEx(cam_pos_nodes); if (n.getContent() == CONTENT_IGNORE || m_nodedef->get(n).solidness == 2) occlusion_culling_enabled = false; } for (std::map<v2s16, MapSector*>::iterator si = m_sectors.begin(); si != m_sectors.end(); ++si) { MapSector *sector = si->second; v2s16 sp = sector->getPos(); if (m_control.range_all == false) { if (sp.X < p_blocks_min.X || sp.X > p_blocks_max.X || sp.Y < p_blocks_min.Z || sp.Y > p_blocks_max.Z) continue; } MapBlockVect sectorblocks; sector->getBlocks(sectorblocks); /* Loop through blocks in sector */ u32 sector_blocks_drawn = 0; for (MapBlockVect::iterator i = sectorblocks.begin(); i != sectorblocks.end(); ++i) { MapBlock *block = *i; /* Compare block position to camera position, skip if not seen on display */ if (block->mesh) block->mesh->updateCameraOffset(m_camera_offset); float range = 100000 * BS; if (!m_control.range_all) range = m_control.wanted_range * BS; float d = 0.0; if (!isBlockInSight(block->getPos(), camera_position, camera_direction, camera_fov, range, &d)) continue; blocks_in_range++; /* Ignore if mesh doesn't exist */ if (!block->mesh) { blocks_in_range_without_mesh++; continue; } /* Occlusion culling */ if (occlusion_culling_enabled && isBlockOccluded(block, cam_pos_nodes)) { blocks_occlusion_culled++; continue; } // This block is in range. Reset usage timer. block->resetUsageTimer(); // Limit block count in case of a sudden increase blocks_would_have_drawn++; if (blocks_drawn >= m_control.wanted_max_blocks && !m_control.range_all && d > m_control.wanted_range * BS) continue; // Add to set block->refGrab(); m_drawlist[block->getPos()] = block; sector_blocks_drawn++; blocks_drawn++; if (d / BS > farthest_drawn) farthest_drawn = d / BS; } // foreach sectorblocks if (sector_blocks_drawn != 0) m_last_drawn_sectors.insert(sp); } m_control.blocks_would_have_drawn = blocks_would_have_drawn; m_control.blocks_drawn = blocks_drawn; m_control.farthest_drawn = farthest_drawn; g_profiler->avg("CM: blocks in range", blocks_in_range); g_profiler->avg("CM: blocks occlusion culled", blocks_occlusion_culled); if (blocks_in_range != 0) g_profiler->avg("CM: blocks in range without mesh (frac)", (float)blocks_in_range_without_mesh / blocks_in_range); g_profiler->avg("CM: blocks drawn", blocks_drawn); g_profiler->avg("CM: farthest drawn", farthest_drawn); g_profiler->avg("CM: wanted max blocks", m_control.wanted_max_blocks); }