virtualx-engine/doc/classes/RoomManager.xml
lawnjelly 788f075b44 Portals - Allow user to set roaming expansion margin
Previously a crude metric was used to decide on the roaming expansion margin, but it created unexpected results in some scenarios. Instead this setting is exposed to the user via the RoomManager, allowing them to tailor it to the world size, room sizes, roaming objects sizes and the speeds of movement.
2021-11-12 15:46:04 +00:00

112 lines
13 KiB
XML

<?xml version="1.0" encoding="UTF-8" ?>
<class name="RoomManager" inherits="Spatial" version="3.5">
<brief_description>
The RoomManager node is used to control the portal culling system.
</brief_description>
<description>
In order to utilize the portal occlusion culling system, you must build your level using [Room]s and [Portal]s. Before these can be used at runtime, they must undergo a short conversion process to build the [code]room graph[/code], runtime data needed for portal culling. The [code]room graph[/code] is controlled by the [RoomManager] node, and the [RoomManager] also contains settings that are common throughout the portal system.
</description>
<tutorials>
</tutorials>
<methods>
<method name="rooms_clear">
<return type="void" />
<description>
This function clears all converted data from the [b]room graph[/b]. Use this before unloading a level, when transitioning from level to level, or returning to a main menu.
</description>
</method>
<method name="rooms_convert">
<return type="void" />
<description>
This is the most important function in the whole portal culling system. Without it, the system cannot function.
First it goes through every [Room] that is a child of the [code]room list[/code] node (and [RoomGroup]s within) and converts and adds it to the [code]room graph[/code].
This works for both [Room] nodes, and [Spatial] nodes that follow a special naming convention. They should begin with the prefix [i]'Room_'[/i], followed by the name you wish to give the room, e.g. [i]'Room_lounge'[/i]. This will automatically convert such [Spatial]s to [Room] nodes for you. This is useful if you want to build you entire room system in e.g. Blender, and reimport multiple times as you work on the level.
The conversion will try to assign [VisualInstance]s that are children and grandchildren of the [Room] to the room. These should be given a suitable [code]portal mode[/code] (see the [CullInstance] documentation). The default [code]portal mode[/code] is [code]STATIC[/code] - objects which are not expected to move while the level is played, which will typically be most objects.
The conversion will usually use the geometry of these [VisualInstance]s (and the [Portal]s) to calculate a convex hull bound for the room. These bounds will be shown in the editor with a wireframe. Alternatively you can specify a manual custom bound for any room, see the [Room] documentation.
By definition, [Camera]s within a room can see everything else within the room (that is one advantage to using convex hulls). However, in order to see from one room into adjacent rooms, you must place [Portal]s, which represent openings that the camera can see through, like windows and doors.
[Portal]s are really just specialized [MeshInstance]s. In fact you will usually first create a portal by creating a [MeshInstance], especially a [code]plane[/code] mesh instance. You would move the plane in the editor to cover a window or doorway, with the front face pointing outward from the room. To let the conversion process know you want this mesh to be a portal, again we use a special naming convention. [MeshInstance]s to be converted to a [Portal] should start with the prefix [i]'Portal_'[/i].
You now have a choice - you can leave the name as [i]'Portal_'[/i] and allow the system to automatically detect the nearest [Room] to link. In most cases this will work fine.
An alternative method is to specify the [Room] to link to manually, appending a suffix to the portal name, which should be the name of the room you intend to link to. For example [i]'Portal_lounge'[/i] will attempt to link to the room named [i]'Room_lounge'[/i].
There is a special case here - Godot does not allow two nodes to share the same name. What if you want to manually have more than one portal leading into the same room? Surely they will need to both be called, e.g. [i]'Portal_lounge'[/i]?
The solution is a wildcard character. After the room name, if you use the character [i]'*'[/i], this character and anything following it will be ignored. So you can use for example [i]'Portal_lounge*0'[/i], [i]'Portal_lounge*1'[/i] etc.
Note that [Portal]s that have already been converted to [Portal] nodes (rather than [MeshInstance]s) still need to follow the same naming convention, as they will be relinked each time during conversion.
It is recommended that you only place objects in rooms that are desired to stay within those rooms - i.e. [code]portal mode[/code]s [code]STATIC[/code] or [code]DYNAMIC[/code] (not crossing portals). [code]GLOBAL[/code] and [code]ROAMING[/code] objects are best placed in another part of the scene tree, to avoid confusion. See [CullInstance] for a full description of portal modes.
</description>
</method>
</methods>
<members>
<member name="active" type="bool" setter="rooms_set_active" getter="rooms_get_active" default="true">
Switches the portal culling system on and off.
It is important to note that when portal culling is active, it is responsible for [b]all[/b] the 3d culling. Some editor functionality may be more difficult to use, so switching the active flag is intended to be used to make sure your [Room] / [Portal] layout works within the editor.
Switching to [code]active[/code] will have no effect when the [code]room graph[/code] is unloaded (the rooms have not yet been converted).
</member>
<member name="debug_sprawl" type="bool" setter="set_debug_sprawl" getter="get_debug_sprawl" default="false">
Large objects can 'sprawl' over (be present in) more than one room. It can be useful to visualize which objects are sprawling outside the current room.
Toggling this setting turns this debug view on and off.
</member>
<member name="default_portal_margin" type="float" setter="set_default_portal_margin" getter="get_default_portal_margin" default="1.0">
Usually we don't want objects that only [b]just[/b] cross a boundary into an adjacent [Room] to sprawl into that room. To prevent this, each [Portal] has an extra margin, or tolerance zone where objects can enter without sprawling to a neighbouring room.
In most cases you can set this here for all portals. It is possible to override the margin for each portal.
</member>
<member name="gameplay_monitor" type="bool" setter="set_gameplay_monitor_enabled" getter="get_gameplay_monitor_enabled" default="false">
When using a partial or full PVS, the gameplay monitor allows you to receive callbacks when roaming objects or rooms enter or exit the [b]gameplay area[/b]. The gameplay area is defined as either the primary, or secondary PVS.
These callbacks allow you to, for example, reduce processing for objects that are far from the player, or turn on and off AI.
You can either choose to receive callbacks as notifications through the [code]_notification[/code] function, or as signals.
[code]NOTIFICATION_ENTER_GAMEPLAY[/code]
[code]NOTIFICATION_EXIT_GAMEPLAY[/code]
Signals: [code]"gameplay_entered"[/code], [code]"gameplay_exited"[/code]
</member>
<member name="merge_meshes" type="bool" setter="set_merge_meshes" getter="get_merge_meshes" default="false">
If enabled, the system will attempt to merge similar meshes (particularly in terms of materials) within [Room]s during conversion. This can significantly reduce the number of drawcalls and state changes required during rendering, albeit at a cost of reduced culling granularity.
[b]Note:[/b] This operates at runtime during the conversion process, and will only operate on exported or running projects, in order to prevent accidental alteration to the scene and loss of data.
</member>
<member name="overlap_warning_threshold" type="int" setter="set_overlap_warning_threshold" getter="get_overlap_warning_threshold" default="1">
When converting rooms, the editor will warn you if overlap is detected between rooms. Overlap can interfere with determining the room that cameras and objects are within. A small amount can be acceptable, depending on your level. Here you can alter the threshold at which the editor warning appears. There are no other side effects.
</member>
<member name="portal_depth_limit" type="int" setter="set_portal_depth_limit" getter="get_portal_depth_limit" default="16">
Portal rendering is recursive - each time a portal is seen through an earlier portal there is some cost. For this reason, and to prevent the possibility of infinite loops, this setting provides a hard limit on the recursion depth.
[b]Note:[/b] This value is unused when using [code]Full[/code] PVS mode.
</member>
<member name="preview_camera" type="NodePath" setter="set_preview_camera_path" getter="get_preview_camera_path" default="NodePath(&quot;&quot;)">
Portal culling normally operates using the current [Camera] / [Camera]s, however for debugging purposes within the editor, you can use this setting to override this behaviour and force it to use a particular camera to get a better idea of what the occlusion culling is doing.
</member>
<member name="process_priority" type="int" setter="set_process_priority" getter="get_process_priority" override="true" default="10000" />
<member name="pvs_mode" type="int" setter="set_pvs_mode" getter="get_pvs_mode" enum="RoomManager.PVSMode" default="1">
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.
</member>
<member name="roaming_expansion_margin" type="float" setter="set_roaming_expansion_margin" getter="get_roaming_expansion_margin" default="1.0">
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.
</member>
<member name="room_simplify" type="float" setter="set_room_simplify" getter="get_room_simplify" default="0.5">
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.
The [code]room_simplify[/code] value can be used to gain fine control over this process. It determines how similar planes can be for them to be considered the same (and duplicates removed). The value can be set between 0 (no simplification) and 1 (maximum simplification).
The value set here is the default for all rooms, but individual rooms can override this value if desired.
The room convex hulls are shown as a wireframe in the editor.
</member>
<member name="roomlist" type="NodePath" setter="set_roomlist_path" getter="get_roomlist_path" default="NodePath(&quot;&quot;)">
For the [Room] conversion process to succeed, you must point the [RoomManager] to the parent [Node] of your [Room]s and [RoomGroup]s, which we refer to as the [code]roomlist[/code] (the roomlist is not a special node type, it is normally just a [Spatial]).
</member>
<member name="show_margins" type="bool" setter="set_show_margins" getter="get_show_margins" default="true">
Shows the [Portal] margins when the portal gizmo is used in the editor.
</member>
<member name="use_secondary_pvs" type="bool" setter="set_use_secondary_pvs" getter="get_use_secondary_pvs" default="false">
When receiving gameplay callbacks when objects enter and exit gameplay, the [b]gameplay area[/b] can be defined by either the primary PVS (potentially visible set) of [Room]s, or the secondary PVS (the primary PVS and their neighbouring [Room]s).
Sometimes using the larger gameplay area of the secondary PVS may be preferable.
</member>
</members>
<constants>
<constant name="PVS_MODE_DISABLED" value="0" enum="PVSMode">
Use only [Portal]s at runtime to determine visibility. PVS will not be generated at [Room]s conversion, and gameplay notifications cannot be used.
</constant>
<constant name="PVS_MODE_PARTIAL" value="1" enum="PVSMode">
Use a combination of PVS and [Portal]s to determine visibility (this is usually fastest and most accurate).
</constant>
<constant name="PVS_MODE_FULL" value="2" enum="PVSMode">
Use only the PVS (potentially visible set) of [Room]s to determine visibility.
</constant>
</constants>
</class>