Viewport cull mask and canvas item visibility layer not working
Tested versions
4.2.stable
System information
Windows 10
Issue description
Canvas item with layer other than 1 cannot be seen unless "Canvas Cull Mask" value include layer 1. Looks like setting any value without the layer 1 active on a viewport just hide everything.
Note : My guess is that there is an issue with how the cull flag are handled, the value may be tested as a bool somewhere. EDIT After more test i found the issue, the layer visibility from parent taken into account, children are not tested if layer visiblity test fail in parents
Steps to reproduce
Change Visibility Layer of Canvas Item to something else than 1.
Try changing the value of Canvas Cull Mask of your viewport
Minimal reproduction project (MRP)
Can you please try with 4.2.2 to make sure this hasn't already been fixed in a supported version
@JonqsGames This is not a bug and the intended behavior. It's a bit monotonous, but there is no inherit-visibility-layer setting, so each canvas item and every one of its decedents needs to be set explicitly to the visibility layer it should show on. Of course, if you have a good proposal though for a better workflow, I'd love to take a look!
In this case, I think default value of Visibility Layer should be "all value ticked".
Made the proposal but maybe the real solution is to have two value like "modulate" and "self_modulate" or even have a similar behavior than for 3D (the case is different because all 2d item are CanvasItem but not all Node3D are VisualInstance3D)
You can enable top_level to make child nodes' layer independent.
@KoBeWi Since top_level remove the propragation of Transform the solution is equivalent to have two separate world for each viewport wich is not the usecase described here.
Perhaps it'd be better to have an inherit-from-parent dropdown like some of our other settings that would disable or ignore the set visibility layers? You would probably have the same amount of setup as all the other ideas, but while we couldn't add it as default without breaking compatibility, you could set it on all your nodes generally without having to keep track of specific layers and be able to reparent it to another viewport without having to change anything.
I may be missing some context, but that sounds like a more reasonable and familiar workflow. If popular, we could make it the default eventually. Seems like it'd be more common to want to inherit by default and only need to set it in special cases.
@markdibarry Mentionned that solution but i think it may be more complex to implement and i disagree on what the default behavior should be. I understand that all CanvasItem are kind of visual (mainly due to possibility of Y sorting) but i think the behavior should be the same than for the visual layer in 3D. Here is an update of the reproduction project to show the difference between 2D and 3D: ViewportVisibilityLayers (2).zip My final point on this matter, right now i'm not sure that anyone is using this, most people watch tutorial and online ressources that push to other solution (Have two separate worlds, using RemoteTransform2D ...). So i think the behavior should be changed, i made the simplest proposal but any other solution that prevent me from checking the whole arborescence to check the right layer will be good for my usecase.
I may be underestimating (I usually am), but I don't think it'd be that complex to implement (I also might just be getting excited about a smoother workflow for parallax :laughing: ). Since visibility_layer is handled on one line in the culling, the harder part would just be making the dropdown option:
I think it'd be worth having an easier workflow for visibility, but you're right about 2D and 3D being just so crazy different in their whole workflow. From looking around the UI it feels like any attempt to align is gonna lead to a ton of more problems. For example, visibility is handled on a per-node basis (any canvas item) for 2D via "visibility layer", but it's handled specifically on the Camera3D node via "cull mask". I'd be interested to know what all would need to change to make the workflows look intuitively similar, but my guess is a lot. :melting_face:
I think it's worth exploring the inheritance method since it fits into our current concepts in other nodes, and for your scenario, you'd just need to change the value of one node. Then again, I could be totally missing something, but at least for split screens this would make the workflow pretty nice rather than having to go through all decedents and change them to the specific layer.
As mentionned in #93335 i think #93351 is not solving the issue but if the inheritance is the intended behavior, it would have helped me finding why my layer was not working.
Oh for sure. It's just a non-compatibility-breaking start we can put in place until we flesh out a long-term solution.
Can anybody explain the reasoning behind visibility layers depending on inheritance to begin with? I would have expected it to work like other bitmask settings, and just search the whole tree, rendering or not rendering nodes according to their individual settings, completely ignoring the hierarchy. Any other default behavior seems very counterintuitive.
Principle of rendering in 2D is a bit different, in 3D we have depth sorting but in 2D rendering order is done by exploring the node tree downward. There is option to mitigate that (See Ordering parameters of a CanvasItem) and option to handle things differently called Y-Sorting.
That's why the simplest solution was choosen for that: using inheritance. In the current implementation if VisibilityLayer test fail, the downward exploration stops (and the whole branch is ignored).
So to have the behavior you describe, a big change in the way node are rendered would be needed. That's why for now keeping inheritance maybe easier.
My main problem with this is when I want to make a minimap. Each entity has 2 children: the detailed representation, and the icon representation. I just left visibility layers as they are. However, now I want to make the minimap exclusively renders icons. In order to do that, I have to set icon child to another layer. But then, godot said this:
A Viewport will render a CanvasItem if it and all its parents share a layer with the Viewport's canvas cull mask.
Which means now I have to go back and track every node that is ancestor of every icon, add another tick to the new layer. That is not possible since my project grew large AFAIK, and it would be the equal of modify every scene.
If anyone has found a solution or a reasonable workaround, I would love to know.
Why does your minimap need a detailed representation if you only render icons?
The minimap only has icons, indeed. But the real world (which renders via main camera) has a detailed representation for characters, enemies, .etc.
By the way, I decided to manually turn on the other visibility layer for all ancestors of icon nodes. It was fast. But firstly, my project was small so I can't tell the same for other people. Secondly, it's still very error prone, for example I might forget to tick the minimap layer for the next entity I make.
@Ryu204 Why does your minimap reuse the main camera then?
I have a minimap in my own game. Two ways of doing a minimap in Godot are a 2nd camera that only renders certain visibility layers OR a 2d control with icons under it that you control yourself via code (can be a camera2d, can be just some transform magic and normal controls, depends on how many entities you want on the minimap)
Why does your minimap reuse the main camera then?
No, it does not. I use second camera for that. This is what I am doing:
- Create a camera and put a
SubViewportContainer > SubViewportas its parent - Modify the
SubViewport'scanvas cull maskso it contains 2 layers: Layer 1, and another layer for the minimap (layer 2) - Modify a lot of scenes to contain layer 2 in their visibility settings as I mentioned above
The SubViewport workaround is because of we cannot directly set which layers will be render in a 2D camera (I think? correct me if I'm wrong).
@Ryu204: Neat trick to automate the last bullet point is to put scenes that you want to show on minimap in a separate group. And then write a two-liner of GDSCript that says if in group minimap then set layer 2
Oh that's definitely helpful. Thank you :)
@Zireael07 as much as your solution works for some usecases the way of doing things like @Ryu204 did should work imo.
I also ran in this. This Github issue was the only place to find out about this intended feature. So I would appreciate a little hint at the Viewport-Docs-Page maybe?
It's actually written in the doc :
The rendering layer in which this CanvasItem is rendered by Viewport nodes. A Viewport will render a CanvasItem if it and all its parents share a layer with the Viewport's canvas cull mask.
As mentioned in my PR #93335 the behavior is not matching its 3D pendant and that is why nobody is using it currently, my proposal is to unify the two by just changing the default value to be all layer check by default (just like it is for 3d visibility).