Transparent image drawing order

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
timmeh42
Citizen
Posts: 90
Joined: Wed Mar 07, 2012 7:32 pm
Location: Cape Town, South Africa

Transparent image drawing order

Post 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.
Attachments
Liquid.love
(6.26 KiB) Downloaded 128 times
User avatar
Xgoff
Party member
Posts: 211
Joined: Fri Nov 19, 2010 4:20 am

Re: Transparent image drawing order

Post 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)
User avatar
slime
Solid Snayke
Posts: 3132
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: Transparent image drawing order

Post 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.
User avatar
timmeh42
Citizen
Posts: 90
Joined: Wed Mar 07, 2012 7:32 pm
Location: Cape Town, South Africa

Re: Transparent image drawing order

Post 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
User avatar
Boolsheet
Inner party member
Posts: 780
Joined: Wed Dec 29, 2010 4:57 am
Location: Switzerland

Re: Transparent image drawing order

Post 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)
Shallow indentations.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Bing [Bot] and 65 guests