diff --git a/doc/classes/RoomManager.xml b/doc/classes/RoomManager.xml
index 63022ddd472..9ef94c77261 100644
--- a/doc/classes/RoomManager.xml
+++ b/doc/classes/RoomManager.xml
@@ -75,6 +75,11 @@
Optionally during conversion the potentially visible set (PVS) of rooms that are potentially visible from each room can be calculated. This can be used either to aid in dynamic portal culling, or to totally replace portal culling.
In [code]Full[/code] PVS Mode, all objects within the potentially visible rooms will be frustum culled, and rendered if they are within the view frustum.
+
+ In order to reduce processing for roaming objects, an expansion is applied to their AABB as they move. This expanded volume is used to calculate which rooms the roaming object is within. If the object's exact AABB is still within this expanded volume on the next move, there is no need to reprocess the object, which can save considerable CPU.
+ The downside is that if the expansion is too much, the object may end up unexpectedly sprawling into neighbouring rooms and showing up where it might otherwise be culled.
+ In order to balance roaming performance against culling accuracy, this expansion margin can be customized by the user. It will typically depend on your room and object sizes, and movement speeds. The default value should work reasonably in most circumstances.
+
During the conversion process, the geometry of objects within [Room]s, or a custom specified manual bound, are used to generate a [b]convex hull bound[/b].
This convex hull is [b]required[/b] in the visibility system, and is used for many purposes. Most importantly, it is used to decide whether the [Camera] (or an object) is within a [Room]. The convex hull generating algorithm is good, but occasionally it can create too many (or too few) planes to give a good representation of the room volume.
diff --git a/scene/3d/room_manager.cpp b/scene/3d/room_manager.cpp
index 26b2d4222fa..044e01e069e 100644
--- a/scene/3d/room_manager.cpp
+++ b/scene/3d/room_manager.cpp
@@ -313,6 +313,7 @@ void RoomManager::_bind_methods() {
LIMPL_PROPERTY_RANGE(Variant::INT, portal_depth_limit, set_portal_depth_limit, get_portal_depth_limit, "0,255,1");
LIMPL_PROPERTY_RANGE(Variant::REAL, room_simplify, set_room_simplify, get_room_simplify, "0.0,1.0,0.005");
LIMPL_PROPERTY_RANGE(Variant::REAL, default_portal_margin, set_default_portal_margin, get_default_portal_margin, "0.0, 10.0, 0.01");
+ LIMPL_PROPERTY_RANGE(Variant::REAL, roaming_expansion_margin, set_roaming_expansion_margin, get_roaming_expansion_margin, "0.0, 3.0, 0.01");
#undef LIMPL_PROPERTY
#undef LIMPL_PROPERTY_RANGE
@@ -382,7 +383,15 @@ void RoomManager::set_portal_depth_limit(int p_limit) {
_settings_portal_depth_limit = p_limit;
if (is_inside_world() && get_world().is_valid()) {
- VisualServer::get_singleton()->rooms_set_params(get_world()->get_scenario(), p_limit);
+ VisualServer::get_singleton()->rooms_set_params(get_world()->get_scenario(), p_limit, _settings_roaming_expansion_margin);
+ }
+}
+
+void RoomManager::set_roaming_expansion_margin(real_t p_dist) {
+ _settings_roaming_expansion_margin = p_dist;
+
+ if (is_inside_world() && get_world().is_valid()) {
+ VisualServer::get_singleton()->rooms_set_params(get_world()->get_scenario(), _settings_portal_depth_limit, _settings_roaming_expansion_margin);
}
}
diff --git a/scene/3d/room_manager.h b/scene/3d/room_manager.h
index 5455f1e5a82..76e54e00955 100644
--- a/scene/3d/room_manager.h
+++ b/scene/3d/room_manager.h
@@ -88,6 +88,9 @@ public:
void set_portal_depth_limit(int p_limit);
int get_portal_depth_limit() const { return _settings_portal_depth_limit; }
+ void set_roaming_expansion_margin(real_t p_dist);
+ real_t get_roaming_expansion_margin() const { return _settings_roaming_expansion_margin; }
+
void set_pvs_mode(PVSMode p_mode);
PVSMode get_pvs_mode() const;
@@ -256,6 +259,7 @@ private:
real_t _overlap_warning_threshold = 1.0;
Room::SimplifyInfo _room_simplify_info;
int _settings_portal_depth_limit = 16;
+ real_t _settings_roaming_expansion_margin = 1.0;
// debug override camera
ObjectID _godot_preview_camera_ID = -1;
diff --git a/servers/visual/portals/portal_renderer.cpp b/servers/visual/portals/portal_renderer.cpp
index 6bfb1137d11..884caf0d4eb 100644
--- a/servers/visual/portals/portal_renderer.cpp
+++ b/servers/visual/portals/portal_renderer.cpp
@@ -822,20 +822,6 @@ void PortalRenderer::rooms_finalize(bool p_generate_pvs, bool p_cull_using_pvs,
// from position
_rooms_lookup_bsp.create(*this);
- // calculate the roaming expansion margin based on the average room size
- Vector3 total_size = Vector3(0, 0, 0);
- for (int n = 0; n < get_num_rooms(); n++) {
- total_size += get_room(n)._aabb.size;
- }
- if (get_num_rooms()) {
- total_size /= get_num_rooms();
- AABB temp;
- temp.size = total_size;
-
- // longest axis of average room * fudge factor
- _roaming_expansion_margin = temp.get_longest_axis_size() * 0.08;
- }
-
// calculate PVS
if (p_generate_pvs) {
PVSBuilder pvs;
diff --git a/servers/visual/portals/portal_renderer.h b/servers/visual/portals/portal_renderer.h
index b0ade7bbd09..7bafa1307a7 100644
--- a/servers/visual/portals/portal_renderer.h
+++ b/servers/visual/portals/portal_renderer.h
@@ -156,7 +156,10 @@ public:
void rooms_finalize(bool p_generate_pvs, bool p_cull_using_pvs, bool p_use_secondary_pvs, bool p_use_signals, String p_pvs_filename, bool p_use_simple_pvs, bool p_log_pvs_generation);
void rooms_override_camera(bool p_override, const Vector3 &p_point, const Vector *p_convex);
void rooms_set_active(bool p_active) { _active = p_active; }
- void rooms_set_params(int p_portal_depth_limit) { _tracer.set_depth_limit(p_portal_depth_limit); }
+ void rooms_set_params(int p_portal_depth_limit, real_t p_roaming_expansion_margin) {
+ _tracer.set_depth_limit(p_portal_depth_limit);
+ _roaming_expansion_margin = p_roaming_expansion_margin;
+ }
void rooms_set_cull_using_pvs(bool p_enable) { _cull_using_pvs = p_enable; }
void rooms_update_gameplay_monitor(const Vector &p_camera_positions);
diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h
index f27f104b290..3890dec59d8 100644
--- a/servers/visual/visual_server_raster.h
+++ b/servers/visual/visual_server_raster.h
@@ -598,7 +598,7 @@ public:
BIND8(rooms_finalize, RID, bool, bool, bool, bool, String, bool, bool)
BIND4(rooms_override_camera, RID, bool, const Vector3 &, const Vector *)
BIND2(rooms_set_active, RID, bool)
- BIND2(rooms_set_params, RID, int)
+ BIND3(rooms_set_params, RID, int, real_t)
BIND3(rooms_set_debug_feature, RID, RoomsDebugFeature, bool)
BIND2(rooms_update_gameplay_monitor, RID, const Vector &)
diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp
index 6a39d2a063c..639d3d51076 100644
--- a/servers/visual/visual_server_scene.cpp
+++ b/servers/visual/visual_server_scene.cpp
@@ -1346,10 +1346,10 @@ void VisualServerScene::rooms_set_active(RID p_scenario, bool p_active) {
scenario->_portal_renderer.rooms_set_active(p_active);
}
-void VisualServerScene::rooms_set_params(RID p_scenario, int p_portal_depth_limit) {
+void VisualServerScene::rooms_set_params(RID p_scenario, int p_portal_depth_limit, real_t p_roaming_expansion_margin) {
Scenario *scenario = scenario_owner.getornull(p_scenario);
ERR_FAIL_COND(!scenario);
- scenario->_portal_renderer.rooms_set_params(p_portal_depth_limit);
+ scenario->_portal_renderer.rooms_set_params(p_portal_depth_limit, p_roaming_expansion_margin);
}
void VisualServerScene::rooms_set_debug_feature(RID p_scenario, VisualServer::RoomsDebugFeature p_feature, bool p_active) {
diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h
index ca5b2285dc1..f1fcc7d6d8c 100644
--- a/servers/visual/visual_server_scene.h
+++ b/servers/visual/visual_server_scene.h
@@ -668,7 +668,7 @@ public:
virtual void rooms_finalize(RID p_scenario, bool p_generate_pvs, bool p_cull_using_pvs, bool p_use_secondary_pvs, bool p_use_signals, String p_pvs_filename, bool p_use_simple_pvs, bool p_log_pvs_generation);
virtual void rooms_override_camera(RID p_scenario, bool p_override, const Vector3 &p_point, const Vector *p_convex);
virtual void rooms_set_active(RID p_scenario, bool p_active);
- virtual void rooms_set_params(RID p_scenario, int p_portal_depth_limit);
+ virtual void rooms_set_params(RID p_scenario, int p_portal_depth_limit, real_t p_roaming_expansion_margin);
virtual void rooms_set_debug_feature(RID p_scenario, VisualServer::RoomsDebugFeature p_feature, bool p_active);
virtual void rooms_update_gameplay_monitor(RID p_scenario, const Vector &p_camera_positions);
diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h
index 2ab43c22b5a..dc140ecf053 100644
--- a/servers/visual/visual_server_wrap_mt.h
+++ b/servers/visual/visual_server_wrap_mt.h
@@ -521,7 +521,7 @@ public:
FUNC8(rooms_finalize, RID, bool, bool, bool, bool, String, bool, bool)
FUNC4(rooms_override_camera, RID, bool, const Vector3 &, const Vector *)
FUNC2(rooms_set_active, RID, bool)
- FUNC2(rooms_set_params, RID, int)
+ FUNC3(rooms_set_params, RID, int, real_t)
FUNC3(rooms_set_debug_feature, RID, RoomsDebugFeature, bool)
FUNC2(rooms_update_gameplay_monitor, RID, const Vector &)
diff --git a/servers/visual_server.h b/servers/visual_server.h
index 6540ea683d1..8f3ef95a671 100644
--- a/servers/visual_server.h
+++ b/servers/visual_server.h
@@ -921,7 +921,7 @@ public:
virtual void rooms_finalize(RID p_scenario, bool p_generate_pvs, bool p_cull_using_pvs, bool p_use_secondary_pvs, bool p_use_signals, String p_pvs_filename, bool p_use_simple_pvs, bool p_log_pvs_generation) = 0;
virtual void rooms_override_camera(RID p_scenario, bool p_override, const Vector3 &p_point, const Vector *p_convex) = 0;
virtual void rooms_set_active(RID p_scenario, bool p_active) = 0;
- virtual void rooms_set_params(RID p_scenario, int p_portal_depth_limit) = 0;
+ virtual void rooms_set_params(RID p_scenario, int p_portal_depth_limit, real_t p_roaming_expansion_margin) = 0;
virtual void rooms_set_debug_feature(RID p_scenario, RoomsDebugFeature p_feature, bool p_active) = 0;
virtual void rooms_update_gameplay_monitor(RID p_scenario, const Vector &p_camera_positions) = 0;