How to get region coordinates of a texture within a Shader? Need this for a text shader.

Godot Version

v4.5.beta2.official [e1b4101e3]

Question

How do I get the coordinates of the region rect being rendered from a larger texture in shader code? I.e. the position of the top-left part of my texture region and its size. I need this in order to write a vertex shader that smoothly stretches the output draw to be larger so that it can encompass all the space needed to add the shadow. This is the version of the line I’m using, which would work if I was using a normal texture:

VERTEX = vec2(VERTEX.x, VERTEX.y * (1.0 + TEXTURE_PIXEL_SIZE.y * thickness));

However, I’m writing this to be applied to text, and all the text characters are on a single texture, so it doesn’t work and can’t work unless I can get the bounds of the region being rendered and do my calculations with those. Alternatively, if anyone knows a non-invasive way to make each character its own texture without tearing the guts out of RichTextLabel or writing my own implementation, I’m all ears.

To give more precise details - I’m trying to write a shader to add a drop shadow under text drawn by a RichTextLabel. I want to achieve an end effect where each character’s shadow has a slightly different offset, to give the illusion of an actual light source. I tried writing a GDExtension to just force something similar, but I found the code in a RichTextLabel that actually sends text to the TextServer for rendering, and it doesn’t seem to be exposed. I also tried writing an engine module, but the tutorial for having separate libraries built as .dll’s doesn’t actually work on Windows, and the compiler refuses to compile on both MSVC and MinGW (but still works for compiling the engine normally, as well as internal engine modules). This is a known problem with multiple GitHub issues, not a configuration error on my end, and I already spent pretty much an entire day trying to make that work. RichTextEffect is how I would have preferred to do this, but it doesn’t actually allow you to manipulate shadow positions or render the same character more than once at all in any way.

My other option is to just write my own implementation of RichTextLabel, but no, I’m not going to do that. Alternatively, I could just actually build my changes into the engine’s .exe file (and then have to redo them if I ever update engine versions), but I really don’t want to do that. I’m fine with having an engine module as like a .dll, but doing it that way seems like a bad idea.

I’m not sure if this will work for your use-case but you can access the region rect value in the fragment() function with REGION_RECT starting from Godot 4.5-dev4. It was added here Expose built-in region information by dsmtE · Pull Request #90436 · godotengine/godot · GitHub

You can know if the rendered character is part of the outline/shadow or not with CharFXTransform.outline so you can tweak its position there like:

class_name ShadowEffect extends RichTextEffect

var bbcode = "shadow"

func _process_custom_fx(char_fx: CharFXTransform) -> bool:
	if char_fx.outline:
		char_fx.offset = Vector2(randi_range(-20, 20), randi_range(-20, 20))
	return true

Result:

Oh. Somehow even though I like, saw the code of the richtextlabel where it was very clearly just sending things to the text server twice, the synapses never connected that the shadow was actually being drawn as a second pass with bbcode.

There is currently no way in Godot to get the coordinates of an individual character in the texture atlas directly from a vertex or fragment shader, unless the engine manually passes them to you as uniforms or vertex attributes, which it does not do in the case of a RichTextLabel.

Mini Militia App Lock

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.