Pixel Perfect 2D

June 19, 2015 in Technology

How do I make a pixel art game that looks great? We get that question a lot. If you start your pixel game with all the default settings in Unity, it will look terrible! But the current version of Unity can be made to render pixelated games that don’t suck. Read on for a rundown of do’s and dont’s.

goodbad

Image on the left is rendered on a poorly calibrated camera while the one on the right is properly calibrated. (click on image to see full-res)

The Secret Sauce

The secret to making your pixelated game look nice is to ensure that your sprite is rendered on a nice pixel boundary. In other words, ensure that each pixel of your sprite is rendered on one screen pixel (or any other round number). The trick to achieving this result is tweaking the camera’s orthographic size (and live with the consequences).

The Basics: What Is Orthographic Size?

On an orthographic camera, the orthographic size dictates how many units in world space the screen’s height is divided into. So on a screen height of 1080 with orthographic size of 5, each world space unit will take up 108 pixels (1080 / (5*2)). It’s 5 * 2 because orthographic size specifies the size going from the center of the screen to the top.

Therefore if your Sprite’s Pixels Per Unit (PPU) settings is 108, it will be rendered nicely.

Practical Approach To Achieving Pixel Perfect.

To apply this on an actual project requires a bit more considerations and planning ahead. Since you can’t tweak the physical resolution of the target device and you only have a very limited range of PPU (by way of asset bundle variant), the only real number that you can play with is the orthographic size.

Changing the orthographic size will have the effect of increasing or decreasing the visible world space. This impacts your game code directly and need to be accounted for. Here’s a table with various scaling scenarios

Vertical Resolution PPU PPU Scale Orthographics Size Size Change
768 32 1x 12 100%
1080 32 1x 16.875 140%
1080 48 1x 11.25 93.75%
1080 32 2x 8.4375 70.31%
1440 32 2x 11.25 93.75%
1536 32 2x 12 100%

* Orthographic size = ((Vert Resolution)/(PPUScale * PPU)) * 0.5

There are three well known techniques to handle the scaling and it is quite plausible that you will employ all three in your project.

Technique #1: Thick Borders

For a small difference, a simple ‘thick border’ will suffice. Depending on your game’s design, a few percentage bigger or smaller than your reference screen size can be easily filled with the thick border.borderThe overall screen size grows but the art size stays the same. This can be easily dealt with by increasing the thickness of the floor/roof.

However, when the screen increases beyond a certain size, a thick border will no longer be practical.

Technique #2: Increase Asset Resolution

If you start out with a reference screen height of 768 and PPU of 32, going to 1080 is going to be troublesome as your assets will not scale nicely.

The table above illustrates scaling a game starting from 768 all to way to 1536 with three alternatives on how to deal with 1080. The most interesting number to look at is the orthographic size. The ideal situation is that as your screen size grows, the orthographic size remains the same. This will ensure that your assets will take up the same amount of screen space as they do with your reference resolution.

From the table above, using an alternate sprite at PPU 48 would create a visible world space that’s only 6.25% smaller than your reference size. This could be easily dealt with using the thick border approach.

1080

PPU 32 vs PPU 48 at 1080 with ortho size 11.25. Notice the terrible looking PPU 32 sprites on the left. Color shifted on the right to clearly show swapped asset variants.

Swapping the sprite assets can be easily done at runtime using AssetBundle Variants. See a demo here.

Technique #3: Halving Orthographic Size

If your screen grows big enough, we could display your sprites at 2x by applying a scaling factor to the calculation of the orthographic size. For the case of 1440, we could keep using the PPU 32 sprites but calculate the orthographic size as such (1440/(2*32)) * 0.5 which gives you 11.25.

This means, each world space units will contain 64 screen pixels. This effectively tells the engine to render 32 pixels from the sprite onto 64 pixels on screen. This gives a nice whole number factor of 2 which will look good at the same time giving you a world space that’s just 6.25% smaller than your reference setup.

This technique does not require new assets to be created.

image00

* The PPU 32 sprites are now rendered twice as big but still look fantastic. This only works for whole number enlargement.

Other Tweaks

These other settings are essential to make things as crisp as possible.

On the sprite:

  • Ensure your sprites are using lossless compression e.g. True Color
  • Turn off mipmapping
  • Use Point sampling

In Render Quality Settings:

  • Turn off anisotropic filtering
  • Turn off anti aliasing

(Optional) Turn on pixel snapping in the sprite shader by creating a custom material that uses the Sprite/Default shader and attaching it to the SpriteRenderer.

Implementation Details

To implement the above system requires 2 parts.

  1. Create a simple component that calculates the orthographic size for the camera based on the screen height.
    1. Allow for overrides for certain resolutions so that the user could dictate the PPU settings for that resolution
    2. This calculation takes place at the start of the scene
  2. Load the right asset bundle variant based on the screen height. Either load the default bundle or one that’s based on the override settings.

    pixelperfectcomponentPixelPerfect component

Check out a demo project that demonstrates this approach

Known Issues

Even with all these number tweaking, there are still a few issues:

  • Physics and animation systems might move/rotate your object to a position or rotation that’s not ideal.
  • Single-pixel width art assets will render poorly if they are allowed to be rotated arbitrarily. This is true no matter what you do. The only real solution to this is to either:
    • Avoid single pixel art
    • Always ensure they are axis aligned

Conclusion

Making pixel perfect 2D games is possible with the current version of Unity. However, as detailed above, there are consequences and known issues, but they are not insurmountable nor are they blockers. Long live retro style games!

Comments (16)

Subscribe to comments
  1. Michael Chugg

    June 23, 2015 at 4:51 pm / 

    Hey everyone, we should vote for the feature here: http://feedback.unity3d.com/suggestions/pixelperfect-2d-mode

    Let Unity know we want this to be part of the core engine.

    1. Shannon oney

      June 26, 2015 at 12:04 am / 

      That is like so so true

  2. Teku Studios

    June 22, 2015 at 4:12 pm / 

    There is also a very interesting plug-in in the Asset Store that would be perfect to have in Unity, ‘Pixel Art Rotation’:

    http://www.assetstore.unity3d.com/en/#!/content/33829

    Instead of the standard rotation of Unity2D, Pixel Art Rotation rotates the sprites pixel by pixel, letting you create a perfect retro style looking game. You can also rotate your animated sprites. That’s definitely a feature I’d love to see in Unity for 2D pixelated games. Here’s how it looks:

    http://s17.postimg.org/cl4rwfvnz/imagen_01.jpg
    http://asthreeworks.com/wp-content/uploads/2015/03/pixel-rotation-paradise-lost-first-contact.gif

  3. Tinnus

    June 20, 2015 at 4:44 pm / 

    https://www.assetstore.unity3d.com/en/#!/content/33558I've also authored a script that’s available in the Asset Store and can help you make retro-looking games with less effort :)

    This works at the camera level, basically making the game render to a fixed resolution no matter the aspect ratio, actual screen resolution or screen size. This way all pixels should stay in the right place and you almost don’t have to worry about different devices, assuming you want to keep the same “game screen height” in all cases. Also this looks better the smaller your game resolution is compared to the actual screen, and if they are a multiple of each other since that will make all game pixels have the same size (which is just a limitation of the math involved, really).

    As a bonus this often looks awesome for rendering Myst-style low-res versions of a 3D scene if that’s your thing, and also runs very fast (usually faster than rendering the 3D scene at full res :)

    1. Tinnus

      June 20, 2015 at 4:45 pm / 

      Damn HTML formatting. This is the correct link: https://www.assetstore.unity3d.com/en/#!/content/33558

  4. Hawken King

    June 20, 2015 at 10:32 am / 

    It’s an interesting solution if you have a fixed resolution.

  5. Devman

    June 20, 2015 at 4:39 am / 

    Getting pixel display perfect to work seems like something that should just work out of the box.

    1. Paul Tham

      June 22, 2015 at 3:47 am / 

      @Devman, @Andre, responses like yours are a great way to judge how much we need to do on a particular area. For sure, we’ll keep looking into this area. Stay tuned.

  6. andre

    June 20, 2015 at 2:57 am / 

    You guys really need to implement an internal engine solution to this. Its not the devs job to get sprites to render ‘correctly’, it’s the engine’s job.
    Also you guys addressed simple scenarios, what about if you want to publish to all mobile platforms… that’s a lot of different screen heights…

  7. tsw

    June 19, 2015 at 9:27 pm / 

    the physics portion is a issue… would be an idea to simply apply some kind of stepping logic in the transformations, but i’m not sure how that could be applied and/or solved.

    1. Paul Tham

      June 22, 2015 at 3:48 am / 

      Yes, we looked into this a little bit but I didn’t want to share something that was too experimental. Stay tuned on this one.

  8. eskivor

    June 19, 2015 at 7:25 pm / 

    Thanks for your advices ! I currently use only the “other tricks” on the sprite and in thr render quality settings and it’s aldready really effective. I will certainly check for the resolution and size of the camera after, if I need a better result.

  9. Pixelatto

    June 19, 2015 at 12:39 pm / 

    It’s not always as easy as this post says… There’s a lot more stuff you have to handle if you want REAL pixel perfection. I made my own asset to make this easier and published it in the store long ago. It even supports perspective cameras :)

    Check it out: https://www.assetstore.unity3d.com/en/#!/content/14498

    (Sorry about the self-promotion kindof, but I believe this is relevant here)

    1. Pixelguy

      June 19, 2015 at 3:39 pm / 

      Looks cool and very useful but you need to respond to that review from 4 months ago where you got 2 stars for not commenting your code. The claim was also made that your code doesn’t work in all cases.

      Despite all the other good reviews that one stands out because you never responded to it, which makes the customer’s claims seem more legitimate.

      1. Pixelatto

        June 19, 2015 at 5:39 pm / 

        I should’ve missed those D: It’s so bad that these comments don’t pop up any kind of notification…
        Thank you very much for pointing out, they are already replied.

  10. Tom

    June 19, 2015 at 11:39 am / 

Comments are closed.