Universal Text Shine (Bitmap Font Compatible + 360° Angle)

Description

A robust shine/sheen effect designed specifically for Godot Label, RichTextLabel, and TextureRect.

The Problem:

Standard shine shaders use UV coordinates. Because Godot stores font characters in a “Texture Atlas” (scattered randomly on a sheet), standard shaders create broken, scattered shine effects on text, or different speeds for different letters.

The Solution:

This shader uses VERTEX positions to map the shine across the physical size of the control, creating a perfectly smooth, uniform bar that travels across your text regardless of font type, font size, or character position.

Features:

*   Bitmap Font Compatible: Works perfectly on pixel art fonts and dynamic fonts.

*   360° Rotation: The shine works correctly from any direction (Top-down, Diagonal, Left-Right) using dot-product logic rather than slope calculations.

*   Color Safe: Respects the Modulate / Font Color of your label.

 

⚠️ Setup Required:

Because the shader needs to normalize the pixel coordinates, you must pass the label’s size to the shader via script.

1. Attach this script to your Label and provide your material:

func _ready():

    # Pass the initial size to the shader

    (material as ShaderMaterial).set_shader_parameter("text_size", size)

    

    # Update if text changes or label resizes

    resized.connect(func(): 

        if material:

            (material as ShaderMaterial).set_shader_parameter("text_size", size)

    )

2. Animation Tip:

Tween the shine_progress from 0.0 to 1.0. The shader automatically calculates the start and end positions based on the angle, so 0.0 is always “just before entering” and 1.0 is always “just after leaving.”

Shader code
shader_type canvas_item;

uniform vec4 shine_color : source_color = vec4(1.0, 1.0, 1.0, 1.0);
uniform float shine_progress : hint_range(0.0, 10.0, 0.001) = 0.0;
uniform float shine_size : hint_range(0.01, 1.0, 0.01) = 0.1;
uniform float shine_angle : hint_range(0.0, 360.0, 0.1) = 45.0; 

// Must be set via GDScript!
uniform vec2 text_size = vec2(100.0, 100.0); 

varying vec2 pixel_pos;

void vertex() {
	// Capture absolute pixel position
	pixel_pos = VERTEX;
}

void fragment() {
	vec4 tex = texture(TEXTURE, UV);
	vec4 original_color = tex * COLOR;
	// 1. Normalize position based on label size (0.0 to 1.0)
	vec2 box_uv = pixel_pos / text_size;
	
	// 2. Calculate Direction Vector
    float rad = radians(shine_angle);
    vec2 dir = vec2(cos(rad), sin(rad));
    float projection = dot(box_uv, dir);;
	
	// 4. Calculate dynamic boundaries
	// We project all 4 corners of the box to find the exact start/end for this angle
	float p1 = dot(vec2(0.0, 0.0), dir);
	float p2 = dot(vec2(1.0, 0.0), dir);
	float p3 = dot(vec2(0.0, 1.0), dir);
	float p4 = dot(vec2(1.0, 1.0), dir);
	
	float min_dist = min(min(p1, p2), min(p3, p4));
	float max_dist = max(max(p1, p2), max(p3, p4));
	
	// 5. Map progress to these bounds
	// We subtract shine_size from start so it begins completely invisible
	float current_pos = mix(min_dist - shine_size, max_dist, shine_progress);
	
	// 6. Create the band
	float shine = step(current_pos, projection) - step(current_pos + shine_size, projection);
	
	COLOR = original_color;
	COLOR.rgb = mix(COLOR.rgb, shine_color.rgb, shine * shine_color.a);
}
Tags
2d, bitmap-font, effect, highlight, Label, metallic-shine, sheen, shine, text, ui
The shader code and all code snippets in this post are under MIT license and can be used freely. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

Related shaders

2D Controlled Shine Highlight With Angle Adjustment

3D Item Highlighter (with Angle Adjustment!)

Universal Transition Shader

guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments