Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect texture UV for Label #23210

Open
sicienss opened this issue Oct 22, 2018 · 19 comments
Open

Incorrect texture UV for Label #23210

sicienss opened this issue Oct 22, 2018 · 19 comments

Comments

@sicienss
Copy link

sicienss commented Oct 22, 2018

Godot version:
3.0.6

OS/device:
Windows 8.1, Toshiba Satellite

Issue description:
For shaders attached to Labels, UV is not as expected. If you attach a shader to a Label and try to do a simple vertical gradient on it, UV.y = 1.0 does not correspond to the bottom of the Label.

Steps to reproduce:

  1. Create a Label.
  2. Add a dynamic font of your choosing.
  3. Attach the following shader.
  4. Observe that the bottom of the text does not have color (1.0, 0.0, 0.0), as would be expected at UV = 1.0.
  5. The multiplier must be changed to around 10.0 in order to see the expected gradient.
shader_type canvas_item;
render_mode unshaded;

// One would expect UV.y = 1.0 to correspond to the bottom of the text.
// This does not seem to be the case, as the bottom of the text is not pure red.
// You must change the multiplier to around 10.0 in order to see the desired gradient.

uniform float multiplier = 1.0; 

void fragment()
{
float texture_alpha = texture(TEXTURE, UV).a;

if (texture_alpha > 0.0)
{
	COLOR = vec4(UV.y * multiplier, 0.0, 0.0, texture_alpha);
}

else
{ 
	COLOR = texture(TEXTURE, UV);
}

}

Minimal reproduction project:
ExampleProject.zip

@QbieShay
Copy link
Contributor

I get 404 on the example project

@CptPotato
Copy link
Contributor

Probably because some form of texture caching or a texture atlas (character map) is implemented in which case this would be expected.

@wingedadventurer
Copy link
Contributor

What's the status on this? I'm unable to add some texture overlay over the label.

This screenshot describes the problem with UVs:
11-18-2019_1

@clayjohn
Copy link
Member

UV is used to determine which character to draw. So UV value for fonts corresponds to a particular color.

This issue will be fixed by #32861

@KoBeWi
Copy link
Member

KoBeWi commented Oct 24, 2020

Still valid in 6c173e2

@Zylann
Copy link
Contributor

Zylann commented Jun 27, 2021

This issue will be fixed by #32861

Considering text is drawn as many rectangles of various sizes, I'm not sure if FULLRECT_UV would behave as "intended" for text. At least, not as described in the first post. Characters can vary in height, so you would end up with the same gradient, "restarting" on each of them. But you may want to add an effect to text which uses the height of the line instead, the width of the whole line, or even the full rectangle of the entire label, rather than the individual rectangles. For a full-label rectangle this can be worked out by passing the rectangle as a uniform, but other cases will require splitting the label apart.

Probably because some form of texture caching or a texture atlas (character map) is implemented in which case this would be expected.

So I think adding more information to text shaders would make this is an enhancement rather than a bug.

@Calinou
Copy link
Member

Calinou commented Jul 15, 2021

This was confirmed to occur in the Vulkan renderer as of fabc3b9 with #50452.

@RitzyMage
Copy link

I'm having this issue as well; are there any known workarounds?

@Calinou
Copy link
Member

Calinou commented Jul 16, 2021

I'm having this issue as well; are there any known workarounds?

Other than using a separate Viewport and applying a shader on the viewport, I can't think of any.

@gianlluca
Copy link
Contributor

This issue is really frusting, I made a dropshadow shader that works very well on a multiple types of Controls and Sprites but I can't make work on Labels and RichTexts.

Other than using a separate Viewport and applying a shader on the viewport, I can't think of any.

I have this idea days ago but the text inside another Viewport is very aliased, different from a Label on root Viewport that is very smooth.

The shader acting on different nodes:

Label:
Label

PNG on a TextureRect:
TextureRect

ViewportContainer with a Viewport and a Label inside:
Viewort

There's no current way to I can get the full Label UV instead of each character UV?

@Zylann
Copy link
Contributor

Zylann commented Jul 16, 2021

You don't always need UVs do make a drop shadow. The problem you have is different. With labels, the target rectangle in the world used to draw each letter does not bleed further than the letters area. To do what you want with a shader, it requires a larger drawing area, like a margin, which is probably not possible because you risk drawing parts of different letters from the characters atlas. You might be able to extend the drawing area with the shader (assuming you can tell which vertices of the quad belong to which corner, not sure how you can do that), but at this point you would have to instruct the font importer to put more empty space between characters of the atlas (there are options for extra spacing on DynamicFont but they dont seem to do that).

Another way to do drop shadow is to just duplicate the label with a dark color behind the first label.

I also see options for "shadow" in the Label's "custom constants" but I have no idea how they work, they don't seem to do anything. But that would be a better option than duplicating.

@Calinou
Copy link
Member

Calinou commented Jul 16, 2021

I also see options for "shadow" in the Label's "custom constants" but I have no idea how they work, they don't seem to do anything.

In the Label's Custom Constants section, you need to set Shadow Offset X and/or Y to non-zero values, then in the Custom Colors section, set a shadow color with an alpha component greater than 0. Shadow As Outline should be kept to 0 (it's a legacy outline system that will likely be removed in 4.0).

This gives you the same visual ressult as using a second Label node, but it doesn't require you to update the position/text of both nodes manually.

@gianlluca
Copy link
Contributor

gianlluca commented Jul 16, 2021

The problem you have is different. With labels, the target rectangle in the world used to draw each letter does not bleed further than the letters area.

Now I understand why even with the changes of this pull #32861 my shader doesn't work, even if I can get the whole label uv, the shader will work only inside this rectangles.

I will assume this thing was designed with optimization in mind (draw only on character size), but this thing makes impossible to do very cool shaders not only the dropshadow, outline shaders based too.

I confess I don't understand anything about how texts are rendered in game engines but I'll ask, make a proposal to have a different text node having one rectangle for all text focused to receive shaders like this is ridiculous?

@Calinou
Copy link
Member

Calinou commented Jul 16, 2021

I will assume this thing was designed with optimization in mind (draw only on character size), but this thing makes impossible to do very cool shaders not only the dropshadow, outline shaders based too.

Outlines are supported natively in DynamicFont, so you don't need a shader to draw one 🙂

If you need more than one outline, see godotengine/godot-proposals#2564. It may be possible to use two Label nodes, one with a different DynamicFont each (each with its own outline style).

I confess I don't understand anything about how texts are rendered in game engines but I'll ask, make a proposal to have a different text node having one rectangle for all text focused to receive shaders like this is ridiculous?

This may be achievable with the CanvasGroup node in Godot 4.0.

@gianlluca
Copy link
Contributor

gianlluca commented Jul 17, 2021

Well to help people redirected to this from some search mechanism with the same problem than I

I reach what I want by applying the shader on duplicated label behind the original and by offsetting the rect position, I modify the shader to not bleed the rectangles mentioned by Zylann.

Why did I want to use the shader instead of native shadow from DynamicFont?

I want to have a really dark shadow but with smooth edges which is something common to shadows, thing that native shadow from DynamicFont doesn't support!

Native Shadow:
NativeShadow

Shader on duplicated Label behind:
DuplicatedLabel

a different text node having one rectangle for all text

To finish I still think that something like this would give an infinity more control about stylizing text with shaders! I'll not bump this issue anymore!

@Calinou
Copy link
Member

Calinou commented Jul 17, 2021

I want to have a really dark shadow but with smooth edges wich is something common to shadows, thing that native shadow from DynamicFont doesn't support!

You don't have to use an opaque color for the shadow. You can use a translucent color with alpha < 1.0. It will still be a hard shadow, but it will look softer and less harsh overall.

@tripodsan
Copy link

tripodsan commented Sep 22, 2023

inspired by #32861 (comment), you can do:

varying vec2 full_uv;
void vertex () {
  full_uv = VERTEX.xy;
}

void fragment() {
  COLOR.a = texture(TEXTURE, UV).a;
  COLOR.g = full_uv.x / 20.0;
}

with the caveat that the size of the rect needs to be passed in the shader (via an uniform):

image

@awardell
Copy link
Contributor

awardell commented Nov 1, 2023

@tripodsan

full_uv = VERTEX.xy;

I'm on 4.2 and VERTEX.xy only provides (0,0) in the vertex function. Am I missing something, or does this workaround no longer work?

@tripodsan
Copy link

tripodsan commented Nov 3, 2023

works for me in Godo 4.1.2

image

updated version:

shader_type canvas_item;

// the fragment UV does not represent the UV of the
// canvas_item rect but some uv of the font texture
// in order to get the canvas item UV the item size
// needs to be passed into the shader.
uniform vec2 size;

varying vec2 iuv;

void vertex () {
  iuv = VERTEX.xy / size;
}

void fragment() {
  COLOR.a = texture(TEXTURE, UV).a;
  COLOR.gb = iuv.xy;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests