Page 1 of 1

[Solved] Pixels dimensions not constant with setFilter("nearest","nearest")

Posted: Sun Sep 05, 2021 9:43 pm
by Eglaios
I wrote some code to change my game's scale when the window is resized, and used "nearest" filter mode.

Though, depending on how the window is resized, pixels appear to have irregular dimensions :
The same image at 3 different scales. Notice how the 2 eyes don't get the same width
Image

More than scaling, I also change drawing offset and width/height to match it, but I don't think that's very pertinent...
Without "nearest" mode, it looks just fine on any scale, so I guess it's all about that filter...


So what would be the reason why "nearest" filter mode displays irregular pixel sizes?


Thank you!

Re: Pixels dimensions not constant with setFilter("nearest","nearest")

Posted: Sun Sep 05, 2021 10:00 pm
by pgimeno
If you scale e.g. a 3x3 image to 4x3 with nearest neighbour, how do you expect it to look like?

Not sure what you'd expect, but personally I'd expect that one of the pixel columns gets duplicated, and that pixel column will look twice as wide as the others.

If I scale it to 8x3 instead, since 8/3 is 2.6666..., I'd expect to have two pixel columns with size 3 pixels wide and one pixel column with size 2 pixels, for a total size of 3+2+3 = 8 which is the target horizontal size.

And so on. If the final size is not a multiple of the original one, you'll get columns of different widths. If you don't want that to happen, you must use integer scale factors.

Re: Pixels dimensions not constant with setFilter("nearest","nearest")

Posted: Sun Sep 05, 2021 10:07 pm
by darkfrei
Just round the scale factor to the nearest or use antialiasing, not perfect pixels.

Re: Pixels dimensions not constant with setFilter("nearest","nearest")

Posted: Sun Sep 05, 2021 11:07 pm
by Eglaios
pgimeno wrote: Sun Sep 05, 2021 10:00 pm If you scale e.g. a 3x3 image to 4x3 with nearest neighbour, how do you expect it to look like?
The scale is always set as "width = lenght"

Of course, I keep the same ratio no matter how the window is resized : The whole thing is displayed through Canvas with variable width/height, and centered, and the remaining areas stays black so there's no problem for fullscreen (I guess)

Like that :
Image

I'll try to floor a bit everything to see if that fixes it...

Re: Pixels dimensions not constant with setFilter("nearest","nearest")

Posted: Sun Sep 05, 2021 11:39 pm
by pgimeno
There's one way that might work. Draw to a canvas with nearest neighbour using this scale:

floor(target resolution / original resolution)

That should get you uniform pixels. Then draw the canvas to the screen with a linear filter, using this scale:

target resolution / original resolution / integer scale calculated above

That will blur only a one pixel thin line around each pixel, which will hopefully look sharpish enough. Picture and PoC attached.

Re: Pixels dimensions not constant with setFilter("nearest","nearest")

Posted: Mon Sep 06, 2021 9:58 pm
by Eglaios
pgimeno wrote: Sun Sep 05, 2021 11:39 pm There's one way that might work. [...]
This is much appreciated and I [kinda] understand better (distinguish which element has to be scaled using which scale hurts a bit, and I discovered canvas on this same project)...

As I said in another post, I am rendering my stuff through Simple Tiled Implementation (tilemap renderer).
I modified the code to match what you shown, but I still have an issue :

Image
(At least, tiles are fixed, that's good! Thank you!)

So as you can see, everything but the hero are getting drawn just fine...
The tiles are part of the tileset, already in the .lua map file, and are spread on different layers.
For the hero sprite, I create a custom layer in load(), in main.lua.
Then, every layer is put on a canvas, then drawn on screen from Map:draw(), in assets/lib/sti/init.

Would there be anything I missed in the hero layer, or is it something else that screws it up?
(Sorry to ask you to look in this... hope it is'nt that messy...)


Thank you again!

Re: Pixels dimensions not constant with setFilter("nearest","nearest")

Posted: Tue Sep 07, 2021 2:31 am
by Eglaios
Well... Big brain me happened to forgot to set the hero's sprite setFilter to "nearest"...

...And it works! Thank you all for your support, I'm kind of impressed of the help I could get over there!
(And I hope I won't abuse of it)