Masked progress bar and shaders

I want to understand how to create a progress bar based on image, through a texture drawing (1 = full image, 0.5 - only half of it). Not without the help of the chat gpt, I created a material and shaders, I partially figured it out myself, but still, I don’t fully understand why it doesn’t work - the progress bar is not drawn by progress value (see code of shadefs).
If I assume correctly, the problem is that the shader tries to draw the entire atlas, and not the selected part. Help with a working shader and an explanation of how it ultimately works.

fp-shader

in mediump vec2 var_texcoord0;

out vec4 out_fragColor;

uniform mediump sampler2D texture_sampler;
uniform fs_uniforms
{
    mediump vec4 tint;
    mediump vec4 progress;
};

void main()
{
    if (var_texcoord0.x > progress.x) {
        discard;
    }
    // Pre-multiply alpha since all runtime textures already are
    mediump vec4 tint_pm = vec4(tint.xyz * tint.w, tint.w);
    out_fragColor = texture(texture_sampler, var_texcoord0.xy) * tint_pm;
}

vp-shader:

in vec4 position;
in vec2 texcoord0;

out vec2 var_texcoord0;

uniform vs_uniforms
{
    highp mat4 view_proj;
};

void main()
{
    gl_Position = view_proj * vec4(position.xyz, 1.0);
    var_texcoord0 = texcoord0;
}

material

name: "progress_bar"
tags: "sprite"
vertex_program: "/main/gui/progress_bar.vp"
fragment_program: "/main/gui/progress_bar.fp"
vertex_constants {
  name: "view_proj"
  type: CONSTANT_TYPE_VIEWPROJ
}
fragment_constants {
  name: "tint"
  type: CONSTANT_TYPE_USER
  value {
    x: 1.0
    y: 1.0
    z: 1.0
    w: 1.0
  }
}
fragment_constants {
  name: "progress"
  type: CONSTANT_TYPE_USER
  value {
    x: 1.0
  }
}
samplers {
  name: "texture_sampler"
  wrap_u: WRAP_MODE_CLAMP_TO_EDGE
  wrap_v: WRAP_MODE_CLAMP_TO_EDGE
  filter_min: FILTER_MODE_MIN_DEFAULT
  filter_mag: FILTER_MODE_MAG_DEFAULT
}

I would probably base my code on either the sprite.material or the gui.material depending on if I use a sprite or gui box node and then discard like you do if the horizontal uv coord is above the threshold.

What kind of component are you using now?

I trying to make textured progress bar using game object

Ok, using a sprite component then?

I would start from the beginning and copy sprite.material, sprite.fp and sprite.vp from builtins and modify your copy of the material and use that on your sprite. Start with the most basic thing and hardcore a cut off point for when to discard pixels in your fragment shader. Start with 0.5 and you should see only half of your sprite image.

I am typing this on a phone with no access to a computer hence why I am not able to provide better hands on help and an example.

2 Likes

It’s always easier when a user shares a ready-to-test minimal project that’s easy to open and check what’s wrong, because there’s not enough context about your setup to help you.

Since I don’t have enough info, I can only guess. The most frequent issue related to this is the use of atlases and the assumption that every sprite has normalized UVs from 0 to 1. But:

  • var_texcoord0 that Defold passes to sprites is global within the whole texture atlas, not inside the current flip-book region. When your bar occupies, say, the range 0.40–0.70 of the atlas width, the smallest var_texcoord0.x you’ll ever see is ~0.40, never 0.0 — Shader - UVs based on whole atlas?

  • Your uniform progress.x = 0.5 was compared against those 0.4–0.7 UVs, so the test never matched the local width you expected, and the entire quad (or none of it) survived the discard.

(Also check this forum topic: Shader - UVs based on whole atlas?)

P.S. since you already use ChatGPT, try to use o3 for such questions, it will be able to use search in internet (for example, on forum)

3 Likes

Thanks for explaining. I wrote here after all my attempts.
Yes, I found the that topic topic and tried to comprehend the meaning through it. but not completely.
and yes, i just used the specified linguistic model.
After all I have made my post.
It’s sad that I can’t implement my idea - styled progress bar over game unit, made as game object, without animated image or gui. Only with shader.
I will made it by easiest way - animated progres bars with 10 images.

Ah, god point Alexey. So making use of this example will help them: