Search Unity

  1. Unity 2018.3 is now released.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. We've updated our Terms of Service. Please read our blog post from Unity CTO and Co-Founder Joachim Ante here
    Dismiss Notice
  4. Want to provide direct feedback to the Unity team? Join the Unity Advisory Panel.
    Dismiss Notice
  5. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice

[BUG] Renderer fails to take into account screen DPI

Discussion in 'Project Tiny' started by abeisgreat, Dec 20, 2018.

  1. abeisgreat

    abeisgreat

    Joined:
    Nov 21, 2016
    Posts:
    25
    Hey tin-arians,

    I'm struggling a bit to get my sprites to render looking good. Here's an example of some sprites...

    Screen Shot 2018-12-19 at 4.41.27 PM.png

    If I use low-res sprites (on the left), it ends up blurry, but if I use higher res (on the right) it ends up chunky.

    Tiny is set to use "source" images and I fiddled around with all the sprite importing settings (Full rect vs not, making sure compression quality was high, etc), but I can't make things not ugly.

    Any advice on where to look to sort this?
     
  2. AbdulAlgharbi

    AbdulAlgharbi

    Unity Technologies

    Joined:
    Jul 27, 2018
    Posts:
    8
    Hi
    Did you try setting the Sprite filter mode to Point (No filter)?
    it's in the Sprite import settings
    upload_2018-12-20_10-10-38.png
     
  3. abeisgreat

    abeisgreat

    Joined:
    Nov 21, 2016
    Posts:
    25
    Thanks for the advice Abdul, but the result of doing that is a more intensified pixelized look.

    I think I've came to the conclusion that this is a bug in the renderer which is subtle on vector art and almost invisible on pixel art (which is why it's not noticeable in the demo projects).

    I believe it likely only occurs on high DPI screens and is a result of not taking into effect the device's window.devicePixelRatio.

    It looks like tiny is setting the canvas size to what it naively believes is the correct size of the screen, but is actually the faked resolution which the system provides for compatibility. Generally this is great for browsers because native rendering of fonts, etc works perfectly when scaling however when things are rasterized onto a canvas then the scaling becomes very obvious.

    To quickly see this issue on your own machine you can load up a tiny game with vector art and use the brower's zoom functionality. As you zoom out, it's slowly reducing devicePixelRatio to 1:1 and thus reducing the artifacts from the scaling of the canvas. Zooming in has the opposite effect. You'll still see your entire game, but it'll get more and more ugly.

    For reference, here is a high-res vector sprite rendered to the screen at 100% zoom (normal) on the left. You can see the greasy edge and pixelated corner vs. the same sprite at 30% zoom on the right. It's smoother and sharper like you'd expect.

    Screen Shot 2018-12-26 at 1.23.16 PM.png Screen Shot 2018-12-26 at 1.23.10 PM.png

    You can see a fix for this exact issue on MDN as the window.devicePixelRatio is most useful for solving this exact bug.
     
    Cowcak likes this.
  4. abeisgreat

    abeisgreat

    Joined:
    Nov 21, 2016
    Posts:
    25
    Sorry for the spam, but here is a very approachable way to recreate this issue. If you load up Tiny Arms Revenge on mobile. One of these images is the normal render and one is with the "Desktop Site" option in mobile Chrome enabled (which reduces the pixel ratio closer to 1). Note how the change is nearly invisible except on the Unity logo where it's dramatically cleaner on one screen.

    Screenshot_20181227-102005.png Screenshot_20181227-101959.png
     
  5. andrewmil

    andrewmil

    Joined:
    Dec 30, 2018
    Posts:
    7
    Same. Tiny Project look pixelated on high DPI screens - macbook, iphone and other ((
    So, I can't use it for Playable ad now
     
  6. Cowcak

    Cowcak

    Joined:
    Mar 11, 2015
    Posts:
    6
    Same. This issue is really sad because I was thrilled to use Tiny for my projects, but this makes it usable only for pixel art games. Because the art is sharp only when using desktop mode on mobile and for example in Facebook Messenger it's always pixelated.
     
  7. abeisgreat

    abeisgreat

    Joined:
    Nov 21, 2016
    Posts:
    25
    I got bored of waiting so I wrote some code to mess with the runtime and fix this issue. I've tested in on Firefox, Chrome, and Chrome mobile. It's possible that there are issues with this hack in other browsers, that being said, I feel pretty confident it'll work.

    Here is a fix...


    Check out this gist with the workaround. You'll want to copy the entire file and place it into a Behavior / System which your game uses. Make sure to paste the code *next* to your namespace so something like...

    Code (JavaScript):
    1. (function HDPI_Hacks_By_abeisgreat() {
    2.   ...
    3. })();
    4. namespace game {
    5.   ...
    6. }
    Here's how it works...

    This fix works like this...
    1. Detach Tiny's window resize event listener.
    2. Create a new resize listener with our own code which manually adjusts the canvas size to take window.devicePixelRatio into account.
    3. Scale the canvas using CSS so that the new high-res canvas is forced into a smaller foot-print (closing the DPI gap)
    4. Detach Tiny's canvas touch and mouse event listeners (which rely on Tiny's understanding of canvas resolution to trigger game changes).
    5. Create new listeners which adjust event data as it comes in to take into account our scaled up canvas.
    6. Invoke the underlying Tiny methods with the new faked touch / mouse data.
    7. Wait for the game to exist, then invoke a "resize" event which fixes the resolution in an instant.
    Is this a permanent fix?

    Nah, we still need a patch in Tiny to support this natively. Looking at the runtime code it's clear that screen DPI was being thought of while writing the renderer. I'm guessing they ran into issues with webgl acting differently than traditional canvas rendering, but that's speculation.
     
    Last edited: Jan 5, 2019
  8. andrewmil

    andrewmil

    Joined:
    Dec 30, 2018
    Posts:
    7
    Hi! I also tried make a fix, but no success. So now I trying to use yours and get the error:

    TypeScriptError: Cannot find global value 'Promise'.
    TypeScriptError: An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor
     
  9. abeisgreat

    abeisgreat

    Joined:
    Nov 21, 2016
    Posts:
    25
    Whoops, sorry about that - I've updated the gist, can you try again and let me know how it goes?
     
    andrewmil likes this.
  10. andrewmil

    andrewmil

    Joined:
    Dec 30, 2018
    Posts:
    7
    Thank you, it's working! Perfect for web, but does't work for instant games and playable ad :(
    Waiting for update :)
     
  11. abeisgreat

    abeisgreat

    Joined:
    Nov 21, 2016
    Posts:
    25
    Sorry I don't know anything about those formats so my fix will probably remain web only :( hope it still helps someone though!
     
  12. pankaj_khanduja_10

    pankaj_khanduja_10

    Joined:
    May 16, 2017
    Posts:
    5
    Thank you brother @abeisgreat Big Thumps Up.
    I was facing this issue from last couple of days.
     
  13. pankaj_khanduja_10

    pankaj_khanduja_10

    Joined:
    May 16, 2017
    Posts:
    5
    One more thing - we don't need to Detach auto-resize canvas as it works with enabling auto-resize canvas.
    For supporting multiple resolution - just use "uiScameMode - ScalewithScreenSize"
     
    abeisgreat likes this.