godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.12k stars 69 forks source link

Add show flag propagation #6018

Open JeffVenancius opened 1 year ago

JeffVenancius commented 1 year ago

Describe the project you are working on

Just thinking about a video tutorial on Youtube.

Describe the problem or limitation you are having in your project

I was seeing a video about how Godot handles visibility and how it checks every frame if a node is visible when the parent is also visible. This, sometimes, can be redundant - on this redundancy we could implement a flag that says: "hey, the parent IS visible, so all child also are, don't need to check them".

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

It would be a flag that works on all CanvasItems, Spatials, Canvas Layers, etc... The default should be false, but if it was set to true, Godot would just assume all childs are visible. The collateral is that the user won't be able to hide a child of the particular parent, so that should be shown in the editor too - Maybe a warning.

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

if (all_visible){
  for (int i = 0; i < get_child_count(); i++) {
    assume all is visible.
    }
  }

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

I think it could be used often, but I don't think it could be implemented without changing the source.

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

I think it could be used often, but I don't think it could be implemented without changing the source.

YuriSizov commented 1 year ago

I was seeing a video about how Godot handles visibility and how it checks every frame if a node is visible when the parent is also visible.

Can you point to a specific part of the codebase where that happens? Godot doesn't check that every frame, not in any expensive way. When visibility changes that information is propagated to the node's children and cached. See, for example, implementations of CanvasItem::is_visible(), CanvasItem::is_visible_in_tree(), CanvasItem::set_visible.

JeffVenancius commented 1 year ago

I checked on the video and on the source and found in servers/renderer_canvas_cull.cpp, at void RendererCanvasCull

Here's the video: https://www.youtube.com/watch?v=YYoLqAEpHmo

Perharps it was an exageration of mine to say it checks it every frame? Still, can this idea be used in any way? It would atleast cut a if on a for loop check.

YuriSizov commented 1 year ago

So what this video shows is that rendering is quite expensive and rendering items outside of the player's view is excessive. It also shows that there are some innate optimizations for things outside of the player's view; some form of frustum culling, let's say. But it's not as effective as a targeted optimization on the developer's part using a visibility notifier. That's because for things outside of the player's view you still need to calculate whether they are, or aren't. And for hidden things this step is not performed at all.

In both 3.x and 4.x the fact that the parent is visible is already accounted for, and cached in the node's own visibility status with the VisualServer/RenderingServer. The check that was pointed in the video doesn't do any complex computation. It is in fact saving you performance and is why hiding the node or using a notifier helps.

What doesn't work quite as efficiently is the automatic culling. That's because children of a particular node can still be visible on screen even if their parent isn't, depending on their global position. Imagine you have a world root that is always at 0,0(,0) and every other spatial node is a descendant of it. Of course you don't want to hide those nodes just because the world origin is not on screen, right? So this check is performed on every node in the tree, and thus is not as efficient as outright hiding the node or its parent where necessary.

Maybe that's what you suggest, avoid the culling computation by adding a flag so a parent can tell the rendering backend that, hey, if this node is visible, consider children visible, if not — then consider them hidden? If so, then I think this case is already handled well by the visibility notifier node that is demonstrated and suggested in the video. You can in fact very granularly control whether a branch of nodes should be considered visible or not with an explicitly defined area.


Rendering guys may want to correct me, so pardon this laymen explanation.

Calinou commented 1 year ago

Indeed, I think using the VisibilityEnabler node here works well enough. This kind of optimization will require some manual work no matter what you do, as the engine cannot guess what you want to do without a risk of false positives.

There's a case to be made for disabling frustum culling for specific nodes, but it only really makes sense in 3D for objects with complex animations: https://github.com/godotengine/godot-proposals/issues/5975

timothyqiu commented 1 year ago

See also https://github.com/godotengine/godot/pull/68738