Need a shader for UI Outlining

Godot Version

4.4.1 Stable

Question

Hello! Does anybody know a shader that can outline the textures of overlapping UI components, but only the edges that are outside (if that makes any sense?). I have PanelContainers with custom StyleBox for 9-Patch Rectangle textures. I want to create an effect similar to the UI preview from this game asset, like this:


As you can see, the board and the banner are two different components but they were outlined as if they were one. I know I can just prefab the texture to be like that already but that defeats the purpose of it being scalable and modular. My scene tree currently looks like this:

I already found a shader that draws a pixel-perfect outline of the texture in a PanelContainer, but it doesn’t seem to apply it to its children, and I think if it could, it would apply it even on overlapping texture borders. Any suggestions on where I can find such shader, if there is one, or ideas on how I can make it (and how to set it up)? Thanks in advance!

TL,DR: I need a shader that outlines only the outside of overlapping textures.

Hi,

I’ve been doing a few research and testing on that topic a while ago, and sadly I didn’t found a perfect solution back then. After searching a bit right now, it doesn’t seem like there’s been a new video or reddit thread giving us a cool solution for this :frowning:
I’m still lacking a lot in technical art knowledge in Godot so I’m not saying that there’s no solution to this, but if there’s one, it’s probably not trivial.

Anyway, here’s one technique that’s a bit annoying to setup but that would work (in theory at least, I’ve used that technique a few years ago in Unity, but I don’t see why it would not work here), is to create a script that will create copies of the controls to outline, place them inside a control that’s rendered behind the rest of the UI, and dynamically apply the outline material to these copies.
Basically, it’s just building a second UI behind the first one only to apply the shader on it, so nothing fancy, but that should work fine and at least, that’s automated and dynamic.

Obviously you’ll have to handle the case of moving UI, but that should not be hard at all. Also, it would add things to draw on screen which you typically tend to avoid when making games, but, your UI doesn’t seem to have hundreds of elements to outline, so that should not be an issue, performance wise.

1 Like

I haven’t tested it for UI, but maybe CanvasGroup or BackBufferCopy could work?
Idea being that you somehow “collect” those sprites or parts of the screen together (so they are a single draw call) then apply shader over that. Maybe it is even possible to place this into it’s own canvas layer then do the magic? I have used this for 2D characters with separate parts (hats, clothes and such) to treat them as whole, but not sure if something similar can be done with UI elements.

2 Likes

I did try with CanvasGroup and unfortunately it didn’t work. Maybe I didn’t use a correct setup, but I honestly don’t think it would work as CanvasGroup are made to work with 2D nodes.
EDIT: mrcdk proved me wrong below.

No idea about BackBufferCopy though, but that would be worth a try!
Just important to note that part of the node’s documentation:

Note: Since this node inherits from Node2D (and not Control), anchors and margins won’t apply to child Control-derived nodes. This can be problematic when resizing the window. To avoid this, add Control-derived nodes as siblings to the BackBufferCopy node instead of adding them as children.

1 Like

You could use a CanvasGroup as the parent of whatever you want to outline and a shader like his one 2D outline/inline, configured for CanvasGroup - Godot Shaders to draw the outline.

3 Likes

Finally! I honestly didn’t think CanvasGroup can be used like this. Thank you! I’ll try it later when I get home.

Late reply. Got it working, though there are some issues where the border overlapped with the texture’s built-in (drawn) border. But, I think I can try solving this on my own. Thanks again!