Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Smooth Movement vs Pixel Perfect Sprites Need Help!

Discussion in '2D' started by illMadeCoder, Jan 5, 2016.

  1. illMadeCoder

    illMadeCoder

    Joined:
    Mar 20, 2015
    Posts:
    3
    Hello Unity Forum,

    (I really need help so I'm going to go into the best detail I can.)

    I've spent about 10-15 hours on this over the last two days and I'm simply stuck between a rock and a hard spot at this point, and I'd rather just have the best of both worlds. Either the sprites in the project I started have to be blurred by the bilinear filter mode for smooth movement, or with point (no filter) I can achieve pixel perfect looking sprites with https://www.assetstore.unity3d.com/en/#!/content/14498 BUT the downside is that the movement becomes much more discrete looking, you can sort of see the pixels snap into place after each movement.

    I'll talk about both solutions and hopefully someone can help me out.

    Before we get into it here's the sprite sheet I'm working with --

    And the script for movement in case that matters to someone --

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class PlayerController : MonoBehaviour
    5. {
    6.     private Transform _Transform;
    7.     private Rigidbody2D _Rigidbody2D;
    8.     private SpriteRenderer _SpriteRender;
    9.     [SerializeField] private Sprite[] _sprite = new Sprite[3]; //down, up, right
    10.     [SerializeField] private float speed = 3f;
    11.     private Vector2 moveVector;
    12.  
    13.     void Start()
    14.     {
    15.         _Transform = GetComponent<Transform>();
    16.         _Rigidbody2D = GetComponent<Rigidbody2D>();
    17.         _SpriteRender = GetComponentInChildren<SpriteRenderer>();
    18.     }
    19.  
    20.     void Update()
    21.     {
    22.         float xInput = Input.GetAxisRaw("Horizontal"), yInput = Input.GetAxisRaw("Vertical");
    23.  
    24.  
    25.         if (xInput == 1 || xInput == -1)
    26.         {
    27.             _SpriteRender.sprite = _sprite[2];
    28.             if (xInput == 1)
    29.                 _SpriteRender.flipX = false;
    30.             if (xInput == -1)
    31.                 _SpriteRender.flipX = true;
    32.         }
    33.         if (yInput == -1)
    34.             _SpriteRender.sprite = _sprite[0];
    35.         if (yInput == 1)
    36.             _SpriteRender.sprite = _sprite[1];
    37.  
    38.  
    39.         moveVector = new Vector2(xInput, yInput);
    40.         //_Rigidbody2D.velocity = moveVector * speed;
    41.     }
    42.  
    43.     void FixedUpdate()
    44.     {
    45.         MoveRigidBody();
    46.     }
    47.    
    48.  
    49.     void MoveRigidBody()
    50.     {
    51.         _Rigidbody2D.velocity = moveVector * speed;
    52.     }
    53. }
    ---------------------------------------------------------------------------------------------------------------------------------------------

    Solution (1) : Smooth but Blur
    Build -- https://drive.google.com/file/d/0BxVy31mpcFlXZGwzM285ZWtycjQ/view?usp=sharing

    This is probably the better of the two solutions except besides the blur it has one obvious flaw I'll get into later.

    Firstly, here are the settings I'm using on the sprites --
    BlurButSmoothSettings.PNG

    and here is the point filter version of the sprite
    BlurButSmoothBLURRY.PNG

    Importantly the PPU is 32 and the camera is a size 12 and the resolution is 1024x768.

    The blur is annoying but acceptable if not for the fact that depending on where the sprite is on the screen it goes between crisp and blur. I have no idea why, here's an example.

    From This: (Crispy) BlurButSmoothCrisp.PNG to this (Blurry) BlurButSmoothBLURRY.PNG with only a side step.

    I don't like it being blurry but if it has to be for smooth movement I'd make the sacrifice but it at least needs to be consistently blurry.

    ---------------------------------------------------------------------------------------------------------------------------------------------


    Solution (2) : Crisp but Stutter
    Build -- https://drive.google.com/file/d/0BxVy31mpcFlXUWpJOUtNdWFGX1E/view?usp=sharing

    If I could simply remove the small stutter this would be the perfect solution I prioritize smooth movement over crisp sprites.

    With this solution I switch the filter mode to point (no filter)

    And suddenly like magic the sprite becomes crispy and everything gets hopeful until I start the build and begin to move and look closely at the sprite. The movement seems a bit janky, like there interpolation becomes bad, it's a consistent jank but it's certainly there. It becomes more obvious when you filter the sprite then put both side by side, with a blur it is smooth, without there is bad interpolation.

    I purchased Pixel Perfect by Pixelatto hoping that would help but the stutter still seems to be there with the pixel perfect script on the sprite and camera.

    ---------------------------------------------------------------------------------------------------------------------------------------------



    Extras:
    Just in case it matters here are the quality settings --

    qsettings.PNG


    I've tried playing with the camera size, the PPU, the pixel snap material, the compression size, the format, and finally I've played around with the mip map setting.

    Hopefully I didn't miss anything, I've read just about every other forum on this as well.

    Thanks for any help you can contribute, I really appreciate it.
     

    Attached Files:

    Last edited: Jan 6, 2016
  2. illMadeCoder

    illMadeCoder

    Joined:
    Mar 20, 2015
    Posts:
    3
    I'd like to bump this once to see if there's any suggestions and to add a poor fix to the problem. I've introduced a new script which will turn on the bilinear filter while moving on the x axis. It still makes the sprite very blurry but I think it's the best option I have so far. A huge disadvantage of this is that any sprites on the spritesheet will be blurred during this so the sprites need to be cut into separate spritesheets.

    Here's the script

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class FilterMove : MonoBehaviour
    5. {
    6.     private Sprite _sprite;
    7.     private Rigidbody2D _rigidBody2D;
    8.  
    9.     void Start ()
    10.     {
    11.         _sprite = this.gameObject.GetComponent<SpriteRenderer>().sprite;
    12.         _rigidBody2D = this.gameObject.GetComponentInParent<Rigidbody2D>();
    13.     }
    14.    
    15.     void Update ()
    16.     {
    17.         if (_rigidBody2D.velocity.x != 0)
    18.             _sprite.texture.filterMode = FilterMode.Bilinear;
    19.         else
    20.             _sprite.texture.filterMode = FilterMode.Point;
    21.     }
    22. }
     
  3. MoonJellyGames

    MoonJellyGames

    Joined:
    Oct 2, 2014
    Posts:
    324
    I managed to get a pixel-perfect look, but my game has a completely static camera, so if yours moves, you'll likely need to have something in your camera's update that rounds its position to the nearest something (I don't know what exactly). Anyways, this is how I set it up:

    - Point filtering
    - No mipmaps
    - Disable anti-aliasing
    - Sprites imported at 32 px/unit
    - Camera orthographic size: (Screen.height / 2 / pxPerUnit)
    - Camera position: (0.01, 0); I absolutely hate this, but for some reason, my sprites don't quite display properly when the camera is at (0, 0).
    - Resolution: 1366x768 (my laptop's resolution)
    - Sprites have a material with PixelSnap enabled
    - Sprite sheet atlases are all power of 2 in size. I think this may be unnecessary though...
    - What is important (I think) is that each sprite on the sheet is drawn within a power of 2-sized cell. So if your sprite is 18x20, you'll have to draw it at the centre of a 32x32 cell.

    Also note that since upgrading to Unity 5 my moving sprites do not appear pixel-perfect in the editor unless I either remove the PixelSnap material or change the display resolution to Free Aspect. In builds of the game, however builds of the game will display properly with the above-listed settings.

    One last thing is that I have some collision objects with "Continuous" collision detection. These objects look distorted with PixelSnap material, so I use the default for them. I don't expect them to look pixel-perfect anyways because they are round and are often rolling around (rotation is always going to cause some distortion).

    Anyways, maybe that'll give you a few more things to play around with.
     
    Last edited: Jul 15, 2016
    theANMATOR2b likes this.
  4. fadden

    fadden

    Joined:
    Feb 11, 2015
    Posts:
    13
    theANMATOR2b likes this.
  5. Douvantzis

    Douvantzis

    Joined:
    Mar 21, 2016
    Posts:
    79
    On top of jester-race's answer, I'll dig a bit deeper on setting the camera's orthographic size.

    In order to achieve a pixel-perfect result, each sprite pixel must be rendered to an integer multiple of screen pixels. Having this in mind, you have to make the correct calculations and adjust the camera's size to achieve that. To achieve that, you should know the camera's render size, your asset's pixels per unit and chose a desired camera size.

    I have created a simple free camera script that just these calculations for you. You can get it for free from the asset store and read a deeper explanation of the problem on my blog post.

    Check out this HTML5 demo. If you switch off the pixel perfect mode, you'll notice the same artifacts that you describe.