# Pixel Perfect Camera - Optimization for seamless camera movement

Hi everyone!

I am working on a 2D Pixel-Art game using the pixel perfect camera component with “upscale render texture” checked - which i seem to need to keep my particles and rotating objects pixel perfect.
What i do not like about this however is that the camera movement now snaps to pixels (i understand why this is happening but want to get rid of it).

During my research i found out about a technique how to achieve this in gamemaker and i was wondering how i could translate that to unity. As far as i understand they resize the camera output texture to screen size + 1px and then they move the camera in whole pixel amounts and for subpixel-movement they offset the output texture instead.
Here is the link to the tutorial.

My idea on how to achieve this for unity camera (with URP) was to modify the viewport rect of the camera but unfortunatly that does not seem to work with the pixel perfect camera component.

The following code shows no effect when the pixel perfect camera component is enabled but it does work when it is turned off:

``````{
viewportXOffset += 0.001f;
myCamera.rect = new Rect(viewportXOffset, -0.1f, 1.1f, 1.1f);
}
``````

Do i have to render my camera output to a rendertexture which i then offset instead? Wouldn’t that be pretty performance heavy (i am targeting mobile devices)?

I really hope somebody can help. I spend weeks on my Camera-Script already and now i am all out of ideas.

Best regards and thanks in advance.

Here is a code snippet s a starting point and to make my question more clear. I want to make something like this work:

``````private void Start () {
float viewportXSize = (myCamera.pixelWidth + 1f) / myCamera.pixelWidth;
float viewportYSize = (myCamera.pixelHeight + 1f) / myCamera.pixelHeight;
}

private void FixedUpdate () {
//Positioning stuff...

unroundedPosition = new Vector3(x, y, cameraContainer.position.z);
roundedPosition = new Vector3(RoundToNearestPixel(x), RoundToNearestPixel(y), cameraContainer.position.z);
Vector3 roundedOffset = unroundedPosition - roundedPosition;

cameraContainer.position = roundedPosition;
myCamera.rect = new Rect(roundedOffset.x, roundedOffset.y, viewportXSize, viewportYSize);
}

public static float RoundToNearestPixel(float unityUnits)
{
float valueInPixels = (Screen.height / (myCamera.orthographicSize * 2)) * unityUnits;
valueInPixels = Mathf.Round(valueInPixels);
float adjustedUnityUnits = valueInPixels / (Screen.height / (myCamera.orthographicSize * 2));
}
``````

I searched the same thing and found that reddit post but also found this Reddit - Dive into anything haven’t tested it yet but guess its the same thing?

1 Like

Thanks for your suggestion and for sharing the link.
I tried the script and it show’s no effect in my project. Unity API states that “OnRenderImage” is not supported when using Universal Render Pipeline and that ScriptableRenderPass should be used instead. However i can’t find a simple example script that shows how ScriptableRenderPass should be used…

There is also the FinalBlitPass that might be relevant for this?

Anyway after 1/2 hours after reading about all this stuff i’m done for now and may get back to it later.

After a lot of research i (kinda made it work). Screen texture is not yet scaled up correctly but the camera movement is nice and smooth.

``````using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//using UnityEngine.U2D;
using UnityEngine.Rendering;

public class SmoothPixelPerfectCameraMovement : MonoBehaviour
{
public UnityEngine.Experimental.Rendering.Universal.PixelPerfectCamera pcc;
private Vector2 viewportScale;
private RenderTexture tempRenderTexture;
private Camera myCamera;
private int width, height;

private void Start()
{
myCamera = Camera.main;
SetWidthAndHeight();

RenderPipelineManager.beginFrameRendering += FrameRenderingStart;
RenderPipelineManager.endFrameRendering += FrameRenderingEnd;
}

private void OnDestroy()
{
RenderPipelineManager.beginFrameRendering -= FrameRenderingStart;
RenderPipelineManager.endFrameRendering -= FrameRenderingEnd;
}

private void FrameRenderingStart(ScriptableRenderContext context, Camera[] cameras)
{
if(width != Screen.width || height != Screen.height)
SetWidthAndHeight();

tempRenderTexture = RenderTexture.GetTemporary(width, height, 16);

//you only need to change texture format if you want to use HDR colors e.q. with Glow Post Processing
if(SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.RGB111110Float))
{
tempRenderTexture.format = RenderTextureFormat.RGB111110Float;
} else { Debug.Log("RenderTexture format not supported"); }

myCamera.targetTexture = tempRenderTexture;
Graphics.SetRenderTarget(tempRenderTexture); //dont think this is actually needed
}

private void FrameRenderingEnd(ScriptableRenderContext context, Camera[] cameras)
{
myCamera.targetTexture = null; //blit directly into render buffer
Vector2 screenWorldBounds = new Vector2(myCamera.orthographicSize * 2 * Screen.width / Screen.height, myCamera.orthographicSize * 2);
Vector2 direction = new Vector2(Mathf.Round(transform.position.x * pcc.assetsPPU) / pcc.assetsPPU - transform.position.x, Mathf.Round(transform.position.y * pcc.assetsPPU) / pcc.assetsPPU - transform.position.y);
Graphics.Blit(tempRenderTexture, null as RenderTexture, Vector2.one, -(direction / screenWorldBounds));

RenderTexture.ReleaseTemporary(tempRenderTexture);
}

private void SetWidthAndHeight()
{
width = Screen.width;
height = Screen.height;
}
}
``````

Unity does all this automagically now. Just check the pixel snap option in your sprite material.

Why would a sprite setting influence the camera movement?
Anyway pixel snap seems to be disabled on the URP sprite materials.

I have also been wondering about this, and the post here actually confirmed my initial idea on how to go about doing this. But more I think about it, this should really be supported by the Unity… anyway, I am also gojng to try my work around soon.

1 Like

Sprites that are not snapping to “pixel” (an xy position that is a division of the PPU) tend to move around in the camera view from pixel to pixel when moving the camera at slow speeds. Sprites that are positioned at an exact division of a unit will stay in place.

Unity, please make it a feature. It is crucial for pixel-perfect-camera package. Crucial.

Can you trying using Pixel Snapping as the Grid Snapping option to see if this mitigates the issue you are having. If not, I’ll add to our backlogs as a feature request.

I tried all Pixel Perfect Camera settings before diving into custom solutions but pixel snapping looks really bad imo when having small amount of PPU and slow camera movement, since the jumping between the pixels is highly noticable.

As i said though, my script fixed the problem for me. However this seems to work with Unity Version 2020.1.15f1 only - at least i kept having the problem, when i updated to a later version (which might be connected to some changes with the render pipeline or sth)…

I’d like to necro this post as a request as well.
Pixel perfection with smooth movements is highly desired. This means sub-pixels are allowed! Pixel perfect looks awful.

A game that does this well is Stardew Valley. There is no pixel morphing in that game from non-pixel perfect movements, however everything rests at a pixel perfect location. The camera is also allowed to move in sub-pixel movements which makes it feel super smooth.

This is not possible with the current implementation of PixelPerfect components

you guys are crazy, stardew valley is the farthest from pixel perfect you can get

im always saying, stop obsessing with getting your game pixel perfect, its to the point you want to copy stardew which is not pixel perfect and you dont even notice, so why do you think your players will notice your game is pixel perfect when you dont even notice it for stardew

check this if you dont believe https://imgur.com/a/zJSR5

It does do something that prevents that “shimmer” effect though.
You are right in that it is not exactly pixel perfect, but it also does something that does not cause the shimmer effect, as well as have a smooth camera. And that is something that we are all after.

thats just called a normal camera

to prevent the shimmer you just have to fix your ortographic size to a set value based on the ppu of your assets

stardew valley also has a very stable camera, it doesnt bounce, it doesnt dampen, always centered on the character, or some other object

if you ran stardew valley in windowed mode and sized it into a small window you would see shimmer too (not sure if the game allows you to do this though)

Hello, I have the same problem. The script above helped me a lot, but I still get some error messages with it, for example, the scene view is black while the game is running. Can you send me a finished version of the script, that would help me a lot.

Sorry but I abandoned the project a long time ago.
I think I did not make any big changes after posting this here. I remember that the script stopped working when I tried to update to a later version of Unity. Is using the mentioned Unity Version 2020.1.15f1 an option for you?

If so, i can provide you the script or the whole unity project to look into it.

I’m trying to solve this exact problem; this is the closest I’ve come to a possible solution.
If you could provide the project, or even just the script it would be a huge help.
I’m new to Unity so I’m way out of my depth here, but I need to use upscaling for my project and I really don’t like how jittery the camera feels.

Did you solved it?