Skip to content
Fundamental · ShapingBeginner

Shaping curves

Bend a 0–1 ramp with pow, exp and abs to control how a value rises and falls.

How it works

Many values in a shader are a ramp from 0 to 1: a UV coordinate, a remapped distance, an animation’s progress, a dot product clamped to positive. A straight ramp is rarely the look you want. A shaping curve is a function that takes a 0–1 input to a 0–1 output but changes what happens in between (most keep 0 at 0 and 1 at 1), so a gradient can hug one end, an edge can get sharper, or a pulse can rise fast and fade slowly.

To see a curve, plot it: light up the pixels whose height is close to the function of their x.

float y = pow(uv.x, 2.0);                                // the curve to inspect
float line = 1.0 - smoothstep(0.0, 0.01, abs(uv.y - y)); // 1 near the curve
vec3 color = mix(vec3(y), vec3(0.1, 0.9, 0.3), line);    // a green line over the ramp

Powers

pow(x, k) on 0–1 is the workhorse. With k above 1 the curve stays low and rises late (an ease-in); with k below 1 it rises early and flattens out (an ease-out). 1.0 - pow(1.0 - x, k) mirrors the curve, giving the ease-out that matches pow(x, k)’s ease-in. A Fresnel rim light raises 1.0 - dot(n, v) to a power for exactly this reason: a higher power pushes the glow into a thinner band at the silhouette.

pow is undefined for a negative base, and for a zero base with an exponent of zero or less. Clamp the base first, pow(max(x, 0.0), k), whenever it can dip below zero.

Exponentials

exp(-k * x) starts at 1 and decays toward 0 without ever reaching it: the shape of fog thickening with distance and of a glow fading away from a shape. A larger k decays faster. Multiplying a rising term by a falling one gives an impulse that shoots up and fades slowly; x * exp(1.0 - x) peaks at exactly 1 when x is 1.

Folding with abs

abs(x) folds negative values up, turning a -1..1 ramp into a V. 1.0 - abs(uv.x * 2.0 - 1.0) is a tent: 0 at both edges and 1 in the middle. For a rounded version, 4.0 * x * (1.0 - x) is a parabola that is 0 at both ends and 1 at x = 0.5, a cheap way to fade something in and back out over one 0–1 range.

smoothstep as a curve

smoothstep(0.0, 1.0, x) is itself a shaping curve: an S that eases in and out (see smoothstep). Feeding it its own output makes the S steeper.

The point is to combine them. Each curve costs a few instructions, and a chain of two or three, such as a remap, then a power, then a smoothstep, covers most of the shaping a shader needs before reaching for a lookup texture. Plot each link while you build the chain.

Further reading