Using Pixel Perfect Camera with various resolutions and applying the custom camera scale

Using Pixel Perfect Camera with various resolutions and applying the custom camera scale.

I have found a lot of different information about using Pixel Perfect Camera in Unity, but I realize that there are many possible problems and constraints with using it. So I’ll ask a question for my individual case.

Problem and setup

I’ve seen a lot of similar questions, but after trying to implement this in different ways, I saw that it still carries a lot of limitations.

  1. I have characters sprite atlases where each sprite is 128x128px, also I have other atlases for smaller/bigger world objects (64x64px & 256x256px accordingly).
  2. I set the PPU to 128 for all my sprites and turned off compression.
  3. In the sprite editor I set all pivots in pixel units. Then I added pixel perfect camera to the main camera (I do not use Cinemachine virtual camera).
  4. Pixel Perfect Camera Settings :

PPU : 128
Ref Resolution : X = 1920; Y = 1080
Crop Frame : None
Grid Snapping : Upscale Render Texture

So my pixel perfect camera works correctly except for the main problem - the camera zoom.

My characters and objects are too close to the camera, but I do not want to change their scales or sprite sizes. I also tried to set other PPU values but there are the same result or other problems appear.
I also tried to implement the pixel perfect camera logic without using the build in component itself, but there is the player jittery diagonal movement appears (I know that this is the correct behaviour but I do not want that).

So my final solution was to mannualy update Pixel Perfect Camera → Reference resolution using a script.
I noticed that when I set this settings in the PPC :

PPU : 128
Ref Resolution : X = 3840; Y = 2160
Crop Frame : WindowBox
Grid Snapping : Upscale Render Texture

Everything looks as I want It to (in 1920x1080 resolution) in 3840x2160 it is zoomed in again, so there is a certain pattern here, if I set the Reference Resolution to 2 times (or another value for scale correction) the screen size through the script, I get the desired camera distance.

Script :

[RequireComponent(typeof(PixelPerfectCamera))]
public class AutoCorrectResolution : MonoBehaviour
{
    private PixelPerfectCamera _pixelPerfectCamera;

    private int _lastScreenWidth;
    private int _lastScreenHeight;


    private void Awake()
    {
        _pixelPerfectCamera = GetComponent<PixelPerfectCamera>();
        UpdateReferenceResolution();
    }

    private void Update()
    {
        TryUpdateReferenceResolution();
    }

    private void TryUpdateReferenceResolution()
    {
        if ((Screen.width != _lastScreenWidth) || (Screen.height != _lastScreenHeight))
        {
            UpdateReferenceResolution();
        }
    }
    private void UpdateReferenceResolution()
    {
        _pixelPerfectCamera.refResolutionX = Screen.width * 2;
        _pixelPerfectCamera.refResolutionY = Screen.height * 2;

        _lastScreenWidth = Screen.width;
        _lastScreenHeight = Screen.height;
    }
}

Main question according to the problem

Is my solution acceptable in this situation, or is it too much of a stretch and it is worth doing something different? I have tried many different solutions and only this approach has given the required result, maybe I’m missing something?

P.s. I apologize if I have described something wrong or not mentioned, it is my first time working with Pixel Perfect and I’m asking a question on the forum, so I hope it’s okay.

TL; DR: try using 640x360 reference resolution at 64 ppu with 32x32 character sprites. Or use a non pixel perfect workflow

Reference resolution for pixel perfect isn’t what you think it is.

Pixel perfect essentially means the pixels scale and move perfectly based on the reference resolution vs game resolution. For the scaling and movement to be perfect, the game resolution / reference resolution must be an integer. You are doing the opposite or something

To get an integer multiple, we must choose a sufficiently small reference resolution that is big enough to contain enough detail for our game that is an integer scale of our target monitor resolutions(usually 1080p, 1440p, 2160p). Usually people go with 640x360 reference resolution because it scales to 720p,1080p,1440p,2160p perfectly

For ppu people usually go with 64 or 100(I had issues with 128ppu possibly because grid snapping can’t handle 1/128f without floating point precision issues not 100% sure)

At 640x360 with 64ppu your game view camera view will show 360/64=5.625 world units in Y axis. If your characters are 32x32, you can stack about 11 characters on top of each other compared to your 8.44 with 1080p ref resolution or ~16.88 with 2160p ref resolution.

If you dont want to lose the detail of 128x128 character sprites compared to 32x32 sprites you should just go with non pixel perfect workflow. Usually developers create sprites for the largest target resolution which shows the entire detail of the sprites. The sprites automatically scale down and lose the detail when the game resolution is lower than target resolution(they start showing subpixels). For subpixels at the highest target resolution they just paint the sprites for 2x resolution and scale the gameobjects by 0.5

(skip the rest if you don’t care why your characters are big)

Why you are getting big characters:
If your reference resolution is something as large as 1080p and you use 128ppu the camera view(independent of the game resolution) will occupy 1080/128 = 8.4375 world units in Y axis. Since your character sprites are 128x128(i.e. 1 world unit) you can stack about 8.5 characters on top of each other.

What you can do to decrease character size in game view is:

  • increase your reference resolution(incrases camera’s world units) – not recommended
  • decrease ppu(increases camera’s world units) – not recommended
  • decrease character pixel sizes(decreases character’s world units)

Cheers

2 Likes

Thanks for the reply, I guess I’ll have to resize the sprites or stop using Pixel Perfect. Now I understand the problem better and will try to solve it in a normal way.

1 Like