Hello again, reader! I’m back to talk about shaders again. A number of weeks ago I had the pleasure of working with Jack McClenaghan to create a distortion shader and beat-mapper for an outrun themed project he and some others were working on – Synthracer Maxiumum.
The idea behind the game was that players would drive around a track whilst objects in the world around the them distorted to beat of the music. But this wasn’t any distortion, it had to be glitchy and retro, so as to fit with the game’s 80s outrun aesthetic. All this took some doing, but it turned out pretty damn well.
First, let’s look at the distortion shader itself. The shader is divided into two parts: the standard distortion, and the pulse.
The standard distortion takes the entire model and applies a complicated series of sine waves to each individual vertex, shifting its position accordingly. These sine values are inverted when applied to one side of the object however, so as not to have it look as though the object is being distorted in a particular direction.
That sine wave looks like this:
So long as the standard distortion effect is running, it loops through the x = 0.8 to x = 0.9 section of the sine waves. This is because otherwise the distortion will regularly die down and almost completely flatten out. Additionally, the sine wave ripples down the object, so that the distortion appears shaky, and so that each point doesn’t just alternate between ‘in’ and ‘out’ positions.
Now because this is a particularly complex sine wave that I use, it means that the distortion effect simply does not work on simpler objects with lower numbers of vertices, as there just isn’t enough to distort. At least not in any way that doesn’t just look terrible.
The second part of this shader is the pulse. The pulse is designed to create a small, but more intense area of distortion that shifts down the length of the object. So whilst the standard distortion affects the whole object, only a small section is affected by this, which is what makes is appear as though it ‘pulses’.
There is one particular issue with this part of the shader, as for some reason it does not like distorting any vertices with a y value below 0 (in terms of local space). I’ve tried countless workarounds, but nothing quite seems to work. However, if the model has no vertices below 0 when created, then everything works just fine.
Together, the two parts of the shader create an effect that is an excellent fit for use with music.
Lastly, I also created a beat-mapper to read the music that was currently playing, and respond to its beats, at which point the distortion effects would kick in. Now this is not quite as complex as it sounds, as Unity kindly provides the audioSource.GetSpectrumData() function. Since this gave me all the information to begin with, all I had to do was analyse it.
I kept the number of channels that the spectrum was divided into relatively small at 64. This way, most of the bass sounds I wanted to respond to in each song would fall into the same channel, since they were all relatively similar. A little bit of trial and error gave me the correct channel to be checking, at which point it was simply a matter of checking when it went over the given threshold to send out an OnBeat() command.
However, since one song had a lot more bass synth than others, I did have to up the threshold there to prevent the beats from just going wild. For this, I simply checked the average value of the bass over the past 8 beats, and assigned the threshold accordingly. This was necessary since all three tracks were in one audio file, leaving me no easy way around it.
When everything came together, I must say the game did look truly fantastic. Admittedly, most of the work was not mine, but I’m glad to have been able to help. I’m a big fan outrun aesthetics, and this game really did hit that nail on the head.