Add a setting to group transparency sorted triangles by buffer (#15115)

This commit is contained in:
DS 2024-11-28 14:22:53 +01:00 committed by GitHub
parent c175046d30
commit df4e70b2c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 66 additions and 14 deletions

@ -1843,6 +1843,11 @@ video_driver (Video driver) enum ,opengl,opengl3,ogles2
# Set to 0 to disable it entirely. # Set to 0 to disable it entirely.
transparency_sorting_distance (Transparency Sorting Distance) int 16 0 128 transparency_sorting_distance (Transparency Sorting Distance) int 16 0 128
# Draw transparency sorted triangles grouped by their mesh buffers.
# This breaks transparency sorting between mesh buffers, but avoids situations
# where transparency sorting would be very slow otherwise.
transparency_sorting_group_by_buffers (Transparency Sorting Group by Buffers) bool true
# Radius of cloud area stated in number of 64 node cloud squares. # Radius of cloud area stated in number of 64 node cloud squares.
# Values larger than 26 will start to produce sharp cutoffs at cloud area corners. # Values larger than 26 will start to produce sharp cutoffs at cloud area corners.
cloud_radius (Cloud radius) int 12 1 62 cloud_radius (Cloud radius) int 12 1 62

@ -73,6 +73,7 @@ static const std::string ClientMap_settings[] = {
"trilinear_filter", "trilinear_filter",
"bilinear_filter", "bilinear_filter",
"anisotropic_filter", "anisotropic_filter",
"transparency_sorting_group_by_buffers",
"transparency_sorting_distance", "transparency_sorting_distance",
"occlusion_culler", "occlusion_culler",
"enable_raytraced_culling", "enable_raytraced_culling",
@ -115,6 +116,9 @@ void ClientMap::onSettingChanged(std::string_view name, bool all)
m_cache_bilinear_filter = g_settings->getBool("bilinear_filter"); m_cache_bilinear_filter = g_settings->getBool("bilinear_filter");
if (all || name == "anisotropic_filter") if (all || name == "anisotropic_filter")
m_cache_anistropic_filter = g_settings->getBool("anisotropic_filter"); m_cache_anistropic_filter = g_settings->getBool("anisotropic_filter");
if (all || name == "transparency_sorting_group_by_buffers")
m_cache_transparency_sorting_group_by_buffers =
g_settings->getBool("transparency_sorting_group_by_buffers");
if (all || name == "transparency_sorting_distance") if (all || name == "transparency_sorting_distance")
m_cache_transparency_sorting_distance = g_settings->getU16("transparency_sorting_distance"); m_cache_transparency_sorting_distance = g_settings->getU16("transparency_sorting_distance");
if (all || name == "occlusion_culler") if (all || name == "occlusion_culler")
@ -1337,7 +1341,8 @@ void ClientMap::updateTransparentMeshBuffers()
} }
if (do_sort_block) { if (do_sort_block) {
blockmesh->updateTransparentBuffers(m_camera_position, block->getPos()); blockmesh->updateTransparentBuffers(m_camera_position, block->getPos(),
m_cache_transparency_sorting_group_by_buffers);
++sorted_blocks; ++sorted_blocks;
} else { } else {
blockmesh->consolidateTransparentBuffers(); blockmesh->consolidateTransparentBuffers();

@ -182,6 +182,7 @@ private:
bool m_cache_trilinear_filter; bool m_cache_trilinear_filter;
bool m_cache_bilinear_filter; bool m_cache_bilinear_filter;
bool m_cache_anistropic_filter; bool m_cache_anistropic_filter;
bool m_cache_transparency_sorting_group_by_buffers;
u16 m_cache_transparency_sorting_distance; u16 m_cache_transparency_sorting_distance;
bool m_loops_occlusion_culler; bool m_loops_occlusion_culler;

@ -3,6 +3,7 @@
// Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com> // Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
#include "mapblock_mesh.h" #include "mapblock_mesh.h"
#include "CMeshBuffer.h"
#include "client.h" #include "client.h"
#include "mapblock.h" #include "mapblock.h"
#include "map.h" #include "map.h"
@ -818,7 +819,8 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack,
return true; return true;
} }
void MapBlockMesh::updateTransparentBuffers(v3f camera_pos, v3s16 block_pos) void MapBlockMesh::updateTransparentBuffers(v3f camera_pos, v3s16 block_pos,
bool group_by_buffers)
{ {
// nothing to do if the entire block is opaque // nothing to do if the entire block is opaque
if (m_transparent_triangles.empty()) if (m_transparent_triangles.empty())
@ -834,24 +836,56 @@ void MapBlockMesh::updateTransparentBuffers(v3f camera_pos, v3s16 block_pos)
m_transparent_buffers_consolidated = false; m_transparent_buffers_consolidated = false;
m_transparent_buffers.clear(); m_transparent_buffers.clear();
std::vector<std::pair<scene::SMeshBuffer *, std::vector<u16>>> ordered_strains;
std::unordered_map<scene::SMeshBuffer *, size_t> strain_idxs;
if (group_by_buffers) {
// find (reversed) order for strains, by iterating front-to-back
// (if a buffer A has a triangle nearer than all triangles of another
// buffer B, A should be drawn in front of (=after) B)
scene::SMeshBuffer *current_buffer = nullptr;
for (auto it = triangle_refs.rbegin(); it != triangle_refs.rend(); ++it) {
const auto &t = m_transparent_triangles[*it];
if (current_buffer == t.buffer)
continue;
current_buffer = t.buffer;
auto [_it2, is_new] =
strain_idxs.emplace(current_buffer, ordered_strains.size());
if (is_new)
ordered_strains.emplace_back(current_buffer, std::vector<u16>{});
}
}
// find order for triangles, by iterating back-to-front
scene::SMeshBuffer *current_buffer = nullptr; scene::SMeshBuffer *current_buffer = nullptr;
std::vector<u16> current_strain; std::vector<u16> *current_strain = nullptr;
for (auto i : triangle_refs) { for (auto i : triangle_refs) {
const auto &t = m_transparent_triangles[i]; const auto &t = m_transparent_triangles[i];
if (current_buffer != t.buffer) { if (current_buffer != t.buffer) {
if (current_buffer) {
m_transparent_buffers.emplace_back(current_buffer, std::move(current_strain));
current_strain.clear();
}
current_buffer = t.buffer; current_buffer = t.buffer;
if (group_by_buffers) {
auto it = strain_idxs.find(current_buffer);
assert(it != strain_idxs.end());
current_strain = &ordered_strains[it->second].second;
} else {
ordered_strains.emplace_back(current_buffer, std::vector<u16>{});
current_strain = &ordered_strains.back().second;
}
} }
current_strain.push_back(t.p1); current_strain->push_back(t.p1);
current_strain.push_back(t.p2); current_strain->push_back(t.p2);
current_strain.push_back(t.p3); current_strain->push_back(t.p3);
} }
if (!current_strain.empty()) m_transparent_buffers.reserve(ordered_strains.size());
m_transparent_buffers.emplace_back(current_buffer, std::move(current_strain)); if (group_by_buffers) {
// the order was reversed
for (auto it = ordered_strains.rbegin(); it != ordered_strains.rend(); ++it)
m_transparent_buffers.emplace_back(it->first, std::move(it->second));
} else {
for (auto it = ordered_strains.begin(); it != ordered_strains.end(); ++it)
m_transparent_buffers.emplace_back(it->first, std::move(it->second));
}
} }
void MapBlockMesh::consolidateTransparentBuffers() void MapBlockMesh::consolidateTransparentBuffers()

@ -209,8 +209,14 @@ public:
/// Center of the bounding-sphere, in BS-space, relative to block pos. /// Center of the bounding-sphere, in BS-space, relative to block pos.
v3f getBoundingSphereCenter() const { return m_bounding_sphere_center; } v3f getBoundingSphereCenter() const { return m_bounding_sphere_center; }
/// update transparent buffers to render towards the camera /** Update transparent buffers to render towards the camera.
void updateTransparentBuffers(v3f camera_pos, v3s16 block_pos); * @param group_by_buffers If true, triangles in the same buffer are batched
* into the same PartialMeshBuffer, resulting in fewer draw calls, but
* wrong order. Triangles within a single buffer are still ordered, and
* buffers are ordered relative to each other (with respect to their nearest
* triangle).
*/
void updateTransparentBuffers(v3f camera_pos, v3s16 block_pos, bool group_by_buffers);
void consolidateTransparentBuffers(); void consolidateTransparentBuffers();
/// get the list of transparent buffers /// get the list of transparent buffers

@ -302,6 +302,7 @@ void set_default_settings()
settings->setDefault("arm_inertia", "true"); settings->setDefault("arm_inertia", "true");
settings->setDefault("show_nametag_backgrounds", "true"); settings->setDefault("show_nametag_backgrounds", "true");
settings->setDefault("show_block_bounds_radius_near", "4"); settings->setDefault("show_block_bounds_radius_near", "4");
settings->setDefault("transparency_sorting_group_by_buffers", "true");
settings->setDefault("transparency_sorting_distance", "16"); settings->setDefault("transparency_sorting_distance", "16");
settings->setDefault("enable_minimap", "true"); settings->setDefault("enable_minimap", "true");