Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
Downsizing textures with smoothing — Gideros Forum

Downsizing textures with smoothing

Perhaps this might be useful to someone:

I often have a large texture or RenderTarget I want to scale down, but just setting the scale of a Sprite doesn't do any anti-aliasing/smoothing. If you're downsizing by 50%, you just get a pixel from where every other row meets every other column, so you're only including one of every 4 pixels, and the result looks blocky. If the image is of something with fine detail, like a bushy fishing fly made of wrapped feathers, the pixelated result it can look pretty rough.

I wrote a function to blend all the pixels from the source texture into the reduced one, pixel by pixel. It works fine, but of course that's really slow. Then it dawned on me that there's a much faster way to do it, letting the GPU do the work. Just draw the scaled down texture several times with decreasing alpha so all the layers get the same total weight, using a TextureRegion that's offset for each layer. That offset means if you're getting only every Nth pixel from the source, one layer gets every Nth pixel starting at 1, the next gets every Nth pixel starting at 2, etc. So the final pixel in the reduced texture is a blend of the corresponding pixels from the larger original texture.

Anyway, if you want to scale down a texture with smoothing, the following function will take a texture or RenderTarget and downsize it that way:
 
function smoothedDownsize(rt, width)
	-- Ignores height, preserves aspect ratio
	local rtw, rth = rt:getWidth(), rt:getHeight()
	local scale = width / rtw
	local dest_rt = RenderTarget.new(width, rth * scale)
	local range = 1 / scale -- If going down 50%, range is 2, meaning 2 rows of source make 1 row of dest
 
	local b = Bitmap.new(rt)
	b:setScale(scale)
	dest_rt:draw(b)
	local layers_drawn = 1
	for step = 1, range do
		for ox = -1, 1, 2 do
			for oy = -1, 1, 2 do
				local tr = TextureRegion.new(rt, ox * step, oy * step, rtw, rth)
				local b = Bitmap.new(tr)
				b:setScale(scale)
				b:setAlpha(1 / (layers_drawn + 1))
				dest_rt:draw(b)
				layers_drawn += 1
			end
		end
	end
 
	return dest_rt
end
+1 -1 (+2 / -0 )Share on Facebook

Comments

Sign In or Register to comment.