From f7a695c212bea96887b32b859645f621fd8f1b48 Mon Sep 17 00:00:00 2001 From: sfence Date: Sat, 14 Dec 2024 17:01:06 +0100 Subject: [PATCH] Optimize raycast performance (#15233) by skipping nodes not on the ray with selection boxes smaller than 1x1x1 early on --- doc/lua_api.md | 2 ++ src/environment.cpp | 6 ++++++ src/nodedef.cpp | 12 ++++++++++++ src/nodedef.h | 5 +++++ 4 files changed, 25 insertions(+) diff --git a/doc/lua_api.md b/doc/lua_api.md index 7fe464a30..d753b6b53 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -9948,6 +9948,8 @@ Used by `core.register_node`. selection_box = { -- see [Node boxes] for possibilities + -- Selection boxes that oversize node size can cause + -- significant performance drop of Raycasts. }, -- Custom selection box definition. Multiple boxes can be defined. -- If "nodebox" drawtype is used and selection_box is nil, then node_box diff --git a/src/environment.cpp b/src/environment.cpp index fe582afd4..e66c7e2de 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -163,6 +163,8 @@ void Environment::continueRaycast(RaycastState *state, PointedThing *result_p) break; // About to go out of bounds } + const v3s16 pos_on_ray = state->m_iterator.m_current_node_pos; + // For each untested node for (s16 z = new_nodes.MinEdge.Z; z <= new_nodes.MaxEdge.Z; z++) for (s16 y = new_nodes.MinEdge.Y; y <= new_nodes.MaxEdge.Y; y++) @@ -175,6 +177,10 @@ void Environment::continueRaycast(RaycastState *state, PointedThing *result_p) if (!is_valid_position) continue; + // Optimization: Skip non-oversized selection boxes for other positions. + if ((pos_on_ray != np) && !nodedef->get(n).has_big_selection_box) + continue; + PointabilityType pointable = isPointableNode(n, nodedef, state->m_liquids_pointable, state->m_pointabilities); diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 81348cf23..0fde1b68e 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -1257,6 +1257,15 @@ inline void NodeDefManager::fixSelectionBoxIntUnion() m_selection_box_union.MaxEdge.Z / BS - 0.5f); } +inline void NodeDefManager::calcBigSelectionBox(content_t id, const ContentFeatures &def) +{ + aabb3f box_union; + getNodeBoxUnion(def.selection_box, def, &box_union); + m_content_features[id].has_big_selection_box = + (box_union.MinEdge.X < -BS/2) || (box_union.MaxEdge.X > BS/2) || + (box_union.MinEdge.Y < -BS/2) || (box_union.MaxEdge.Y > BS/2) || + (box_union.MinEdge.Z < -BS/2) || (box_union.MaxEdge.Z > BS/2); +} void NodeDefManager::eraseIdFromGroups(content_t id) { @@ -1312,6 +1321,7 @@ content_t NodeDefManager::set(const std::string &name, const ContentFeatures &de getNodeBoxUnion(def.selection_box, def, &m_selection_box_union); fixSelectionBoxIntUnion(); + calcBigSelectionBox(id, def); // Add this content to the list of all groups it belongs to for (const auto &group : def.groups) { const std::string &group_name = group.first; @@ -1525,6 +1535,8 @@ void NodeDefManager::deSerialize(std::istream &is, u16 protocol_version) getNodeBoxUnion(f.selection_box, f, &m_selection_box_union); fixSelectionBoxIntUnion(); + + calcBigSelectionBox(i, f); } // Since liquid_alternative_flowing_id and liquid_alternative_source_id diff --git a/src/nodedef.h b/src/nodedef.h index c3f88ce83..e33f42699 100644 --- a/src/nodedef.h +++ b/src/nodedef.h @@ -425,6 +425,8 @@ struct ContentFeatures NodeBox node_box; NodeBox selection_box; NodeBox collision_box; + //! Whether any selection box extent is > BS/2. + bool has_big_selection_box; // --- SOUND PROPERTIES --- @@ -774,6 +776,9 @@ private: */ void fixSelectionBoxIntUnion(); + //! Calculates ContentFeatures::&has_big_selection_box + void calcBigSelectionBox(content_t id, const ContentFeatures &def); + //! Features indexed by ID. std::vector m_content_features;