Imagine moving an indicator from one button to another. We know where it starts and where it ends. What should its position be one quarter of the way through the move?
We can answer with the displacement from chapter 02. First find the change needed to reach the target. Then take only part of that change.
Take part of a displacement
Use two points in our equal-unit coordinate space. Both components have the same scale; positive Y points up.
vec2 a = vec2(-0.6, -0.3);
vec2 b = vec2( 0.6, 0.5);
vec2 displacement = b - a; // (1.2, 0.8)
The displacement says “move 1.2 right and 0.8 up.” A quarter of it is (0.3, 0.2). Add that smaller displacement to A:
float t = 0.25;
vec2 position = a + (b - a) * t;
// (-0.6, -0.3) + (0.3, 0.2) = (-0.3, -0.1)
t is a dimensionless fraction, not a distance. With t = 0, we add no displacement. With t = 1, we add the whole displacement and reach B. Halfway means t = 0.5, regardless of how far apart A and B are.
The same scalar multiplies both components. We take the same fraction of the horizontal and vertical change. This is what keeps the point on the straight line through A and B.
Do we need normalize(b - a) from the previous chapter? No. That would discard the distance between the endpoints. At t = 1, adding a unit direction would move only one unit from A. Here we need the original displacement to reach B exactly.
Write it with two weights
Expand the same expression and group the contributions from the endpoints:
a + (b - a) * t
= a + b * t - a * t
= a * (1.0 - t) + b * t
The two weights are 1 - t and t. They always add to one. At a quarter of the journey, the result is 0.75 * a + 0.25 * b. At the midpoint, both weights are 0.5.
We are taking a weighted combination of point coordinates in the same space. This differs from simply adding two positions: the weights preserve the common coordinate origin. Shifting both endpoints by the same amount shifts the result by that amount too.
GLSL gives this operation a name you may remember from the first book:
vec2 position = mix(a, b, t);
For these floating-point inputs, mix evaluates the weighted blend. Finding a value between two endpoints this way is linear interpolation. The two formulas are mathematically equivalent. Different evaluation orders can introduce tiny floating-point differences, so compare their results with a small tolerance rather than requiring every last bit to match.
Go beyond the endpoints
Nothing in the formula stops at B. At t = 1.5, we take one and a half displacements:
vec2 position = a + vec2(1.2, 0.8) * 1.5;
// (-0.6, -0.3) + (1.8, 1.2) = (1.2, 0.9)
Estimating a value beyond the endpoint interval is extrapolation. A negative t goes behind A; for example, t = -0.5 gives (-1.2, -0.7). In the weighted form, one weight is now negative.
mix does not clamp its parameter. If an indicator must stay inside its segment, make that rule explicit:
vec2 position = mix(a, b, clamp(t, 0.0, 1.0));
Our playground leaves t unclamped within its control range, -0.5 to 1.5, so you can see both behaviors. If A and B coincide, their displacement is zero and the result stays at A for every value of t. No normalization or division is involved.