Search Unity

  1. We are migrating the Unity Forums to Unity Discussions. On July 12, the Unity Forums will become read-only. On July 15, Unity Discussions will become read-only until July 18, when the new design and the migrated forum contents will go live. Read our full announcement for more information and let us know if you have any questions.

Best Practice for Pixel Perfect World Space UI?

Discussion in '2D' started by TonyLi, Apr 23, 2019.

  1. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,774
    Is there a best practice for pixel perfect world space UIs such as health bars or information boxes above characters' heads? They contain text framed in a sprite.

    Use a screen space canvas and manually position every frame it using Camera.WorldToViewportPoint?

    Use a world space canvas and position and size it on exact pixel bounds?

    Render it to a sprite and let the camera's Pixel Perfect script handle it?
     
  2. zioth

    zioth

    Joined:
    Jan 9, 2019
    Posts:
    111
    Just render them in a canvas, with Render Mode set to "Screen Space." The canvas will stay relative to screen space while the player moves, so there's no need to reposition anything on Update().

    Pixel-perfect really only works if you're targeting a single resolution. If your game is going to work at multiple resolutions, your text will be antialiased, and you'll need a higher resolution sprite to prevent blurring. Vector elements (like boxes, buttons etc) will render fine at all resolutions.
     
  3. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,774
    The project is targeting a single, specific reference resolution.

    That's the catch. The UI elements (sprite frame and text) must follow a moving object (e.g., NPC/enemy). But to be pixel perfect, they need to move on exact pixel boundaries.
     
  4. zioth

    zioth

    Joined:
    Jan 9, 2019
    Posts:
    111
    Oh, that's much harder. You'll probably have to do one of the things you suggested. Of the your three ideas, I think repositioning every frame (or every few frames) on a screen canvas would give you the highest performance. But why is it so important? Use a higher-resolution sprite and depend on antialiasing for the text, then use multiple world-space canvases that track characters. It should look pretty good, and it will scale nicely (farther away characters will have smaller bars and text).
     
    liamdidato likes this.
  5. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,774
    It's a 2D platformer. Characters are all the same distance from the orthographic camera.

    The effect that I'm trying to achieve is pixel-perfect moving text with a bitmap font. The text needs to be aligned on an exact pixel boundary. As it moves, it needs to jump from one pixel boundary to the next.
     
  6. kruczynski0

    kruczynski0

    Joined:
    Jul 5, 2020
    Posts:
    1
    Hi, i have the same problem, díd you find a way to make it work?
     
  7. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,774
    I think I ended up using a screen space canvas for that one.
     
  8. taelgalli

    taelgalli

    Joined:
    Dec 7, 2016
    Posts:
    1
    For anyone facing this problem I found this solution:

    Code (CSharp):
    1. public class PixelPerfectSnapBehavior : MonoBehaviour
    2. {
    3.     [SerializeField] private float pixelsPerUnit = 100f;
    4.  
    5.     void LateUpdate()
    6.     {
    7.         Vector3 position = transform.localPosition;
    8.         position.x = Mathf.Round(position.x * pixelsPerUnit) / pixelsPerUnit;
    9.         position.y = Mathf.Round(position.y * pixelsPerUnit) / pixelsPerUnit;
    10.         transform.localPosition = position;
    11.     }
    12. }
    Adding this component will turn you Image into a pixel perfect Image snapping it to the nearest pixel possible.
     
    obecerra1228 likes this.
  9. obecerra1228

    obecerra1228

    Joined:
    Dec 21, 2017
    Posts:
    1
    taelgalli's solution worked for me, thank you!