VFX Frame Interpolator (with Gradient Tint)
A simple shader that allows you to smoothly interpolate animation frames in a sprite sheet. This makes your 16 frame VFX look smooth! As a bonus, the ability to use a gradient has also been added!
Hint: To get the best results, use a gradient where the alpha is 0 at the start and set your desired color at the end. The red channel of the sprite sheet mask will then map to the gradient.
Shader code
shader_type canvas_item;
uniform int frames = 4; // Number of frames in the sprite sheet.
uniform float animation_progress : hint_range(0.0, 1.0, 0.001) = 0.0; // Animation progress (0.0 to 1.0).
uniform sampler2D sprite_sheet; // Sprite sheet containing animation frames.
uniform sampler2D gradient : source_color; // Gradient for final color lookup.
uniform float y_offset = 0.0; // Vertical UV offset for the sprite sheet.
uniform float y_size = 1.0; // Vertical UV scale for the sprite sheet.
// Creates a smooth S-curve
float quadratic_ease_in_out(float t) {
t = clamp(t, 0.0, 1.0);
// Formula: 2t^2 for first half, 1 - 2(1-t)^2 for second half.
return t < 0.5 ? 2.0 * t * t : 1.0 - 2.0 * pow(1.0 - t, 2.0);
}
void fragment() {
vec2 uv = UV;
float frame_width = 1.0 / float(frames); // Width of a single frame.
float timeline_pos = animation_progress * float(frames); // Position on the animation timeline.
// Determine current and next frame indices.
int current_frame_idx = int(floor(timeline_pos));
int next_frame_idx = int(ceil(timeline_pos));
// Clamp frame indices to valid range.
current_frame_idx = clamp(current_frame_idx, 0, frames - 1);
next_frame_idx = clamp(next_frame_idx, 0, frames - 1);
// Calculate X-start for current and next frames.
float current_frame_x_start = float(current_frame_idx) * frame_width;
float next_frame_x_start = float(next_frame_idx) * frame_width;
// Apply vertical offset and scale to UV.
uv.y *= y_size;
uv.y += y_offset;
// Calculate full UVs for sampling from sprite sheet.
vec2 current_uv = vec2(current_frame_x_start + uv.x * frame_width, uv.y);
vec2 next_uv = vec2(next_frame_x_start + uv.x * frame_width, uv.y);
// Sample colors from sprite sheet for current and next frames.
vec4 color_current = texture(sprite_sheet, current_uv);
vec4 color_next = texture(sprite_sheet, next_uv);
// Interpolation factor based on the fractional part of timeline position.
float linear_t = fract(timeline_pos);
// Apply eased interpolation.
float eased_t = quadratic_ease_in_out(linear_t);
// Interpolate between frame colors.
vec4 interpolated_color = mix(color_current, color_next, eased_t);
// Use the red channel of the interpolated color to sample from the gradient.
float sample_channel = interpolated_color.r;
vec4 final_color = texture(gradient, vec2(sample_channel, 0.0));
COLOR = final_color;
}




Thanks for this. Might come handy