From d0ba3555209b38bd7700b8246ff7c6b49e78fcde Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Wed, 28 Jul 2021 17:17:36 +0100 Subject: [PATCH] Portals - add autoplace priority setting to CullInstance The default autoplace algorithm places instances in the highest priority Room. It became apparent that there are some situations in which users will want to override this and force placement in a Room from a particular RoomGroup, especially an "outside" RoomGroup. This setting allows the user to specify a preference for Room priority. When set to 0, the setting is ignored and the highest priority Room is chosen. --- doc/classes/CullInstance.xml | 5 +++++ scene/3d/cull_instance.cpp | 5 +++++ scene/3d/cull_instance.h | 11 +++++++++++ scene/3d/room_manager.cpp | 12 ++++++++++++ 4 files changed, 33 insertions(+) diff --git a/doc/classes/CullInstance.xml b/doc/classes/CullInstance.xml index 36d7fc69e72..6ee7d632d67 100644 --- a/doc/classes/CullInstance.xml +++ b/doc/classes/CullInstance.xml @@ -15,6 +15,11 @@ + + When set to [code]0[/code], [CullInstance]s will be autoplaced in the [Room] with the highest priority. + When set to a value other than [code]0[/code], the system will attempt to autoplace in a [Room] with the [code]autoplace_priority[/code], if it is present. + This can be used to control autoplacement of building exteriors in an outer [RoomGroup]. + When a manual bound has not been explicitly specified for a [Room], the convex hull bound will be estimated from the geometry of the objects within the room. This setting determines whether the geometry of an object is included in this estimate of the room bound. [b]Note:[/b] This setting is only relevant when the object is set to [code]PORTAL_MODE_STATIC[/code] or [code]PORTAL_MODE_DYNAMIC[/code], and for [Portal]s. diff --git a/scene/3d/cull_instance.cpp b/scene/3d/cull_instance.cpp index 8cc30eb1158..ae7985f0e88 100644 --- a/scene/3d/cull_instance.cpp +++ b/scene/3d/cull_instance.cpp @@ -48,6 +48,9 @@ void CullInstance::_bind_methods() { ClassDB::bind_method(D_METHOD("set_include_in_bound"), &CullInstance::set_include_in_bound); ClassDB::bind_method(D_METHOD("get_include_in_bound"), &CullInstance::get_include_in_bound); + ClassDB::bind_method(D_METHOD("set_portal_autoplace_priority", "priority"), &CullInstance::set_portal_autoplace_priority); + ClassDB::bind_method(D_METHOD("get_portal_autoplace_priority"), &CullInstance::get_portal_autoplace_priority); + ADD_GROUP("Portals", ""); BIND_ENUM_CONSTANT(PORTAL_MODE_STATIC); @@ -58,9 +61,11 @@ void CullInstance::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "portal_mode", PROPERTY_HINT_ENUM, "Static,Dynamic,Roaming,Global,Ignore"), "set_portal_mode", "get_portal_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_in_bound"), "set_include_in_bound", "get_include_in_bound"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "autoplace_priority", PROPERTY_HINT_RANGE, "-16,16,1", PROPERTY_USAGE_DEFAULT), "set_portal_autoplace_priority", "get_portal_autoplace_priority"); } CullInstance::CullInstance() { _portal_mode = PORTAL_MODE_STATIC; _include_in_bound = true; + _portal_autoplace_priority = 0; } diff --git a/scene/3d/cull_instance.h b/scene/3d/cull_instance.h index 87d47cf7637..bb61ffa8d69 100644 --- a/scene/3d/cull_instance.h +++ b/scene/3d/cull_instance.h @@ -51,6 +51,9 @@ public: void set_include_in_bound(bool p_enable) { _include_in_bound = p_enable; } bool get_include_in_bound() const { return _include_in_bound; } + void set_portal_autoplace_priority(int p_priority) { _portal_autoplace_priority = p_priority; } + int get_portal_autoplace_priority() const { return _portal_autoplace_priority; } + CullInstance(); protected: @@ -61,6 +64,14 @@ protected: private: PortalMode _portal_mode; bool _include_in_bound; + + // Allows instances to prefer to be autoplaced + // in specific RoomGroups. This allows building exteriors + // to be autoplaced in outside RoomGroups, allowing a complete + // exterior / interior of building in one reusable Scene. + // The default value 0 gives no preference (chooses the highest priority). + // All other values will autoplace in the selected RoomGroup priority by preference. + int _portal_autoplace_priority; }; #endif diff --git a/scene/3d/room_manager.cpp b/scene/3d/room_manager.cpp index 4f9be0a59ee..86731271f0d 100644 --- a/scene/3d/room_manager.cpp +++ b/scene/3d/room_manager.cpp @@ -1121,14 +1121,26 @@ bool RoomManager::_autoplace_object(VisualInstance *p_vi) { int best_priority = -INT32_MAX; Room *best_room = nullptr; + // if not set to zero (no preference) this can override a preference + // for a certain RoomGroup priority to ensure the instance gets placed in the correct + // RoomGroup (e.g. outside, for building exteriors) + int preferred_priority = p_vi->get_portal_autoplace_priority(); + for (int n = 0; n < _rooms.size(); n++) { Room *room = _rooms[n]; if (room->contains_point(centre)) { + // the standard routine autoplaces in the highest priority room if (room->_room_priority > best_priority) { best_priority = room->_room_priority; best_room = room; } + + // if we override the preferred priority we always choose this + if (preferred_priority && (room->_room_priority == preferred_priority)) { + best_room = room; + break; + } } }