Before continuing with this lesson, if you are joining this series for the first time, I highly recommend reading the complete overview of everything we have covered so far.
A Beginner's Journey Through GLSL So Far
@hey2d/a-beginners-journey-through-glsl-so-far-d2z
That article covers the foundations we have been building throughout this series, including:
mix() functionclamp() functionOnce you are comfortable with those ideas, this lesson will feel like a natural next step.
So far we have used either vUv.x or vUv.y to create gradients.
When we use:
float t = vUv.x;
the gradient moves from left to right.
When we use:
float t = vUv.y;
the gradient moves from bottom to top.
But what if we want both directions at the same time?
Instead of choosing one coordinate, we simply combine both.
float t = (vUv.x + vUv.y) * 0.5;
This single line creates a diagonal gradient.
Let's look at it piece by piece.
vUv.x + vUv.y
Both coordinates range from 0 to 1.
Adding them together gives values between 0 and 2.
| x | y | Result |
|---|---|---|
| 0 | 0 | 0 |
| 1 | 0 | 1 |
| 0 | 1 | 1 |
| 1 | 1 | 2 |
The problem is that our color interpolation usually expects numbers between 0 and 1.
So we divide by two.
(vUv.x + vUv.y) * 0.5
Now the values are safely back inside the range we expect.
Thinking about the four corners makes the formula much easier to understand.
| Position | vUv.x | vUv.y | t |
|---|---|---|---|
| Bottom left | 0 | 0 | 0 |
| Top right | 1 | 1 | 1 |
| Top left | 0 | 1 | 0.5 |
| Bottom right | 1 | 0 | 0.5 |
Notice something interesting.
The bottom left corner is completely dark.
The top right corner becomes completely bright.
The other two corners sit exactly halfway between them.
Because of this, our eyes perceive a smooth diagonal transition across the screen.
The exercise originally looks like this.
float t = 0.0;
Since t never changes, every pixel receives exactly the same value.
The entire screen stays black.
Your task is simply to replace it with
float t = (vUv.x + vUv.y) * 0.5;
Nothing else needs to change.
Immediately the screen transforms from a flat color into a diagonal gradient.
This is another great reminder that even a single number can completely change the appearance of a shader.
Many beginners ask why we multiply instead of simply writing
float t = vUv.x + vUv.y;
The answer is range.
vUv.x goes from 0 to 1.
vUv.y goes from 0 to 1.
Together they produce values from 0 to 2.
Most interpolation functions such as mix() are designed to work with values between 0 and 1.
Multiplying by 0.5 scales the range back down.
You can also think of it as taking the average of the two coordinates.
Although it looks diagonal, mathematically it is not measuring distance from one corner.
The top left and bottom right corners both have the same value.
That means they receive exactly the same brightness.
Even so, our eyes naturally interpret the result as a diagonal gradient because the brightness increases smoothly from one corner to the opposite corner.
Later in this series we will learn other techniques that create different diagonal and radial patterns.
Now experiment with another formula.
float t = vUv.x * vUv.y;
Instead of adding the coordinates, this multiplies them together.
The result feels completely different.
Most of the image stays darker, and the brightness only starts increasing as both coordinates become larger.
This is a great exercise because it teaches an important lesson.
Addition and multiplication are not just mathematical operations.
Inside shaders they become artistic tools that create entirely different visual patterns.
#ifdef GL_ES
precision mediump float;
#endif
varying vec2 vUv;
void main()
{
float t = (vUv.x + vUv.y) * 0.5;
vec3 color = vec3(t);
gl_FragColor = vec4(color, 1.0);
}
This shader creates a grayscale diagonal gradient where the bottom left corner starts black and the top right corner becomes white.