I’m creating a custom shader for CanvasGroups. Basically, it’s a playing card with multiple elements inside it. I’m using the shader for multiple effects, including rounding the corners.
I got everything working properly when the card is in upright position (or rotated 90, 180, 270 degrees), but the UVs mess things up with any angle between those. UV is getting bigger when rotated, making its coordinates unreliable. Any ideas on how to fix this?
CanvasGroup has the shader and is the one being rotated. It doesn’t make a difference if I rotate a parent of the CanvasGroup either. The outcome is the same.
It’s a weird way of doing this. Why not contain everything in a control container like panel? With panel you get rounded cornered box for free, no shaders or textures needed.
But if you insist on doing it like this, simply leave the canvas group node be and put another sprite inside it that will draw the card background/frame
I’m still pretty new to Godot. If there’s a better way to achieve what I want, I’m absolutely open to new implementation ideas! Here’s what I want to be able to do:
Round corders (using an image mask or any other way of achieving it)
Build the card using multiple nodes (sprites and labels)
Be able to apply a singular shader to the whole card
I’m not sure how I could use a panel with rounded corners to achieve all 3 goals, especially the last one. That’s why I’m currently placing them into a CanvasGroup, to be able to apply a shader to the card as a single entity.
I’m not sure what you mean by this. By nature, CanvasGroup cannot have graphics applied to itself, but it works as a container for other nodes, like Sprite2Ds. I described by node tree in the opening post.
I fail to see how that changes anything. Can you post a list of your suggested node tree? I believe it won’t change the outcome of applying a shader to said CanvasGroup.
The shader in the canvas group doesn’t need to do the rounded corner part then. Just read the screen texture and assign to COLOR. It won’t have to deal with UV which gets extended to encompassing bounding box of all rotated children.
CanvasGroup
Background Sprite
Other stuff you currently have
That won’t accomplish what I show and explain, where I use the rounded corner image as a mask for everything inside the card. I can bake the rounded corners to any elements inside, but that doesn’t fix the UV issues. I want to have other shader effects on the card too, of which many use bitmaps to achieve said effects. They are stretched in a similar fashion whenever the card is rotated. The rounded corners is just the most visible one.
I would really want to get the UVs match the rotated CanvasGroup. That is the core issue I have.
Afaik, you can’t. CanvasGroup’s bounding box is not exposed to script so you have nothing to work with if you wanted to recalculate UVs. If the bounding box was known it could be possible with a bit of simple math to calculate the UV area that covers the content in rotated state.
If you need masking you can use canvas item’s clip children feature. Drop the canvas group and use a sprite as a root node, add an additional effect sprite on top of everything:
Clipping Sprite (rounded corner texture, enable clip children)
Your content
Effect sprite (shader drawing the effect)
That doesn’t let me apply a shader to your example’s root_mask (one of the main things I wanted to accomplish). Still, thank you so much for trying to help me with the problem.
Here’s the shader code we wrote to properly shrink UV for a rotated CanvasGroup in case someone else has the same problem.
Which the system doesn’t know and you need to guess/input it manually. If something is larger than the mask and sticks out (which is the sole purpose of using a mask) you’ll have hard time keeping track of that size.
Why do you need to run a shader on the canvas group? If you need to overlay a shader effect, just put an additional sprite on top of everything and run the shader on that sprite. Much simpler to manage than hacking the canvas group and guessing its bounding box size.
I’m setting it via code. I’m using this for my cards, which are always the same size. Scaling doesn’t affect this behaviour.
As far as I know, I cannot do ‘destructive’ shaders when I only overlay it to a new child node, like fading the card out using noise. I find it very helpful to be able to apply the shader directly to the group, not its children nodes. I’m not guessing the size of my CanvasGroup as it’s always the same size (and can be set in code too).