FilterMode Bluriness and Workarounds
Posted: Wed May 03, 2023 10:29 am
Hey all,
When adjusting the FilterMode parameter (https://love2d.org/wiki/FilterMode), I can't get it the way I want. The "nearest" filter mode distorts the size of the pixels and the "linear" filter makes the image too blurry. What I'd really like is a linear filter that only interpolates the pixels on the border between the two colors, and doesn't interpolate all the pixels.
For example, imagine a 2x1 grayscale image with one white and one black pixel. It looks like [1,0]. If I try to interpolate that up to be 11 pixels wide, with the nearest filter, there would be a different number of white pixels and black pixels, six of one and five of the other. With the linear filter, there would be an equal number of black and white pixels, but there would also be 5 pixels in the middle at different stages of interpolation between white and black. What I'd like is a filter mode where there are 5 white pixels, 5 black pixels, and only the very middle pixel (on the border between black and white) is a gray value. This preserves the balance between the two colors while also not making the image unduly blurry.
Here are a couple of strategies I've been considering to get around this:
1. Store larger versions of the image. When scaling down, things aren't even close to as bad. Solves the problem perfectly but feels super cludgy. Lmao at storing a 640 by 640 version of a 64 by 64 piece of pixel art simply to get around this issue.
2. Manually scale the image up with the "nearest" filter to a multiple of the image's original size, draw it to a canvas, and then scale that canvas back down using the "linear" filter to reduce it to the size I want. Also feels cludgy, but probably going with this one. But then that's a bunch of boilerplate I have to call every time I load an image...
local scaleFactor = math.ceil(size / img:getHeight())
local canv = love.graphics.newCanvas(scaleFactor * img:getHeight(),
scaleFactor * img:getHeight())
love.graphics.setCanvas(canv)
img:setFilter("nearest")
love.graphics.setColor(1, 1, 1)
love.graphics.draw(img, 0, 0, 0, scaleFactor)
canv:setFilter("linear")
I'm wondering what veterans of LOVE2D would do here, if anything. Also, how easy would it be to submit a PR implementing a new filter that only interpolates on the border? Is that the kind of thing that would get merged, assuming that I wrote it properly?
When adjusting the FilterMode parameter (https://love2d.org/wiki/FilterMode), I can't get it the way I want. The "nearest" filter mode distorts the size of the pixels and the "linear" filter makes the image too blurry. What I'd really like is a linear filter that only interpolates the pixels on the border between the two colors, and doesn't interpolate all the pixels.
For example, imagine a 2x1 grayscale image with one white and one black pixel. It looks like [1,0]. If I try to interpolate that up to be 11 pixels wide, with the nearest filter, there would be a different number of white pixels and black pixels, six of one and five of the other. With the linear filter, there would be an equal number of black and white pixels, but there would also be 5 pixels in the middle at different stages of interpolation between white and black. What I'd like is a filter mode where there are 5 white pixels, 5 black pixels, and only the very middle pixel (on the border between black and white) is a gray value. This preserves the balance between the two colors while also not making the image unduly blurry.
Here are a couple of strategies I've been considering to get around this:
1. Store larger versions of the image. When scaling down, things aren't even close to as bad. Solves the problem perfectly but feels super cludgy. Lmao at storing a 640 by 640 version of a 64 by 64 piece of pixel art simply to get around this issue.
2. Manually scale the image up with the "nearest" filter to a multiple of the image's original size, draw it to a canvas, and then scale that canvas back down using the "linear" filter to reduce it to the size I want. Also feels cludgy, but probably going with this one. But then that's a bunch of boilerplate I have to call every time I load an image...
local scaleFactor = math.ceil(size / img:getHeight())
local canv = love.graphics.newCanvas(scaleFactor * img:getHeight(),
scaleFactor * img:getHeight())
love.graphics.setCanvas(canv)
img:setFilter("nearest")
love.graphics.setColor(1, 1, 1)
love.graphics.draw(img, 0, 0, 0, scaleFactor)
canv:setFilter("linear")
I'm wondering what veterans of LOVE2D would do here, if anything. Also, how easy would it be to submit a PR implementing a new filter that only interpolates on the border? Is that the kind of thing that would get merged, assuming that I wrote it properly?