Scaling in Bitmap Based Games

Hi Guys,

So, I'm working on a Pixel Art game and I am just wondering when working with Bitmaps how do you deal with scaling? I'm concerned because it seems like the Pixel Art can only be scaled by a whole number amount (with Nearest Neighbor Filtering), in order to perfectly preserve the look of the Sprite. I think in Handmade Hero Day 109 Casey mentioned that for a game like HmH which uses relatively high resolution bitmap graphics, he doesn't really care about blur from scaling since the Bilinear Filtering does a good enough job, and he likes the ability to have arbitrary scaling, but does this apply for things like Bitmap Fonts and Pixel Art also? I assume since Pixel Art is so low res, it may make more sense to just scale to the nearest whole number multiple then add black bars as needed as opposed to having arbitrary scaling? however, i don't really have an intuition on how scaling would effect bitmap fonts; it seems to me like it would get pretty blurry if scaled up too big, but I didn't find Casey talking about it in the Archive (is this another thing where HmH doesn't need to worry about it cause it uses High Reso textures?).

Edited by Draos on Reason: Initial post
Yes, nearest-neighbor filter is your best choice if you want to preserve blocky pixel art look.

But if that is not a requirement then there are some fancy upscaling algorithms you can use. Note that they won't look like pixel art when scaled up, but they won't be blurry.

Examples:
hqx (2x, 3x, 4x scaling) - https://en.wikipedia.org/wiki/Hqx
waifu2x (DNN based scaler) - https://github.com/nagadomi/waifu2x
pixscaler (also DNN based) - https://github.com/mitaki28/pixcaler
depixelizing pixel art - https://johanneskopf.de/publications/pixelart/
Some of them are offline based, but I'm sure that with some effort they can be converted to real-time algorithms.

See more: https://en.wikipedia.org/wiki/Pixel-art_scaling_algorithms




Edited by Mārtiņš Možeiko on
as for bitmap fonts, would it just be best to have the font be at a size that looks good at all my target resolutions. in HmH the fonts look pretty good at 1080p the target resolution, but I have no clue if it would be blurry or pixelly on say a 4K display, etc if scaled up. it seems to me like just scaling a bitmap font will inevitably result in a pixelly look. so is it worth it to just make the bitmap font texture huge, so we don't need to upscale? or do bitmap fonts tend to look ok with bilinear filtering?

also thanks! i'll experiment with those filters.

Edited by Draos on
Unless you plan to support any unicode symbol possible, the size of font texture does not really matter. It will be small compared to all the other assets you have in the game. So I would not worry about texture size for fonts.
Here's one more DNN based: https://www.resetera.com/threads/...mes-you-can-do-it-yourself.88272/
Pretty good looking results - check other pages on its topic.

Edited by Mārtiņš Možeiko on
There is a single texture sample technique for preserving the pixel art look (but also maintaining quality) at non-integer scales. Here's a demo:



This technique has been discussed by d7 at times, and he has even prepared a Shadertoy that allows you to check out both the effect and the implementation. Check it out here: https://www.shadertoy.com/view/MlB3D3

Edited by Ryan Fleury on
Delix
There is a single texture sample technique for preserving the pixel art look (but also maintaining quality) at non-integer scales. Here's a demo:



This technique has been discussed by d7 at times, and he has even prepared a Shadertoy that allows you to check out both the effect and the implementation. Check it out here: https://www.shadertoy.com/view/MlB3D3


What are the drawbacks aside from the very minor (if barely perceptible) warping? Is there any performance cost?

Edited by NelsonMandella on
NelsonMandella
What are the drawbacks aside from the very minor (if barely perceptible) warping? Is there any performance cost?


To be honest, I'm not sure I know which warping you're speaking of. What are you referring to here?

The performance cost is of course nonzero; however, the technique just requires some additional arithmetic without branching. I haven't measured it, though, as it has not been an issue for me.
Delix
NelsonMandella
What are the drawbacks aside from the very minor (if barely perceptible) warping? Is there any performance cost?


To be honest, I'm not sure I know which warping you're speaking of. What are you referring to here?

The performance cost is of course nonzero; however, the technique just requires some additional arithmetic without branching. I haven't measured it, though, as it has not been an issue for me.


Thought I noticed some subtle wobbling, but now I'm not so sure having just watched it again. Guess I'll have to give it a go myself to assess the performance implications. Anyways, thanks a lot for bringing it to everyone's attention!
Hey Ryan,

I'm wondering how you deal with edges of objects using this algorithm. I'm currently using it in my game and as a result of the blending between neighboring pixels, at the edge of tiles(using a tilemap) I either get gaps(if I set source pixels that lie outside of the tile to (0, 0, 0, 0)) or I get jiggling(if I just clamp the uvs).

I know one solution is to add padding around objects in the art so they that blend how you expect them to, but it doesn't seem like this would work in cases where tiles need to be seamless with more than one other tile.

The rendering in your game seems to have less issues(none as far as I can see in your videos) than mine, so I'm wondering if you address this or just avoided it altogether. Maybe I'm missing something?
Hey Bok! Sorry for the late response, just saw this.

I also had issues with this. I solved this issue by compositing tiles at an integral offset to a texture, then rendering that texture at the correct fractional offset with the technique.
Delix
Hey Bok! Sorry for the late response, just saw this.

I also had issues with this. I solved this issue by compositing tiles at an integral offset to a texture, then rendering that texture at the correct fractional offset with the technique.


Thanks for the reply!

I'm still struggling to get a good result with this technique on my tiles. Would you mind going into more detail on this? I assume this requires you to collect all the tiles currently visible on the screen and render them to a texture(screen sized?) at an integral offset AND an integer scale? You would need to do this per "layer" in your world in order to render transparency correctly, right?

It seems like I've made some technical decisions that are making this very difficult on me, which perhaps you don't have:
- My world is composed of multiple tilemaps, so even if I composited each tilemap to a texture like you said, I would get seams in between tilemaps. So I figure I have to do this in screen space.
- My tilemaps are made up of multiple layers which can go either behind or in front of non tilemap entities(top down game). So I'd have to do this per layer, and even then, some tiles are meant to be connected but also require being on different layers(imagine a vertical column where the base is meant to be behind the player depending on where they're standing, but the top is meant to always be in front). These would have a visible gap where they're on different layers.
- The middle layer, which is meant to be on the same plane as the player and other entities, has to be sorted based on y position, so drawing this entire layer at once(after compositing to a texture), doesn't seem possible since the tilemap and the entities moving around aren't necessarily at the same fractional offset.

Let me know if I'm missing something obvious, this just seems very difficult to do perfectly in my situation. I'm still using it on non tiled entities and just snapping the camera to pixel locations, it looks great, but I'm obviously unable to zoom in/out without issues.