Progress Bar Anything
Add a simple progress display within canvas items.
This is a very simple shader that was intended to be used to make hybrid Button + Progress Bars. It fills left to right and allows you to define a fill color, min/max and current values.
This was inspired by the idle game “Your Chronicle” which used buttons that doubled as progress bars and I wanted a similar effect.
Shader code
shader_type canvas_item;
uniform vec4 fill_color: source_color = vec4(1.0);
uniform float min_val;
uniform float current_val;
uniform float max_val;
/*
linear normalization from one range to another
*/
float linear(float old_min, float old_max, float new_min, float new_max, float current) {
float old_range = (old_max - old_min);
float new_range = (new_max - new_min);
float new_val = (((current - old_min) * new_range) / old_range ) + new_min;
return new_val;
}
void fragment() {
vec4 color = COLOR;
float normalized = linear(min_val, max_val, 0.0, 1.0, current_val);
/*
If the fragcoord.x is less than or equal to the calculated point
between min and max that current_value falls on, mix with our
fill color
*/
if (UV.x <= normalized) {
color.rgb = mix(color.rgb, fill_color.rgb, 0.5);
}
COLOR = color;
}
Great shader!
I ended up needing to have the color fill vertically instead of horizontally. Here is the shader code:
Vertical Shader
Added fill_from_top boolean – When true the progress will fill starting from the top of the sprite the shader is attached to. When false the progress will fill starting from the bottom of the sprite that the shader is attached toshader_type canvas_item;
uniform vec4 fill_color: source_color = vec4(1.0);
uniform float min_val;
uniform float current_val;
uniform float max_val;
uniform bool fill_from_top = true;
/*
linear normalization from one range to another
*/
float linear(float old_min, float old_max, float new_min, float new_max, float current) {
float old_range = (old_max – old_min);
float new_range = (new_max – new_min);
float new_val = (((current – old_min) * new_range) / old_range ) + new_min;
return new_val;
}
void fragment() {
vec4 color = COLOR;
if(fill_from_top) {
float normalized = linear(min_val, max_val, 0.0, 1.0, current_val);
if (UV.y <= normalized) {
color.rgb = mix(color.rgb, fill_color.rgb, 0.5);
}
}
else {
float real_current_val = max_val – current_val;
float normalized = linear(min_val, max_val, 0.0, 1.0, real_current_val);
if (UV.y >= normalized) {
color.rgb = mix(color.rgb, fill_color.rgb, 0.5);
}
}
COLOR = color;
}
Horizontal Shader (basically this same shader but with some extra flexibility):
Added fill_from_left boolean – When true the progress will fill starting from the left of the sprite the shader is attached to (how this shader was originally made). When false the progress will fill starting from the right of the sprite the shader is attached toshader_type canvas_item;
uniform vec4 fill_color: source_color = vec4(1.0);
uniform float min_val;
uniform float current_val;
uniform float max_val;
uniform bool fill_from_left = true;
/*
linear normalization from one range to another
*/
float linear(float old_min, float old_max, float new_min, float new_max, float current) {
float old_range = (old_max – old_min);
float new_range = (new_max – new_min);
float new_val = (((current – old_min) * new_range) / old_range ) + new_min;
return new_val;
}
void fragment() {
vec4 color = COLOR;
if(fill_from_left) {
float normalized = linear(min_val, max_val, 0.0, 1.0, current_val);
if (UV.x <= normalized) {
color.rgb = mix(color.rgb, fill_color.rgb, 0.5);
}
}
else {
float real_current_val = max_val – current_val;
float normalized = linear(min_val, max_val, 0.0, 1.0, real_current_val);
if (UV.x >= normalized) {
color.rgb = mix(color.rgb, fill_color.rgb, 0.5);
}
}
COLOR = color;
}
If I get more time I might just post these as standalone shaders on this site and link back to here. Thanks for the starting point!
Oh cool! You should upload it yourself as “vertical progress bar anything” or something 🙂 I’m glad this was able to help someone pivot off of it to make something new!
I wonder if both functionalities could be provided in a single shader without a significant effort lift