GLSL provides a small set of built-in functions, such as smoothstep, mix, and step, that shader code relies on constantly, yet their exact definitions are rarely written out in full. Deriving them explicitly makes it possible to reproduce, extend, or debug them outside a shader as well.
Definition of Smoothstep Function
By taking \(x^2\) a function is obtained that starts smoothly at \(0\) but ends rather abruptly at \(1\). Taking the same function, shifting it one unit to the right and flipping it around gives \(-(x-1)^2\). Adding \(1\) moves the parabola to \(1\) and yields a function with a smooth ending.
Interpolating both functions
\[\begin{array}{rl} f(x) &= x^2\\ g(x) &= 1-(x-1)^2 \end{array} \]
produces a smooth function
\[\sigma(x) = f(x) \cdot (1-x) + g(x) \cdot x = x^2(3-2x)\]
Since the function should operate on \([0,1]\), the input value \(x\) is clamped:
\[x'=\max(0, \min(1, x))\]
Because the smoothstep function in GLSL has two ramp parameters \(a\) and \(b\), the curve is first shifted by \(a\):
\[x'=\max(0, \min(1, x - a))\]
The second ramp parameter \(b\) depends on the slope of the ramp, so
\[x'=\max\left(0, \min\left(1, \frac{x - a}{b-a} \right)\right)\]
which finally leads to the smooth step function:
\[\sigma(x; a, b):= \sigma\left(\max\left(0, \min\left(1, \frac{x - a}{b-a} \right)\right)\right)\]
If \(b < a\), the function flips over, which matches the behavior of the GLSL implementation.
Dragging the sliders moves the ramp parameters \(a\) and \(b\); moving \(b\) past \(a\) flips the curve, exactly as derived above.
Definition of Mix Function
The mix function performs linear interpolation between \(\mathbf{a}\) and \(\mathbf{b}\) by a factor \(p\):
\[\text{mix}(\mathbf{a}, \mathbf{b}, p) := \mathbf{a} + p \cdot (\mathbf{b} - \mathbf{a})\]
Definition of Step Function
The step function is a hard threshold:
\[\text{step}(\mathbf{a}, \mathbf{b}) := \mathbf{a}\leq\mathbf{b}\text{ ? }\mathbf{1} : \mathbf{0}\]
Smooth Staircase
Let \(\sigma : [0, 1]\to[0,1]\) be a step function with \(\sigma(x)=0\) for all \(x<\epsilon\) and \(\sigma(x)=1\) for all \(x>1-\epsilon\). A smooth staircase with step size \(1\) is then
\[\Gamma(x) = \sigma(x - \left\lfloor x\right\rfloor) + \left\lfloor x\right\rfloor\]
Given a required step width and height, \(\Gamma\) rescales to
\[\Gamma(x ; w, h) = h\cdot \Gamma\left(\frac{x}{w}\right) = h\cdot \left[\sigma\left(\frac{x}{w} - \left\lfloor \frac{x}{w}\right\rfloor\right) + \left\lfloor \frac{x}{w}\right\rfloor\right]\]
Alternative Absolute Function
Since the absolute value function \(f(x) = |x|\) has no derivative at \(x=0\), it can instead be defined as \(f(x) = \sqrt{x^2}\), and a shifting parameter \(\epsilon\geq0\) smooths the corner:
\[f(x) = \sqrt{x^2+\epsilon}-\epsilon\]
Derivation of Logical Float Functions
Boolean logic on the values \(0\) and \(1\) can be reproduced with ordinary float arithmetic, which is useful whenever a shader needs to avoid branching:
\[\begin{array}{rl} \text{not}(x) &:= 1 - x\\ \text{and} (x, y) &:= x y\\ \text{or} (x, y) &:= \text{not}(\text{and}(\text{not}(x), \text{not}(y))) = x + y - x y\\ \text{xor} (x, y) &:= \text{or}(\text{and}(x, \text{not}(y)), \text{and}(y, \text{not}(x))) = x + y - 2 x y\\ \text{implies}(x, y) &:= \text{or}(\text{not}(x), y) = 1 - x + x y\\ x\text{ ? } y : z &:= x y + (1 - x) z = z + x(y - z)\\ \end{array} \]
References
- KhronosGLSLThe Khronos Group, The OpenGL Shading Language (GLSL) Specification.