Hey! They’re not all too advanced, but I still thought I’d share a little something on the custom shaders that were written for our LD37 entry, LOCK AND RELOAD. c:
Since the posts easily get a bit lengthy, I’ll divide this into a series of more bite-sized posts so that I don’t have to sacrifice all too much clarity for the sake of space. We’ll start with the main shader that gives the game its look and feel!
Some of the effects are connected to slightly fundamental parts of the story, and since the game ended up being really short due to time constraints, I recommend you play the game first to avoid the spoilers and get the most out of the game with it’s little twists! So I’ll be adding a “read more” tag at to some parts to hide some of the stuff from the front page of the blog.
Note: the game was made in Unity and the shaders were written accordingly and so any code will be given as boiled down versions of the shader code written for that, but obviously everything is readily convertible to something like GLSL with minor to no changes.
Post effect filter
This one won’t spoil a thing as it is the very first thing to see upon starting the game: the wonky colour effects and checkerboard overlay. There’s also a dark vignette as well as some increased contrast.
This effect applies to the whole final rendered image rather than individual objects and is therefore done in one step at the end of each frame, simply applying the shader to each pixel, or fragment.
Let’s go! ᕕ( ᐛ )ᕗ
The low-fi colour effect
This is achieved by first multiplying the colour values (which are all normalised between 0.0 and 1.0) by some factor, then rounding the numbers so that any resulting decimals disappear, and then dividing the values back down again by the original factor. This effectively decreases the colour variation. The smaller the factor, the greater the effect.
col.rgb *= factor; col.rgb = round(col.rgb); col.rgb /= factor;
The contrast effect is fundamentally not so complicated. It can be done in different ways, but for this particular game what I found worked best was to subtract some of the intensity of the colour if the original colour was below some tolerance value, but multiply it by some factor if it were above it.
col.rgb += (col.rgb < tolerance) ? 0.5 : 1.5;
Alternating dark and bright squares are all over the screen. This isn’t some texture; just a little bit of maths. By checking the position of each pixel on the screen and figuring out whether it’s even using the modulo operator (which gives the remainder of a division), we can figure out whether the number is evenly divisible by two and thereby whether it’s odd or even.
If we multiply the coördinates by some factor to pretend that the screen is smaller or bigger than it really is, we can control how big the squares get. We apply the effect by darkening odd squares and leaving even ones untouched or vice versa.
col.rgb -= ((floor(x * s) % 2.0) - (floor(y * s) % 2.0)) * darkness;
In this case, a vignette is a darkening of the corners of the screen. We’re basically applying darkness to the whole screen except an oval in the middle, leaving the corners dark but the middle unaffected. Circles are easy. We can achieve an oval by pretending that our rectangular canvas is in fact square.
fixed ratio = height / width; fixed2 middle = fixed2(0.5 * ratio, 0.5);
We can then check the distance from the center to the current fragment, adjusted for the rectangle’s ratio, to get its position inside a circle, which will appear as an oval thanks to the ratio.
fixed2 pos = fixed2(x * ratio, y); fixed factor = length(pos - middle); col.rgb -= factor * darkness;
You will probably want to adjust some values by multiplying them by various factors to make your vignette look the way you want.
That’s it for this part! In the next one (and I won’t be posting it right away as I don’t want to be spammy), we’ll be talking about the first of the two effects in the game that required extra cameras and render textures!
Stay tooned! ☆