Sergio Flores

April 03, 2017

Pixel Perfect rendering in Unity




It's common to find developers frustrated with pixel art in Unity, at first, it seems so difficult to get the sprites to render as pixel perfect, right?
So I decided to write a short guide, with all things that you need to setup in order to get this working without using any third-party assets!

First, let's make sure all our sprites in Unity have the proper settings:



 

What matters here is the following:


  • Texture type - Must be "Sprite (2D And UI)"

  • Pixels per Unit - Must be 100, which is the default, especially if you don't have a clue what happens if you change this!

  • Generate Mip Maps - Must be unchecked, as Mipmaps make no sense for pixel art

  • Filter Mode - Must be "Point (no filter)",  otherwise sprites will get blurry


Now, attach the following script to your camera (in a new file, called CameraFix.cs)
using UnityEngine;

[ExecuteInEditMode]
public class CameraFix : MonoBehaviour {

    [Range(1, 4)]
    public int pixelScale = 1;

    private int pixelsPerUnit = 100;
    private float halfScreen = 0.5f;

    private Camera _camera;

    void Update()
    {
        // getting the camera
        // note: this could be done in Start()
        // however when running in Editor Mode you might get a null Camera here, this is mostly for helping newbies
        if (_camera == null) {
            _camera = GetComponent<Camera>();
            _camera.orthographic = true;
        }
        _camera.orthographicSize = Screen.height * ((halfScreen / pixelsPerUnit) / pixelScale);
    }
}

And that's it!

If you need to change the pixels per unit for some reason (I dont recommend it), just change that constant in the code.

PS: As a bonus I added that pixelScale slider, that you can change in the inspector. It's basically just a zoom in the pixel art, you can keep it a 1x for making sure you art appears in the original size.

Still not working?


Check if you did any of the following mistakes:

  • Unity does have a game view zoom slider that is terrible and useless for pixel art. Worse, for some weird reasons it keeps changing to values different from 1.
    Keep it at 1x, other values will make your art appear blurry in the editor!

  • Keep all transform scales at 1, or at least use integer numbers (eg: 2 or 4, and never 1.5 or 3.3 for example!)
    If you don't understand why, well, the scale in this case will say how many pixels in the screen a pixel from your sprite will occupy. So if you don't use an integer number, the pixels can't be properly display in a equal division.

  • If moving sprites are not pixel perfect (or well, even static sprites....). Make sure their transforms position only have integer numbers too. That means, you can't put a sprite at position (0.5f, 0, 0).
    Wait, so that means your sprites movement will lose all fluidity and everything will move like crap?
    Yes, unless you keep using decimal numbers for position,  but truncate them via shaders. Thankfully, Unity sprite shaders come with a "Pixel snap" checkbox, you can use that.


Pixel perfect rotations


You could just not use rotations (most old 2d games actually avoid those, as many consoles either not supported rotating sprites or it looked bad), but if you really need them...

First, rotations will always look terrible, especially you are drawing your pixel art at scale other than 1x. At that point, once you add rotations you'll start getting pixels of different sizes appearing on the screen, which is very bad.
There is a way get pixel perfect rotations though, in the sense that pixels will keep the same size even with rotations, but it requires a more complex setup:

  • First, you need to attach a Render texture to your main camera. Now everything in the scene will be rendered to this texture.

  • All pixel art must now be drawn at the original size, if you are using my CameraFix script, make sure the pixelScale is at 1X, very important!

  • Now, create a second camera, and put an UI image on a separate layer for that new camera. The size of the image should match the texture size, or be an integer multiple (eg:2, 3, 4)


By doing this setup, the scene is first rendered to a texture at 1 to 1 scale, which guarantees that any rotation is done without breaking the pixel grid (which looks horrible but I've seen tons of indie games doing it...).
After that, we have the whole scene stored in a texture, we can do whatever we want it, and the obvious thing is to output it to the screen, using an UI image.
By the way, if you are fan of screen shake, with this setup you can just offset the UI image a few pixels randomly and you get instant screen shake, without touching the camera at all.

In fact, the best way to make sure rotations look good with pixel art is to generate them by hand, instead of relying in a engine to rotate stuff for you.
You can either do it by hand, to have full control, or use some algorithms like RotSprite, which as far as I know it is too slow to be pratical to implement as runtime effect (eg: as a shader)

Pixel perfect fonts


Ahaha, it's simple, don't use Unity builtin text.
Well, you can disable smoothing in the font import, make sure you are using a bitmap TTF font, plus make sure you are using a font size that matches the bitmap designed font height.
If you are lucky, then that might be enough.

Using a mono-spaced font is also a good bet, most old-school console games did have monospaced fonts, usually not by choice but because the text was usually displayed as tiles instead of sprites, leading to fixed width / spacing.

The best thing here is to make a custom pixel-art font, and render text as sprites. There are free tools like bmfont that can generate a font atlas for you in PNG format, along with a XML file containing the characters position in the atlas. It's perfectly doable if you have any kind of programming experience.
Another free alternative is this site that lets you design a custom font pixel by pixel.

Also, please, never mix pixel art with a pixel size with fonts with a completly different random pixel size, it looks so terrible and yet, I find tons of indie guys doing it!

Pixel perfect GUI


A game with the GUI using a different pixel scale/proportion compared to the rest of the game is not acceptable!

All in all, there's not much to say about this topic, this ties in with having pixel perfect fonts / text.
Careful when using a Canvas Scaler, you need to be sure that the GUI/Canvas has the same resolution as the rest of the game!
Also it is a good idea to use a Render Texture like suggested previously, as this will give you more control over the resolution.

The aspecto ratio dilemma


By running the game at different resolutions, you will get different view areas for your game levels.
Why, well, because different resolutions will have different aspect ratios.
This can be a problem in multiplayer games if it gives advantages to players with more resolution, and can also be a problem if you are designing a game that has art done at specific fixed resolution / aspect ratio, like a pixel art background.

This one of the biggest hurdles in doing pixel art in Unity, and I've seen many developers quit at this point and just go back to Game Maker or something else that makes 2D easier.

I here will list a couple of solutions:

  • By rendering to a render texture with fixed resolution, you guarantee that it looks the same in all computers (however you might have to live with some empty black space on the edges in some resolutions...).

  • You can also either have a dynamic size for the render texture, or calculate a size that instead of requiring black bars just overflows the screen (meaning some part of the game will be cut off-screen in some resolutions, but at least there won't be any black bars).

  • There's also a Screen.SetResolution method. Can be used to force a fixed resolution, but it does not work the same in all platforms, plus it only accepts some resolutions, so if you want to make your game run at the original Gameboy resolution or something, this won't do.

  • I've seen some guys doing different pixel art for different aspect ratios (there are only 3 or 4 more common ratios).
    In some cases it is possible to extend the pixel art backgrounds / tilemaps / levels by some extra pixels / tiles in all 4 directions to compensate for all possible aspect ratios.


Subpixel camera scrolling


If you did the render texture setup for better control and a more retro look, you now understand that the camera movement looks terrible when rendering the UI image as 2x or 4x or mostly anything else. Because that scale number now is equivalent to how many pixels the camera skips with every step, ouch!

There is a solution though, take the fractional part of the camera position, multiply that fractional part by the scale (aka number of skips) and you get a pseudo subpixel offset that you can apply to the UI Image, which will fix the pixel skipping. Good luck getting this to work, its not easy!

If you need more details about doing this scrolling trick, feel free to read this blog, which contains more technical info about this technique.

 

Tags: #tutorials, #unity3d, #graphics, #coding

Follow me on Twitter for more cool stuff!