I'm implementing Porter/Duff compositing with OpenGL and I need to work with
ARGB 32bit image data.
After experimenting for some time I discovered that the image data must be
premultiplied in order to obtain the correct compositing results.
So the question pops in my mind: is there a way to Premultiply/Unpremultiply
alpha at hardware speeds with OpenGL ?
Cheers,
Mik
--
The first question is: "Where is the data?"
If it's in main RAM then forget it. Your main
CPU will be faster than a round trip to the
graphics card (it's "hardware" too...)
If the data is on the graphics card then you
can do it with a pixel shader. Treat the data
as a texture and draw a quad with 1:1 pixel
mapping and process the data along the way.
--
<\___/>
/ O O \
\_____/ FTB. For email, remove my socks.
We’re judging how a candidate will handle a nuclear
crisis by how well his staff creates campaign ads.
It’s a completely nonsensical process.
as you guessed the data is graphics mem (i.e. a texture).
So you're suggesting me a pixel shader ?
And what happens when I want to read back (to system memory) the processed
unpremultiplied pixels ?
Mik
--
"fungus" <uma...@SOCKSartlum.com> ha scritto nel messaggio
news:QVUCh.994$ak1...@news.ono.com...
On a nice graphics card, yes.
> And what happens when I want to read back (to system memory) the processed
> unpremultiplied pixels ?
>
glGetTexImage()/glReadPixels()
--8<----
uniform sampler2D texture;
void main()
{
vec4 s = texture2D(texture,gl_TexCoord[0].st);
vec4 d = gl_FragColor;
float extra_alpha = 0.1;
s.a = s.a * extra_alpha;
if (s.a == 0.0) gl_FragColor = d;
else if (s.a == 1.0) gl_FragColor = s;
else if (d.a == 0.0) {gl_FragColor = s;}
else
{
float a = s.a + d.a - s.a * d.a;
gl_FragColor.a = a;
gl_FragColor.r = (s.a*s.r+d.a*d.r-s.a*d.a*d.r)/a;
gl_FragColor.g = (s.a*s.g+d.a*d.g-s.a*d.a*d.g)/a;
gl_FragColor.b = (s.a*s.b+d.a*d.b-s.a*d.a*d.b)/a;
}
}
--8<----
Of course I have no experience at all with fragment shaders and I'm getting
a warning from the compiler: "warning C7050: gl_FragColor might be used
before being initialized".
Any hint ?
Cheers,
Mik
--
"fungus" <uma...@SOCKSartlum.com> ha scritto nel messaggio
news:ZiVCh.2517$M51....@news.ono.com...
I guess it's about the line:
vec4 d = gl_FragColor;
At that point, you haven't written anything to gl_FragColor yet, so it's
uninitialized.
"Notice that the fragment shader has no access to the frame buffer. This
implies that operations such as blending occur only after the fragment
shader has run."
The big mistake is that I was thinking of reading the framebuffer contents
with gl_FragColor..
Mmmh.. maybe I could implement my blending by binding a pbuffer object to a
texture (or even a FBO) and then access the dest pixels from there, right ?
Mik
"Rolf Magnus" <rama...@t-online.de> ha scritto nel messaggio
news:erikca$2mk$01$1...@news.t-online.com...
> Mmmh.. maybe I could implement my blending by binding a pbuffer
> object to a texture (or even a FBO) and then access the dest
> pixels from there, right?
As long as the render target is not the source of any fragment.
If you try to read contents from the buffer you're writing to
you get a lot of problems. GPUs are highly parallel and may do a
lot of operations out of order, so you need some synchronisation
point. The easiest way to do this, is just to make a copy of the
current buffer contents to a texture and use this in the
following procoess. Blending is one of the last remaining fixed
function pipeline steps, that is not yet freely programmable by
OpenGL. But this is a goal for the next bigger advance of OpenGL
development.
Better use a FBO, since PBuffers are a bit clumsy to use as
texture units.
Wolfgang Draxinger
--
E-Mail address works, Jabber: hexa...@jabber.org, ICQ: 134682867
you have to know that I'm doing all this in order to solve what I consider
an OpenGL problem:
The result of blending (SRC_OVER) a src translucent color with a dest
transparent one (i.e. 0x00000000 argb) is wrong as the src color is always
blend by taking the dest color into account.
But, if the dest color alpha is 0, then it must not affect the result, as
it's completely transparent.
Cheers,
Mik
--
> Many thanks Wolfgang,
>
> you have to know that I'm doing all this in order to solve what
> I consider an OpenGL problem:
>
> The result of blending (SRC_OVER) a src translucent color with
> a dest transparent one (i.e. 0x00000000 argb) is wrong as the
> src color is always blend by taking the dest color into
> account.
>
> But, if the dest color alpha is 0, then it must not affect the
> result, as it's completely transparent.
What is your blending equation? Maybe it can be done with fixed
function OpenGL alone.
glBlendFuncSeparateEXT(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE,
GL_ONE_MINUS_SRC_ALPHA)
It seems this approssimates the SRC_OVER as best (but not as expected).
Src pixels are not premultiplied.
Mik
--
"Wolfgang Draxinger" <wdrax...@darkstargames.de> ha scritto nel messaggio
news:2gldb4-...@darkstargames.dnsalias.net...
>
> I'm using
>
> glBlendFuncSeparateEXT(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
> GL_ONE, GL_ONE_MINUS_SRC_ALPHA)
>
> It seems this approssimates the SRC_OVER as best (but not as
> expected). Src pixels are not premultiplied.
Actually I wanted to know your desired blending _equation_ i.e.
something like
R_dest := "something which has R_src in it"
G_dest := "something which has G_src in it"
B_dest := "something which has B_src in it"
e.g. the usually used alpha blending is
<R,G,B>_dest := <R,G,B>_dest * (1-A) + <R,G,B>_src * A;
a2*X2 + a1*X1 - a2*a1*X1
X(total) = --------------------------
a1 + a2 - a1*a2
pseudo-code
s = source pixel <a,r,g,b> (float)
d = dest pixel <a,r,g,b> (float)
c = computed pixel <a,r,g,b> (float)
here we compute the final a,r,g,b of s SRC_OVER b
float a = (s.a + d.a - s.a * d.a)
float r = (s.a * s.r + d.a * d.r - s.a * d.a * d.r)/a
float g = (s.a * s.g + d.a * d.g - s.a * d.a * d.g)/a
float b = (s.a * s.b + d.a * d.b - s.a * d.a * d.b)/a
c.a = a; c.r = r; c.g = g c.b = b
now we can write c to the framebuffer.
Cheers,
Mik
--
"Wolfgang Draxinger" <wdrax...@darkstargames.de> ha scritto nel messaggio
news:csmeb4-...@darkstargames.dnsalias.net...
Generally you want to keep opacity weighted colors in the frame buffer
-- this would save you those pesky divides. You can do the divide by
alpha after reading the frame buffer back; it will be more accurate anyway.
So, if d is opacity weighted, your formula for r becomes:
r = s.a * s.r + d.r - s.a * d.r
or
r = s.a * s.r + (1 - s.a) * d.r
which is GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA.
For alpha, your formula is:
a = s.a + d.a - s.a * d.a
or
a = s.a + (1 - s.a) * d.a
which is also GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA.
See how simple it can be?
--
Andy V
I'm still in the fog :)
- create a PBuffer or a FBO (640x400, int argb),
- clear it with 0x00000000 (transparent black)
- create a translucent texture (640,400, int argb)
- clear it with 0x1fff0000 (semi-transparent red)
- enable blending
- set blending function to SRC_ALHA,ONE_MINUS_SRC_ALPHA
- draw the texture to the buffer at 0,0 (2d, upper left corner, no lights)
- read the buffer pixels (glReadPixels)
- you should get that the pixels affected from the texure are all ==
0x1fff0000 (according to the blending function)
It's not. You'll get a darker red. You'll notice that the pixels have been
affected by the current buffer color (black). It is wrong, as the background
alpha is 0.
According to the math:
Let's say that s<argb> is the texture pixel
and d<argb> is the background.
we have d.a = 0, so
a = s.a + (1 - s.a) * d.a
becomes
a = sa + (1 - s.a) * 0
or
a = sa
and for the other RGB components..
float r = (s.a * s.r + d.a * d.r - s.a * d.a * d.r)/a
becomes
r = (s.a * s.r + 0 * d.r - s.a * 0 * d.r) / a
or
r = (s.a * s.r) / a
or
r = s.r
se we can say that the result is
a = s.a
r = s.r
g = s.g
b = s.b
as expected.
As we can see, the dest color (the background in our case) does not affect
the result if its alpha is 0.
Perfect! ...but it's not, according to the real-world test.
What the hell am I missing ?
Mik
--
"Andy V" <nob...@nowhere.net> ha scritto nel messaggio
news:CqGdnfs2aukupXvY...@comcast.com...
What's the color of the polygon you apply the texture to ?
What's your texture blend mode ?
Your source alpha isn't FF, it's 1F, so
r = s.a * s.r + (1 - s.a) * d.r
is
r = 1F/FF * s.r + 0 .
jbw
from my code (java/lwjgl)
// modulate texture graphics with a color
EXTBlendFuncSeparate.glBlendFuncSeparateEXT(GL11.GL_SRC_ALPHA,
GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glColor4f(1f, 1f, 1f, extraAlpha);
GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE,
GL11.GL_MODULATE);
GL11.glEnable(GL11.GL_BLEND);
--
back to math
--
if
a = s.a
and
d.a = 0
then (from my original code)
float r = (s.a * s.r + d.a * d.r - s.a * d.a * d.r)/a
becomes
r = (s.a * s.r) / s.a
so the result is
r = s.r
Mik
--
"jbwest" <jbw...@comcast.net> ha scritto nel messaggio
news:2aKdna1zMdTtdHvY...@comcast.com...
Dont top post, see below,.
"Michele Puccini" <m...@c-l-a-s-s-x.it> wrote in message
news:bLQFh.9$zP2...@nntpserver.swip.net...
so your RED gets diminished by ExtraAlpha, which when read back, is thus <
FF . As expected.
jbw
No, consider the extra alpha = 1.
GL11.glColor4f(1f, 1f, 1f, 1f);
Basically the blending SHOULD NOT take the background color into account
when it is completely transparent (alpha = 0). The math says that, but not
the opengl results. Maybe because the 99.9% of the code around is targeted
to a window context and relies on the fact that the background is always
opaque (alpha = 1). But when you render to a PBuffer or to a FBO..
Mik
--
Umm, you have texture ALPHA as 1F, and you have MODULATE, so the ALPHA is
1F/FF * ExtraAlpha.
Try it with a WHITE background.
jbw
>>> so your RED gets diminished by ExtraAlpha, which when read back, is thus
>>> < FF . As expected.
>>>
>>> jbw
>>
>> No, consider the extra alpha = 1.
>>
>> GL11.glColor4f(1f, 1f, 1f, 1f);
>>
>> Basically the blending SHOULD NOT take the background color into account
>> when it is completely transparent (alpha = 0). The math says that, but
>> not the opengl results. Maybe because the 99.9% of the code around is
>> targeted to a window context and relies on the fact that the background
>> is always opaque (alpha = 1). But when you render to a PBuffer or to a
>> FBO..
>>
>>
>> Mik
>> --
>>
> Umm, you have texture ALPHA as 1F, and you have MODULATE, so the ALPHA is
> 1F/FF * ExtraAlpha.
> Try it with a WHITE background.
>
> jbw
Yes, the white bg approximates the results, but there are still problems in
the compositing approach.
I still suspect on something missing in the opengl implementation when
blending to translucent buffers. Of course I'm missing something..
Mik
--
Do you understand why changing the background changed the result? Do you
understand the impact of having the texture alpha at 1F ? OpenGL is doing
what it's advertised to do; if you create the correct equation, you can do
what you want.
jbw
> FBO..
>>>>
>>>>
>>>> Mik
>>>> --
>>>>
>>> Umm, you have texture ALPHA as 1F, and you have MODULATE, so the ALPHA
>>> is 1F/FF * ExtraAlpha.
>>> Try it with a WHITE background.
>>>
>>> jbw
>>
>> Yes, the white bg approximates the results, but there are still problems
>> in the compositing approach.
>> I still suspect on something missing in the opengl implementation when
>> blending to translucent buffers. Of course I'm missing something..
>>
>> Mik
>> --
>
> Do you understand why changing the background changed the result? Do you
> understand the impact of having the texture alpha at 1F ? OpenGL is doing
> what it's advertised to do; if you create the correct equation, you can do
> what you want.
>
> jbw
> Do you understand why changing the background changed the result?
No, because it should not.
Any fragment with alpha = 0 is a NO-OP for SRC_OVER.
> Do you understand the impact of having the texture alpha at 1F ?
Yes, it should blend to the background.
But when the background's alpha is 0, the blend should not happen at all.
From the math I see that:
A SRC_OVER B = A (if B has alpha = 0)
A SRC_OVER B = B (if A has alpha = 0)
A SRC_OVER B = A (if A has alpha = 1)
> If you create the correct equation, you can do what you want.
Which is the equation, then ?
Cheers,
Mik
--
Guessing at your frame buffer organization, I assume this is red ff and
alpha 1f. This is not an opacity weighted color. Using (SRC_ALPHA,
ONE_MINUS_SRC_ALPHA) assumes that the destination buffer contains
opacity weighted colors -- you have violated this. Instead, your
destination should be cleared to 1f1f0000.
--
Andy V
use glAlphafunc for source alpha == 0.
>
>> Do you understand the impact of having the texture alpha at 1F ?
>
> Yes, it should blend to the background.
> But when the background's alpha is 0, the blend should not happen at all.
> From the math I see that:
>
> A SRC_OVER B = A (if B has alpha = 0)
> A SRC_OVER B = B (if A has alpha = 0)
> A SRC_OVER B = A (if A has alpha = 1)
>
>> If you create the correct equation, you can do what you want.
>
> Which is the equation, then ?
>
> Cheers,
>
> Mik
> --
>
A SRC_OVER B = B (if A has alpha = 0)
This is handled simply by an alpha-test of not zero (glAphafunc)
A SRC_OVER B = A (if B has alpha = 0)
A SRC_OVER B = A (if A has alpha = 1)
Something that includes DEST_ALPHA, not the SRC_ALPHA based equation
referred to before.
jbw
>
>
>
>
>