I got simple hp bar container from open game art, rendered the texture and now I am wondering how to fill it and change the amount of filling.

I decided to render red rectangle over the container and change its size programmatically via matrix modification. However, I am not sure if this is the best way. What if I want something fancier than simple red color, what if I want to fill HP bar with some kind of texture?

Note that I can only use OpenGL.


1 Answer 1


For complex hp bars, I recommend using two images.

  • Empty hp bar.
  • Filled hp bar.

And draw them partially in x or y direction. enter image description here

  • You can use two quads, adjusting the vertex coordinates and texture limits, one on the left and the other one on the right.
  • Or you can use a shader, that receives an offset uniform variable and two textures and draw one of them depending on the texture coords (u,v).

Note: you can also mix both images in one texture atlas.


enter image description here

By default, your quad will display both images. x between 0.0-1.0 and y between 0.0 and 1.0. They are the standard coordinates to render an image inside a quad.

First we need to draw only half of the image. So we narrow the texture component from 0.0-1.0 to 0.0-0.5. Simply dividing by two (because there are two images).

vec2 texCoord = vec2(vTextureCoord.x / 2.0, vTextureCoord.y)


vec2 texCoord = vec2(vTextureCoord.x / 2.0 + 0.0, vTextureCoord.y)

That will show the left image. To show the right one (filled), we need texCoord x in the range 0.5-1.0. That can be achieved adding an offset to skip the left part (1.0/2.0). 1 image skipped of two.

vec2 texCoord = vec2(vTextureCoord.x / 2 + 0.5, vTextureCoord.y)

So just changing the offset from 0.0 to 0.5, we can draw the left (0.0 offset) or the right image (0.5 offset).

We need an external filled value, between 0.0 and 1.0, because the texture range goes from 0.0 to 1.0. If filled is not in the range [0.0-1.0] you need to do some maths to transform in the 0.0-1.0 range. For vertical image, we compare the texture.y coordinate with the filled value, if y is above the filled limit, then we show the left one (empty) if not, we show the right one (filled).

float offset = vTextureCoord.y > uFilled ? 0.0 : 0.5;

equivalent to

float offset;
if ( vTextureCoord.y > uFilled ) { offset = 0.0 }
else { offset = 0.5 }

Fragment shader

#version 330 core
out vec4 FragColor;

in vec2 vTextureCoord;

uniform float uFilled;          // between 0.0 and 1.0
uniform sampler2D uTexture;

void main() {
    // if vertical texture coord is greater than uFilled, use the empty one (left), otherwise the filled one (right)
    float offset = vTextureCoord.y > uFilled ? 0.0 : 0.5;
    vec2 texCoord = vec2(vTextureCoord.x / 2 + offset, vTextureCoord.y);
    FragColor = texture(uTexture, texCoord);

Vertex shaders

#version 330 core
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec2 aTextureCoord;

out vec2 vTextureCoord;

void main() {
    gl_Position = vec4(aPosition, 1.0f);
    vTextureCoord = aTextureCoord;


Following the @Raildex recommendation in the comments. Example using gray scale additional images to fill the progress bar. Just an example of what can be done.

enter image description here

Left one using two images, right one using four images.

enter image description here

  • 1
    \$\begingroup\$ Thank you gotanod, I actually wondered why hp bar assets are usually consist of 2 images of filled and empty one. That helps a lot \$\endgroup\$
    – Steyrix
    Jan 12, 2023 at 12:58
  • 2
    \$\begingroup\$ I recommend using 3 textures. One for the Background, a Greyscale fill map and the texture that contains only the filling. Just do a simple threshold with the greyscale texture (which represnets the filling from 0 to 1) and you can have arbitrary shapes and fill progressions. \$\endgroup\$
    – Raildex
    Jan 15, 2023 at 11:21
  • 2
    \$\begingroup\$ @Raildex Interesting, instead of filling in one fixed direction (x/y i.e u/v), with the grayscale (or 1 channel texture) you can predefine the way it will be filled using any original pattern. \$\endgroup\$
    – gotanod
    Jan 15, 2023 at 22:22
  • 2
    \$\begingroup\$ @cppBeginner use any tool that lets you generate gradients. Photoshop, Paint.NET, GIMP... \$\endgroup\$
    – Raildex
    Feb 11 at 8:29
  • 1
    \$\begingroup\$ @cppBeginner Try drawing solid bands of colors from black to white, and then use a tool like "smudge tool" in gimp to mix the layers. \$\endgroup\$
    – gotanod
    Feb 13 at 21:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .