Browse Source

Add Rooms and Portals docs (#5111)

Co-authored-by: Hugo Locurcio <[email protected]>
lawnjelly 4 years ago
parent
commit
1a44e8f9e7
31 changed files with 576 additions and 9 deletions
  1. 1 0
      tutorials/3d/index.rst
  2. 104 0
      tutorials/3d/portals/advanced_room_and_portal_usage.rst
  3. 101 0
      tutorials/3d/portals/editing_rooms_and_portals.rst
  4. 115 0
      tutorials/3d/portals/first_steps_with_rooms_and_portals.rst
  5. BIN
      tutorials/3d/portals/img/convex_hull.png
  6. BIN
      tutorials/3d/portals/img/cull_instance.png
  7. BIN
      tutorials/3d/portals/img/example_scenetree.png
  8. BIN
      tutorials/3d/portals/img/freeform.png
  9. BIN
      tutorials/3d/portals/img/portal_inspector.png
  10. BIN
      tutorials/3d/portals/img/portal_points.png
  11. BIN
      tutorials/3d/portals/img/room_manager.png
  12. BIN
      tutorials/3d/portals/img/room_overlap.png
  13. BIN
      tutorials/3d/portals/img/room_points.png
  14. BIN
      tutorials/3d/portals/img/roomgroup_notification.png
  15. BIN
      tutorials/3d/portals/img/roomgroups.png
  16. BIN
      tutorials/3d/portals/img/simple_room.png
  17. BIN
      tutorials/3d/portals/img/simple_scenetree.png
  18. BIN
      tutorials/3d/portals/img/tent.png
  19. BIN
      tutorials/3d/portals/img/tent_terrain.png
  20. BIN
      tutorials/3d/portals/img/visibility_enabler.png
  21. 15 0
      tutorials/3d/portals/index.rst
  22. 36 0
      tutorials/3d/portals/introduction_to_rooms_and_portals.rst
  23. 92 0
      tutorials/3d/portals/rooms_and_portals_example.rst
  24. BIN
      tutorials/3d/portals/tutorial_simple/img/tutorial_simple1.png
  25. BIN
      tutorials/3d/portals/tutorial_simple/img/tutorial_simple2.png
  26. BIN
      tutorials/3d/portals/tutorial_simple/img/tutorial_simple3.png
  27. BIN
      tutorials/3d/portals/tutorial_simple/img/tutorial_simple4.png
  28. BIN
      tutorials/3d/portals/tutorial_simple/img/tutorial_simple5.png
  29. BIN
      tutorials/3d/portals/tutorial_simple/img/tutorial_simple6.png
  30. 94 0
      tutorials/3d/portals/using_objects_in_rooms_and_portals.rst
  31. 18 9
      tutorials/optimization/optimizing_3d_performance.rst

+ 1 - 0
tutorials/3d/index.rst

@@ -20,3 +20,4 @@
    csg_tools
    csg_tools
    fps_tutorial/index
    fps_tutorial/index
    vertex_animation/index
    vertex_animation/index
+   portals/index

+ 104 - 0
tutorials/3d/portals/advanced_room_and_portal_usage.rst

@@ -0,0 +1,104 @@
+Advanced Room and Portal usage
+==============================
+
+Gameplay callbacks
+~~~~~~~~~~~~~~~~~~
+
+Although occlusion culling greatly reduces the number of objects that need to be rendered, there are other costs to maintaining objects in a game besides the final rendering. For instance, in Godot, animated objects will still be animated whether they appear on screen or not. This can take up a lot of processing power, especially for objects that use software skinning (where skinning is calculated on the CPU).
+
+Fear not, rooms and portals can solve these problems, and more.
+
+By building our system of rooms for our game level, not only do we have the information needed for occlusion culling, we also have handily created the information required to know which rooms are in the local "gameplay area" of the player (or camera). If you think about it, in a lot of cases, there is no need to do a lot of simulation on objects that have nothing to do with gameplay.
+
+The gameplay area is not confined to just the objects you can see in front of you. AI monsters behind you still need to attack you when your back is turned! In Godot the gameplay area is defined as the *potentially visible set* (PVS) of rooms, from the room you are currently within. That is, if there is any part of a room that can possibly be viewed from any part of the room you are in (even from a corner), it is considered within the PVS, and hence the gameplay area.
+
+This works because if a monster is in an area that is completely out of view for yourself or the monster, you are less likely to care what it is doing.
+
+How does a monster know whether it is within the gameplay area?
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This problem is solved because the portal system contains a subsystem called the **Gameplay Monitor** that can be turned on and off from the :ref:`RoomManager<class_RoomManager>`. When switched on, any roaming objects that move inside or outside the gameplay area (whether by moving themselves, or the player moving) will receive callbacks to let them know of this change.
+
+You can choose to either receive these callbacks as ``signals``, or as ``notifications``.
+
+Notifications can be handled in GDScript or other scripting languages:
+
+.. code-block:: none
+
+	func _notification(what):
+		match what:
+			NOTIFICATION_ENTER_GAMEPLAY:
+				print("notification enter gameplay")
+			NOTIFICATION_EXIT_GAMEPLAY:
+				print("notification exit gameplay")
+
+Signals are sent just as any other signal. They can be attached to functions using the editor inspector. The signals are called ``gameplay_entered`` and ``gameplay_exited``.
+
+In fact, you don't just receive these callbacks for ``ROAMING`` objects. In addition Rooms and RoomGroups (which can be used to form groups of rooms) can also receive callbacks. For example, you can use this to trigger AI behaviour when the player reaches certain points in a level.
+
+VisbilityNotifiers / VisibilityEnablers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Gameplay callbacks have one more useful function. By default in Godot, animation and physics are still processed regardless of whether an object is within view. This can sap performance, especially when using software skinning.
+
+The engine's solution to this problem is the :ref:`VisibilityNotifier<class_VisibilityNotifier>` node, and its slightly easier to use variation, the :ref:`VisibilityEnabler<class_VisibilityEnabler>` node. VisibilityEnabler can be used to switch off animation and sleep physics when an object is outside the view frustum. You do this by simply placing a VisibilityEnabler node in your subscene (for e.g. a monster). It will do the rest. Consult the :ref:`VisibilityEnabler<class_VisibilityEnabler>` documentation for full details.
+
+.. image:: img/visibility_enabler.png
+
+What if the VisibilityEnabler could turn off objects when they were occlusion culled? Well it turns out VisibilityEnabler can. All you have to do is enable the **Gameplay Monitor** in the RoomManager and the rest happens automatically.
+
+.. _doc_rooms_and_portals_roomgroups:
+
+RoomGroups
+~~~~~~~~~~
+
+A :ref:`RoomGroup<class_RoomGroup>` is a special node which allows you to deal with a group of rooms at once, instead of having write code for them individually. This is especially useful in conjunction with gameplay callbacks. The most important use for RoomGroups is to delineate between "inside" and "outside" areas.
+
+.. image:: img/roomgroups.png
+
+For instance, when outside you may wish to use a :ref:`DirectionalLight<class_DirectionalLight>` to represent the sun. When the outside RoomGroup receives an ``enter gameplay`` callback, you can turn the light on, and you can turn it off when the RoomGroup exits gameplay. With the light off, performance will increase as there is no need to render it indoors.
+
+This is an example of a simple RoomGroup script to turn on and off a DirectionalLight. Note that you can also use signals for callbacks (the choice is up to you):
+
+.. image:: img/roomgroup_notification.png
+
+.. tip:: You can apply the same technique for switching on and off weather effects, skyboxes and much more.
+
+Internal Rooms
+~~~~~~~~~~~~~~
+
+There is one more trick that RoomGroups have up their sleeve. A very common desire is to have a game level with a mixed outdoor and indoor environment. We have already mentioned that rooms can be used to represent both rooms in a building, and areas of landscape, such as a canyon.
+
+What happens if you wish to have a house in a terrain 'room'?
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+With the functionality described so far you *can* do it - you would need to place portals around the exterior of the house though, forming needless rooms above the house. This has been done in many games. But what if there was a simpler way?
+
+It turns out there is a simpler way of handling this scenario. Godot supports *rooms **within** rooms* (we will call them **"internal rooms"**). That is, you can place a house within a terrain room, or even a building, or set of buildings, and even have exit portals in different terrain rooms!
+
+To create internal rooms, you don't need to place a room within another room in the scene tree - in fact you will get a warning if you try this. Instead, create them as regular rooms. The internal rooms should be grouped together with a RoomGroup as parent. If you look in the inspector for the RoomGroup, there is a **Room Group Priority** which defaults to ``0``.
+
+If you want a room or set of rooms to be internal, set the priority to a higher value than the outer (enclosing) room, using the RoomGroup.
+
+The system uses the priority setting to give priority to the internal room when deciding which room a camera or object is within. Higher priority *always* wins. Everything else works in a mostly similar way.
+
+The only differences:
+
+- Portals between internal rooms and outer rooms should always *be placed in the inner (internal) room*.
+- Portals of internal rooms are not considered as part of the bound of outer rooms.
+- ``STATIC`` and ``DYNAMIC`` objects from outer rooms will not sprawl into internal rooms. If you want objects to cross these portals, place them in the internal room. This is to prevent large objects like terrain sections sprawling into entire buildings, and rendering when not necessary.
+
+Internal room example
+^^^^^^^^^^^^^^^^^^^^^
+
+The tent is a simple room inside a terrain room (which contains the ground, the trees etc).
+
+.. image:: img/tent.png
+
+.. note:: To use internal rooms for buildings, it is usually a good idea to split the *interior* mesh of the building from the *exterior*. The exterior can be placed in the outer room (so it can be seen from outside, but not from the inside), and the interior should be placed in the interior room (so it only visible inside, or through the portal).
+
+.. image:: img/tent_terrain.png
+
+This is perfect for improving performance in open world games. Often your buildings can be scenes (including the rooms and portals) that can be reused. When viewed from the outside, interiors will mostly be culled, and when viewing from the inside other buildings and most of the outside will be culled. The same goes for other players and objects that are inside and outside the buildings.
+
+*Scene is 'Diorama Eco scene' by Odo, with slight changes for illustration purposes.* `CC Attribution <https://creativecommons.org/licenses/by/4.0/>`_

+ 101 - 0
tutorials/3d/portals/editing_rooms_and_portals.rst

@@ -0,0 +1,101 @@
+Editing Rooms and Portals
+=========================
+
+Example SceneTree
+~~~~~~~~~~~~~~~~~
+
+Putting all the ideas together, here is an example scene tree:
+
+.. image:: img/example_scenetree.png
+
+- We have used a :ref:`RoomGroup<class_RoomGroup>` to denote an outside area.
+- The :ref:`MeshInstance<class_MeshInstance>`\ s inside the :ref:`Room<class_Room>`\ s are either ``STATIC`` or ``DYNAMIC``.
+- We have created a :ref:`Spatial<class_Spatial>` (I decided to call it 'Freeform', but you could use any name) under which to place ``STATIC`` and ``DYNAMIC`` objects that will be autoplaced in rooms
+  (Freeform is inside the ``roomlist``, but *not* inside a room.)
+- The player and the monsters are on branches *OUTSIDE* the ``roomlist``.
+- The player and monster meshes have portal mode ``ROAMING`` so they can be in any room.
+- The camera is outside the ``roomlist``.
+
+.. _doc_rooms_and_portals_blender:
+
+Creating room systems in Blender (or other modeling tools)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Although you can create your room system entirely within the editor, you can also build rooms and portals within your modeling tool. There is one small snag - modeling tools such as Blender have no knowledge of Room, RoomGroup and Portal nodes. In order to work around this we use the naming conventions that were discussed earlier.
+
+Rooms should be created as Empty objects with names such as ``Room_kitchen`` (substituting your preferred room name). If you place meshes within the rooms within the modeling tool, these Empties will form Spatial nodes in Godot, and will be converted to room nodes automatically during the room conversion phase.
+
+Creating a RoomGroup is done by creating an Empty object with the name prefix ``RoomGroup``. For instance, you can create an Empty object called ``RoomGroup_house`` and it will be converted to a RoomGroup.
+
+Creating Portals in modeling tools
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Portals also use the same naming convention as within Godot - the name should start with the prefix ``Portal_`` followed by the name of the room the portal should link to. However, for portals, we want to specify the shape and position of the polygon within the modeling tool, so the nodes should be Meshes rather than Empties.
+
+Portal meshes have some restrictions to work properly. They must be convex, and the polygon points should be in the same plane. The accuracy to the plane does not have to be exact, as Godot will automatically average the direction of the portal plane. Once converted to a :ref:`Portal<class_Portal>` node, the snapping to the portal plane is enforced, and the vertices are specified (and editable) as 2D coordinates in the inspector, rather than 3D points.
+
+Portal point editing
+~~~~~~~~~~~~~~~~~~~~
+
+Portals are defined by a combination of the transform of the portal node, and by a set of points which form the corners.
+
+The default portal has 4 corners as shown in the inspector:
+
+.. image:: img/portal_points.png
+
+You can edit these points in the inspector to make a better match to the opening in your game level. But bear in mind it generally better to keep the number of points as low as possible for the efficiency of the system. It is better to risk rendering a little too much than to spend the time culling objects at 20 different edges, for example.
+
+Room point editing
+~~~~~~~~~~~~~~~~~~
+
+You also have the option to manually edit the points used to define the convex hull of a room. These points are not present by default, you would typically create them by pressing the **Generate Points** button in the editor toolbar, when a room is selected. This will transfer the auto bound from the geometry (or manual ``Bound_`` mesh) into the inspector. Once there are points in the inspector, they will be used and override any other method. So if you wish to revert your manual editing, simply delete all the points.
+
+.. image:: img/room_points.png
+
+Manually editing rooms' points is more difficult than editing portal points, but it can be useful in some situations, especially where the auto-bound doesn't *quite* get the right result you want. It is usually a good idea to use a lot of **Simplification** in the inspector for the Room before generating the points. Be aware though that by default, the **Simplification** value will be inherited from the RoomManager.
+
+RoomManager
+~~~~~~~~~~~
+
+Show Debug
+^^^^^^^^^^
+
+This can be used to turn on and off display of portals in the editor, and control the amount of logging. Debug will always be set to ``false`` on exported projects.
+
+Debug Sprawl
+^^^^^^^^^^^^
+
+This mode will only display meshes that are sprawling through portals from the current camera room. Large statics that cross portals are usually the ones you want to sprawl. Typical examples might be terrain mesh areas, or large floor or ceiling meshes. You usually don't want things like door frames to sprawl to the adjacent room - that is what fine tuning the **Portal Margin** is for.
+
+Merge Meshes
+^^^^^^^^^^^^
+
+To keep drawcalls to a minimum, the system offers the option to automatically merge similar ``STATIC`` meshes within a room (also known as *static batching*). This can increase performance in many cases. The culling accuracy is reduced, but as a room is a fairly logical unit for culling, this trade off usually works in your favor.
+
+Plane Simplification
+^^^^^^^^^^^^^^^^^^^^
+
+In some cases, automatically generated convex hull bounds may contain a very large number of planes. This is not ideal because it slows down determining which room a camera or object is within. The system can optionally simplify hulls. The degree of simplification can be selected by the user, between ``0`` (no simplification) and ``1`` (maximum simplification). You can also override this value in individual rooms.
+
+Portals
+~~~~~~~
+
+Portal Active
+^^^^^^^^^^^^^
+
+Portals can be turned on and off at runtime. This is especially useful if you have open and closing doors.
+
+Two Way
+^^^^^^^
+
+Portals can either be two way or one way. One way portals may be useful for example to create windows that can be seen out of, but not seen into. This can help performance when viewing buildings from outdoors.
+
+Particle Systems
+~~~~~~~~~~~~~~~~
+
+Be aware that when placing ``STATIC`` particle systems, the AABB on conversion may have zero size. This means the particle system may be unexpectedly culled early. To prevent this, either set the particle system ``portal mode`` to ``DYNAMIC``, or alternatively, add an **Extra Cull Margin** to the particle system in the Geometry Inspector.
+
+Multimeshes
+~~~~~~~~~~~
+
+Note that multimeshes will be culled as a group, rather than individually. You should therefore attempt to keep them localised to the same area wherever possible.

+ 115 - 0
tutorials/3d/portals/first_steps_with_rooms_and_portals.rst

@@ -0,0 +1,115 @@
+First steps with Rooms and Portals
+==================================
+
+The RoomManager
+~~~~~~~~~~~~~~~
+
+Anytime you want to use the portal system, you need to include a special node in your scene tree, called the :ref:`RoomManager<class_RoomManager>`. The RoomManager is responsible for the runtime maintenance of the system, especially converting the objects in your rooms into a *room graph* which is used at runtime to perform occlusion culling and other tasks.
+
+Room Conversion
+^^^^^^^^^^^^^^^
+
+This conversion must take place every time you want to activate the system, it does not store the *room graph* in your project (for flexibility and to save memory). You can either trigger it by pressing the **Convert Rooms** button in the editor toolbar when the RoomManager is selected, or you can call the ``rooms_convert()`` method in the RoomManager. This latter method will be what you use in-game. Note that for safety, best practice is to call ``rooms_clear()`` before unloading / changing levels.
+
+If you convert the level while the editor is running, the portal culling system will take over from the normal Godot frustum culling. This may affect some editor features. For this reason, you can turn the portal culling on and off, using the **Active** setting in the RoomManager node.
+
+.. note:: To use the RoomManager, you have to tell it where the rooms are in your scene tree, or rather where the RoomList node is. This RoomList is the parent of your rooms - see below. If the RoomList is not set, conversion will fail, and you will see a warning dialog box.
+
+.. image:: img/room_manager.png
+
+Rooms
+~~~~~
+
+What is a room?
+^^^^^^^^^^^^^^^
+
+:ref:`Room<class_Room>`\ s are a way of spatially partitioning your level into areas that make sense in terms of the level design. Rooms often quite literally *are* rooms (for instance in a building). Ultimately though, as far as the engine is concerned, a room respresents a **non-overlapping** convex volume, in which you would typically place most of your objects that fall within that area.
+
+A room doesn't need to correspond to a literal room. It could for example also be a canyon in an outdoor area, or a smaller part of a concave room. With a little imagination, you can use the system in almost any scenario.
+
+Why convex?
+^^^^^^^^^^^
+
+The reason why rooms are defined as convex volumes (or *convex hulls* as they are known), is that mathematically, it is very easy to determine whether a point is within a convex hull. A simple plane check will tell you the distance of a point from a plane. If a point is behind all the planes bounding the convex hull, then by definition, it is inside the room. This makes all kinds of things easier in the internals of the system, such as checking which room a camera is within.
+
+*A convex hull. The hull is defined as a series of planes facing outward. If a point is behind all the planes, it is within the hull.*
+
+.. image:: img/convex_hull.png
+
+Why non-overlapping?
+^^^^^^^^^^^^^^^^^^^^
+
+If two rooms overlap, and a camera or player is in this overlapping zone, then there is no way to tell which room the object should be in (and hence render from), or be rendered in. This requirement for non-overlapping rooms does have implications for level design.
+
+If you accidentally create overlapping rooms, the editor will flag a warning when you convert the rooms, and indicate any overlapping zones in red.
+
+.. image:: img/room_overlap.png
+
+The system does attempt to cope with overlapping rooms as best as possible by making the current room *"sticky"*. Each object remembers which room it was in last frame, and stays within it as long as it does not move outside the convex hull room bound. This can result in some hysteresis in these overlapping zones.
+
+There is one exception however for *internal rooms*. (These internal rooms are described later, you do not have to worry about these to start with.)
+
+How do I create a room?
+^^^^^^^^^^^^^^^^^^^^^^^
+
+A :ref:`Room<class_Room>` is a node type that can be added to the scene tree like any other. You can place objects within the room by making them children and grand-children of the Room node. Instead of placing the rooms as children of a scene root node, you will need to create a Spatial especially for the job of being the parent of all the rooms. This node we will refer to as the ``RoomList``. You will need to assign the roomlist node in the RoomManager, so the RoomManager knows where to find the rooms.
+
+Room naming convention
+^^^^^^^^^^^^^^^^^^^^^^
+
+Unlike most nodes in Godot, a specific naming convention should be followed in order to identify each room. The name should have the prefix ``Room_`` followed by the name you wish to give the room, e.g. ``Room_kitchen``, ``Room_lounge``. If you don't follow these naming guidelines, the system will warn you and may not work correctly.
+
+How do I define the shape and position of my room convex hull?
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Because defining the room bound is the most important aspect of the system, there are THREE methods available to define the shape of a room in Godot:
+
+1. Use the geometry of the objects contained within the room to automatically create an approximate bound.
+2. Provide a manual bound. This is a MeshInstance in the room that has geometry in the shape of the desired bound, with a name prefixed by ``Bound_``. This is something you might choose to do if you create your levels in Blender or similar (see :ref:`doc_rooms_and_portals_blender`).
+3. By manually editing the points that define the convex hull, in the room inspector.
+
+While the first option can be all that is required, particularly with simple rooms, or for pre-production, the power of the manual bounds gives you ultimate control (at the expense of a small amount of editing). You can also combine the two approaches, perhaps using automatic bounds for most rooms but manually editing problem areas.
+
+The automatic method is used whenever a manual bound is not supplied.
+
+*A simple pair of rooms. The portal margin is shown with translucent red, and the room hulls are shown with green wireframe.*
+
+.. image:: img/simple_room.png
+
+Portals
+~~~~~~~
+
+If you create some rooms, place objects within them, then convert the level in the editor, you will see the objects in the rooms appearing and showing as you move between rooms. There is one problem however! Although you can see the objects within the room that the camera is in, you can't see to any neighbouring rooms! For that we need portals.
+
+:ref:`Portal<class_Portal>`\ s are special convex polygons. You position over the openings between rooms, in order to allow the system to see between them. You can create a portal node directly in the editor. The default portal has 4 points and behaves much like a ``plane`` :ref:`MeshInstance<class_MeshInstance>`. You can add or remove points using the inspector. A portal will require at least 3 points to work - this is because it needs to form a polygon rather than a point or line.
+
+Portals only need to be placed in one of each pair of neighbouring rooms (the *"source room"*). The system will automatically make them two way unless you choose otherwise in the portal node's properties. The portal normal should face *outward* from the source room. The front face should be visible from *outside* the room. The editor gizmo indicates the direction the portal is facing with an arrow, and a different color for each face.
+
+.. image:: img/portal_inspector.png
+
+Like rooms, portals also follow a naming convention which is as follows:
+
+- Prefix ``Portal_``.
+- Optional : You can add a suffix of the room that the portal will lead to ('destination room'). E.g. ``Portal_kitchen``. This name is not just descriptive; it affects behavior when converting rooms (see below).
+
+The suffix is optional. In many cases, the system can automatically detect the nearest room that you intended to link to and do this for you. It is usually only in problem areas you will need to use the suffix.
+
+In rare cases, you may end up with two or more portals that you want to give the same name, because they lead into the same destination room. However, Godot does not allow duplicate names at the same level in the scene tree. The solution to this is the wildcard character ``*``. If you place a wildcard at the end of the name, the rest of the characters will be ignored. For example, ``Portal_Kitchen*1`` and ``Portal_Kitchen*2``.
+
+All in all there are three ways of specifying which room a portal should link to:
+- Leaving the name suffix blank to use auto-linking.
+- Add suffix to the Portal node's name.
+- Assigning the **Linked Room** in the inspector for a Portal node. This is simply a shortcut for setting the name by renaming the node.
+
+.. note:: Portals have some restrictions to work properly. They should be convex, and the polygon points should be in the same plane. The snapping of points to a plane is enforced because portal points are only defined in 2D (with X and Y coordinates). The node transform is used to convert these to world-space 3D points. The node transform thus determines the portal orientation.
+
+Trying it out
+~~~~~~~~~~~~~
+
+By now you should be able to create a couple of rooms, add some nodes such as MeshInstances within the rooms, and add a portal between the rooms. Try converting the rooms in the editor, and see if you can now see the objects in neighbouring rooms, through the portal.
+
+.. image:: img/simple_scenetree.png
+
+You have now mastered the basic principles of the system.
+
+The next step is to look at the different types of objects that can be managed by the system.

BIN
tutorials/3d/portals/img/convex_hull.png


BIN
tutorials/3d/portals/img/cull_instance.png


BIN
tutorials/3d/portals/img/example_scenetree.png


BIN
tutorials/3d/portals/img/freeform.png


BIN
tutorials/3d/portals/img/portal_inspector.png


BIN
tutorials/3d/portals/img/portal_points.png


BIN
tutorials/3d/portals/img/room_manager.png


BIN
tutorials/3d/portals/img/room_overlap.png


BIN
tutorials/3d/portals/img/room_points.png


BIN
tutorials/3d/portals/img/roomgroup_notification.png


BIN
tutorials/3d/portals/img/roomgroups.png


BIN
tutorials/3d/portals/img/simple_room.png


BIN
tutorials/3d/portals/img/simple_scenetree.png


BIN
tutorials/3d/portals/img/tent.png


BIN
tutorials/3d/portals/img/tent_terrain.png


BIN
tutorials/3d/portals/img/visibility_enabler.png


+ 15 - 0
tutorials/3d/portals/index.rst

@@ -0,0 +1,15 @@
+.. _doc_rooms_and_portals:
+
+Rooms and Portals
+=================
+
+.. toctree::
+   :maxdepth: 1
+   :name: toc-portals
+
+   introduction_to_rooms_and_portals
+   first_steps_with_rooms_and_portals
+   using_objects_in_rooms_and_portals
+   advanced_room_and_portal_usage
+   editing_rooms_and_portals
+   rooms_and_portals_example

+ 36 - 0
tutorials/3d/portals/introduction_to_rooms_and_portals.rst

@@ -0,0 +1,36 @@
+.. _doc_portals_introduction:
+
+Introduction to Rooms and Portals
+=================================
+
+The rooms and portals system is an optional component of Godot that allows you to partition your 3D game levels into a series of :ref:`Room<class_Room>` s (*aka cells*), and :ref:`Portal<class_Portal>` s. Portals are openings between the rooms that the :ref:`Camera<class_Camera>` (and lights) can see through.
+ 
+This allows several features:
+
+- **Portal occlusion culling**, which can increase performance by reducing the number of objects that are drawn, both to cameras and to shadow maps.
+
+- **Gameplay callbacks**, which allow turning off activity outside the gameplay area - AI, physics, animation, processing etc.
+
+The trade off for these features is that we have to manually partition our level into rooms, and add portals between them.
+
+.. note:: Godot portals should not be confused with those in the `game of the same name <https://en.wikipedia.org/wiki/Portal_(video_game)>`__. They do not warp space, they simply represent a window that the camera (or lights) can see through.
+
+Minimizing manual labour
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Although the effort involved in creating rooms for a large level may seem daunting, there are several factors which can make this much easier:
+
+- If you are "kit bashing" and reusing rooms or areas already, this is an ideal way to save effort. Your level tiles can be rooms, with portals already placed.
+- If you are creating procedural levels, you can create rooms and portals as part of the procedural generation algorithm you're writing.
+- Finally, if you are manually creating freeform levels, bear in mind there are absolutely no rules as to how far you go with portalling. Even if you separate a large game level into only two rooms, with a single portal between them, this can still result in relatively large performance gains.
+
+The performance benefits (especially in terms of occlusion) follow an L-shaped curve, with the lion's share occurring when you have created just a few rooms. So do not be afraid to be lazy - **\*work smart\***.
+
+In general, when it comes to medium and large-sized levels, it is better to do a little portalling than none at all.
+
+Some caveats
+^^^^^^^^^^^^
+
+.. note:: The portal system should be considered an **advanced feature** of Godot. You should not attempt to use rooms and portals until you are familiar with the Godot editor, and have successfully made at least a couple of test games.
+
+It gives you great power as a game designer, but the trade off is that it requires a very technical approach to level design. It is aimed at producing professional-grade results, and assumes the user is prepared to put in the work for this. It is not intended to be used for all 3D games. Not all games will significantly benefit from portals, and it may require more time than a short game jam allows.

+ 92 - 0
tutorials/3d/portals/rooms_and_portals_example.rst

@@ -0,0 +1,92 @@
+Rooms and Portals example
+=========================
+
+Download this tutorial project:
+`Simple Portals Example <https://github.com/lawnjelly/godot-demo-projects/tree/portals_simple_demo/3d/portals/room_and_portals_simple_example>`_
+.
+
+Introduction
+~~~~~~~~~~~~
+
+This tutorial will introduce you to building a "Hello World" room system with two rooms, and a portal in between.
+
+Step 1
+~~~~~~
+
+.. image:: tutorial_simple/img/tutorial_simple1.png
+
+- Create a new project.
+- Add a :ref:`Spatial<class_Spatial>` as the scene root (on the screenshot, it's called "Root").
+- Next add a :ref:`RoomManager<class_RoomManager>` node. We will need this later to process the room system.
+- Next we need to start defining our rooms. We create all our rooms under another Spatial we have called 'RoomList'.
+- Add a new :ref:`Room<class_Room>` node as a child of the roomlist.
+- Give it a  name that starts with the prefix ``Room_``. We add our chosen name as a suffix. Here, we have used ``kitchen``.
+- We will now create the geometry of our room. The names you give to the geometry is up to you.
+- Create a :ref:`MeshInstance<class_MeshInstance>` for the floor. Create a box by adding a CubeMesh resource to the MeshInstance. Scale and position it to form a floor.
+- Create MeshInstances for the walls. Create more box meshes for this, then scale and position them. Be sure to leave an opening on one side. You will need to create two wall segments to do this on that side.
+
+Step 2
+~~~~~~
+
+.. image:: tutorial_simple/img/tutorial_simple2.png
+
+- Now we need to create the other room.
+- You can do this simply by duplicating the first room (select the ``Room_kitchen`` node, right click and choose **Duplicate**).
+- Rotate and position the second room so that the openings line up.
+- Rename the second room to ``Room_lounge``.
+
+Step 3
+~~~~~~
+
+.. image:: tutorial_simple/img/tutorial_simple3.png
+
+- Next, we will add a portal between the two rooms.
+- Create a new :ref:`Portal<class_Portal>` in the kitchen, and call it ``Portal_lounge``. The naming scheme tells the system which room it should link to.
+- Scale and position the portal using the node ``Transform`` in the inspector, so it fits within the opening between the two rooms.
+- The portal plane should face *outward* from the source room, i.e. towards the lounge. This direction is indicated by the arrow in the editor gizmo, and portal gizmo's color.
+
+Step 4
+~~~~~~
+
+.. image:: tutorial_simple/img/tutorial_simple4.png
+
+- To make things more exciting, we want to add a few more boxes to the rooms.
+- Placing these boxes as children or grandchildren of the room nodes explicitly tells the system which room the objects should be in. However, we can also create these objects *outside* the rooms. Provided they are in the RoomList branch, the system will attempt to automatically place them in the correct room at runtime.
+- On the screenshot, the boxes were places as children of a Spatial I have called ``Freeform`` to keep things tidy.
+- Boxes also have a green SpatialMaterial assigned to them to make them stand out more from the rest of the room.
+- Let's also create an :ref:`OmniLight<class_OmniLight>` so it will be autoplaced in one of the rooms.
+
+Step 5
+~~~~~~
+
+.. image:: tutorial_simple/img/tutorial_simple5.png
+
+- Next comes a crucial stage. We must let the RoomManager know where the rooms are!
+- Select the RoomManager and look in the Inspector window in the **Paths** section.
+- You need to assign the **Room List** to point to the RoomList node we created earlier (which is the parent of all the rooms).
+
+Step 6
+~~~~~~
+
+.. image:: tutorial_simple/img/tutorial_simple6.png
+
+- Make sure you have saved your project before this next step. It is always a good idea to save and make a backup before converting.
+- Select the RoomManager, and you will see a button in the toolbar at the top of the 3d editor viewport called **Convert Rooms**. Press this button.
+- If all goes well, the RoomManager will have created the runtime data (the *room graph*) to perform occlusion culling at runtime.
+- You can see a log of the conversion process in the output window. This is helpful for finding problems.
+- If you now move the editor camera inside the rooms, you should see the meshes in the opposite room being culled depending on what you can see through the portal.
+
+Conclusion
+~~~~~~~~~~
+
+This concludes this simple tutorial. Don't be afraid to experiment with the new room system you have created.
+
+Some things to try
+^^^^^^^^^^^^^^^^^^
+
+- Create different types of geometry. CSG nodes, Particle systems, and Multimeshes are all supported by the portal system.
+- Try creating a Camera and adding it to the scene. If you run the scene you will notice that the portal culling is not active. This is because the ``room graph`` must be created each time you load a level, by converting the rooms. Instead of using a button in the editor, in real games you call a function in the RoomManager to convert the level, called ``rooms_convert()``. Try this out with a script, perhaps running within a ``_ready()`` function.
+- The geometry you created so far is all ``STATIC`` (non-moving). If you look in the inspector for geometry nodes, you will see they derive from ``CullInstance``. Here you can set the **Portal Mode** for objects in the portal system. This determines how the node is processed.
+- If you now write a script to move one of your objects within a room and view it through a Camera as the scene runs, you may notice that the object gets culled incorrectly. This is because ``STATIC`` objects are assumed not to move in the system. If you instead change the object to ``DYNAMIC``, it should now update the culling correctly.
+- There are several ``portal_modes``, these are described in the main documentation.
+- Try turning the portal on and off at runtime from your script. You can call ``set_portal_active()`` to open and close the portal. 

BIN
tutorials/3d/portals/tutorial_simple/img/tutorial_simple1.png


BIN
tutorials/3d/portals/tutorial_simple/img/tutorial_simple2.png


BIN
tutorials/3d/portals/tutorial_simple/img/tutorial_simple3.png


BIN
tutorials/3d/portals/tutorial_simple/img/tutorial_simple4.png


BIN
tutorials/3d/portals/tutorial_simple/img/tutorial_simple5.png


BIN
tutorials/3d/portals/tutorial_simple/img/tutorial_simple6.png


+ 94 - 0
tutorials/3d/portals/using_objects_in_rooms_and_portals.rst

@@ -0,0 +1,94 @@
+Using objects in Rooms and Portals
+==================================
+
+Normally, when you use Godot, all objects that you can see (:ref:`VisualInstance<class_VisualInstance>`\ s) are treated in the same way by the engine. The portal renderer is slightly different, in that it makes a distinction between the different roles objects will have in your game. It makes this distinction to define the :ref:`Room<class_Room>`\ s, and to render and process everything in the most efficient way.
+
+Portal mode
+~~~~~~~~~~~
+
+If you look in the inspector, every VisualInstance in Godot is derived from a :ref:`CullInstance<class_CullInstance>`, where you can set a ``PortalMode``. This determines how objects will behave in the portal system.
+
+.. image:: img/cull_instance.png
+
+STATIC
+^^^^^^
+
+The default mode for objects is ``STATIC``. Static objects are objects within rooms that will not move throughout the lifecycle of the level. Things like floors, walls, ceilings are good candidates for ``STATIC`` objects.
+
+DYNAMIC
+^^^^^^^
+
+Dynamic mode is for objects that are expected to move during the game. But there is a limitation - **they must not move outside of their original room**. These objects are handled very efficiently by the system. Examples might include moving platforms, and elevators.
+
+ROAMING
+^^^^^^^
+
+Roaming mode is for objects that can move between rooms. Things like players and enemies should be marked as roaming. These are more expensive to calculate than ``STATIC`` or ``DYNAMIC`` modes, because the system has to keep track of which room a roaming object is within.
+
+GLOBAL
+^^^^^^
+
+Global mode is for objects that you don't want occlusion culled at all. Things like a main player's weapon, bullets and some particle effects are good candidates for ``GLOBAL`` mode.
+
+IGNORE
+^^^^^^
+
+Ignore is a special mode for objects that will be essentially free in the system. Manual bounds (``Bound_``) get converted to ignore portal mode automatically. They don't need to show up during the game, but are kept in the scene tree in case you need to convert the level multiple times (e.g. in the Editor). You might also choose to use this for objects that you *only* want to show up in the editor (when RoomManager is inactive).
+
+Should you place objects within rooms (in the scene tree) or not?
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``STATIC`` and ``DYNAMIC`` objects are ideally placed within rooms in the scene tree. The system needs to know which room they are in during conversion as it assumes they will never change room. Placing them within rooms in the scene tree allows you to explicitly tell the system where you want them.
+
+Autoplace
+^^^^^^^^^
+
+However, for ease of use, it is also possible to place ``STATIC`` and ``DYNAMIC`` objects *outside* the rooms in the scene tree, but within the RoomList branch. The system will attempt to **autoplace** the objects into the appropriate room. This works in most cases but if in doubt, use the explicit approach. This explicit approach is especially needed when dealing with internal rooms, which have some restrictions for sprawling objects.
+
+.. image:: img/freeform.png
+
+Note that if you place ``STATIC`` and ``DYNAMIC`` objects outside of rooms, they will not contribute to the room bound. If you are using the room geometry to derive the bound, tables and chairs can be placed outside the room. However, walls and floors should be explicitly within the Room's branch of the scene tree to ensure the bound is correct.
+
+``ROAMING`` and ``GLOBAL`` objects are recommended to be kept in a branch of the scene tree outside of any rooms or the RoomList. They *can* be placed inside the rooms, but to save confusion, they are normally better kept on their own branch. There are no restrictions on the placement of ``IGNORE`` objects.
+
+Object Lifetimes
+^^^^^^^^^^^^^^^^
+
+It is important to note that the lifetime of ``STATIC`` and ``DYNAMIC`` objects is tied to the lifetime of the level, between when you call ``rooms_convert()`` to activate the portal system, and calling ``rooms_clear()`` to unload the system. This is because quite a bit of pre-processing goes on during the conversion phase in order to render them efficiently.
+
+You should therefore not try to create or delete ``STATIC`` or ``DYNAMIC`` objects while the portal system is active. Doing so will cause the system to automatically unload because it is in an invalid state. You can however, freely ``show()`` and ``hide()`` these objects.
+
+The sequence should be therefore:
+- Load your level.
+- Place any ``STATIC`` or ``DYNAMIC`` objects.
+- Then run ``rooms_convert()`` *after* all the ``STATIC`` and ``DYNAMIC`` objects were added to the scene tree.
+
+Objects that are ``ROAMING``, ``GLOBAL`` or ``IGNORE`` can be freely created and deleted as required.
+
+Sprawling
+~~~~~~~~~
+
+Although users can usually ignore the internals of the portal system, they should be aware that it is capable of handling objects that are so big they end up in more than one room. Each object has a central room, but using the AABB or geometry the system can detect when an object extends across a portal into a neighbouring room (or several rooms). This is referred to as **sprawling**.
+
+This means that if the corner of an object extends into a neighbouring room, but the object's main room is not showing (e.g. a train where the end is in a different room), the object will not be culled, and will still be shown. The object will only be culled if it is not present in any of the rooms that are visible.
+
+Portal Margins
+^^^^^^^^^^^^^^
+
+It is hard to place objects exactly at the edges of rooms, and if we chose to sprawl objects to the adjacent room the moment a portal was crossed (even by a very small amount), there would be an unnecessary amount of sprawling, and objects would end up being rendered when not really required. To counter this, portals have an adjustable ``margin`` over which an object can cross without being considered in the next room. The margin is shown in the editor gizmo as a red translucent area.
+
+You can set the margin globally in the RoomManager. You can also override this margin value in any portal if you need to finetune things. As you edit the margin values in the inspector, you should see the margins update in the 3D editor viewport.
+
+Include in Bound
+^^^^^^^^^^^^^^^^
+
+The support for objects that are larger than a single room has one side effect. You may not want to include some objects in the calculation of the automatic room bound. You can turn this on and off in the inspector for each object. See **Cull Instance > Include In Bound**.
+
+While sprawling works great for large moving objects, it also gives you a lot more leeway in level design. You can for instance create a large terrain section and have it present in multiple rooms, without having to split up the mesh.
+
+Lighting
+~~~~~~~~
+
+In general lights are handled like any other visual instance. They can be placed in rooms, and they will sprawl to affect neighbouring rooms, following the dimensions and direction of the light. The exception to this is :ref:`DirectionalLight<class_DirectionalLight>`\ s. DirectionalLights have no source room as they affect *everywhere*. They should therefore not be placed in a room. As DirectionalLights can be expensive, it is a good idea to turn them off when inside, see the later :ref:`doc_rooms_and_portals_roomgroups` section for details on how to do this.
+
+Congratulations! You have now mastered the intermediate techniques required to use rooms and portals. You can use these to make games already, but there are many more features.

+ 18 - 9
tutorials/optimization/optimizing_3d_performance.rst

@@ -31,8 +31,7 @@ prepass* and is enabled by default in Godot when using the GLES3 renderer.
 However, unneeded objects are still reducing performance.
 However, unneeded objects are still reducing performance.
 
 
 One way we can potentially reduce the amount to be rendered is to take advantage
 One way we can potentially reduce the amount to be rendered is to take advantage
-of occlusion. As of Godot 3.3, there is no built in support for occlusion in
-Godot. However, with careful design you can still get many of the advantages.
+of occlusion.
 
 
 For instance, in our city street scenario, you may be able to work out in advance
 For instance, in our city street scenario, you may be able to work out in advance
 that you can only see two other streets, ``B`` and ``C``, from street ``A``.
 that you can only see two other streets, ``B`` and ``C``, from street ``A``.
@@ -40,24 +39,34 @@ Streets ``D`` to ``Z`` are hidden. In order to take advantage of occlusion, all
 you have to do is work out when your viewer is in street ``A`` (perhaps using
 you have to do is work out when your viewer is in street ``A`` (perhaps using
 Godot Areas), then you can hide the other streets.
 Godot Areas), then you can hide the other streets.
 
 
-This is a manual version of what is known as a "potentially visible set". It is
-a very powerful technique for speeding up rendering. You can also use it to
+This example is a manual version of what is known as a *potentially visible set*.
+It is a very powerful technique for speeding up rendering. You can also use it to
 restrict physics or AI to the local area, and speed these up as well as
 restrict physics or AI to the local area, and speed these up as well as
 rendering.
 rendering.
 
 
+Portal Rendering
+~~~~~~~~~~~~~~~~
+
+However, there is a much easier way to take advantage of occlusion. Godot features
+an advanced portal rendering system, which can perform occlusion culling from cameras and
+lights. See :ref:`doc_rooms_and_portals`.
+
+This is not a fully automatic system and it requires some manual setup. However, it potentially
+offers significant performance increases.
+
 .. note::
 .. note::
 
 
-    In some cases, you may have to adapt your level design to add more occlusion
-    opportunities. For example, you may have to add more walls to prevent the player
+    In some cases, you can adapt your level design to add more occlusion
+    opportunities. For example, you can add more walls to prevent the player
     from seeing too far away, which would decrease performance due to the lost
     from seeing too far away, which would decrease performance due to the lost
     opportunies for occlusion culling.
     opportunies for occlusion culling.
 
 
 Other occlusion techniques
 Other occlusion techniques
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 
-There are other occlusion techniques such as portals, automatic PVS, and
-raster-based occlusion culling. Some of these may be available through add-ons
-and may be available in core Godot in the future.
+As well as the portal system and manual methods, there are various other occlusion
+techniques such as raster-based occlusion culling. Some of these may be available
+through add-ons or may be available in core Godot in the future.
 
 
 Transparent objects
 Transparent objects
 ~~~~~~~~~~~~~~~~~~~
 ~~~~~~~~~~~~~~~~~~~