clientmap.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404
  1. /*
  2. Minetest
  3. Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "clientmap.h"
  17. #include "client.h"
  18. #include "client/mesh.h"
  19. #include "mapblock_mesh.h"
  20. #include <IMaterialRenderer.h>
  21. #include <matrix4.h>
  22. #include "mapsector.h"
  23. #include "mapblock.h"
  24. #include "nodedef.h"
  25. #include "profiler.h"
  26. #include "settings.h"
  27. #include "camera.h" // CameraModes
  28. #include "util/basic_macros.h"
  29. #include "client/renderingengine.h"
  30. #include <queue>
  31. namespace {
  32. // A helper struct
  33. struct MeshBufListMaps
  34. {
  35. struct MaterialHash
  36. {
  37. size_t operator()(const video::SMaterial &m) const noexcept
  38. {
  39. // Only hash first texture. Simple and fast.
  40. return std::hash<video::ITexture *>{}(m.TextureLayers[0].Texture);
  41. }
  42. };
  43. using MeshBufListMap = std::unordered_map<
  44. video::SMaterial,
  45. std::vector<std::pair<v3s16, scene::IMeshBuffer *>>,
  46. MaterialHash>;
  47. std::array<MeshBufListMap, MAX_TILE_LAYERS> maps;
  48. void clear()
  49. {
  50. for (auto &map : maps)
  51. map.clear();
  52. }
  53. void add(scene::IMeshBuffer *buf, v3s16 position, u8 layer)
  54. {
  55. assert(layer < MAX_TILE_LAYERS);
  56. // Append to the correct layer
  57. auto &map = maps[layer];
  58. const video::SMaterial &m = buf->getMaterial();
  59. auto &bufs = map[m]; // default constructs if non-existent
  60. bufs.emplace_back(position, buf);
  61. }
  62. };
  63. }
  64. static void on_settings_changed(const std::string &name, void *data)
  65. {
  66. static_cast<ClientMap*>(data)->onSettingChanged(name);
  67. }
  68. // ClientMap
  69. ClientMap::ClientMap(
  70. Client *client,
  71. RenderingEngine *rendering_engine,
  72. MapDrawControl &control,
  73. s32 id
  74. ):
  75. Map(client),
  76. scene::ISceneNode(rendering_engine->get_scene_manager()->getRootSceneNode(),
  77. rendering_engine->get_scene_manager(), id),
  78. m_client(client),
  79. m_rendering_engine(rendering_engine),
  80. m_control(control),
  81. m_drawlist(MapBlockComparer(v3s16(0,0,0)))
  82. {
  83. /*
  84. * @Liso: Sadly C++ doesn't have introspection, so the only way we have to know
  85. * the class is whith a name ;) Name property cames from ISceneNode base class.
  86. */
  87. Name = "ClientMap";
  88. m_box = aabb3f(-BS*1000000,-BS*1000000,-BS*1000000,
  89. BS*1000000,BS*1000000,BS*1000000);
  90. /* TODO: Add a callback function so these can be updated when a setting
  91. * changes. At this point in time it doesn't matter (e.g. /set
  92. * is documented to change server settings only)
  93. *
  94. * TODO: Local caching of settings is not optimal and should at some stage
  95. * be updated to use a global settings object for getting thse values
  96. * (as opposed to the this local caching). This can be addressed in
  97. * a later release.
  98. */
  99. m_cache_trilinear_filter = g_settings->getBool("trilinear_filter");
  100. m_cache_bilinear_filter = g_settings->getBool("bilinear_filter");
  101. m_cache_anistropic_filter = g_settings->getBool("anisotropic_filter");
  102. m_cache_transparency_sorting_distance = g_settings->getU16("transparency_sorting_distance");
  103. m_loops_occlusion_culler = g_settings->get("occlusion_culler") == "loops";
  104. g_settings->registerChangedCallback("occlusion_culler", on_settings_changed, this);
  105. m_enable_raytraced_culling = g_settings->getBool("enable_raytraced_culling");
  106. g_settings->registerChangedCallback("enable_raytraced_culling", on_settings_changed, this);
  107. }
  108. void ClientMap::onSettingChanged(const std::string &name)
  109. {
  110. if (name == "occlusion_culler")
  111. m_loops_occlusion_culler = g_settings->get("occlusion_culler") == "loops";
  112. if (name == "enable_raytraced_culling")
  113. m_enable_raytraced_culling = g_settings->getBool("enable_raytraced_culling");
  114. }
  115. ClientMap::~ClientMap()
  116. {
  117. g_settings->deregisterChangedCallback("occlusion_culler", on_settings_changed, this);
  118. g_settings->deregisterChangedCallback("enable_raytraced_culling", on_settings_changed, this);
  119. }
  120. void ClientMap::updateCamera(v3f pos, v3f dir, f32 fov, v3s16 offset, video::SColor light_color)
  121. {
  122. v3s16 previous_node = floatToInt(m_camera_position, BS) + m_camera_offset;
  123. v3s16 previous_block = getContainerPos(previous_node, MAP_BLOCKSIZE);
  124. m_camera_position = pos;
  125. m_camera_direction = dir;
  126. m_camera_fov = fov;
  127. m_camera_offset = offset;
  128. m_camera_light_color = light_color;
  129. v3s16 current_node = floatToInt(m_camera_position, BS) + m_camera_offset;
  130. v3s16 current_block = getContainerPos(current_node, MAP_BLOCKSIZE);
  131. // reorder the blocks when camera crosses block boundary
  132. if (previous_block != current_block)
  133. m_needs_update_drawlist = true;
  134. // reorder transparent meshes when camera crosses node boundary
  135. if (previous_node != current_node)
  136. m_needs_update_transparent_meshes = true;
  137. }
  138. MapSector * ClientMap::emergeSector(v2s16 p2d)
  139. {
  140. // Check that it doesn't exist already
  141. MapSector *sector = getSectorNoGenerate(p2d);
  142. // Create it if it does not exist yet
  143. if (!sector) {
  144. sector = new MapSector(this, p2d, m_gamedef);
  145. m_sectors[p2d] = sector;
  146. }
  147. return sector;
  148. }
  149. void ClientMap::OnRegisterSceneNode()
  150. {
  151. if(IsVisible)
  152. {
  153. SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
  154. SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
  155. }
  156. ISceneNode::OnRegisterSceneNode();
  157. // It's not needed to register this node to the shadow renderer
  158. // we have other way to find it
  159. }
  160. void ClientMap::getBlocksInViewRange(v3s16 cam_pos_nodes,
  161. v3s16 *p_blocks_min, v3s16 *p_blocks_max, float range)
  162. {
  163. if (range <= 0.0f)
  164. range = m_control.wanted_range;
  165. v3s16 box_nodes_d = range * v3s16(1, 1, 1);
  166. // Define p_nodes_min/max as v3s32 because 'cam_pos_nodes -/+ box_nodes_d'
  167. // can exceed the range of v3s16 when a large view range is used near the
  168. // world edges.
  169. v3s32 p_nodes_min(
  170. cam_pos_nodes.X - box_nodes_d.X,
  171. cam_pos_nodes.Y - box_nodes_d.Y,
  172. cam_pos_nodes.Z - box_nodes_d.Z);
  173. v3s32 p_nodes_max(
  174. cam_pos_nodes.X + box_nodes_d.X,
  175. cam_pos_nodes.Y + box_nodes_d.Y,
  176. cam_pos_nodes.Z + box_nodes_d.Z);
  177. // Take a fair amount as we will be dropping more out later
  178. // Umm... these additions are a bit strange but they are needed.
  179. *p_blocks_min = v3s16(
  180. p_nodes_min.X / MAP_BLOCKSIZE - 3,
  181. p_nodes_min.Y / MAP_BLOCKSIZE - 3,
  182. p_nodes_min.Z / MAP_BLOCKSIZE - 3);
  183. *p_blocks_max = v3s16(
  184. p_nodes_max.X / MAP_BLOCKSIZE + 1,
  185. p_nodes_max.Y / MAP_BLOCKSIZE + 1,
  186. p_nodes_max.Z / MAP_BLOCKSIZE + 1);
  187. }
  188. class MapBlockFlags
  189. {
  190. public:
  191. static constexpr u16 CHUNK_EDGE = 8;
  192. static constexpr u16 CHUNK_MASK = CHUNK_EDGE - 1;
  193. static constexpr std::size_t CHUNK_VOLUME = CHUNK_EDGE * CHUNK_EDGE * CHUNK_EDGE; // volume of a chunk
  194. MapBlockFlags(v3s16 min_pos, v3s16 max_pos)
  195. : min_pos(min_pos), volume((max_pos - min_pos) / CHUNK_EDGE + 1)
  196. {
  197. chunks.resize(volume.X * volume.Y * volume.Z);
  198. }
  199. class Chunk
  200. {
  201. public:
  202. inline u8 &getBits(v3s16 pos)
  203. {
  204. std::size_t address = getAddress(pos);
  205. return bits[address];
  206. }
  207. private:
  208. inline std::size_t getAddress(v3s16 pos) {
  209. std::size_t address = (pos.X & CHUNK_MASK) + (pos.Y & CHUNK_MASK) * CHUNK_EDGE + (pos.Z & CHUNK_MASK) * (CHUNK_EDGE * CHUNK_EDGE);
  210. return address;
  211. }
  212. std::array<u8, CHUNK_VOLUME> bits;
  213. };
  214. Chunk &getChunk(v3s16 pos)
  215. {
  216. v3s16 delta = (pos - min_pos) / CHUNK_EDGE;
  217. std::size_t address = delta.X + delta.Y * volume.X + delta.Z * volume.X * volume.Y;
  218. Chunk *chunk = chunks[address].get();
  219. if (!chunk) {
  220. chunk = new Chunk();
  221. chunks[address].reset(chunk);
  222. }
  223. return *chunk;
  224. }
  225. private:
  226. std::vector<std::unique_ptr<Chunk>> chunks;
  227. v3s16 min_pos;
  228. v3s16 volume;
  229. };
  230. void ClientMap::updateDrawList()
  231. {
  232. ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG);
  233. m_needs_update_drawlist = false;
  234. for (auto &i : m_drawlist) {
  235. MapBlock *block = i.second;
  236. block->refDrop();
  237. }
  238. m_drawlist.clear();
  239. for (auto &block : m_keeplist) {
  240. block->refDrop();
  241. }
  242. m_keeplist.clear();
  243. const v3s16 cam_pos_nodes = floatToInt(m_camera_position, BS);
  244. v3s16 p_blocks_min;
  245. v3s16 p_blocks_max;
  246. getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max);
  247. // Number of blocks occlusion culled
  248. u32 blocks_occlusion_culled = 0;
  249. // Number of blocks frustum culled
  250. u32 blocks_frustum_culled = 0;
  251. MeshGrid mesh_grid = m_client->getMeshGrid();
  252. // No occlusion culling when free_move is on and camera is inside ground
  253. // No occlusion culling for chunk sizes of 4 and above
  254. // because the current occlusion culling test is highly inefficient at these sizes
  255. bool occlusion_culling_enabled = mesh_grid.cell_size < 4;
  256. if (m_control.allow_noclip) {
  257. MapNode n = getNode(cam_pos_nodes);
  258. if (n.getContent() == CONTENT_IGNORE || m_nodedef->get(n).solidness == 2)
  259. occlusion_culling_enabled = false;
  260. }
  261. const v3s16 camera_block = getContainerPos(cam_pos_nodes, MAP_BLOCKSIZE);
  262. m_drawlist = std::map<v3s16, MapBlock*, MapBlockComparer>(MapBlockComparer(camera_block));
  263. auto is_frustum_culled = m_client->getCamera()->getFrustumCuller();
  264. // Uncomment to debug occluded blocks in the wireframe mode
  265. // TODO: Include this as a flag for an extended debugging setting
  266. // if (occlusion_culling_enabled && m_control.show_wireframe)
  267. // occlusion_culling_enabled = porting::getTimeS() & 1;
  268. // Set of mesh holding blocks
  269. std::set<v3s16> shortlist;
  270. /*
  271. When range_all is enabled, enumerate all blocks visible in the
  272. frustum and display them.
  273. */
  274. if (m_control.range_all || m_loops_occlusion_culler) {
  275. // Number of blocks currently loaded by the client
  276. u32 blocks_loaded = 0;
  277. // Number of blocks with mesh in rendering range
  278. u32 blocks_in_range_with_mesh = 0;
  279. MapBlockVect sectorblocks;
  280. for (auto &sector_it : m_sectors) {
  281. const MapSector *sector = sector_it.second;
  282. v2s16 sp = sector->getPos();
  283. blocks_loaded += sector->size();
  284. if (!m_control.range_all) {
  285. if (sp.X < p_blocks_min.X || sp.X > p_blocks_max.X ||
  286. sp.Y < p_blocks_min.Z || sp.Y > p_blocks_max.Z)
  287. continue;
  288. }
  289. // Loop through blocks in sector
  290. for (const auto &entry : sector->getBlocks()) {
  291. MapBlock *block = entry.second.get();
  292. MapBlockMesh *mesh = block->mesh;
  293. // Calculate the coordinates for range and frustum culling
  294. v3f mesh_sphere_center;
  295. f32 mesh_sphere_radius;
  296. v3s16 block_pos_nodes = block->getPosRelative();
  297. if (mesh) {
  298. mesh_sphere_center = intToFloat(block_pos_nodes, BS)
  299. + mesh->getBoundingSphereCenter();
  300. mesh_sphere_radius = mesh->getBoundingRadius();
  301. } else {
  302. mesh_sphere_center = intToFloat(block_pos_nodes, BS)
  303. + v3f((MAP_BLOCKSIZE * 0.5f - 0.5f) * BS);
  304. mesh_sphere_radius = 0.0f;
  305. }
  306. // First, perform a simple distance check.
  307. if (!m_control.range_all &&
  308. mesh_sphere_center.getDistanceFrom(m_camera_position) >
  309. m_control.wanted_range * BS + mesh_sphere_radius)
  310. continue; // Out of range, skip.
  311. // Keep the block alive as long as it is in range.
  312. block->resetUsageTimer();
  313. blocks_in_range_with_mesh++;
  314. // Frustum culling
  315. // Only do coarse culling here, to account for fast camera movement.
  316. // This is needed because this function is not called every frame.
  317. float frustum_cull_extra_radius = 300.0f;
  318. if (is_frustum_culled(mesh_sphere_center,
  319. mesh_sphere_radius + frustum_cull_extra_radius)) {
  320. blocks_frustum_culled++;
  321. continue;
  322. }
  323. // Raytraced occlusion culling - send rays from the camera to the block's corners
  324. if (!m_control.range_all && occlusion_culling_enabled && m_enable_raytraced_culling &&
  325. mesh &&
  326. isMeshOccluded(block, mesh_grid.cell_size, cam_pos_nodes)) {
  327. blocks_occlusion_culled++;
  328. continue;
  329. }
  330. if (mesh_grid.cell_size > 1) {
  331. // Block meshes are stored in the corner block of a chunk
  332. // (where all coordinate are divisible by the chunk size)
  333. // Add them to the de-dup set.
  334. shortlist.emplace(mesh_grid.getMeshPos(block->getPos()));
  335. // All other blocks we can grab and add to the keeplist right away.
  336. m_keeplist.push_back(block);
  337. block->refGrab();
  338. } else if (mesh) {
  339. // without mesh chunking we can add the block to the drawlist
  340. block->refGrab();
  341. m_drawlist.emplace(block->getPos(), block);
  342. }
  343. }
  344. }
  345. g_profiler->avg("MapBlock meshes in range [#]", blocks_in_range_with_mesh);
  346. g_profiler->avg("MapBlocks loaded [#]", blocks_loaded);
  347. } else {
  348. // Blocks visited by the algorithm
  349. u32 blocks_visited = 0;
  350. // Block sides that were not traversed
  351. u32 sides_skipped = 0;
  352. std::queue<v3s16> blocks_to_consider;
  353. v3s16 camera_mesh = mesh_grid.getMeshPos(camera_block);
  354. v3s16 camera_cell = mesh_grid.getCellPos(camera_block);
  355. // Bits per block:
  356. // [ visited | 0 | 0 | 0 | 0 | Z visible | Y visible | X visible ]
  357. MapBlockFlags meshes_seen(mesh_grid.getCellPos(p_blocks_min), mesh_grid.getCellPos(p_blocks_max) + 1);
  358. // Start breadth-first search with the block the camera is in
  359. blocks_to_consider.push(camera_mesh);
  360. meshes_seen.getChunk(camera_cell).getBits(camera_cell) = 0x07; // mark all sides as visible
  361. // Recursively walk the space and pick mapblocks for drawing
  362. while (!blocks_to_consider.empty()) {
  363. v3s16 block_coord = blocks_to_consider.front();
  364. blocks_to_consider.pop();
  365. v3s16 cell_coord = mesh_grid.getCellPos(block_coord);
  366. auto &flags = meshes_seen.getChunk(cell_coord).getBits(cell_coord);
  367. // Only visit each block once (it may have been queued up to three times)
  368. if ((flags & 0x80) == 0x80)
  369. continue;
  370. flags |= 0x80;
  371. blocks_visited++;
  372. // Get the sector, block and mesh
  373. MapSector *sector = this->getSectorNoGenerate(v2s16(block_coord.X, block_coord.Z));
  374. MapBlock *block = sector ? sector->getBlockNoCreateNoEx(block_coord.Y) : nullptr;
  375. MapBlockMesh *mesh = block ? block->mesh : nullptr;
  376. // Calculate the coordinates for range and frustum culling
  377. v3f mesh_sphere_center;
  378. f32 mesh_sphere_radius;
  379. v3s16 block_pos_nodes = block_coord * MAP_BLOCKSIZE;
  380. if (mesh) {
  381. mesh_sphere_center = intToFloat(block_pos_nodes, BS)
  382. + mesh->getBoundingSphereCenter();
  383. mesh_sphere_radius = mesh->getBoundingRadius();
  384. } else {
  385. mesh_sphere_center = intToFloat(block_pos_nodes, BS) + v3f((mesh_grid.cell_size * MAP_BLOCKSIZE * 0.5f - 0.5f) * BS);
  386. mesh_sphere_radius = 0.87f * mesh_grid.cell_size * MAP_BLOCKSIZE * BS;
  387. }
  388. // First, perform a simple distance check.
  389. if (!m_control.range_all &&
  390. mesh_sphere_center.getDistanceFrom(intToFloat(cam_pos_nodes, BS)) >
  391. m_control.wanted_range * BS + mesh_sphere_radius)
  392. continue; // Out of range, skip.
  393. // Frustum culling
  394. // Only do coarse culling here, to account for fast camera movement.
  395. // This is needed because this function is not called every frame.
  396. float frustum_cull_extra_radius = 300.0f;
  397. if (is_frustum_culled(mesh_sphere_center,
  398. mesh_sphere_radius + frustum_cull_extra_radius)) {
  399. blocks_frustum_culled++;
  400. continue;
  401. }
  402. // Calculate the vector from the camera block to the current block
  403. // We use it to determine through which sides of the current block we can continue the search
  404. v3s16 look = block_coord - camera_mesh;
  405. // Occluded near sides will further occlude the far sides
  406. u8 visible_outer_sides = flags & 0x07;
  407. // Raytraced occlusion culling - send rays from the camera to the block's corners
  408. if (occlusion_culling_enabled && m_enable_raytraced_culling &&
  409. block && mesh &&
  410. visible_outer_sides != 0x07 && isMeshOccluded(block, mesh_grid.cell_size, cam_pos_nodes)) {
  411. blocks_occlusion_culled++;
  412. continue;
  413. }
  414. if (mesh_grid.cell_size > 1) {
  415. // Block meshes are stored in the corner block of a chunk
  416. // (where all coordinate are divisible by the chunk size)
  417. // Add them to the de-dup set.
  418. shortlist.emplace(block_coord.X, block_coord.Y, block_coord.Z);
  419. // All other blocks we can grab and add to the keeplist right away.
  420. if (block) {
  421. m_keeplist.push_back(block);
  422. block->refGrab();
  423. }
  424. } else if (mesh) {
  425. // without mesh chunking we can add the block to the drawlist
  426. block->refGrab();
  427. m_drawlist.emplace(block_coord, block);
  428. }
  429. // Decide which sides to traverse next or to block away
  430. // First, find the near sides that would occlude the far sides
  431. // * A near side can itself be occluded by a nearby block (the test above ^^)
  432. // * A near side can be visible but fully opaque by itself (e.g. ground at the 0 level)
  433. // mesh solid sides are +Z-Z+Y-Y+X-X
  434. // if we are inside the block's coordinates on an axis,
  435. // treat these sides as opaque, as they should not allow to reach the far sides
  436. u8 block_inner_sides = (look.X == 0 ? 3 : 0) |
  437. (look.Y == 0 ? 12 : 0) |
  438. (look.Z == 0 ? 48 : 0);
  439. // get the mask for the sides that are relevant based on the direction
  440. u8 near_inner_sides = (look.X > 0 ? 1 : 2) |
  441. (look.Y > 0 ? 4 : 8) |
  442. (look.Z > 0 ? 16 : 32);
  443. // This bitset is +Z-Z+Y-Y+X-X (See MapBlockMesh), and axis is XYZ.
  444. // Get he block's transparent sides
  445. u8 transparent_sides = (occlusion_culling_enabled && block) ? ~block->solid_sides : 0x3F;
  446. // compress block transparent sides to ZYX mask of see-through axes
  447. u8 near_transparency = (block_inner_sides == 0x3F) ? near_inner_sides : (transparent_sides & near_inner_sides);
  448. // when we are inside the camera block, do not block any sides
  449. if (block_inner_sides == 0x3F)
  450. block_inner_sides = 0;
  451. near_transparency &= ~block_inner_sides & 0x3F;
  452. near_transparency |= (near_transparency >> 1);
  453. near_transparency = (near_transparency & 1) |
  454. ((near_transparency >> 1) & 2) |
  455. ((near_transparency >> 2) & 4);
  456. // combine with known visible sides that matter
  457. near_transparency &= visible_outer_sides;
  458. // The rule for any far side to be visible:
  459. // * Any of the adjacent near sides is transparent (different axes)
  460. // * The opposite near side (same axis) is transparent, if it is the dominant axis of the look vector
  461. // Calculate vector from camera to mapblock center. Because we only need relation between
  462. // coordinates we scale by 2 to avoid precision loss.
  463. v3s16 precise_look = 2 * (block_pos_nodes - cam_pos_nodes) + mesh_grid.cell_size * MAP_BLOCKSIZE - 1;
  464. // dominant axis flag
  465. u8 dominant_axis = (abs(precise_look.X) > abs(precise_look.Y) && abs(precise_look.X) > abs(precise_look.Z)) |
  466. ((abs(precise_look.Y) > abs(precise_look.Z) && abs(precise_look.Y) > abs(precise_look.X)) << 1) |
  467. ((abs(precise_look.Z) > abs(precise_look.X) && abs(precise_look.Z) > abs(precise_look.Y)) << 2);
  468. // Queue next blocks for processing:
  469. // - Examine "far" sides of the current blocks, i.e. never move towards the camera
  470. // - Only traverse the sides that are not occluded
  471. // - Only traverse the sides that are not opaque
  472. // When queueing, mark the relevant side on the next block as 'visible'
  473. for (s16 axis = 0; axis < 3; axis++) {
  474. // Select a bit from transparent_sides for the side
  475. u8 far_side_mask = 1 << (2 * axis);
  476. // axis flag
  477. u8 my_side = 1 << axis;
  478. u8 adjacent_sides = my_side ^ 0x07;
  479. auto traverse_far_side = [&](s8 next_pos_offset) {
  480. // far side is visible if adjacent near sides are transparent, or if opposite side on dominant axis is transparent
  481. bool side_visible = ((near_transparency & adjacent_sides) | (near_transparency & my_side & dominant_axis)) != 0;
  482. side_visible = side_visible && ((far_side_mask & transparent_sides) != 0);
  483. v3s16 next_pos = block_coord;
  484. next_pos[axis] += next_pos_offset;
  485. v3s16 next_cell = mesh_grid.getCellPos(next_pos);
  486. // If a side is a see-through, mark the next block's side as visible, and queue
  487. if (side_visible) {
  488. auto &next_flags = meshes_seen.getChunk(next_cell).getBits(next_cell);
  489. next_flags |= my_side;
  490. blocks_to_consider.push(next_pos);
  491. }
  492. else {
  493. sides_skipped++;
  494. }
  495. };
  496. // Test the '-' direction of the axis
  497. if (look[axis] <= 0 && block_coord[axis] > p_blocks_min[axis])
  498. traverse_far_side(-mesh_grid.cell_size);
  499. // Test the '+' direction of the axis
  500. far_side_mask <<= 1;
  501. if (look[axis] >= 0 && block_coord[axis] < p_blocks_max[axis])
  502. traverse_far_side(+mesh_grid.cell_size);
  503. }
  504. }
  505. g_profiler->avg("MapBlocks sides skipped [#]", sides_skipped);
  506. g_profiler->avg("MapBlocks examined [#]", blocks_visited);
  507. }
  508. g_profiler->avg("MapBlocks shortlist [#]", shortlist.size());
  509. assert(m_drawlist.empty() || shortlist.empty());
  510. for (auto pos : shortlist) {
  511. MapBlock *block = getBlockNoCreateNoEx(pos);
  512. if (block) {
  513. block->refGrab();
  514. m_drawlist.emplace(pos, block);
  515. }
  516. }
  517. g_profiler->avg("MapBlocks occlusion culled [#]", blocks_occlusion_culled);
  518. g_profiler->avg("MapBlocks frustum culled [#]", blocks_frustum_culled);
  519. g_profiler->avg("MapBlocks drawn [#]", m_drawlist.size());
  520. }
  521. void ClientMap::touchMapBlocks()
  522. {
  523. if (m_control.range_all || m_loops_occlusion_culler)
  524. return;
  525. ScopeProfiler sp(g_profiler, "CM::touchMapBlocks()", SPT_AVG);
  526. v3s16 cam_pos_nodes = floatToInt(m_camera_position, BS);
  527. v3s16 p_blocks_min;
  528. v3s16 p_blocks_max;
  529. getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max);
  530. // Number of blocks currently loaded by the client
  531. u32 blocks_loaded = 0;
  532. // Number of blocks with mesh in rendering range
  533. u32 blocks_in_range_with_mesh = 0;
  534. for (const auto &sector_it : m_sectors) {
  535. const MapSector *sector = sector_it.second;
  536. v2s16 sp = sector->getPos();
  537. blocks_loaded += sector->size();
  538. if (!m_control.range_all) {
  539. if (sp.X < p_blocks_min.X || sp.X > p_blocks_max.X ||
  540. sp.Y < p_blocks_min.Z || sp.Y > p_blocks_max.Z)
  541. continue;
  542. }
  543. /*
  544. Loop through blocks in sector
  545. */
  546. for (const auto &entry : sector->getBlocks()) {
  547. MapBlock *block = entry.second.get();
  548. MapBlockMesh *mesh = block->mesh;
  549. // Calculate the coordinates for range and frustum culling
  550. v3f mesh_sphere_center;
  551. f32 mesh_sphere_radius;
  552. v3s16 block_pos_nodes = block->getPosRelative();
  553. if (mesh) {
  554. mesh_sphere_center = intToFloat(block_pos_nodes, BS)
  555. + mesh->getBoundingSphereCenter();
  556. mesh_sphere_radius = mesh->getBoundingRadius();
  557. } else {
  558. mesh_sphere_center = intToFloat(block_pos_nodes, BS)
  559. + v3f((MAP_BLOCKSIZE * 0.5f - 0.5f) * BS);
  560. mesh_sphere_radius = 0.0f;
  561. }
  562. // First, perform a simple distance check.
  563. if (!m_control.range_all &&
  564. mesh_sphere_center.getDistanceFrom(m_camera_position) >
  565. m_control.wanted_range * BS + mesh_sphere_radius)
  566. continue; // Out of range, skip.
  567. // Keep the block alive as long as it is in range.
  568. block->resetUsageTimer();
  569. blocks_in_range_with_mesh++;
  570. }
  571. }
  572. g_profiler->avg("MapBlock meshes in range [#]", blocks_in_range_with_mesh);
  573. g_profiler->avg("MapBlocks loaded [#]", blocks_loaded);
  574. }
  575. void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
  576. {
  577. bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
  578. std::string prefix;
  579. if (pass == scene::ESNRP_SOLID)
  580. prefix = "renderMap(SOLID): ";
  581. else
  582. prefix = "renderMap(TRANSPARENT): ";
  583. /*
  584. This is called two times per frame, reset on the non-transparent one
  585. */
  586. if (pass == scene::ESNRP_SOLID)
  587. m_last_drawn_sectors.clear();
  588. /*
  589. Get animation parameters
  590. */
  591. const float animation_time = m_client->getAnimationTime();
  592. const int crack = m_client->getCrackLevel();
  593. const u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
  594. const v3f camera_position = m_camera_position;
  595. /*
  596. Get all blocks and draw all visible ones
  597. */
  598. u32 vertex_count = 0;
  599. u32 drawcall_count = 0;
  600. // For limiting number of mesh animations per frame
  601. u32 mesh_animate_count = 0;
  602. //u32 mesh_animate_count_far = 0;
  603. /*
  604. Update transparent meshes
  605. */
  606. if (is_transparent_pass)
  607. updateTransparentMeshBuffers();
  608. /*
  609. Draw the selected MapBlocks
  610. */
  611. MeshBufListMaps grouped_buffers;
  612. std::vector<DrawDescriptor> draw_order;
  613. video::SMaterial previous_material;
  614. auto is_frustum_culled = m_client->getCamera()->getFrustumCuller();
  615. const MeshGrid mesh_grid = m_client->getMeshGrid();
  616. for (auto &i : m_drawlist) {
  617. v3s16 block_pos = i.first;
  618. MapBlock *block = i.second;
  619. MapBlockMesh *block_mesh = block->mesh;
  620. // If the mesh of the block happened to get deleted, ignore it
  621. if (!block_mesh)
  622. continue;
  623. // Do exact frustum culling
  624. // (The one in updateDrawList is only coarse.)
  625. v3f mesh_sphere_center = intToFloat(block->getPosRelative(), BS)
  626. + block_mesh->getBoundingSphereCenter();
  627. f32 mesh_sphere_radius = block_mesh->getBoundingRadius();
  628. if (is_frustum_culled(mesh_sphere_center, mesh_sphere_radius))
  629. continue;
  630. v3f block_pos_r = intToFloat(block->getPosRelative() + MAP_BLOCKSIZE / 2, BS);
  631. float d = camera_position.getDistanceFrom(block_pos_r);
  632. d = MYMAX(0,d - BLOCK_MAX_RADIUS);
  633. // Mesh animation
  634. if (pass == scene::ESNRP_SOLID) {
  635. // Pretty random but this should work somewhat nicely
  636. bool faraway = d >= BS * 50;
  637. if (block_mesh->isAnimationForced() || !faraway ||
  638. mesh_animate_count < (m_control.range_all ? 200 : 50)) {
  639. bool animated = block_mesh->animate(faraway, animation_time,
  640. crack, daynight_ratio);
  641. if (animated)
  642. mesh_animate_count++;
  643. } else {
  644. block_mesh->decreaseAnimationForceTimer();
  645. }
  646. }
  647. /*
  648. Get the meshbuffers of the block
  649. */
  650. if (is_transparent_pass) {
  651. // In transparent pass, the mesh will give us
  652. // the partial buffers in the correct order
  653. for (auto &buffer : block_mesh->getTransparentBuffers())
  654. draw_order.emplace_back(block_pos, &buffer);
  655. }
  656. else {
  657. // otherwise, group buffers across meshes
  658. // using MeshBufListMaps
  659. for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
  660. scene::IMesh *mesh = block_mesh->getMesh(layer);
  661. assert(mesh);
  662. u32 c = mesh->getMeshBufferCount();
  663. for (u32 i = 0; i < c; i++) {
  664. scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
  665. video::SMaterial& material = buf->getMaterial();
  666. video::IMaterialRenderer* rnd =
  667. driver->getMaterialRenderer(material.MaterialType);
  668. bool transparent = (rnd && rnd->isTransparent());
  669. if (!transparent) {
  670. if (buf->getVertexCount() == 0)
  671. errorstream << "Block [" << analyze_block(block)
  672. << "] contains an empty meshbuf" << std::endl;
  673. grouped_buffers.add(buf, block_pos, layer);
  674. }
  675. }
  676. }
  677. }
  678. }
  679. // Capture draw order for all solid meshes
  680. for (auto &map : grouped_buffers.maps) {
  681. for (auto &list : map) {
  682. // iterate in reverse to draw closest blocks first
  683. for (auto it = list.second.rbegin(); it != list.second.rend(); ++it) {
  684. draw_order.emplace_back(it->first, it->second, it != list.second.rbegin());
  685. }
  686. }
  687. }
  688. TimeTaker draw("Drawing mesh buffers");
  689. core::matrix4 m; // Model matrix
  690. v3f offset = intToFloat(m_camera_offset, BS);
  691. u32 material_swaps = 0;
  692. // Render all mesh buffers in order
  693. drawcall_count += draw_order.size();
  694. for (auto &descriptor : draw_order) {
  695. scene::IMeshBuffer *buf = descriptor.getBuffer();
  696. if (!descriptor.m_reuse_material) {
  697. auto &material = buf->getMaterial();
  698. // Apply filter settings
  699. material.forEachTexture([this] (auto &tex) {
  700. setMaterialFilters(tex, m_cache_bilinear_filter, m_cache_trilinear_filter,
  701. m_cache_anistropic_filter);
  702. });
  703. material.Wireframe = m_control.show_wireframe;
  704. // pass the shadow map texture to the buffer texture
  705. ShadowRenderer *shadow = m_rendering_engine->get_shadow_renderer();
  706. if (shadow && shadow->is_active()) {
  707. auto &layer = material.TextureLayers[ShadowRenderer::TEXTURE_LAYER_SHADOW];
  708. layer.Texture = shadow->get_texture();
  709. layer.TextureWrapU = video::E_TEXTURE_CLAMP::ETC_CLAMP_TO_EDGE;
  710. layer.TextureWrapV = video::E_TEXTURE_CLAMP::ETC_CLAMP_TO_EDGE;
  711. // Do not enable filter on shadow texture to avoid visual artifacts
  712. // with colored shadows.
  713. // Filtering is done in shader code anyway
  714. layer.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST;
  715. layer.MagFilter = video::ETMAGF_NEAREST;
  716. layer.AnisotropicFilter = 0;
  717. }
  718. driver->setMaterial(material);
  719. ++material_swaps;
  720. material.TextureLayers[ShadowRenderer::TEXTURE_LAYER_SHADOW].Texture = nullptr;
  721. }
  722. v3f block_wpos = intToFloat(mesh_grid.getMeshPos(descriptor.m_pos) * MAP_BLOCKSIZE, BS);
  723. m.setTranslation(block_wpos - offset);
  724. driver->setTransform(video::ETS_WORLD, m);
  725. descriptor.draw(driver);
  726. vertex_count += buf->getIndexCount();
  727. }
  728. g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true));
  729. // Log only on solid pass because values are the same
  730. if (pass == scene::ESNRP_SOLID) {
  731. g_profiler->avg("renderMap(): animated meshes [#]", mesh_animate_count);
  732. }
  733. if (pass == scene::ESNRP_TRANSPARENT) {
  734. g_profiler->avg("renderMap(): transparent buffers [#]", draw_order.size());
  735. }
  736. g_profiler->avg(prefix + "vertices drawn [#]", vertex_count);
  737. g_profiler->avg(prefix + "drawcalls [#]", drawcall_count);
  738. g_profiler->avg(prefix + "material swaps [#]", material_swaps);
  739. }
  740. static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step,
  741. float step_multiplier, float start_distance, float end_distance,
  742. const NodeDefManager *ndef, u32 daylight_factor, float sunlight_min_d,
  743. int *result, bool *sunlight_seen)
  744. {
  745. int brightness_sum = 0;
  746. int brightness_count = 0;
  747. float distance = start_distance;
  748. dir.normalize();
  749. v3f pf = p0;
  750. pf += dir * distance;
  751. int noncount = 0;
  752. bool nonlight_seen = false;
  753. bool allow_allowing_non_sunlight_propagates = false;
  754. bool allow_non_sunlight_propagates = false;
  755. // Check content nearly at camera position
  756. {
  757. v3s16 p = floatToInt(p0 /*+ dir * 3*BS*/, BS);
  758. MapNode n = map->getNode(p);
  759. if(ndef->getLightingFlags(n).has_light &&
  760. !ndef->getLightingFlags(n).sunlight_propagates)
  761. allow_allowing_non_sunlight_propagates = true;
  762. }
  763. // If would start at CONTENT_IGNORE, start closer
  764. {
  765. v3s16 p = floatToInt(pf, BS);
  766. MapNode n = map->getNode(p);
  767. if(n.getContent() == CONTENT_IGNORE){
  768. float newd = 2*BS;
  769. pf = p0 + dir * 2*newd;
  770. distance = newd;
  771. sunlight_min_d = 0;
  772. }
  773. }
  774. for (int i=0; distance < end_distance; i++) {
  775. pf += dir * step;
  776. distance += step;
  777. step *= step_multiplier;
  778. v3s16 p = floatToInt(pf, BS);
  779. MapNode n = map->getNode(p);
  780. ContentLightingFlags f = ndef->getLightingFlags(n);
  781. if (allow_allowing_non_sunlight_propagates && i == 0 &&
  782. f.has_light && !f.sunlight_propagates) {
  783. allow_non_sunlight_propagates = true;
  784. }
  785. if (!f.has_light || (!f.sunlight_propagates && !allow_non_sunlight_propagates)){
  786. nonlight_seen = true;
  787. noncount++;
  788. if(noncount >= 4)
  789. break;
  790. continue;
  791. }
  792. if (distance >= sunlight_min_d && !*sunlight_seen && !nonlight_seen)
  793. if (n.getLight(LIGHTBANK_DAY, f) == LIGHT_SUN)
  794. *sunlight_seen = true;
  795. noncount = 0;
  796. brightness_sum += decode_light(n.getLightBlend(daylight_factor, f));
  797. brightness_count++;
  798. }
  799. *result = 0;
  800. if(brightness_count == 0)
  801. return false;
  802. *result = brightness_sum / brightness_count;
  803. /*std::cerr<<"Sampled "<<brightness_count<<" points; result="
  804. <<(*result)<<std::endl;*/
  805. return true;
  806. }
  807. int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
  808. int oldvalue, bool *sunlight_seen_result)
  809. {
  810. ScopeProfiler sp(g_profiler, "CM::getBackgroundBrightness", SPT_AVG);
  811. static v3f z_directions[50] = {
  812. v3f(-100, 0, 0)
  813. };
  814. static f32 z_offsets[50] = {
  815. -1000,
  816. };
  817. if (z_directions[0].X < -99) {
  818. for (u32 i = 0; i < ARRLEN(z_directions); i++) {
  819. // Assumes FOV of 72 and 16/9 aspect ratio
  820. z_directions[i] = v3f(
  821. 0.02 * myrand_range(-100, 100),
  822. 1.0,
  823. 0.01 * myrand_range(-100, 100)
  824. ).normalize();
  825. z_offsets[i] = 0.01 * myrand_range(0,100);
  826. }
  827. }
  828. int sunlight_seen_count = 0;
  829. float sunlight_min_d = max_d*0.8;
  830. if(sunlight_min_d > 35*BS)
  831. sunlight_min_d = 35*BS;
  832. std::vector<int> values;
  833. values.reserve(ARRLEN(z_directions));
  834. for (u32 i = 0; i < ARRLEN(z_directions); i++) {
  835. v3f z_dir = z_directions[i];
  836. core::CMatrix4<f32> a;
  837. a.buildRotateFromTo(v3f(0,1,0), z_dir);
  838. v3f dir = m_camera_direction;
  839. a.rotateVect(dir);
  840. int br = 0;
  841. float step = BS*1.5;
  842. if(max_d > 35*BS)
  843. step = max_d / 35 * 1.5;
  844. float off = step * z_offsets[i];
  845. bool sunlight_seen_now = false;
  846. bool ok = getVisibleBrightness(this, m_camera_position, dir,
  847. step, 1.0, max_d*0.6+off, max_d, m_nodedef, daylight_factor,
  848. sunlight_min_d,
  849. &br, &sunlight_seen_now);
  850. if(sunlight_seen_now)
  851. sunlight_seen_count++;
  852. if(!ok)
  853. continue;
  854. values.push_back(br);
  855. // Don't try too much if being in the sun is clear
  856. if(sunlight_seen_count >= 20)
  857. break;
  858. }
  859. int brightness_sum = 0;
  860. int brightness_count = 0;
  861. std::sort(values.begin(), values.end());
  862. u32 num_values_to_use = values.size();
  863. if(num_values_to_use >= 10)
  864. num_values_to_use -= num_values_to_use/2;
  865. else if(num_values_to_use >= 7)
  866. num_values_to_use -= num_values_to_use/3;
  867. u32 first_value_i = (values.size() - num_values_to_use) / 2;
  868. for (u32 i=first_value_i; i < first_value_i + num_values_to_use; i++) {
  869. brightness_sum += values[i];
  870. brightness_count++;
  871. }
  872. int ret = 0;
  873. if(brightness_count == 0){
  874. MapNode n = getNode(floatToInt(m_camera_position, BS));
  875. ContentLightingFlags f = m_nodedef->getLightingFlags(n);
  876. if(f.has_light){
  877. ret = decode_light(n.getLightBlend(daylight_factor, f));
  878. } else {
  879. ret = oldvalue;
  880. }
  881. } else {
  882. ret = brightness_sum / brightness_count;
  883. }
  884. *sunlight_seen_result = (sunlight_seen_count > 0);
  885. return ret;
  886. }
  887. void ClientMap::renderPostFx(CameraMode cam_mode)
  888. {
  889. // Sadly ISceneManager has no "post effects" render pass, in that case we
  890. // could just register for that and handle it in renderMap().
  891. MapNode n = getNode(floatToInt(m_camera_position, BS));
  892. const ContentFeatures& features = m_nodedef->get(n);
  893. video::SColor post_color = features.post_effect_color;
  894. if (features.post_effect_color_shaded) {
  895. auto apply_light = [] (u32 color, u32 light) {
  896. return core::clamp(core::round32(color * light / 255.0f), 0, 255);
  897. };
  898. post_color.setRed(apply_light(post_color.getRed(), m_camera_light_color.getRed()));
  899. post_color.setGreen(apply_light(post_color.getGreen(), m_camera_light_color.getGreen()));
  900. post_color.setBlue(apply_light(post_color.getBlue(), m_camera_light_color.getBlue()));
  901. }
  902. // If the camera is in a solid node, make everything black.
  903. // (first person mode only)
  904. if (features.solidness == 2 && cam_mode == CAMERA_MODE_FIRST &&
  905. !m_control.allow_noclip) {
  906. post_color = video::SColor(255, 0, 0, 0);
  907. }
  908. if (post_color.getAlpha() != 0) {
  909. // Draw a full-screen rectangle
  910. video::IVideoDriver* driver = SceneManager->getVideoDriver();
  911. v2u32 ss = driver->getScreenSize();
  912. core::rect<s32> rect(0,0, ss.X, ss.Y);
  913. driver->draw2DRectangle(post_color, rect);
  914. }
  915. }
  916. void ClientMap::PrintInfo(std::ostream &out)
  917. {
  918. out<<"ClientMap: ";
  919. }
  920. void ClientMap::renderMapShadows(video::IVideoDriver *driver,
  921. const video::SMaterial &material, s32 pass, int frame, int total_frames)
  922. {
  923. bool is_transparent_pass = pass != scene::ESNRP_SOLID;
  924. std::string prefix;
  925. if (is_transparent_pass)
  926. prefix = "renderMap(SHADOW TRANS): ";
  927. else
  928. prefix = "renderMap(SHADOW SOLID): ";
  929. u32 drawcall_count = 0;
  930. u32 vertex_count = 0;
  931. MeshBufListMaps grouped_buffers;
  932. std::vector<DrawDescriptor> draw_order;
  933. std::size_t count = 0;
  934. std::size_t meshes_per_frame = m_drawlist_shadow.size() / total_frames + 1;
  935. std::size_t low_bound = is_transparent_pass ? 0 : meshes_per_frame * frame;
  936. std::size_t high_bound = is_transparent_pass ? m_drawlist_shadow.size() : meshes_per_frame * (frame + 1);
  937. // transparent pass should be rendered in one go
  938. if (is_transparent_pass && frame != total_frames - 1) {
  939. return;
  940. }
  941. const MeshGrid mesh_grid = m_client->getMeshGrid();
  942. for (const auto &i : m_drawlist_shadow) {
  943. // only process specific part of the list & break early
  944. ++count;
  945. if (count <= low_bound)
  946. continue;
  947. if (count > high_bound)
  948. break;
  949. v3s16 block_pos = i.first;
  950. MapBlock *block = i.second;
  951. // If the mesh of the block happened to get deleted, ignore it
  952. if (!block->mesh)
  953. continue;
  954. /*
  955. Get the meshbuffers of the block
  956. */
  957. if (is_transparent_pass) {
  958. // In transparent pass, the mesh will give us
  959. // the partial buffers in the correct order
  960. for (auto &buffer : block->mesh->getTransparentBuffers())
  961. draw_order.emplace_back(block_pos, &buffer);
  962. }
  963. else {
  964. // otherwise, group buffers across meshes
  965. // using MeshBufListMaps
  966. MapBlockMesh *mapBlockMesh = block->mesh;
  967. assert(mapBlockMesh);
  968. for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
  969. scene::IMesh *mesh = mapBlockMesh->getMesh(layer);
  970. assert(mesh);
  971. u32 c = mesh->getMeshBufferCount();
  972. for (u32 i = 0; i < c; i++) {
  973. scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
  974. video::SMaterial &mat = buf->getMaterial();
  975. auto rnd = driver->getMaterialRenderer(mat.MaterialType);
  976. bool transparent = rnd && rnd->isTransparent();
  977. if (!transparent)
  978. grouped_buffers.add(buf, block_pos, layer);
  979. }
  980. }
  981. }
  982. }
  983. u32 buffer_count = 0;
  984. for (auto &map : grouped_buffers.maps)
  985. for (auto &list : map)
  986. buffer_count += list.second.size();
  987. draw_order.reserve(draw_order.size() + buffer_count);
  988. // Capture draw order for all solid meshes
  989. for (auto &map : grouped_buffers.maps) {
  990. for (auto &list : map) {
  991. // iterate in reverse to draw closest blocks first
  992. for (auto it = list.second.rbegin(); it != list.second.rend(); ++it)
  993. draw_order.emplace_back(it->first, it->second, it != list.second.rbegin());
  994. }
  995. }
  996. TimeTaker draw("Drawing shadow mesh buffers");
  997. core::matrix4 m; // Model matrix
  998. v3f offset = intToFloat(m_camera_offset, BS);
  999. u32 material_swaps = 0;
  1000. // Render all mesh buffers in order
  1001. drawcall_count += draw_order.size();
  1002. for (auto &descriptor : draw_order) {
  1003. scene::IMeshBuffer *buf = descriptor.getBuffer();
  1004. if (!descriptor.m_reuse_material) {
  1005. // override some material properties
  1006. video::SMaterial local_material = buf->getMaterial();
  1007. local_material.MaterialType = material.MaterialType;
  1008. // do not override culling if the original material renders both back
  1009. // and front faces in solid mode (e.g. plantlike)
  1010. // Transparent plants would still render shadows only from one side,
  1011. // but this conflicts with water which occurs much more frequently
  1012. if (is_transparent_pass || local_material.BackfaceCulling || local_material.FrontfaceCulling) {
  1013. local_material.BackfaceCulling = material.BackfaceCulling;
  1014. local_material.FrontfaceCulling = material.FrontfaceCulling;
  1015. }
  1016. local_material.BlendOperation = material.BlendOperation;
  1017. local_material.Lighting = false;
  1018. driver->setMaterial(local_material);
  1019. ++material_swaps;
  1020. }
  1021. v3f block_wpos = intToFloat(mesh_grid.getMeshPos(descriptor.m_pos) * MAP_BLOCKSIZE, BS);
  1022. m.setTranslation(block_wpos - offset);
  1023. driver->setTransform(video::ETS_WORLD, m);
  1024. descriptor.draw(driver);
  1025. vertex_count += buf->getIndexCount();
  1026. }
  1027. // restore the driver material state
  1028. video::SMaterial clean;
  1029. clean.BlendOperation = video::EBO_ADD;
  1030. driver->setMaterial(clean); // reset material to defaults
  1031. driver->draw3DLine(v3f(), v3f(), video::SColor(0));
  1032. g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true));
  1033. g_profiler->avg(prefix + "vertices drawn [#]", vertex_count);
  1034. g_profiler->avg(prefix + "drawcalls [#]", drawcall_count);
  1035. g_profiler->avg(prefix + "material swaps [#]", material_swaps);
  1036. }
  1037. /*
  1038. Custom update draw list for the pov of shadow light.
  1039. */
  1040. void ClientMap::updateDrawListShadow(v3f shadow_light_pos, v3f shadow_light_dir, float radius, float length)
  1041. {
  1042. ScopeProfiler sp(g_profiler, "CM::updateDrawListShadow()", SPT_AVG);
  1043. for (auto &i : m_drawlist_shadow) {
  1044. MapBlock *block = i.second;
  1045. block->refDrop();
  1046. }
  1047. m_drawlist_shadow.clear();
  1048. // Number of blocks currently loaded by the client
  1049. u32 blocks_loaded = 0;
  1050. // Number of blocks with mesh in rendering range
  1051. u32 blocks_in_range_with_mesh = 0;
  1052. for (auto &sector_it : m_sectors) {
  1053. const MapSector *sector = sector_it.second;
  1054. if (!sector)
  1055. continue;
  1056. blocks_loaded += sector->size();
  1057. /*
  1058. Loop through blocks in sector
  1059. */
  1060. for (const auto &entry : sector->getBlocks()) {
  1061. MapBlock *block = entry.second.get();
  1062. MapBlockMesh *mesh = block->mesh;
  1063. if (!mesh) {
  1064. // Ignore if mesh doesn't exist
  1065. continue;
  1066. }
  1067. v3f block_pos = intToFloat(block->getPosRelative(), BS) + mesh->getBoundingSphereCenter();
  1068. v3f projection = shadow_light_pos + shadow_light_dir * shadow_light_dir.dotProduct(block_pos - shadow_light_pos);
  1069. if (projection.getDistanceFrom(block_pos) > (radius + mesh->getBoundingRadius()))
  1070. continue;
  1071. blocks_in_range_with_mesh++;
  1072. // This block is in range. Reset usage timer.
  1073. block->resetUsageTimer();
  1074. // Add to set
  1075. if (m_drawlist_shadow.emplace(block->getPos(), block).second) {
  1076. block->refGrab();
  1077. }
  1078. }
  1079. }
  1080. g_profiler->avg("SHADOW MapBlock meshes in range [#]", blocks_in_range_with_mesh);
  1081. g_profiler->avg("SHADOW MapBlocks drawn [#]", m_drawlist_shadow.size());
  1082. g_profiler->avg("SHADOW MapBlocks loaded [#]", blocks_loaded);
  1083. }
  1084. void ClientMap::reportMetrics(u64 save_time_us, u32 saved_blocks, u32 all_blocks)
  1085. {
  1086. g_profiler->avg("CM::reportMetrics loaded blocks [#]", all_blocks);
  1087. }
  1088. void ClientMap::updateTransparentMeshBuffers()
  1089. {
  1090. ScopeProfiler sp(g_profiler, "CM::updateTransparentMeshBuffers", SPT_AVG);
  1091. u32 sorted_blocks = 0;
  1092. u32 unsorted_blocks = 0;
  1093. f32 sorting_distance_sq = std::pow(m_cache_transparency_sorting_distance * BS, 2.0f);
  1094. // Update the order of transparent mesh buffers in each mesh
  1095. for (auto it = m_drawlist.begin(); it != m_drawlist.end(); it++) {
  1096. MapBlock* block = it->second;
  1097. if (!block->mesh)
  1098. continue;
  1099. if (m_needs_update_transparent_meshes ||
  1100. block->mesh->getTransparentBuffers().size() == 0) {
  1101. v3s16 block_pos = block->getPos();
  1102. v3f block_pos_f = intToFloat(block_pos * MAP_BLOCKSIZE + MAP_BLOCKSIZE / 2, BS);
  1103. f32 distance = m_camera_position.getDistanceFromSQ(block_pos_f);
  1104. if (distance <= sorting_distance_sq) {
  1105. block->mesh->updateTransparentBuffers(m_camera_position, block_pos);
  1106. ++sorted_blocks;
  1107. }
  1108. else {
  1109. block->mesh->consolidateTransparentBuffers();
  1110. ++unsorted_blocks;
  1111. }
  1112. }
  1113. }
  1114. g_profiler->avg("CM::Transparent Buffers - Sorted", sorted_blocks);
  1115. g_profiler->avg("CM::Transparent Buffers - Unsorted", unsorted_blocks);
  1116. m_needs_update_transparent_meshes = false;
  1117. }
  1118. scene::IMeshBuffer* ClientMap::DrawDescriptor::getBuffer()
  1119. {
  1120. return m_use_partial_buffer ? m_partial_buffer->getBuffer() : m_buffer;
  1121. }
  1122. void ClientMap::DrawDescriptor::draw(video::IVideoDriver* driver)
  1123. {
  1124. if (m_use_partial_buffer) {
  1125. m_partial_buffer->beforeDraw();
  1126. driver->drawMeshBuffer(m_partial_buffer->getBuffer());
  1127. m_partial_buffer->afterDraw();
  1128. } else {
  1129. driver->drawMeshBuffer(m_buffer);
  1130. }
  1131. }
  1132. bool ClientMap::isMeshOccluded(MapBlock *mesh_block, u16 mesh_size, v3s16 cam_pos_nodes)
  1133. {
  1134. if (mesh_size == 1)
  1135. return isBlockOccluded(mesh_block, cam_pos_nodes);
  1136. v3s16 min_edge = mesh_block->getPosRelative();
  1137. v3s16 max_edge = min_edge + mesh_size * MAP_BLOCKSIZE -1;
  1138. bool check_axis[3] = { false, false, false };
  1139. u16 closest_side[3] = { 0, 0, 0 };
  1140. for (int axis = 0; axis < 3; axis++) {
  1141. if (cam_pos_nodes[axis] < min_edge[axis])
  1142. check_axis[axis] = true;
  1143. else if (cam_pos_nodes[axis] > max_edge[axis]) {
  1144. check_axis[axis] = true;
  1145. closest_side[axis] = mesh_size - 1;
  1146. }
  1147. }
  1148. std::vector<bool> processed_blocks(mesh_size * mesh_size * mesh_size);
  1149. // scan the side
  1150. for (u16 i = 0; i < mesh_size; i++)
  1151. for (u16 j = 0; j < mesh_size; j++) {
  1152. v3s16 offsets[3] = {
  1153. v3s16(closest_side[0], i, j),
  1154. v3s16(i, closest_side[1], j),
  1155. v3s16(i, j, closest_side[2])
  1156. };
  1157. for (int axis = 0; axis < 3; axis++) {
  1158. v3s16 offset = offsets[axis];
  1159. int block_index = offset.X + offset.Y * mesh_size + offset.Z * mesh_size * mesh_size;
  1160. if (check_axis[axis] && !processed_blocks[block_index]) {
  1161. processed_blocks[block_index] = true;
  1162. v3s16 block_pos = mesh_block->getPos() + offset;
  1163. MapBlock *block;
  1164. if (mesh_block->getPos() == block_pos)
  1165. block = mesh_block;
  1166. else
  1167. block = getBlockNoCreateNoEx(block_pos);
  1168. if (block && !isBlockOccluded(block, cam_pos_nodes))
  1169. return false;
  1170. }
  1171. }
  1172. }
  1173. return true;
  1174. }