Control Flow & Functions

GLSL ES 1.00 (WebGL 1) restricts loops to constant bounds (for (int i = 0; i < 16; i++)).

10.1 Control flow

GLSL ES 1.00 (WebGL 1) restricts loops to constant bounds (for (int i = 0; i < 16; i++)).

if (d < 0.0) {
    col = vec3(1.0, 0.0, 0.0);
} else if (d < 0.5) {
    col = vec3(0.0, 1.0, 0.0);
} else {
    col = vec3(0.0, 0.0, 1.0);
}

for (int i = 0; i < 8; ++i) {
    if (i >= uLightCount) break;
    color += shade(uLights[i]);
}

int k = 0;
while (k < 10) { k++; }
do { k--; } while (k > 0);

switch (mode) {               // int/uint selector (GLSL 1.30+, ES 3.00+)
    case 0: col = vec3(1); break;
    case 1:
    case 2: col = vec3(0.5); break;
    default: col = vec3(0);
}

float t = cond ? 1.0 : 0.0;

discard;                      // fragment shaders only: drop this fragment
return;

10.2 Branching & divergence

GPUs execute invocations in groups (warps/wavefronts). If invocations in a group take different branches, both paths execute (masked) — divergence costs performance. Prefer branch-free math (mix, step, clamp) for simple selections; uniform branches (same for all invocations, e.g., based on a uniform) are cheap.

10.3 Functions

Rules: no recursion; parameters passed by value (copy-in/copy-out for out/inout); functions must be declared before use; entry point is void main().

float square(float x) { return x * x; }

vec3 lambert(vec3 n, vec3 l, vec3 color) {
    return color * max(dot(n, l), 0.0);
}

void decompose(in vec4 c, out vec3 rgb, out float alpha) {   // out parameters
    rgb = c.rgb;
    alpha = c.a;
}

float sdCircle(vec2 p, float r);          // prototype (declaration before use)
float sdCircle(vec2 p, float r) { return length(p) - r; }

// Overloading by parameter types
float luminance(vec3 c) { return dot(c, vec3(0.2126, 0.7152, 0.0722)); }
float luminance(vec4 c) { return luminance(c.rgb); }