💡 Reference · WebGL / GLSL
📅 March 2026 ⏱ Quick reference 🎯 GLSL ES 3.0 (WebGL 2)

GLSL Built-in Functions Quick Reference

All GLSL ES 3.0 built-in functions grouped by category — math, geometry, texture, derivatives, matrix, and type constructors — with signatures, behaviour notes, and WebGL-specific gotchas. Bookmark this when writing shaders.

1. Type Notation and genType

GLSL built-in signatures use generic type names. A function listed as taking genType actually has overloads for all of the following:

Alias Expands to
genType float, vec2, vec3, vec4
genIType int, ivec2, ivec3, ivec4
genUType uint, uvec2, uvec3, uvec4
genBType bool, bvec2, bvec3, bvec4
mat mat2, mat3, mat4, mat2x3, mat2x4…
gsampler2D sampler2D, isampler2D, usampler2D

When a function takes genType x, genType y, both arguments must have the same type and dimension — you cannot mix vec3 and float without an explicit cast.

GLSL ES 3.0 vs 1.0: WebGL 1 uses GLSL ES 1.00 (no integers, no textureSize, no dFdx in some implementations). WebGL 2 uses GLSL ES 3.00 — requires #version 300 es at the top of the shader. All functions in this reference are GLSL ES 3.0 unless marked 1.0.

2. Angle and Trigonometry Functions

All trig functions operate on radians. Input/output are genType.

Function Description Notes
radians(d) degrees → radians = d · π/180
degrees(r) radians → degrees = r · 180/π
sin(x) Sine Range [−1, 1]
cos(x) Cosine Range [−1, 1]
tan(x) Tangent Undefined at π/2 + kπ
asin(x) Arc sine UB if |x| > 1; returns [−π/2, π/2]
acos(x) Arc cosine UB if |x| > 1; returns [0, π]
atan(y, x) atan2 — full-range arc tangent Returns [−π, π]; preferred over atan(y/x)
atan(y_over_x) Single-arg arc tangent Returns [−π/2, π/2]; use two-arg form at ±π boundary
sinh(x) Hyperbolic sine (eˣ − e⁻ˣ)/2
cosh(x) Hyperbolic cosine (eˣ + e⁻ˣ)/2; always ≥ 1
tanh(x) Hyperbolic tangent Range (−1, 1)
asinh(x) Inverse hyperbolic sine Defined for all x
acosh(x) Inverse hyperbolic cosine UB if x < 1
atanh(x) Inverse hyperbolic tangent UB if |x| ≥ 1
sin/cos wrap trick: If you accumulate a time variable and pass it to sin/cos, once the float exceeds ~10⁵ the period will drift on mediump. Use: float t = mod(uTime, 6.2831853); to keep precision.

3. Exponential and Logarithm Functions

Function Description Notes
pow(x, y) x^y UB if x < 0; if x=0 and y≤0, UB. Prefer exp(y*log(x)) if y is dynamic.
exp(x) Overflows to +∞ for large x; use exp2 for base-2
log(x) ln(x) UB if x ≤ 0
exp2(x) Hardware-accelerated on most GPUs
log2(x) log₂(x) UB if x ≤ 0. Faster than log on many GPUs.
sqrt(x) √x UB if x < 0. For vectors, component-wise.
inversesqrt(x) 1/√x UB if x ≤ 0. Use this instead of 1.0/sqrt(x) — one GPU instruction.

4. Common Math Functions

Function Description Notes
abs(x) |x| component-wise Works for int, uint, float vectors
sign(x) −1, 0, or +1 per component sign(0.0) = 0.0
floor(x) Largest integer ≤ x (as float) floor(−0.5) = −1.0
ceil(x) Smallest integer ≥ x ceil(−0.5) = 0.0
trunc(x) Round toward zero ES 3.0 only. trunc(−0.9) = 0.0
round(x) Round to nearest; ties → even ES 3.0 only. "Banker's rounding"
roundEven(x) Round half to even (IEEE) ES 3.0 only
fract(x) x − floor(x) Always in [0, 1). fract(−0.3) = 0.7
mod(x, y) x − y·floor(x/y) Result sign matches y (not x). For negative x: mod(−1.0, 4.0) = 3.0
modf(x, out i) Returns fract(x); i = trunc(x) i is an out parameter
min(x, y) Component-wise minimum y can be scalar (broadcast)
max(x, y) Component-wise maximum y can be scalar
clamp(x, lo, hi) max(lo, min(hi, x)) UB if lo > hi
mix(x, y, a) Lerp: x·(1−a) + y·a a can be bool vector: mix(x,y,bvec) selects components
step(edge, x) 0 if x < edge; 1 otherwise edge can be scalar or same type as x
smoothstep(e0,e1,x) Hermite interpolation 0→1 UB if e0 ≥ e1. = t²(3−2t) where t=clamp((x−e0)/(e1−e0),0,1)
isnan(x) true if x is NaN ES 3.0 only. Returns bvec/bool
isinf(x) true if x is ±Infinity ES 3.0 only
floatBitsToInt(v) Re-interpret bits as int ES 3.0 only. No conversion — raw bit access
intBitsToFloat(v) Re-interpret int bits as float ES 3.0 only
packSnorm2x16(v) Pack vec2 to uint ES 3.0 only
unpackSnorm2x16(p) Unpack uint to vec2 ES 3.0 only
// Common snippet: smooth hash noise
float hash(vec2 p) {
  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
}

// Safe smoothstep guard
float ss = smoothstep(0.2, 0.8, uv.x); // always e0 < e1

// Select between two values with step (no branch):
vec3 col = mix(colorA, colorB, step(0.5, uv.x));

5. Geometric Functions

Function Signature Description
length(x) float length(genType x) Euclidean length √(x²+y²+…). For vec3: √(x²+y²+z²)
distance(p0,p1) float distance(genType p0, genType p1) = length(p0 − p1). Use for proximity tests.
dot(x, y) float dot(genType x, genType y) Dot product. > 0: same hemisphere. = 0: perpendicular. Negative: opposite side.
cross(x, y) vec3 cross(vec3 x, vec3 y) Cross product. Result ⊥ to both inputs. |cross| = |x|·|y|·sin(θ).
normalize(x) genType normalize(genType x) x / length(x). UB if length = 0. Result has length 1.0.
faceforward(N,I,Nref) genType faceforward(genType N, genType I, genType Nref) Returns N if dot(Nref,I) < 0, else −N. Use for two-sided normals.
reflect(I, N) genType reflect(genType I, genType N) I − 2·dot(N,I)·N. N must be normalized. I is incident direction (toward surface).
refract(I, N, eta) genType refract(genType I, genType N, float eta) Snell's law refraction. eta = n1/n2. Returns (0,0,0) on total internal reflection (check dot before using).
// Phong diffuse + specular in one pass
vec3 N = normalize(vNormal);
vec3 L = normalize(uLightPos - vWorldPos);
vec3 V = normalize(uCamPos - vWorldPos);
vec3 R = reflect(-L, N);

float diff = max(dot(N, L), 0.0);
float spec = pow(max(dot(R, V), 0.0), uShininess);
vec3 color = diff * uDiffuse + spec * uSpecular;

6. Matrix Functions

Function Signature Description
matrixCompMult(x, y) mat matrixCompMult(mat x, mat y) Component-wise matrix multiply. NOT the same as matrix product (use * for that).
outerProduct(c, r) mat outerProduct(genType c, genType r) Column vector × row vector → matrix. mat3 = outerProduct(vec3, vec3).
transpose(m) mat transpose(mat m) Rows become columns. For orthogonal matrix (pure rotation), transpose = inverse.
determinant(m) float determinant(mat m) ES 3.0 only. Non-zero = matrix is invertible.
inverse(m) mat inverse(mat m) ES 3.0 only. UB if determinant ≈ 0. For normal matrix: use transpose(inverse(modelMatrix)).
Matrix multiplication operator: mat4 * vec4 = matrix-vector product (column vector on right). vec4 * mat4 = row vector on left (transpose semantics). Use mat4 * vec4 in vertex shaders for MVP.

7. Texture Lookup Functions

GLSL ES 3.0 uses sampler types and texture() overloads. GLSL ES 1.0 (WebGL 1) used texture2D(), textureCube() etc.

Function Sampler Notes
texture(s, P) gsampler2D, gsampler3D, gsamplerCube, gsampler2DArray… Standard texture lookup at coordinates P. Mip level computed automatically (fragment shader only — needs derivatives).
textureLod(s, P, lod) All above Explicit mip level. Use in vertex shader or for manual LOD control.
textureOffset(s, P, offset) gsampler2D, etc. Constant integer texel offset for neighbour sampling (Sobel, blur, etc.).
texelFetch(s, P, lod) gsampler2D, etc. P is integer texel coordinates — no filtering, no wrapping, no mipmapping. For data textures.
textureSize(s, lod) gsampler2D, etc. ES 3.0 only. Returns ivec2 texture dimensions at specified mip level. Use for pixel-space calculations.
textureGrad(s, P, dPdx, dPdy) All above Explicit gradient for mip selection. Advanced usage: shadow maps, anisotropic filtering.
texture2D(s, P) sampler2D (ES 1.0) 1.0 Equivalent to texture() in ES 1.00 fragment shaders. Not available in ES 3.00.
// Data texture (ping-pong simulation state):
uniform sampler2D uState;
uniform vec2 uRes;

vec4 readCell(ivec2 coord) {
  coord = clamp(coord, ivec2(0), ivec2(uRes) - 1);
  return texelFetch(uState, coord, 0);  // exact integer texel, no filtering
}

// Neighbour sum (Conway / reaction-diffusion):
ivec2 px = ivec2(gl_FragCoord.xy);
vec4 c = readCell(px);
vec4 L = readCell(px + ivec2(-1, 0));
vec4 R = readCell(px + ivec2( 1, 0));
vec4 U = readCell(px + ivec2( 0, 1));
vec4 D = readCell(px + ivec2( 0,-1));

8. Fragment Derivative Functions

Fragment derivative functions are only available in the fragment shader. They compute the rate of change of a value across neighbouring fragment quads.

Function Description
dFdx(p) Partial derivative of p with respect to window x (screen-space column). frag only
dFdy(p) Partial derivative with respect to y (screen-space row). Sign convention: y+ is up in GLSL. frag only
fwidth(p) = abs(dFdx(p)) + abs(dFdy(p)). Approximates "one pixel footprint" at any position. frag only
dFdxFine(p) ES 3.2 only. Fine-grained 2×1 quad derivative (not widely supported in WebGL). frag only
dFdxCoarse(p) ES 3.2 only. 2×2 quad derivative (cheaper, less accurate). frag only

Anti-aliased Shapes with fwidth

// Anti-aliased circle (no MSAA needed):
float circle(vec2 uv, float r) {
  float d = length(uv) - r;
  float w = fwidth(d);          // 1 pixel in distance units
  return 1.0 - smoothstep(-w, w, d);
}

// Anti-aliased grid lines:
float grid(vec2 uv, float spacing) {
  vec2 g = abs(fract(uv / spacing - 0.5) - 0.5);
  vec2 w = fwidth(uv / spacing);
  vec2 line = smoothstep(vec2(0.0), w * 1.5, g);
  return 1.0 - min(line.x, line.y);
}
Precision qualifier reminder: In WebGL fragment shaders, the default float precision is not defined — you must declare it: precision highp float; at the top of every fragment shader. mediump has only ~13 bits of mantissa — equivalent to about 3 decimal digits. Use highp for positions, UVs, and any calculation where you need >3 significant digits.
Availability check: In WebGL 1 (GLSL ES 1.00), derivative functions require the OES_standard_derivatives extension: call gl.getExtension('OES_standard_derivatives') and add #extension GL_OES_standard_derivatives : enable at shader top. In WebGL 2 / GLSL ES 3.00 they are always available.