informa
7 min read
article

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? Here's a short guide, with all things that you need to setup in order to get this done!

(This blog post was originally published at Lunar Labs)

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 very 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:
 

using UnityEngine;
[ExecuteInEditMode]
public class CameraFix : MonoBehaviour {
    [Range(1, 4)]
    public int pixelScale = 1;

    private Camera _camera;

    void Update()
    {
        if (_camera == null)
        {
            _camera = GetComponent<Camera>();
            _camera.orthographic = true;
        }
        _camera.orthographicSize = Screen.height * (0.005f / pixelScale);
    }
}

And that's it!

If you are curious what that's 0.005f means, well, multiplying by this number is the same as diving by 2 (half of the screen) and then diving by 100 (pixels per unit).
So if you need to change the pixels per unit for some reason (I dont recommend it), just change the formula to
 

Screen.height * ((0.5f * pixelsPerUnit) / pixelScale);

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.

  • 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


Rotations will always look terrible, especially you are using a scale other than 1x in the CameraFix script.
There is a way get pixel perfect rotations though, 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.
    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, 4, 8)

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.

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.

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!

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!

I hope this tutorial was useful for you, follow me in Twitter for more cool stuff!

 

Latest Jobs

Treyarch

Playa Vista, California
6.20.22
Audio Engineer

Digital Extremes

London, Ontario, Canada
6.20.22
Communications Director

High Moon Studios

Carlsbad, California
6.20.22
Senior Producer

Build a Rocket Boy Games

Edinburgh, Scotland
6.20.22
Lead UI Programmer
More Jobs   

CONNECT WITH US

Register for a
Subscribe to
Follow us

Game Developer Account

Game Developer Newsletter

@gamedevdotcom

Register for a

Game Developer Account

Gain full access to resources (events, white paper, webinars, reports, etc)
Single sign-on to all Informa products

Register
Subscribe to

Game Developer Newsletter

Get daily Game Developer top stories every morning straight into your inbox

Subscribe
Follow us

@gamedevdotcom

Follow us @gamedevdotcom to stay up-to-date with the latest news & insider information about events & more