"Pixel perfect" GUI is not pixel perfect at all, distorted text in Game tab

Hello. I am making a dialogue system and I'm annoyed by the incosistency of "pixel perfect" UI. I have made a comparision between these "pixels". Purple "pixel" is 27x27 pixels, blue "pixel" is 25x25 pixels and "2x2 pixels" is 22x22 pixels large (enlarged 4x).

Scale factor of "Dialogue" is set to 2 and Reference per pixel unit is set to 50. All other sprites are 16 pixels per unit. Despite all that, the pixels are inconsistent.
Also, letters are distorted in Game tab for some reason. Font is VCR OSD Mono.


Take a look at documention of canvas. The "Pixel Perfect" checkbox has nothing to do (almost) with drawing scaled up pixel art. It says "Should the UI be rendered without antialiasing for precision?", from my observations it might also nudge some positions to whole screen pixels, but that's probably not the same as your scaled up pixelart pixels. But it will not do anything to help consistently size various UI elements. For that you need to do dozen different things for different components, depending how you have setup rest of the stuff, how perfect you want things to be, and how well you want to support different screen resolutions.

Non exhaustive list that you need to get right to get pixel perfect pixelart canvas:

  • Correct canvas sizing logic (if you use scale with screen size and don't force fixed resolution for game window, you will not get pixel perfect result)

  • pixels per unit in canvas and sprite settings (i personally like setting them both to 1, that way there are no questions how they combine and it's immediately obvious when something has wrong size)

  • rect transform size for Image. Rect transform will happily allow you to set arbitrary size ruining any pixel perfectness. "Set native size" slightly helps if you have setup the pixels per unit. Much easier to get things right if you have setup things so that 1 canvas unit = 1 scaled up asset pixel.

  • Anchoring. If you are doing any anchoring to the center of parent or pivot at default 0.5,0.5 position . Better check that dimensions are even numbers. Otherwise you will likely get mess. If dimensions are odd numbers better set anchors and pivot to corners.

  • Anchoring relative to canvas edges. Even if you use constant pixel size. It isn't guaranteed that current screen size is perfect multiple of chosen scale factor. Meaning that canvas size will not be whole units/scaled up pixels. There are different solutions for this. Anchoring everything to the aligned corner of canvas (bottom left if I am not mistaken), not using screen space overlay canvas but using camera canvas with camera configured to do cropping, adding child rect transform to canvas with size rounded [u]to integer size either down (and drawing block borders) or up (single pixel column might be partially outside screen), limiting window size to specif resolution (terrible experience for players).[/u]

  • Any rect transforms in the middle with scale that isn't 1.

  • Any unaligned position result in size varying by +- 1 pixel (if it doesn't produce blurriness)

  • Don't make any measurements while zooming in in Editor. That will potentially introduce additional inconsistencies, because random zoom will likely not be a perfect multiple scale. Better make sure that game view is without any additional scaling and make a screenshot. If you don't support resolution smaller than your monitor, you will have to export the build instead of doing it in Unity editor. Zoom in screenshot using image editor. Enabling grid in image editor with size set to whatever pixel scaling factor should be also helps catching errors, because when things are almost correct it might be correct for half the screen and then shift by one pixel for the rest. Be careful if you have multiple monitors especially if some of them are high DPI, mixed OS desktop scaling settings can introduce errors during screenshot process.

  • Text is it's own source of troubles. I don't even try to get it pixel perfect. A lot of text settings can easily break pixel alignment. It also puts huge limitations on text amount you can display. And even if you get it right, it will probably break once you introduce translations into multiple languages. (But each developer can make their own choices for what to try getting perfect, and when to make tradeoffs).

Reference per pixel unit is set to 50. All other sprites are 16
That sounds like recipe for problems. 50 is not divisible by 16. That that doesn't mean you don't have other source of inconsistencies.

Overall it's a painful process. Just because changing single setting doesn't fix everything doesn't indicate whether it's correct or not. You must have a good understanding of how things work so that you can identify sources of inconsistencies and one by one fix them until you get perfect result. Some of approaches might have slightly simpler setup but all of them have their own limitations and drawbacks.