I wanted to do something nice in Incredipede for transitioning between screens. Instead of just flipping boringly from the title screen to the game map, for example, I wanted it to look like the ink was being pulled off the paper and then reprinted with a map. Like you could see the press pushing the ink into the paper.
You can see what I came up with by watching the begining of the video in my “How do You Play Incredipede” post.
I asked my friend at Gaijin Games, Andrew Hynek, who wrote an amazing looking ink game called Drift Sumi-e for some suggestions. I ended up mangling his ideas into something more me. That is, something simpler and easier to implement.
Incredipede is written in Flash using Stage3d. I use the Starling 2d API because it makes my code simpler and faster. One of the things I love about Stage3d is that I get to write shaders! In assembly! I find this really fun and I wrote a few posts on pixel shaders here.
This fade effect is all with the shaders. The basic idea is simple: I just take the brightest pixels and don’t draw them, then I take the next brightest pixels and stop drawing them until I’ve stopped drawing even the darkest pixels. The problem with doing that is it ends up looking kind of shitty. Here is how it looks if I just take out half of the brightest pixels:
Kind of awful. If you click to enlarge it you can see how individual pixels end up being pulled out of solid spots of colour. The fade ends up looking super pixely, like something from the 80s. Another problem is that all the black pixels just disappear all at once at the very end of the fade.
This is pretty bad but it was a good enough idea to start with. Sarah and I happened to be in Nice with our friend Marc ten Bosch while I was working on this and while we were all walking along an old aqueduct we discussed how to make it better. We thought about using noise to make the effect more organic but eventually came up with the genius idea to use a blurred mask.
The shader code to do the bad, pixely effect is something like:
//get the pixel
tex ft0, v0, fs1 <2d,repeat,linear,nomip>
//save a copy of the pixel in ft3
mov ft3, ft0
//brightness of a pixel ~= (R+R+B+G+G+G)/6
mov ft1 ft0.x
add ft1 ft1 ft0.x
add ft1 ft1 ft0.y
add ft1 ft1 ft0.y
add ft1 ft1 ft0.y
add ft1 ft1 ft0.z
div ft1 ft1 fc2
//ft1 now holds the pixel brightness
//if the brightness is less than our fade constant (which moves between 0 and 1)
//then make ft1 = 0, otherwise make it = 1
sge ft1, fc0, ft1
//multiply the saved pixel by ft1, which will zero it out if it isn’t
//darker than our fade constant
mul oc, ft3, ft1
Even if you don’t know agal assembly this shouldn’t be too hard to read. Most of the code is getting perceived brightness of the pixel with a formula from some friendly people over on Stack Overflow. All it does is take the brightness, check to see if it’s greater than our fade constant and doesn’t draw the pixel if it is.
Now, here is the clever trick that makes it look good. Instead of looking at the pixel in the image I look at the pixel of a blurred version of the image. I still draw the pixel of the normal unblurry image but I use a blurred image to decide whether to draw it or not.
Here’s what the image looks like not faded at all (wonder at the amazing art of Thomas Shahan!):
And here’s what the blurred image looks like:
Now, the player never sees this blurred image, only the graphics card does. We use the pixels from this blurred image to decide what pixels to draw from the unblurred image. Only one line of the shader code has to change. We used to do this:
//get the pixel
tex ft0, v0, fs1 <2d,repeat,linear,nomip>
//save a copy of the pixel in ft3
mov ft3, ft0
Now we do this:
//grab the pixel from the blurry image to check the brightness
tex ft0, v0, fs1 <2d,repeat,linear,nomip>
//grab the pixel from the unblurred image to actually draw
tex ft3, v0, fs0 <2d,repeat,linear,nomip>
We pass both images into the shader and use one as a mask to draw the other. This gives us beautiful unpixely fades that look like this:
So that’s how the Incredipede ink fade is done. I admit that there is a little hand-waving magic here. You have to know how to render-to-texture and write custom shaders in Starling. Which is not terribly easy. And you have to be able to blur your image on the fly. The blurring is actually way harder than the ink-fade transition. I based my blurring on the work of Lars Gerckens.
Mostly I hope this inspired you to try some cool shader tricks of your own! They are pretty fun and you can get some great effects.
This example is taken from my game Incredipede, if you don’t already know what Incredipede is you can head over to Incredipede.com to check it out.