Documentation

Shader Example: Digital Counter

A digital counter in fragment shader.

Header

Your content here

Snippets

Shadertoy

// Single animated counter centered on screen.

const float DIGIT_THICK = 0.055;
const float DIGIT_SCALE = 0.34;
const float COUNT_SPEED = 8.0;
const int   MAX_VALUE   = 999;

// Configs:
// For slower counting: const float COUNT_SPEED = 2.0;
// For larger digits: const float DIGIT_SCALE = 0.28;
// For two-digit only const int MAX_VALUE = 99;

float sdBox(vec2 p, vec2 b)
{
    vec2 d = abs(p) - b;
    return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0);
}

float segH(vec2 p, vec2 c)
{
    return 1.0 - smoothstep(DIGIT_THICK, DIGIT_THICK + 0.01,
                            sdBox(p - c, vec2(0.22, DIGIT_THICK)));
}

float segV(vec2 p, vec2 c)
{
    return 1.0 - smoothstep(DIGIT_THICK, DIGIT_THICK + 0.01,
                            sdBox(p - c, vec2(DIGIT_THICK, 0.18)));
}

float digit7(vec2 p, int d)
{
    float A = segH(p, vec2( 0.0,  0.36));
    float B = segV(p, vec2( 0.23,  0.18));
    float C = segV(p, vec2( 0.23, -0.18));
    float D = segH(p, vec2( 0.0, -0.36));
    float E = segV(p, vec2(-0.23, -0.18));
    float F = segV(p, vec2(-0.23,  0.18));
    float G = segH(p, vec2( 0.0,  0.00));

    bool a=false,b=false,c=false,dn=false,e=false,f=false,g=false;

    if (d == 0) { a=true; b=true; c=true; dn=true; e=true; f=true; }
    if (d == 1) { b=true; c=true; }
    if (d == 2) { a=true; b=true; dn=true; e=true; g=true; }
    if (d == 3) { a=true; b=true; c=true; dn=true; g=true; }
    if (d == 4) { b=true; c=true; f=true; g=true; }
    if (d == 5) { a=true; c=true; dn=true; f=true; g=true; }
    if (d == 6) { a=true; c=true; dn=true; e=true; f=true; g=true; }
    if (d == 7) { a=true; b=true; c=true; }
    if (d == 8) { a=true; b=true; c=true; dn=true; e=true; f=true; g=true; }
    if (d == 9) { a=true; b=true; c=true; dn=true; f=true; g=true; }

    float s = 0.0;
    if (a)  s = max(s, A);
    if (b)  s = max(s, B);
    if (c)  s = max(s, C);
    if (dn) s = max(s, D);
    if (e)  s = max(s, E);
    if (f)  s = max(s, F);
    if (g)  s = max(s, G);

    return s;
}

float drawInt3(vec2 p, int value)
{
    value = clamp(value, 0, 999);

    int h = value / 100;
    int t = (value / 10) % 10;
    int o = value % 10;

    float s = 0.0;

    if (h > 0)
        s = max(s, digit7((p - vec2(-0.52, 0.0)) / DIGIT_SCALE, h));

    if (h > 0 || t > 0)
        s = max(s, digit7((p - vec2(0.00, 0.0)) / DIGIT_SCALE, t));

    s = max(s, digit7((p - vec2(0.52, 0.0)) / DIGIT_SCALE, o));

    return s;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = fragCoord / iResolution.xy;
    vec2 p = uv - 0.5;
    p.x *= iResolution.x / iResolution.y; // aspect correction

    vec3 col = vec3(0.05, 0.06, 0.08);

    int value = int(mod(floor(iTime * COUNT_SPEED), float(MAX_VALUE + 1)));

    float pulse = 0.9 + 0.1 * sin(iTime * 6.28318);

    float plate = 1.0 - smoothstep(0.28, 0.34, length(p * vec2(1.0, 1.3)));
    col += vec3(0.08, 0.09, 0.11) * plate;

    float num = drawInt3(p * 1.2, value);

    vec3 textCol = vec3(0.95, 0.98, 1.0) * pulse;
    col = mix(col, textCol, num);

    fragColor = vec4(col, 1.0);
}