Basics, part 2

Sine and cosine go round in circles

Two small functions turn an angle into a point on a circle and a circle into a wave. Shaders use them for waves, pulses, ripples and turning things.

  • Part 25 min dose
  • Beginner

Sine and cosine sound like school math, and I won’t pretend they aren’t. But they’re also behind almost everything in a shader that pulses, wobbles, ripples or turns. And here’s the nice part. One picture explains both of them, a point going round a circle. Let’s start there, then turn the circle into a wave and set it moving.

How far round, in radians

First, a way to say how far round. You probably know degrees, with 360 for a full turn. Shaders use radians instead. A full turn is 2π2\pi, about 6.28. Half a turn is π\pi (3.14) and a quarter turn is π/2\pi/2 (1.57).

Why such an odd number? A circle with radius 1 is exactly 2π2\pi long all the way round. So an angle in radians is how far you walk along the edge of that circle. The demos on this site call a full turn TAU, a handy name for 2π2\pi. Unity’s own helper file calls it UNITY_TWO_PI.

Watch out for one small trap. sin(90) is not the sine of 90 degrees but of 90 radians, more than 14 whole turns. For degrees, write sin(radians(90)). Or do what I do and think in turns, where a quarter turn is TAU * 0.25.

A point going round

Take a circle with radius 1 around (0,0)(0, 0), the middle from the coordinates lesson. Math books call it the unit circle. Start on the right, turn anticlockwise by an angle aa, and you land on the point

(cos⁡a, sin⁡a)(\cos a,\ \sin a)

And that’s all cosine and sine are. cos⁡a\cos a is how far across the point is, and sin⁡a\sin a is how far up. Both stay between −1-1 and 11, because the point never leaves the circle. On the left half, the cosine is negative. Below the middle, the sine is.

Cosine across, sine up
Drag the point on the circle, or press Tab to reach it and use the arrow keys

Turn on JavaScript to run this demo.

circle.hlsl draws the demo above
Fig. 1

Drag the point round the circle. The mint line is cos⁡a\cos a, the pink line is sin⁡a\sin a and the butter arc is the angle aa. On the right, the pink dot sits at the same height as the point, and the brighter part of the wave is the way you’ve come.

Follow the pink height round. It climbs to 1 at the top, drops to −1-1 at the bottom and comes home again. The curve on the right is that height for every angle, laid side by side. That’s a sine wave. Cosine makes the very same wave, a quarter turn earlier.

From a circle to a wave

That curve is the hardest working shape in shaders. A sine doesn’t care where its number comes from, so feed it a position xx across the picture instead of an angle. Three numbers tune the wave:

y=Asin⁡(f x+p)y = A \sin(f\,x + p)
  • AA is the amplitude, how tall the wave is. It swings from −A-A to AA.
  • ff, the frequency, is how many waves fit in every 2π2\pi of xx. Double it and the waves squeeze together.
  • pp is the phase, and it slides the wave sideways. A phase of 2π2\pi brings it right back where it started.

In code the order doesn’t matter, so sin(x * f + p) * A is the same wave.

Three sliders, one wave

Turn on JavaScript to run this demo.

How tall the wave is. It swings from -A to A.1.00
How many waves fit across this plot.2.00
Slides the wave sideways. At 6.28 it is back where it started.0.00
Code for the plot above
  • f1(x):_A * sin(_F * x + _P)
  • f2(x):sin(x)
Fig. 2

The plot runs from 0 to 2π2\pi, so Frequency f is also how many waves you see. Lower Amplitude A to flatten the mint wave, then drag Phase p and watch it slide left. The dashed pink line is plain sin⁡x\sin x.

Making it move

Now the fun part. Unity hands every shader a clock, _Time.y, that counts the seconds since the scene loaded. Put it in the phase and the wave slides along on its own:

y=Asin⁡(f x+t)y = A \sin(f\,x + t)

Here tt is the time in seconds. A plus slides the wave to the left, a minus to the right, and multiplying tt by a number changes the speed.

For a ripple, let’s swap xx for rr, the pixel’s distance from the middle:

h=Asin⁡(f r−s t)h = A \sin(f\,r - s\,t)

hh is the height of the water and ss sets the speed. The minus pulls every crest outwards, so the rings travel away from the middle. The bright glints are where the water tilts towards a light at the top left.

Ripples on a dark pond

Turn on JavaScript to run this demo.

How tall the ripples are. At 0 the pond is flat.0.80
How tightly the rings are packed.24.0
How fast the rings travel outwards. At 0 they stand still.1.50
ripple.hlsl draws the demo above
Fig. 3

Set Speed s to 0 and the rings stop. The clock still ticks, but nothing in the wave reads it any more. Then raise Frequency f for tight little ripples.

In practice

Once you know the shape, you’ll spot it all over shaders:

  • Waves and wobbles come from the sine of a position plus time. Move a mesh’s points with it and a tail sways.
  • Pulses use the sine of time alone, for a glow that breathes in and out.
  • Rings take the sine of a distance, like the pond.
  • Turning is cosine and sine working together to swing a point around the middle.

The sine dips below 0, and a glow can’t get darker than off. So for a pulse, I lift it into the range 0 to 1:

float pulse = 0.5 + 0.5 * sin(_Time.y * 3.0);

The 3 makes it go round three times faster, so it breathes about every two seconds.

For turning, the demos use the little helper below. It writes a turn as a matrix, a small grid of four numbers. mul(rot2(a), p) turns p anticlockwise by the angle a. Feed it the point (1,0)(1, 0) and out comes (cos⁡a,sin⁡a)(\cos a, \sin a), the point from the circle demo.

float2x2 rot2(float a)
{
    float c = cos(a), s = sin(a);
    return float2x2(c, -s, s, c);
}

Polar coordinates does much more with angles and draws rings, rays and spirals. And the next lesson is about the points and arrows all this turning moves.

Takeaways

  • Shaders measure angles in radians. A full turn is 2π2\pi, which the demos call TAU.
  • (cos⁡a,sin⁡a)(\cos a, \sin a) is a point on a circle of radius 1, with cosine how far across and sine how far up.
  • Asin⁡(f x+p)A \sin(f\,x + p) shapes a wave, and _Time.y in the phase sets it moving.
Search the lessons

Type any word from the lessons, like normalize or smoothstep. The start of a word is enough.