Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to manage activity of objects using PVS / secondary PVS #2366

Closed
lawnjelly opened this issue Feb 27, 2021 · 3 comments
Closed

Add ability to manage activity of objects using PVS / secondary PVS #2366

lawnjelly opened this issue Feb 27, 2021 · 3 comments

Comments

@lawnjelly
Copy link
Member

lawnjelly commented Feb 27, 2021

Describe the project you are working on

First person shooter indoor levels.

Describe the problem or limitation you are having in your project

Reducing processing for objects that are outside the current play area.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Although #2172 deals with occlusion culling and greatly increases performance, rendering is not the only potential bottleneck in large levels. AI and physics and general processing of objects that are not relevant to the current gameplay area can be huge performance hogs in some types of games.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Given that we now already have a rooms and portals structure built for rendering (as part of #2172), an often used extension to this system is utilizing the potentially visible set (PVS) / secondary PVS.

secondary_pvs4

This diagram illustrates the concept. Using the rooms and portals, you can automatically construct a potentially visible set of rooms that a viewer could potentially see from a 'source room'. This algorithm is based on Seth Teller's thesis that was used for Quake and derivate games.

See also here for an explanation (although I made a slight correction in the comments):
https://www.youtube.com/watch?v=Mr1vHM0P8U4

The PVS is typically used for rendering - you take everything in the PVS, and frustum cull it, voila, super cheap occlusion culling. It works very well, especially for high densities of rooms (which may also be called cells, because they may refer to convex areas within what we might normally consider a room). However they have some disadvantages over portals which tend to give more accurate occlusion culling in lower density rooms (at the cost of slight runtime calcs).

However in real games, the PVS structure is useful not just in terms of deciding what is rendered. It can also be used to reduce processing on objects that are not in the gameplay area. This can be used to turn off physics, AI, sound, particle systems, and even network messages for objects that are outside the gameplay area.

Although the PVS can be used, in practice it often makes sense to also calculate what I call the secondary PVS. This is a superset of the PVS - it comprises the PVS, plus the immediate neighbouring rooms of this PVS. This is trivial to calculate and offers a slightly wider gameplay area so that e.g. AI opponents just outside of the visible area will still do their thing and chase the player, instead of 'disappearing from existence' the moment they go through a door.

How would this work

I have already written the code to generate the primary and secondary PVS from the room / portal system. I'm still not absolutely sure the best way of making this information available to users in Godot, so any feedback here would be useful.

One problem is that the room / portal system is held in the visual server, and the data flow relationship from the client (scene tree) to the visual server is mostly one way. See:
https://godotengine.org/article/why-does-godot-use-servers-and-rid

The problem is, we either need to store the relevant data (PVS and room lookup) client side (potentially duplicating it) or we need a way of accessing or getting callbacks from the visual server. Storing the PVS client side is not a problem (as it is calculated as a one off step during conversion), however the room lookup is required in both the visual server and the client.

Some ideas:

  • We could simply bypass the one way relationship for room lookup, and use it in the same way as the current cull functions. The data is read only and could be made thread safe by making re-entrant, and taking care around the conversion and clear calls for the room system.
  • We could alternatively have a callback mechanism via NOTIFICATIONS. The scene tree object could register (with it's Godot instance ID?) and receive notifications for e.g. entering and exiting the primary / secondary PVS. One possible gotcha would be to watch for race conditions whereby the notification was sent during the period that the object was being deleted. But perhaps the notification system deals with this itself.

Either way we could end up with a situation where objects (players, boxes etc) get a callback / notification in e.g. gdscript, and they can do what they want with this information to scale their behaviour. And / or offer some defaults, like turning off _process / _physics_process etc for objects that move outside the gameplay area (this technique is widely used in multiplayer shooters to manage network bandwidth).

If this enhancement will not be used often, can it be worked around with a few lines of script?

It cannot be worked around with script.

Note that this is a useful small extension to rooms / portals, it is not necessary for rooms / portals to work. This kind of technique is commonly used for managing performance in AAA type games. It does not imply that we have to have it in Godot, I'm just bringing up the option.

Is there a reason why this should be core and not an add-on in the asset library?

Needs access to rooms / portals system internal data, can't be done via add-on.

@Zireael07
Copy link

Zireael07 commented Feb 27, 2021

I have a second use case: a procedural town. It's open world, but the map is based on a graph and there is enough clutter (buildings and the like) so that I can be sure that for a given road the player absolutely won't see some other road, and I would like to cut down on physics processing for AI on that other road...

@lawnjelly
Copy link
Member Author

I have a second use case: a procedural town. It's open world, but the map is based on a graph and there is enough clutter (buildings and the like) so that I can be sure that for a given road the player absolutely won't see some other road, and I would like to cut down on physics processing for AI on that other road...

Yes this would work perfectly for that use case, in addition to portal culling. You could probably just automatically place a portal at the end of each street / intersection. I used procedural levels for testing portals in fact, it works very well.

@lawnjelly
Copy link
Member Author

Closing as this has now been added to 3.x.

@Calinou Calinou added this to the 3.x milestone Dec 22, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants