Search Unity

flickering gameobjects (pixel bleeding) when moving, using an ortho camera

Discussion in '2D' started by DGordon, Dec 10, 2013.

  1. DGordon

    DGordon

    Joined:
    Dec 8, 2013
    Posts:
    649
    Hello,

    This is my first time posting here, so if I've placed this in the wrong place (or done any other taboo), my apologies. Its 2:30am here, so I blame any mistakes or incoherence on that :).

    I'm in the middle of creating a 2D system that has a workflow which includes some of the better aspects of both Corona and Flash. As much as I love Unity, for small scale 2D projects, its still faster to be able to create things using a parent/child hierarchy in code with strict X/Y values (at least coming from my company's background). The system allows a user to specify a target resolution, creates a 1:1 pixel to unit ratio for that resolution, and keeps the screen scaled properly whenever the screen's height changes (meaning, it looks the same regardless of screen resolution, with extra padding given on the sides when the w/h ratio changes). It uses the standard AddChild/RemoveChild syntax, has alpha/scaling trickle down through children, an event system that bubbles up, has both interactive and interactiveChildren flags per displayObject (anyone in flash will recognize mouseEnabled and mouseChildren), etc etc.

    Its coming along very nicely except for one problem that I can't figure out how to completely fix. I'm getting a slight bleeding of 1 pixel (either a disappearance or blurriness) that AntiAliasing seems to fix. However, AA is not a possibility because it tanks the FPS with a texture heavy game. I'm assuming this pixel issue is because my x/y positions are aligning to an arbitrary resolution, and therefore are winding up on weird floating points that don't align properly with the screen pixels. I did a test where I just incremented a cube's x/y by a random number (ie: 0.512315, not the exact number) using an orthographic camera, and I was getting the same flickering there, even without any scaling. Using a more normal number (0.5) is fine, its when I have such an odd float that I start to get a 1 pixel bleed/disappearance issue.

    I managed to fix this so long as the game is running in the native resolution (ios devices, native on desktop, etc), but I cannot figure out how to properly fix this so its aligned properly regardless of which resolution its played on (in the editor, or not native reso when I build it as a desktop app).

    I calculate the orthographic size of the camera as follows. I semi-stumbled my way onto this through step-by-step trial and error, so if anything seems arbitrary or unneeded (ie: the scaledOrthoSize formula), that's why.

    Code (csharp):
    1. float width = [insert target width]; // the targeted width of the stage
    2. float height = [insert target height]; // the targeted height of the stage
    3. x = -width/2; // shift the root gameobject over so its centered using the targeted resolution
    4. y = -height/2; // shift the root gameobject over so its centered using the targeted resolution
    5. float scaledOrthoSize = (768.0f/2) * (height/768.0f); // the Orthographic Size to keep the targeted resolution at correct scale
    6. Camera.main.orthographicSize = scaledOrthoSize; // use the scaled ortho size to maintain the targeted resolution.
    7. // at this point 1 (x,y) value = 1 pixel = 1 game unit assuming the game is at the targeted resolution, and will scale properly even if the game is using a different resolution. However, I have a 1 pixel bleeding/flickering issue.
    8.  
    9. float pixelPerfectOrthoSize = Screen.height / 2; // the Orthographic Size for pixel perfect
    10. float pixelSnapRatio = scaledOrthoSize / pixelPerfectOrthoSize // the ratio between the current scaled ortho size and pixel perfect
    11.  
    Then, in my S2DDisplayObject class (component on a game object), whenever I set the x/y value I have the following code. I'm keeping track of the assigned x/y values, but I'm actually converting them to the nearest 10th of a real pixel when assigning the value to the GameObject's position. This has solved the problem of bleeding when using native resolution. It makes sure the game object is never on a funky floating point in relation to the real pixel. However, when the game isn't running in native resolution, this just doesn't work. I'm not going to pretend to understand why. Maybe I made a mistake and it fixed native resolution bleeding for a reason I'm misunderstanding, or maybe I'm close to getting this and just burnt out ... either way, I could really use some help.

    Code (csharp):
    1. private float _x = 0;
    2. public float x { get { return _x; }
    3.     set
    4.     {
    5.         float diffX = value - _x; // get the amount we're changing the x value
    6.         Vector3 pos = transform.localPosition; // store the position vector3
    7.         float diff = diffX % (stage.pixelSnapRatio/10); // how far over the nearest 1/10th pixel have we gone?
    8.         diffX -= diff; // subtract the amount we went over from the amount we're changing the x value
    9.         pos.x += diffX; // modify the gameobject's position by the pixel aligned value, NOT the real assigned value
    10.         _x = value; // store the real value so we don't mess up the real position over multiple calls
    11.         transform.localPosition = pos; // assign the position to the game object
    12.     }
    13. }
    If anyone has some idea of what I'm talking about, and knows the proper way to go about this, I officially dub you my hero. All I want is to get rid of the flickering that's occurring ... everything else is working wonderfully so far, and I'm actually almost done with the core system ... this is the last bug I need to take care of, and then I can just go forward with features. I've just reached the point of randomly trying different values, which means I'm in a very bad spot.

    I can post an online build of this tomorrow so you guys can see the flickering if needed, and if you guys need a better example, I'll put together a small test project that causes this to happen and post a link. I know this is asking a lot, but I can't be the only one to want to do something like this, so I'm sure any answer's will end up helping a lot of us. If there's another post with an answer to this, my apologies, I've been googling this for hours, I must have missed it. This is my last resort.

    Thanks so much!!,
    Dale Donahue
     
  2. DGordon

    DGordon

    Joined:
    Dec 8, 2013
    Posts:
    649
    Okay, I knew I must be misunderstanding something. I set my texture's TextureWrapMode to Clamp and now the textures aren't flickering anymore ... without my hack. Amazing what a person can come up with under duress ;).

    However, I'm using a purchased textmesh and even if I set the font texture's TextureWrapMode to Clamp in code, it still flickers. If anyone has any ideas let me know. In the mean time I'll post an answer if I find it, and hope it helps someone else ...

    [Edit] I've spent some more time on this (rather sleepless night). From all the threads I've seen, there's just an issue rendering things on partial pixels. The clamping helped a tiny bit, but it didn't solve the problem like I thought, and moving textmeshes is EXTREMELY jittery. I tried a test with nothing in it but cubes, quads, and textmeshes moving on the x/y, and if AA is off, they're jittery with both orthographic and perspective cameras.

    I'm unclear how to tackle a proper 2D system given that these things are flickering when moved on anything but a full pixel. I'm going to end this here, but if anyone has any advice on how to proceed, I'd be much appreciated.
     
    Last edited: Dec 10, 2013