Shader for Buttons with Text
Asked Answered
D

11

0

Hi,

I've just started working with shaders and wanted to start with something simple. A Button.
But I ran into a problem that the text of the button has very weird (random?) UV values, which makes it very hard for me to actually make something useful.
Here's a visualization of the button UV:

My Question:
Is this something that can be solved in Godot 4.1? I saw a couple of posts regarding this, but the post were old and referred to Godot 3.x
(https://github.com/godotengine/godot/issues/19736)

Edit:
More information for clarification:

Thanks to Burge I realized that this might be more than just a plain UV issue.
I created the picture using the following code:
Edit:
More information for clarification:

void fragment() {
	COLOR.rgba = vec4(UV.x, UV.y, 0.0, 1.0);
}

The adjustments and Ideas in the replies worked for simply colouring the button. Is there also a nice hack for changing the vertex?
In this example I used the following code to enlarge the button:
uniform float amplitude = 5.0;

void vertex() {
	if(UV.x < 0.5) {
		VERTEX.x = VERTEX.x - amplitude;
	}
	else {
		VERTEX.x = VERTEX.x + amplitude;
	}
	if (UV.y < 0.5) {
		VERTEX.y = VERTEX.y - amplitude;
	}
	else {
		VERTEX.y = VERTEX.y + amplitude;
	}
}

As you can see the UV of the text is messing with the vertex as well.

Thanks in advance,
Daweed

Disservice answered 1/11, 2023 at 17:47 Comment(0)
B
0

Disservice I have no idea what we are looking at here and what you are trying to solve. ๐Ÿ˜‰

If you mean why the boxes are overlapping then my guess would be that it's because of kerning. If we are looking at letters, that is?

Benuecongo answered 1/11, 2023 at 19:16 Comment(0)
P
0

Yes those are font UVs. I'd imagine they're being drawn on top of the texture uvs. Dunno how to distinguish that in a shader on a button.

Planar answered 1/11, 2023 at 20:8 Comment(0)
P
0

So it's definitely overwritten via alpha:

void fragment() {
	COLOR.b = 0.0;
	COLOR.rg = UV.xy;
	COLOR.a = 1.0;
}

gives us

but if I don't mess with the alpha:

void fragment() {
	COLOR.b = 0.0;
	COLOR.rg = UV.xy;
}

So clearly the base UV is THERE underneath the text. Basically what's happening is each of those "squares" you see is one character of text being drawn via quad over the button. The UVs of the corners of the quad are lined up with the font file to grab the correct character. This is the case whether it's sdf or bitmap; it still has to know what it's rendering.

The question then is how to get that background UV data to the "font-quads", and how to distinguish them from the background of the button in our shader. ๐Ÿค”

If I recall correctly, I think TextMeshPro for Unity stored the font UVs in a separate UV channel, but that doesn't seem to be what's happening here.

Edit: More messing around with it:

void vertex() {
	UV0 = UV;
	UV += vec2(.01);
}

void fragment() {
	COLOR.b = 0.0;
	COLOR.rg = UV0;
	COLOR.a = .5 + .5 * COLOR.a;
}

Edit2:
Looking into the engine and "quads" is also probably inaccurate. The TextServer renders them as "glyphs".

Planar answered 1/11, 2023 at 20:49 Comment(0)
P
0

Disservice I saw a couple of posts regarding this, but the post were old and referred to Godot 3.x

Was it this on github that you saw? Seems like it's been unresolved for a long time ๐Ÿ™

Planar answered 1/11, 2023 at 22:44 Comment(0)
P
0

I've come up with some workarounds. They're all pains in the ***.

  1. Button with text. Detect if you're rendering a glyph or not by checking the texture resolution. The glyphs use a separate texture for the font, and in my testing TEXTURE_PIXEL_SIZE == (1/256, 1/256). This seems hacky as hell and unreliable.
  2. Button with no text, Label child of button. This gives the benefit of being able to use separate materials for each, but now the text won't play as nicely with the button sizing. The button will need manual resizing, won't resize with text overflow, text is harder to position nicely, etc. Text also won't change nicely with button state themes.

Whether you go with 1 or 2, if you're shading the text you'd basically need to compare the text's screen coordinates with the button's rect passed via uniform in order to find out your full UV, because that's the only useful coordinates you're given.

  1. Button with no text. MeshInstance2D child of button. TextMesh as the mesh. This will work really well with a shader. You get sensible UVs and vertices and all that. This will play terribly with the button because it isn't a control. I have no idea what it would even do to the draw calls.

Basically with that full_uv = VERTEX.xy; workaround not working, we don't have good options.

Planar answered 2/11, 2023 at 0:28 Comment(0)
G
0

Planar 1. is a good idea. It can be done in almost 100% reliable way. Assign the same StyleBoxTexture override for relevant button state styles. In this stylebox resource set the texture to a dummy 1x1 pixel texture. The font texture surely won't be of that size so it's a good indicator that you're rendering the background.

void fragment(){
	vec3 bgColor = vec3(UV, 0.0);
	vec3 textColor = vec3(1.0, 1.0, 1.0);
	COLOR.rgb = mix(textColor, bgColor, step(1.0, TEXTURE_PIXEL_SIZE.x));
}

Gelinas answered 2/11, 2023 at 1:58 Comment(0)
P
0

Gelinas LOL genius. Still a hack but a much more reliable one!

Planar answered 2/11, 2023 at 2:41 Comment(0)
D
0

Planar I added the link to the Github post I found in the original post. I believe that should be the same thing what I'm experiencing

Disservice answered 2/11, 2023 at 19:26 Comment(0)
D
0

Gelinas Planar
Thanks for the suggestions. They work for displaying the text. I'm still a bit confused why the button / text is handled this way.

I also tried changing the vertex which messed up everything again. I added the example in the original post as I thought that it should belong there.
Do you also have some nice ideas on how to solve this in the shader, or is the "label below button" idea my best option?

Disservice answered 2/11, 2023 at 19:30 Comment(0)
D
0

Benuecongo
Hi,
I added some more context to the post.
The original motivation was to learn why my shaders are behaving in a weird way (Text being shaded in a weird way, or moving the "wrong direction" in vertex shaders).
I'm still new to them and wanted to know if anyone else has these difficulties.

Disservice answered 2/11, 2023 at 19:35 Comment(0)
G
0

Disservice There's nothing weird about it. It behaves in a totally expected way. The shader is attached via base class (CanvasItem) property. So you don't really have control of how more complex derived classes that need more than one shader will use it. In the case of button the engine simply applies the same shader to all of its rendered components - background and each individual text glyph.

If you're only starting with shaders you should go simpler than button. Use a plain ColorRect or Sprite2D node and play with a shader attached to that. The look of Button nodes and most other GUI nodes is not really meant to be controlled by custom shaders.

Gelinas answered 2/11, 2023 at 19:42 Comment(0)

© 2022 - 2024 โ€” McMap. All rights reserved.