Interpolation

In which you learn how to send parameters to a shader that vary across a triangle.

With uniforms, the same value is used for every pixel in the object you draw. Suppose, however, you could give each vertex a different color. How would you expect the pixels between the vertices to be colored?

The GPU will take a vertex shader's output variables and smoothly blend them across the primitive. For example, if one vertex outputs a value of 5 and another vertex outputs a value of 0, then the pixel halfway between them will receive a value of 2.5. This blending is called interpolation.

To output a blended variable from a vertex shader, you declare a global out variable and assign it a value. In the fragment shader, you declare the same variable, but tag it with the in keyword.

A vertex's output variables often get their values from vertex attributes. Here a colors attribute is added to the set of attributes:

const positions = [
  -0.7, -0.5, 0,
   0.7, -0.5, 0,
   0.0,  0.5, 0,
];

const colors = [
  1, 0, 0,
  0, 1, 0,
  0, 0, 1,
];

attributes = new VertexAttributes();
attributes.addAttribute('position', 3, 3, positions);
attributes.addAttribute('color', 3, 3, colors);

The vertex shader receives the color just like it receives the position, as an in variable. This value is copied to an out variable named mixColor:

in vec3 position;
in vec3 color;

out vec3 mixColor;

void main() {
  gl_Position = vec4(position, 1.0);
  mixColor = color;
}

There's no standard naming convention for interpolated variables. The prefix mix is meant to remind you that the variable is blended.

In the fragment shader, mixColor becomes an in variable. The GPU will automatically assign the blended value before the fragment shader runs. You can use it like any other variable. Here it is used to assign the pixel color:

in vec3 mixColor;
out vec4 fragmentColor;

void main() {
  fragmentColor = vec4(mixColor, 1.0);
}

Try adding interpolated color to one of your applications.