Pixel graphics post-effect shader

Johan Svensson
dotcrossdot
Published in
4 min readSep 9, 2018
Final result

The image above is actually from a game that I’m working on on my spare time, and I thought I could share how I’m converting 3D models into something that looks like 2D sprite animations. This is very much work in progress, and I’m experimenting with different setups for the rendering pipeline. I’ll try to explain some of the challenges I’ve run into and how I’ve solved some of them. Once I feel like the source code is in a good place I’ll share that as well. Right now its in a too much of an experimental state though.

3D character

First of all, the reason why I wanted to do this was to be able to make a pixel graphics character with exchangeable parts (gear, weapons etc). I obviously couldn’t do this with normal sprites, but I also couldn’t do it with a 2D rig. The reason for that it that the pixels on the sprites would rotate with the animations, thereby losing the whole “SNES-feel” to the graphics. It also incredibly hard to make complex and good looking animations with a 2D rig. You have to make them very simple or they will not look good, and I want complex and cool animations.

Before
After

There are two cameras in the scene, one that is looking at the 3D character (character camera), and one that is looking at the rest of the scene (scene camera). The character camera is only rendering the 3D character, and passes the image to a render texture. The scene camera does not render the actual 3D character. Instead it renders a quad with a texture (the render texture from the character camera).

Pixel graphics effect

The pixelation effect is currently achieved by lowering the resolution of the character cameras render texture. This technique has both pros and cons. The pros is that the post effect shader can be pretty straight forward (the outline can be calculated pretty easily). The drawback of this technique is that the final pixels are very much affected by the resolution and aspect ratio of the screen. At the moment I got a setup that looks good in 16:9 in 1920x1080. Its not easy at all to make this look good in a general resoltion / aspect ratio. E.g. if you set the resolution to 1024x768 you’ll end up with pixels that have different sizes. The image below shows this artifact at the outline of the helmet and shield.

Artifacts appearing when using different screen resolutions.

I’m currently working on solving this by down sampling the texture in the post effect shader, rather than lowering the render texture resolution. I hope this will make for a better general solution. I’ll update this post once if I get this working.

Outline

The outline of the character is created in the post effect shader. It achieved by letting the character camera also output a depth texture, which we can sample from. For every pixel I look at the surrounding ones and calculate the biggest depth delta to any of those pixels. If the depth delta for the given pixel is bigger than a certain value it gets the outline color, otherwise the texture color.

I’m also using something I call a soft outline. When a pixels neighbor depth delta is above in a “soft threshold”-interval it will be end up being colored somewhere in between the outline color and the texture color. This results in e.g. creases in the armor being colored more like the outline, giving sort of a shadow effect that blends very well with the hard outline at the edges of the character (see image below).

Hard/soft outline.

Animations

One of the cool effects of using this technique is that you can animate the character with a normal rig, and have the final result show as pixel graphics. The animations can be as complex as you like. You can even use motion capture animations if you like. The fight animations in the gif below are actually animated with a “mocap” reference. This is also a really fast way to work, compared to having to draw each frame of the animation.

I chose to use step-interpolation between the keyframes to make them look more like sprite animations, which I think contributes to the overall “SNES-feel” of the game. Having smooth interpolation kind of breaks that illusion in my case, but its definitely something that I want to experiment with later on.

Final result

As mentioned above, this is still work in progress. I’ll update this post and share the source code when its a bit more stable.

Thanks for reading!

--

--