Transparency sorting for DrawList and Materials (#41)

master
Vitaliy 2022-02-25 19:23:03 +03:00 committed by GitHub
parent 277160a954
commit e0b0513465
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 45 additions and 17 deletions

View File

@ -805,6 +805,11 @@ autoscale_mode (Autoscaling mode) enum disable disable,enable,force
# A restart is required after changing this.
show_entity_selectionbox (Show entity selection boxes) bool false
# Sort transparent materials from back to front for proper rendering
# Note: works on a per-chunk basis
# Note: different materials are sorted independently
transparency_sorting (Transparency sorting) bool true
[*Menus]
# Use a cloud animation for the main menu background.

View File

@ -939,6 +939,12 @@
# type: bool
# show_entity_selectionbox = false
# Sort transparent materials from back to front for proper rendering
# Note: works on a per-chunk basis
# Note: different materials are sorted independently
# type: bool
# transparency_sorting = true
## Menus
# Use a cloud animation for the main menu background.

View File

@ -88,6 +88,7 @@ ClientMap::ClientMap(
m_cache_trilinear_filter = g_settings->getBool("trilinear_filter");
m_cache_bilinear_filter = g_settings->getBool("bilinear_filter");
m_cache_anistropic_filter = g_settings->getBool("anisotropic_filter");
m_cache_transparency_sorting = g_settings->getFlag("transparency_sorting");
}
@ -147,8 +148,8 @@ void ClientMap::updateDrawList()
{
ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG);
for (auto &i : m_drawlist) {
MapBlock *block = i.second;
for (auto const &i : m_drawlist) {
MapBlock *block = i.block;
block->refDrop();
}
m_drawlist.clear();
@ -247,7 +248,7 @@ void ClientMap::updateDrawList()
// Add to set
block->refGrab();
m_drawlist[block->getPos()] = block;
m_drawlist.push_back({block, d});
sector_blocks_drawn++;
} // foreach sectorblocks
@ -256,6 +257,12 @@ void ClientMap::updateDrawList()
m_last_drawn_sectors.insert(sp);
}
if (m_drawlist.capacity() > m_drawlist.size() / 4)
m_drawlist.shrink_to_fit();
if (m_cache_transparency_sorting)
std::sort(m_drawlist.begin(), m_drawlist.end(), [] (DrawListItem const &a, DrawListItem const &b) { return a.distance > b.distance; });
g_profiler->avg("MapBlock meshes in range [#]", blocks_in_range_with_mesh);
g_profiler->avg("MapBlocks occlusion culled [#]", blocks_occlusion_culled);
g_profiler->avg("MapBlocks drawn [#]", m_drawlist.size());
@ -306,16 +313,11 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
MeshBufListList drawbufs;
for (auto &i : m_drawlist) {
v3s16 block_pos = i.first;
MapBlock *block = i.second;
// If the mesh of the block happened to get deleted, ignore it
if (!block->mesh)
continue;
float d = 0.0;
if (!isBlockInSight(block->getPos(), camera_position,
for (auto &item : m_drawlist) {
MapBlock *block = item.block;
v3s16 block_pos = block->getPos();
float d;
if (!isBlockInSight(block_pos, camera_position,
camera_direction, camera_fov, 100000 * BS, &d))
continue;
@ -387,6 +389,14 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
// Render all layers in order
for (auto &lists : drawbufs.lists) {
if (m_cache_transparency_sorting) {
static const auto comparator = [] (MeshBufList const &a, MeshBufList const &b) {
// comparing pointers with < is UB unless they belong to the same array, but std::less is always allowed
static const std::less<video::ITexture *> texture_less;
return texture_less(a.m.TextureLayer[0].Texture, b.m.TextureLayer[0].Texture);
};
std::sort(lists.begin(), lists.end(), comparator);
}
for (MeshBufList &list : lists) {
// Check and abort if the machine is swapping a lot
if (draw.getTimerTime() > 2000) {

View File

@ -55,6 +55,11 @@ struct MeshBufListList
void add(scene::IMeshBuffer *buf, v3s16 position, u8 layer);
};
struct DrawListItem {
MapBlock *block;
float distance;
};
class Client;
class ITextureSource;
@ -146,11 +151,12 @@ private:
f32 m_camera_fov = M_PI;
v3s16 m_camera_offset;
std::map<v3s16, MapBlock*> m_drawlist;
std::vector<DrawListItem> m_drawlist;
std::set<v2s16> m_last_drawn_sectors;
bool m_cache_trilinear_filter;
bool m_cache_bilinear_filter;
bool m_cache_anistropic_filter;
bool m_cache_transparency_sorting;
};

View File

@ -245,6 +245,7 @@ void set_default_settings()
settings->setDefault("round_screen", "0");
settings->setDefault("enable_local_map_saving", "false");
settings->setDefault("show_entity_selectionbox", "false");
settings->setDefault("transparency_sorting", "true");
settings->setDefault("texture_clean_transparent", "false");
settings->setDefault("texture_min_size", "0");
settings->setDefault("ambient_occlusion_gamma", "2.2");

View File

@ -123,18 +123,18 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
v3f blockpos_relative = blockpos - camera_pos;
// Total distance
f32 d = MYMAX(0, blockpos_relative.getLength() - block_max_radius);
f32 d = blockpos_relative.getLength();
if (distance_ptr)
*distance_ptr = d;
// If block is far away, it's not in sight
if (d > range)
if (d > range + block_max_radius)
return false;
// If block is (nearly) touching the camera, don't
// bother validating further (that is, render it anyway)
if (d == 0)
if (d <= block_max_radius)
return true;
// Adjust camera position, for purposes of computing the angle,