Scaling 240 vertical resolution to 1080

Hello everyone,

I considered making my game in 384 x 216 or 480 x 270 for easy scaling to 1920 x 1080 but 384 x 216 seems too small and 480 x 270 seems too large. I noticed some games use 240 vertical resolution and I think this would be the best for my game also. I could be wrong but I think Shovel Knight and Bloodstained Curse of the Moon use a 240 vertical resolution.

My question is how do you scale this up to 1080 without it looking bad (since 240 doesn’t scale up to 1080 by a whole number)? It looks great in those games but I don’t know how they do it.

Any advice or insight is greatly appreciated.

By using an anti-aliased upsample of the point sampled (aka nearest neighbor) scaled up original.

I posted an example shader here:

1 Like

That is wonderful! Thank you so much bgolus!!

I tried the example shader and I think it is working as far as the anti-aliasing goes but the transparency of the sprite is showing up as black and if I flip the sprite by setting the x localscale to -1 I can’t see the sprite anymore.

I figure I didn’t set it up correctly. Do you have any idea what could be causing that?

You should render your entire game to a render texture at your internal 240 resolution and then upscale that using that shader, not apply it to your sprites/tiles.

1 Like

The shader in that thread is showing off a technique, it’s not intended to be a useful shader as is. You’d need to apply the technique being used to a copy of the default Sprite shader, or maybe buy the Retro AA asset from the Unity asset store which has a similar shader.

That depends on what you’re trying to go for. If you want something like shovel Knight where it’s being rendered at low resolution, but not look bad when scaled up to fill the screen, sure. If you want just the blocky look of sprites but displayed at high resolution and able to move smoothly across the screen, then using that technique on each Sprite is what you want.

1 Like

Ok I misunderstood that. I will just pick up Retro AA, that should be great.

As far as the Render Texture goes that makes sense. I’m not sure how to set that up though. I have seen it used for making a security camera footage displayed on a monitor in a game, but what is the best way to have that be full screen and the only thing that is seen? I mean, do you just position the main camera perfectly in front of it or is there a better way to do that?

Unity’s Pixel Perfect Camera script has an option for Upscale Render Texture, which I think does what you are saying but how do I apply a shader to that?

Or do I just need to have two cameras and have one render the scene to a texture, and put the texture on a cube and put my other camera in front of that and put the material with the AA shader on the cube?

There’s no reason why Unity’s Pixel Perfect Camera couldn’t be doing this, or something like it, without two cameras. So it’s unfortunate that they don’t. You could probably modify the scripts to make it use this kind of shader when upscaling, but I don’t know how exactly to do that.

BTW, there’s a second option for upscaling a low resolution pixel art render texture that results in a very similar look to using the shader.
Upscale from the original size to the closest integer multiple to the display resolution using point filtering, then scale the rest of the way up using bilinear filtering. This is how Shovel Knight did it. It’s a little easier to implement, though does use a little more GPU memory. Usually pixel art games aren’t super concerned with how much GPU memory they’re using since the entire game can usually exist in the RAM of any modern GPU.

1 Like

That is interesting. I’m not worried about GPU memory for my game. How would you actually set something like that up?

And I was wondering if this could be done as a post processing effect? I saw a script someone made that you attach to your camera and slot in a shader. The script creates a material and applies that shader and then applies it in the OnRenderImage method. Would that technique work for this or is that for something else?

It’s not something that can be done easily as a “post process”, not in terms of something you could do after the Pixel Perfect Camera has already run. Ideally it’d be something that could be injected at the point that the low resolution pixel perfect render texture is rendered back to the full screen resolution frame buffer / render texture. But as best I can tell this step is done by the compiled .asmdef file and not in the c# script making it impossible to augment in a nice way.

1 Like

update: Looks like @customphase ran across this exact problem back in 2018 and came up with a work around.
Pixel Perfect Preview Package page-3#post-3759499

1 Like

It’s very easy to upscale a low-resolution render with sharp pixelated edges in the built-in render pipeline:

//built-in RP only!

RenderTexture rt;
Camera cam;

void Start() {
    rt = new RenderTexture(320, 240, 24);
    cam = GetComponent<Camera>();
}

void OnPreRender() {
    cam.targetTexture = rt;
}

void OnRenderImage(RenderTexture source, RenderTexture destination) {
    Camera.targetTexture = null; //so that our rendered image actually appears onscreen
    //copy our rendered image from the RenderTexture to the display backbuffer
    source.filterMode = FilterMode.Point;
    Graphics.Blit(source, (RenderTexture)null);
    RenderTexture.active = rt;
}

This is similar to what bgolus suggested, “Upscale from the original size to the closest integer multiple to the display resolution using point filtering”, although this example doesn’t automatically use a multiple of the display resolution.