Search Unity

Pixel perfect 2d in 4.3?

Discussion in '2D' started by DarkMarmot, Nov 13, 2013.

  1. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,720
    So, so, SO very true.

    You are one of the few who actually know and admit the truth. Thank you. I really appreciate this honesty and your competency.
     
    Metsubishi and GarBenjamin like this.
  2. coah

    coah

    Joined:
    Oct 20, 2012
    Posts:
    10
    I have tried to do pixel perfect rendering for some time now (before Unity2D), I've never really had a lot of success with it until recently, and it's always been a pain to get something simple together that works well without small problems appearing later on.

    What HubertGendron mentioned, about Pixel Snap is something I never knew existed, I think it's the solution I've been looking for, but I haven't tested it out fully, yet. I think I need to just take some time to remove a bunch of my code to see where it breaks and just how much that setting does.

    What I've done is something nobody here has mentioned yet so this should be interesting.

    Back when I worked on something called 'Daughters of the Void', or 'Methodical Action Platformer' I got pixel perfect rendering done by using these two camera functions;
    Code (CSharp):
    1. Camera.WorldToScreenPoint();
    2. Camera.ScreenToWorldPoint();


    In Unity, I would have an object, say the player, have all its logic in one GameObject and the sprite would be a child to that GameObject running this script.
    Code (CSharp):
    1.  
    2. Vector3 localPosition; // set in start to save the value
    3.  
    4. void Update()
    5. {
    6. Vector3 screenPos = camera.WorldToScreenPoint( transform.parent.transform.position + localPosition );
    7.  
    8.     // based on what scale the pixels should be, crush the value down accordingly to align to that smaller grid.
    9.     screenPos = new Vector3( Mathf.Round(screenPos.x/scale), Mathf.Round(screenPos.y/scale), screenPos.z );
    10.     // scale it back up to a usable resolution, add offset of .5f to get a position between pixels.
    11.     screenPos = new Vector3( (screenPos.x*scale)-0.5f, (screenPos.y*scale)+0.5f, screenPos.z );
    12.  
    13.     transform.position = camera.ScreenToWorldPoint( screenPos );
    14. }



    What I am currently using still has the sprite as a child of its GameObject, using the parents position as its guide. I don't have script's on all sprites, instead sprites just have the tag "sprite" and a script on the main camera puts them all in an array, iterating through them instead.
    One thing to note is that something like a tile-set composed of several tiles could all be positioned together as they all (presumably) have very clean positions, like (1,1) or (-2,5), so the number of iterations can be kept very low, the tiles would just all be children of an object with the "sprite" tag.
    Using a sprite material with Pixel Snap turned on, this works:
    Code (CSharp):
    1. // this should be part of a script on the main camera
    2. void OnPreRender()
    3. {
    4.     Vector3 screenPosition = camera.WorldToScreenPoint( SimplifyVector3( spriteParentPos ) );
    5.     spritePos = camera.ScreenToWorldPoint( screenPosition );
    6. }
    7.  
    8. Vector3 SimplifyVector3( Vector3 v )
    9. {
    10.     return new Vector3( RoundToPixelIncrement(v.x), RoundToPixelIncrement(v.y), RoundToPixelIncrement(v.z) );
    11. }
    12.  
    13. float RoundToPixelIncrement( float num )
    14. {
    15.     int _int;
    16.     float _dec;
    17.  
    18.     _int = (int)Mathf.Floor(num); // keep the integer
    19.     _dec = num - _int; // get a clean decimal 0.*
    20.  
    21.     _dec = Mathf.Round( _dec / pixel ); // get number of increments
    22.     _dec = pixel * _dec; // using those clean the float into increments of PIXEL
    23.  
    24.     return (_int+_dec);
    25. }


    EDIT: Tried to make this more useful, let me know if this is too confusing or if you'd be interested in some clarification about some aspect.
     
    Last edited: Oct 19, 2014
  3. coah

    coah

    Joined:
    Oct 20, 2012
    Posts:
    10
    Here's my current prototype working with what I mentioned above
    https://mega.co.nz/#!nBtQ1B4D!NT14wdYoSAYFUDbuJxsmKkqYCsXoW-rUCeEHkVOb9OU
    GamePad or keyboard
    Arrows, X, Z
    Analog, D-pad, a, b

    grab ledges

    It scales based on screen resolution trying to fit a certain window size. different scales have had messed up sprite positioning in the past but I think it's good at the moment.

    The camera is not good yet.
     
  4. TomasJ

    TomasJ

    Joined:
    Sep 26, 2010
    Posts:
    256
    @coah - nicely done. We have a similar implementation done deep inside the rendering code (meaning your transform will not be touched) of Unity now, however it's not shipped yet. We admit that it should have been fixed earlier #tooManyFeatures

    @CarterG81 - I believe we have discussed this before and the outcome was that to get pixel perfect rendering you need to correctly position both your camera and your sprites. Just like coah demonstrated.
    Saying "Just being honest, whatever developer over at Unity who is in charge of 2D rendering, sucks" doesn't do justice to the engineers.
     
    coah and GarBenjamin like this.
  5. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,720
    edit: (Deleted my lengthy post reiterating the problem and using Pixelatto's transform offsets as example)
    I didn't read the reply to coah, where you admit that this problem should have been fixed a long time ago, and that you have already helped to resolve the issue (it just hasn't been released yet.)

    I stand by my criticisms though, as I don't believe in pretending an engineer's work wasn't flawed, as if they are somehow exempt from the reality that this problem was not only unacceptable, but a huge waste of time for hundreds of people trying to get it to work.

    I know from posts on this very forum, that many abandoned Unity and chose other engines because of problems like this which are still not fixed. Let's just hope this next update actually does fix it.

    Users should not have to jump through hoops or buy assets from the store just to get functionality that every other engine in existence does perfectly well. I mean, come on, it's rendering. The video in video games.

    @TomasJ
    We did discuss it before, and the problem wasn't resolved. Obviously. If it worked, I wouldn't have bought Pixel Perfect by Pixelatto. To reiterate that we discussed it before, as if that resolves the issue, is a bit insulting to say the least. You know...considering my complaint that the problem still exists occurred after that conversation. All while Unity admitting to the flaws being fixed (far too late) in the recent (unreleased) update.
     
  6. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,720
    It is amazing the amount of effort and time the community has spent trying to get Unity, one of the world's most popular game engines, to render correctly.

    How much cumulative time has Unity cost its users due to bad assets from the store or flaws in the engine itself requiring work-arounds? I'm sure that won't be calculated at the next Unite talk :p

    Once these issues are fixed, the engine will be a lot better for 2D pixel game development.
     
  7. coah

    coah

    Joined:
    Oct 20, 2012
    Posts:
    10
    This is solved using the Pixel Snap setting on the Sprite material.
    And the sub-pixel position is most likely because the center of a power of two pixel sprite is not an actual pixel position. if your PPU is 16, then the center pixel position you'd get might either be 0.53125 or 0.46875 (in one axis) where is should be 0.5, a position between the pixels.
    (not sure that's helpful actually)

    If you only add a .5 offset to some objects, that's going to cause issues, doing it to all of them will be a better solution. I had some issues before Unity2D where a moving object the camera focused on seemed to need special positioning and that was a never ending mess of issues where the character would just be offset by a pixel or so, intersecting with the map in bad ways. In the end, is you need to add a special case to some specific object, you should just go back to the roots and look it over again. I finally have a solution that works for all cases and it's much more ideal.

    Maybe I'm rambling, but some of that should be useful.

    This is something I know quite well, its definitely a result of using the Camera functions ScreenToWorldPoint, it generates those odd positions. Why? I don't know. Unity is primarily a 3D engine and it's a bit odd to expect it to behave like a 2D engine when it's 2D is still based on a 3D engine.

    I can understand the frustration, I've gone back many times from making 2D pixelart stuff in Unity because of these issues, but there is a way to do it.
     
  8. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,720
    It's irrelevant if you did no offset at all, or all objects having a .5 offset. The reason I added some with a .5 offset was to try to fix the fact that doing the same thing to all of them didn't work. There would always be problems with some gameobjects at random positions.

    I'm sure what you said is helpful to resolve the issue, but it's not an issue for me anymore since I use Pixelatto's asset. I've wasted enough time trying to fix it myself. Thank you though for contributing. Hopefully in the next release, Unity will just resolve this once and for all.

    I agree there is a way to do it. Honestly, the best way is to just spend the $10 and not have to waste your own time on it.

    One of the biggest weaknesses of Unity compared to creating your own engine, is all the time wasted on stuff like this. Flaws in Unity and its closed source, combined with flaws or deception in assets from the store. (A lot of that time could be used to create the same functionality in your own engine, but actually have it work correctly or fit better with your project). If it weren't for this stuff, Unity would have a lot more going for it (saving tons more time, and having a lot fewer weaknesses).
     
    Rokzero and GarBenjamin like this.
  9. Rokzero

    Rokzero

    Joined:
    May 19, 2014
    Posts:
    5
    I`m still strugling with this problem, I just can`t get rid off those lines appearing between my tiles. Is there any simple solution? I`m niewbie and I don`t want to learn Unity by solving rendering problems.
    I`ve tried almost everything (except pixel snap, couldn`t find it) but I still see those gaps... Is Unity going to fix this? Should I start another project without pixel graphics?
     
  10. coah

    coah

    Joined:
    Oct 20, 2012
    Posts:
    10
    No, don't ever quit! It's pixel snap (probably).

    Create a new material
    Select as its shader Sprites/Default
    You will see a tickbox there for Pixel Snap, turn it on
    Go to your SpriteRenderer component and set this new material as its material instead of the default sprite material.
     
    Rokzero likes this.
  11. Rokzero

    Rokzero

    Joined:
    May 19, 2014
    Posts:
    5
    Thank you VERY MUCH! :) Pixel Snap did the trick, I`m so glad my pixel art looks perfect. Thank you a lot!
     
    TomasJ likes this.
  12. Dendrolo

    Dendrolo

    Joined:
    Nov 12, 2014
    Posts:
    1
    Thanks coah. That helped me too.

    I am new to Unity, just downloaded it yesterday and in my experiments was just figuring out how to place my tiles on the screen. In my case, I made my tiles 64x64, set pixel per unit to 64, but chose a screen resolution and orthographic size which causes my tiles to scale to 32x32. I had artifacts between tiles vertically and when I created and used the new material as per your description, my tiles now look much nicer.
     
    TomasJ likes this.
  13. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,625
    I was just struggling with the pixel perfection thing myself, so read through this thread... For me I have a need to use point sampling on the sprite data because I'm storing `data` in it rather than pixel colors, as such... and the data needs to be read accurately. Because of that, I notice that when I move my sprite (float coords), with pixel snapping ON in the material the width or height or the sprite changes on and off.. like it makes the actual sprite's `number of pixels on screen` change, and this causes a bit of a noticeable `jiggle` in some of the pixels as the texture stretches. But this only seems to happen when the screen resolution is not set up properly in the camera. e.g. I'm targetting 1920x1080 so I have an ortho height of 540. That works fine on that res, but on 2560x1440 or any others, there is a jiggle. It would seem the pixel snap is only designed to really work when the camera's ortho size gives the display an exact 1:1 pixel-texel mapping. That would be fine, except it then means all sprites will be `pixel perfect` but will become SMALLER-looking on a higher resolution display. In my case, I want pixel perfect display, or close to it, without jiggling or size fluctuations, but on any resolution... so that relatively speaking objects on the screen are always the same size to the user. i.e. the interface just scales to fit the display... trying to do scaling at the same time as pixel fitting is almost impossible. I think I might mess with the pixel-snap shader code, though, because if I can pass in some kind of multiplier to convert the camera's ortho size into `what the ortho should be at this resolution`, maybe that'll calculate properly? I'll let you know what I find.
     
    CarterG81 likes this.
  14. MapMan

    MapMan

    Joined:
    Oct 27, 2013
    Posts:
    38
    So is there some kind of a consensus on this matter (other than using Pixel Perfect store asset)? I analyzed this and other threads, materials on the Internet and performed my own tests and this is what I gather
    • I assume default Pixels To Units value (100) for all sprites.
    • The cameras OrthographicSize has to be correct. This boils down to a simple formula:
      Code (CSharp):
      1. Camera.main.orthographicSize = Screen.height / 2f * UnitsPerPixel;
      Where UnitsPerPixel equals to 0.01 (100 pixels per 1 unit).
    • Camera has to be aligned to what I call pixel grid. Given above values, camera transform values have to be rounded with precision up to 0.01.
    • All sprites have to be aligned to pixel grid. Placing sprites at values like x = 0.005 can result in rendering errors.
    • Editor -> Snap Settings can help with aligning sprites in editor.
    Doing the above allowed me to achieve Pixel Perfect effect. Is there anything I missed or maybe someone has some counter arguments (when will it break? got specific test cases?).

    Here are some points that I can't wrap my head around:
    • Why coah's solution supposedly works? Can someone elaborate?
    • Do my sprites need to be POT? Even if that meant extending the actual sprite with a transparent border, just to make it's resolution POT?
    • How does Pixel snap fit into the story? During my tests using a simple shader with Pixel snap turned on didn't help at all. If I met all of the conditions above, I didn't need Pixel snap.

    Additionally, how does all this relate to the game scaling? Let's assume I created all my sprites and scenes to be rendered perfectly at 640x480. Let's now ponder these set up scenarios:
    1. The game runs natively in 640x480 - no scaling, everything looks perfect.
    2. The game runs in 1280x960 - the resolution is exactly twice as big and can be scaled easily using nearest neighbour technique. How well does unity handle that?
    3. The game runs in some arbitrary resolution in the same aspect ratio as the original. The game needs to scale up or down, probably loosing some of the 'crisp' pixel art look. An example game that does that well is FTL.
    4. The game runs in some arbitrary resolution but with a border, the scene is centered on the screen. On high resolutions things can look really small.
    To sum up, how does supporting multiple resolutions tie in with achieving Pixel Perfect look?
     
  15. geroppo

    geroppo

    Joined:
    Dec 24, 2012
    Posts:
    140
    i demand an answer to MapMan's question :)
     
  16. coah

    coah

    Joined:
    Oct 20, 2012
    Posts:
    10
    When it comes to the resolution I don't think you have a lot of options if you want the pixels to be clean. You will need to restrict it to multiplications of the pixel size and then decide what to do with the wasted space. Either do black bars or just let the graphics extend to the sides.

    In my old example I do black bars. If you have a 360 controller, press back to cycle the pixel resolution. I think it's a decent solution.
    https://mega.co.nz/#!GMthyCYY!D3mhsQnEVBGNeV2dDaOeVOUC7LGhL5Te8fOwNHjiPeI
     
  17. geroppo

    geroppo

    Joined:
    Dec 24, 2012
    Posts:
    140
    I was wondering how would you go about "multiplications of the pixel size", suppose that 100 pixels = 1 unity, to move usually you would do something like:
    Code (CSharp):
    1. pos.x += direction.x * speed* Time.deltaTime;
    How would you put the pixels per unit calculations there?
    would direction.x* speed* Time.deltaTime * 0.01 give the right results for moving "pixels per second" ?
     
  18. coah

    coah

    Joined:
    Oct 20, 2012
    Posts:
    10
    The size of the pixels would be determined by the camera. For me scaling was just about showing less on the screen by changing the viewport rect on the camera.

    I wouldn't do anything with the code of any active entities like that.

    I've set up my camera and viewport rect used in that little example project above like this:

    Variables:
    Code (CSharp):
    1. int tileHeight = 18;        // How many tiles high the screen should be
    2.     int tileWidth = 32;          // How many tiles wide the screen should be, if 0 don't limit
    3.     int pixelResolution = 16;   // How many pixels per tile
    4.  
    5.     int gridWidth;          // The intended low screen resolution
    6.     int gridHeight;         // Same ^
    7.     public int scale;       // Current pixel scale
    8.     int maxScale;           // Maximum pixel scale
    Setting up the camera
    Code (CSharp):
    1. void Initalize()
    2.     {
    3.         pixel = 1f/pixelResolution;
    4.  
    5.         camera.orthographic = true;
    6.         camera.orthographicSize = tileHeight / 2;
    7.         camera.backgroundColor = Color.black;
    8.  
    9.         Vector3 startPos = GameObject.Find(GameData.Instance.startingRoom).transform.position;
    10.         transform.position = new Vector3( startPos.x, startPos.y, transform.position.z );
    11.         followGuide.position = transform.position;
    12.  
    13.         gridHeight = tileHeight * pixelResolution;
    14.  
    15.         if( tileWidth != 0 )
    16.         {
    17.             gridWidth = tileWidth * pixelResolution;
    18.         }
    19.         else
    20.         {
    21.             gridWidth = 0;
    22.         }
    23.  
    24.         // if height is taller than witdh we constrain by it, so whatever is the larger we constrain by.
    25.         if( gridHeight > gridWidth )
    26.             maxScale = (int) Mathf.Floor( Screen.height / gridHeight );
    27.         else
    28.             maxScale = (int) Mathf.Floor( Screen.width / gridWidth );
    29.  
    30.         scale = maxScale;
    31.  
    32.         SetScale(0);
    33.  
    34.         Debug.Log("Pixel Scale = "+scale);
    35.     }
    Setting the pixel scale:
    Code (CSharp):
    1. public void SetScale( int newScale )
    2.     {
    3.         if( newScale > maxScale || newScale == 0 )
    4.         {
    5.             newScale = maxScale;
    6.         }
    7.  
    8.         float left;
    9.         float top;
    10.         float width;
    11.         float height;
    12.      
    13.         top = ( Screen.height - ( gridHeight * newScale ) ) / 2;
    14.         height = gridHeight * newScale;
    15.  
    16.         if( gridWidth == 0 )
    17.         {
    18.             left = 0;
    19.             width =  Screen.width;
    20.         }
    21.         else
    22.         {
    23.             left = ( Screen.width - ( gridWidth * newScale ) ) / 2;
    24.             width = gridWidth * newScale;
    25.         }
    26.  
    27.         Debug.Log("width="+width+" height="+height);
    28.  
    29.         camera.pixelRect = new Rect( left, top, width, height );
    30.  
    31.         scale = newScale;
    32.  
    33.     }
    I really don't feel confident that this addresses your concerns... I hope its at least somewhat helpful... or in the ballpark at least.
     
  19. geroppo

    geroppo

    Joined:
    Dec 24, 2012
    Posts:
    140
    That was indeed helpful, thanks alot
     
  20. rebelholic

    rebelholic

    Joined:
    Jan 25, 2014
    Posts:
    6
    Could you provide a source code just about to resolution setup because I am still noob?
     
  21. demion90

    demion90

    Joined:
    Jul 10, 2014
    Posts:
    9
    What is variable pixel meaning and what value should it be?

    I tried value of 1 which makes no sense.
    Also tried value 100 (pixels per unit) and inverse value (1 / 100).
    Pixel material with snap enabled.
    Nothing of this helps.

    When screen resolution goes uneven sprite screen position becomes decimal (not integer) and as far as I understand texture filtration happens - with Billinear mode it becomes blurry and with Point (which is more suitable for pixel art) it is blended with top pixel out of sprite rectangle.

    Question is - how to keep sprite always at integer position so that no pixel distortion / filtration / blending happens?
     
    Last edited: Apr 7, 2015
  22. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,720
    The first thing that comes in mind is simply altering the way you handle movement. If a character goes east, then X + 1. In this way, the math would never become decimal in the first place. The problem with that is that Unity doesn't like it (for example, if you use Unity's Physics then you'd get knocked off into decimal positions very quickly. Unity likes to have decimal positions).

    I am not sure how good it is for performance / bugs, but when testing this I thought of trying to simply convert the end position to an int during a LateUpdate(). I tried this twice, the first time resulted in bugs, the second time worked fine. I don't do that anymore (a bit concerned it would be a bad idea to do it this way) but if it works, it works. Just don't be surprised if it causes problems.

    It would be something like
    Code (csharp):
    1.  
    2. LateUpdate() {
    3. transform.position = new Vector3 ( (int)transform.position.x, (int)transform.position.y,  (int)transform.position.z); }
    4.  
    That may suffice until coah gives you a better answer.

    I'm not really sure what pixel snap does, and if I ever knew I long since forgot, but I imagine Unity's intention was that it's SUPPOSED to do what PixelPerfect ACTUALLY does. (Snaps rendering to integer values to prevent subpixel transforms, so sprites are not rendered via sub pixels, eliminating these issues entirely by providing pixel perfect rendering).

    The problem is that having whole numbers for positions will not resolve Unity's flaws. If you own PixelPerfect, you will see that it starts with a strange decimal offset, and moves in whole numbers up until a certain point (in which it adjusts those decimals). I imagine that maybe this has something to do with why pixel snap doesn't work, because whole integers don't work either. To be honest, none of it makes any sense, and I've seen no other engine with such problems. Then again, I don't use 3D engines to make 2D games except with Unity. I also don't know how Unity does things behind the scenes, so who knows why this really happens. We just know it's S***ty.

    I'm curious if this is all fixed in Unity 5 though???
     
    Last edited: Apr 7, 2015
  23. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,720
  24. demion90

    demion90

    Joined:
    Jul 10, 2014
    Posts:
    9
    Sorry I forgot to mention that I actually use Unity 5. Seems like I managed to get rid of filtration rounding (or flooring) sprite screen position to integer in camera OnPreRender() method only with Pixel snap disabled! (with enabled still excess pixels from top on some uneven height resolutions)

    Code (CSharp):
    1. void OnPreRender()
    2. {
    3.   Vector3 screenPosition = Camera.main.WorldToScreenPoint(Object.transform.parent.position);
    4.   screenPosition = new Vector3(Mathf.Floor(screenPosition.x) - 0.5f, Mathf.Floor(screenPosition.y) + 0.5f, screenPosition.z);
    5.   Object.transform.position = Camera.main.ScreenToWorldPoint(screenPosition);
    6. }
    UPDATE : To fix filtration on DX9 render need to match pixels to texels using 0.5f offset.

    I am still not sure and will test more, thanks for help. Would be nice finally to hear right solution from Unity developers too.
     
    Last edited: Apr 7, 2015
  25. originalterrox

    originalterrox

    Joined:
    Feb 6, 2015
    Posts:
    40
    When you move an object around you will get fuzzy pixels as it smooths between fractions. Pixel Snap will avoid that. You might not notice it until you have some combination of screen scrolling and objects moving slowly, but once you do notice it you will not like it.
     
  26. TruffelsAndOranges

    TruffelsAndOranges

    Joined:
    Nov 9, 2014
    Posts:
    92
    No new words on making pixel snap work correctly? I have the weird lines even to this day. Unity devs, where are you now?
     
  27. IsaiahKelly

    IsaiahKelly

    Joined:
    Nov 11, 2012
    Posts:
    333
    Have you read the recent blog post on the subject? Lots of good information in that.

    Pixel Perfect 2D
     
  28. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    527
    What's the big issue? Use that omnipresent formula to scale your viewport:

    Camera Size = x / ((( x / y ) * 2 ) * s )
    Where:
    x = Screen Width (px)
    y = Screen Height (px)
    s = Desired Height of Photoshop Square (px)
    https://indiehoodgames.wordpress.co...t-calculator-for-orthographic-camera-unity3d/

    Additionally:
    if you pixelsnap your camera too you can even toss in bilinear filtered stuff in without jitter on edges to between point filtered stuff

    I even used it to create a pixelperfection with a tilted camera (although there are some more things you need to consider with a tilted cam)
     
  29. TruffelsAndOranges

    TruffelsAndOranges

    Joined:
    Nov 9, 2014
    Posts:
    92
    Yep. I did read it. I did everything there and also copy pasted their demo source code. Still get the classical erroneous lines at some resolutions that the author of this thread writes about.
     
  30. TruffelsAndOranges

    TruffelsAndOranges

    Joined:
    Nov 9, 2014
    Posts:
    92
    As said before, this does NOT help. This formula does not work if I want to force a x b tiles (think Zelda: A Link to the Past for example) and will create the "omnipresent" lines discussed in this thread. I'll grab a few screenshots using the "omnipresent formula" for you if you want?

    AND NO. Those lines are not present in other game engines. Both LibGDX and Unreal Engine does not create these problems.

    Also. That formula is pretty stupid because you don't even need the width:
    x / ((( x / y ) * 2 ) * s ) =
    x / (( 2x / y ) * s) =
    x / (( 2xs / y ) =
    xy / (2xs) = y / 2s

    Last thing: pixel snapping does not help.
     

    Attached Files:

    Last edited: Jul 2, 2015
  31. TruffelsAndOranges

    TruffelsAndOranges

    Joined:
    Nov 9, 2014
    Posts:
    92
    The only solution I've found, as discussed earlier in other threads, is extrusion. You have to manually extrude EVERY sprite in an external program because the built-in extrusion in the "Advanced" tab does not seem to work per sprite for sprite atlases. If I extrude my sprites, in say Photoshop, the problem is gone. This solution is however VERY unpractical and is not really a good work around.
     
  32. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    527
    Hmm sorry if i sounded harsh, strange, i have never witnessed such lines, even when zooming in at 1:6x6 pixel

    upload_2015-7-3_1-37-22.png upload_2015-7-3_1-40-25.png upload_2015-7-3_1-38-0.png

    Care to share a testbuild showing the problem? I am interested in this... also i will now educate myself on sprite extrusion since i have no idea what this means in this context
     
  33. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    527
    That's a No i guess...
     
  34. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    527
    Finally i was able to see those lines for myself.
    upload_2015-7-10_4-14-29.png

    However, i had to disable pixelsnapping to make them appear, you could try my testbuild and check if those lines are still there while pixelsnapping is on.
    PixelPerfect.7z
    short description:
    -WASD- move the guy
    -keys 1-7 changes zooming (1= 1 artPx = 1x1 screenpx, 5 means 1artPx = 5x5 screenPx)
    - 1. toggle button toggles snapping in general (watch for the bilinear filtered cube while this is on and off)
    - 2. toggle button toggles whether you want pixelsnapping to be on the art-pixels(retro) or screen-pixels (smoother movement)
    - 3. toggle button toggles whether you want the character to snap to the art-pixels

    - i deliberately used a 32x40px tile to have a non power of 2 sized texture
    - 2-Scenes: 01 is Top-Down, 02 is tilted
    - Scripts contain a lot of baggage that is really only needed for my tilted setup (like the stretchfactors that are all 1F if camera is not tilted)
    - XZ-Plane is where the action happens


    If the lines still appear, well, i have no further ideas... I hope my build is at least of some use, maybe i'm deluded but it seems to achieve pixel-perfect rendering unless my eyes are actually potatoes :D

    EDIT: Updated the UI to have a toggle for the ActorSnappingMode (previously there was only ArtPx snapping or no snapping fo the actor)
     

    Attached Files:

    Last edited: Jul 13, 2015
    TruffelsAndOranges likes this.
  35. TruffelsAndOranges

    TruffelsAndOranges

    Joined:
    Nov 9, 2014
    Posts:
    92
    Hey Marrt! Didn't check this thread since I solved it by having my camera snap perfectly to pixels while only supporting 1366x768 and then render that camera to a quad. I could then use a second camera to look at that quad and then change that seconds cameras viewport and adding black borders to support any screen ratio. The math got a bit complicated when I tried to support pixel perfection on any screen ratio.

    I'll check your script as fast as I can. :)
     
  36. AssembledVS

    AssembledVS

    Joined:
    Feb 23, 2014
    Posts:
    229
    I have never seen such lines in my project and was curious if I would see them in Marrt's project. They only appear if:

    - I do not have "maximized on play" enabled, or in other words, if the resolution is not the target resolution
    - Actor snapping is turned off

    Otherwise, there are no lines at any zoom level.
     
  37. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    527
    Actually this is a whole project, If you want something more useable you can take this script, it is simplified for 2D.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.UI;
    4.  
    5. //PixelPerfect Camera in Unity
    6. //from Marrt
    7.  
    8. public    enum SnapMode {SnapToScreenPixel, SnapToArtPixel};
    9.  
    10. public class PixelPerfect : MonoBehaviour {
    11.  
    12.     public    static PixelPerfect instance;    //make sure only one instance of this script exists
    13.  
    14.     //PIXELPERFECT VIEWPORT
    15.     public    Camera        cam;
    16.     public    Transform    camAnchor;
    17.  
    18.     public    Transform    followTarget;
    19.  
    20.     public    SnapMode snapMode = SnapMode.SnapToArtPixel;
    21.  
    22.     //pixel perfect & zoom                                  
    23.     private    float    orthoSize;
    24.     public    float    pxPerUnit        = 16F;        //one Unity MeterSpans pxPerUnit pixels
    25.     private    float    subPixelFactor    = 2F;        //changes with zoom Level
    26.  
    27.     private    bool    pixelSnapOn = true;
    28.     private    float    snap = 0F;    //snapping grid division distance
    29.  
    30.     void Awake(){  
    31.         instance = this;  
    32.         Zoom (2F);
    33.     }
    34.  
    35.     void Update(){
    36.         if(Input.GetKeyDown("1")){Zoom(1F);}
    37.         if(Input.GetKeyDown("2")){Zoom(2F);}
    38.         if(Input.GetKeyDown("3")){Zoom(3F);}
    39.         if(Input.GetKeyDown("4")){Zoom(4F);}
    40.         if(Input.GetKeyDown("5")){Zoom(5F);}
    41.         if(Input.GetKeyDown("6")){Zoom(6F);}
    42.         if(Input.GetKeyDown("7")){Zoom(7F);}  
    43.     }
    44.  
    45.     void LateUpdate(){
    46.         //camerafollow
    47.         if(pixelSnapOn){
    48.             camAnchor.position = snapMode == SnapMode.SnapToArtPixel?    RoundToArtPixelGrid(followTarget.position) : RoundToScreenPixelGrid(followTarget.position);
    49.         }else{
    50.             camAnchor.position = followTarget.position;
    51.         }
    52.     }
    53.    
    54.     private    void Zoom(float subPxFactor){
    55.         print("Pixel 1:"+subPxFactor+"x"+subPxFactor);
    56.         orthoSize    = GetPixelPerfectOrthoSize(subPxFactor);  
    57.         StartCoroutine(ZoomTransition());
    58.     }
    59.  
    60.     private    IEnumerator ZoomTransition(){ //during transition, we cannot be pixelperfect  
    61.         float timer = 1F;
    62.         while(timer >0F){
    63.             cam.orthographicSize = Mathf.Lerp(cam.orthographicSize, orthoSize, Time.deltaTime *10F);
    64.             timer-= Time.deltaTime;      
    65.             yield return null;
    66.         }  
    67.         cam.orthographicSize = orthoSize;
    68.     }
    69.  
    70.     private    float GetPixelPerfectOrthoSize(float screenPixelPerSpritePixelWidth){
    71.    
    72.         subPixelFactor = screenPixelPerSpritePixelWidth;    //1 means 1ArtPixel = 1 ScreenPixel, 2 means 1 Art = 2x2 Screen  
    73.         float s = pxPerUnit *subPixelFactor;  
    74.         snap = 1F/pxPerUnit    /subPixelFactor;
    75.    
    76.         print ("PixelWidth in World Coordinates:("+snap);          
    77.         return cam.pixelHeight / s / 2F;
    78.     }
    79.  
    80.     //Snapping function 1, snaps Camera to Screen Pixels
    81.     public    static Vector3 RoundToScreenPixelGrid(Vector3 worldPos){
    82.         float snapArt    = PixelPerfect.instance.snap;
    83.         return new Vector3(    Mathf.Round( worldPos.x / snapArt    )    *snapArt,
    84.                             Mathf.Round( worldPos.y / snapArt    )    *snapArt,
    85.                             Mathf.Round( worldPos.z / snapArt    )    *snapArt);
    86.     }
    87.  
    88.     //Snapping function 2, snaps Camera to Art Pixels
    89.     public    static Vector3 RoundToArtPixelGrid(Vector3 worldPos){
    90.         float snapArt    = PixelPerfect.instance.snap * PixelPerfect.instance.subPixelFactor;
    91.         return new Vector3(    Mathf.Round( worldPos.x / snapArt    )    *snapArt,
    92.                             Mathf.Round( worldPos.y / snapArt    )    *snapArt,
    93.                             Mathf.Round( worldPos.z / snapArt    )    *snapArt);
    94.     }
    95.    
    96.     //UI-Button Functions
    97.  
    98.     public    void PixelSnapOn(bool on){
    99.         pixelSnapOn = on;
    100.     }
    101.  
    102.     public    void ToggleSnappingMode(bool art){
    103.         if(art){
    104.             snapMode = SnapMode.SnapToArtPixel;
    105.         }else{
    106.             snapMode = SnapMode.SnapToScreenPixel;
    107.         }
    108.     }
    109. }
    110.  
    You can snap every positionVector to your Artworkpixels by calling
    Code (CSharp):
    1. yourTransform.position = PixelPerfect.RoundToArtPixelGrid(yourTransform.position);
     
    Last edited: Jul 23, 2015
    BusyCat likes this.
  38. Douvantzis

    Douvantzis

    Joined:
    Mar 21, 2016
    Posts:
    73
    The PixelSnap option found in the default sprite shader only helps with the shimmering artifacts when translating a sprite in a non pixel-perfect resolution. It does not make the sprites render in a pixel perfect way.

    In order to achieve a pixel-perfect rendering, you need to have each texture pixel rendered to an integer multiple of screen pixels. The code posted by Coah, seems to achieve this. I have created a simple free camera script that works on that principle that allows you to set a desired camera size and it chooses the closest pixel-perfect size for the orthographic camera. You can get it for free from the asset store and read a deeper explanation of the problem on my blog post.
     
    CarterG81 likes this.
  39. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,720
    Thanks for the resource! It is always great when we contribute together to resolve problems like this, rather than hide in our dungeons like a mad scientist with the world's only cure.

    "It's all MINE! Bwahahahahaha!"