Page 1 of 1

Transparent image drawing order

Posted: Wed Mar 14, 2012 6:23 pm
by timmeh42
I've been working on a certain small project (which I will post once it is complete) that requires two semi-transparent images to overlap.
The two images, as they are in fact exactly the same, should blend with each other evenly and equally. However, I'm getting some strange behaviour in which the second image to be drawn appears slightly brighter and overpowers the first. As I am first drawing to a framebuffer, might it have something to do with framebuffers?

The question is, does anyone know how to fix it or what might be causing it?

This picture shows the images being drawn, first the bottom-right one, and then the top-left one. As can be seen, the second seems to overpower the first.
The inset shows the same behaviour when the order is reversed - now the bottom-right image (being the second) seems to overpower the top-left one.
Image

.love file supplied for demonstration - just swap the order of the two draws around.

Re: Transparent image drawing order

Posted: Wed Mar 14, 2012 6:38 pm
by Xgoff
i can't test this theory since i'm not on my computer that can actually run love, but maybe you should try using premultiplied alpha (you need an 0.8 build)

Re: Transparent image drawing order

Posted: Wed Mar 14, 2012 7:35 pm
by slime
Yes, if you intend to draw an alpha-blended framebuffer to the screen then you need to use the "premultiplied" blend mode which is only available in LÖVE 0.8.0.

Re: Transparent image drawing order

Posted: Thu Mar 15, 2012 4:06 pm
by timmeh42
Ouch, no, this isn't good. Using 'premultiplied' blend mode this came out: seems to draw the images with full opacity or full transparency.
(I seem to remember reading about this somewhere on the forum; something to do with framebuffers/canvases not treating alpha correctly - however, it gets treated correctly with 'alpha' blend mode, so idk...) (EDIT: nope, tested it without canvases, still does this. However, 'alpha' blend mode works as it should - as I want it to - without canvases/framebuffers)

Image

(Using slightly bigger images; just had to recreate it and I couldn't remember its original size.)
EDIT: using the same image, love 0.8.0 seems to draw it slightly bigger/brighter... wtf?

Image

Re: Transparent image drawing order

Posted: Thu Mar 15, 2012 5:33 pm
by Boolsheet
LÖVE 0.8.0 doesn't clear the buffer automatically anymore on setRenderTarget or renderTo. You have to explicitly tell it to clear with Canvas:clear().
You want to draw the framebuffer/canvas with premultiplied to the screen, not the things that go on to the framebuffer/canvas.

Code: Select all

is080 = love._version == "0.8.0"

function love.load()
	blob = love.graphics.newImage("blob.png")
	if is080 then
		fbuf = love.graphics.newCanvas()
	else
		fbuf = love.graphics.newFramebuffer()
	end
end

function love.draw()
	if is080 then
		fbuf:clear()

		love.graphics.setCanvas(fbuf)
			love.graphics.draw(blob,400,300)
			love.graphics.draw(blob,420,330)
		love.graphics.setCanvas()

		love.graphics.setBlendMode("premultiplied")
		love.graphics.draw(fbuf)
		love.graphics.setBlendMode("alpha")
	else
		love.graphics.setRenderTarget(fbuf)
			love.graphics.draw(blob,400,300)
			love.graphics.draw(blob,420,330)
		love.graphics.setRenderTarget()

		love.graphics.draw(fbuf)
	end
end
You can draw images with the premultiplied blend mode, but that requires some preprocessing. The R, G, and B channels have to be multiplied with the A channel. Most image editing programs don't do this. I think GIMP has an option for it on the saving dialog with a weird description. And there's the mapPixel function in LÖVE that could do it if you want to test it:

Code: Select all

img:mapPixel(function(x, y, r, g, b, a)
	local pa = a/255
	return r*pa, g*pa, b*pa, a
end)