Premultiplied alpha and GL_ONE vs. raw and GL_SRC_ALPHA

转载自:http://lists.apple.com/archives/mac-opengl/2011/Jan/msg00010.html

  • Subject: Premultiplied alpha and GL_ONE vs. raw and GL_SRC_ALPHA
  • From: Zack Morris <email@hidden>
  • Date: Sat, 8 Jan 2011 11:22:49 -0700
  • Delivered-to: email@hidden
  • Delivered-to: email@hidden
  • Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma;h=domainkey-signature:received:received:subject:from:content-type:message-id:date:to:content-transfer-encoding:mime-version:x-mailer;bh=yl2si8aAoAa2wUNxGL35pGCwm16Z8zfBlGgk4X3yugE=;b=JTI3ormi8c0eqDLTvRsZgi+XfYnWddvN2KripyHGkSPw1RyhM286DfzF+F3j8uPrds/iuG9u2p7bBNhQrBALgtGUYTSlF+zyr+WEl91Sei2FAqYHgcpgjB9aKiQkMpddgriSBaq9isyg40hhfVQTGX6GWWY9/kN7JWGpP00yQ6U=
  • Domainkey-signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma;h=subject:from:content-type:message-id:date:to:content-transfer-encoding:mime-version:x-mailer;b=VR8oDlOZFF95QbJP+12AdFUVVEncY+E0Pe4E4lHHll18xJhc/1bQFvN9FNFrcGLkeQzBGsVXwVo4IC8r1iTDzkue6HRkfrqSoO+Hw7Qr32c6GF/P+S4qmUY1Hcfs3SkLdKNKNc+RACO+LPNy0wJgKv/nkvbolbJwwnv/HmD+row=

Hi, I was hoping someone on this list might know the answer to this.  I'm on a 1.83 Intel Mac Mini with GMA 950 and 10.6.6.

My partner is more the artist and I'm more the engineer, and he's adamant about using premultiplied alpha PNGs because "that's how the iPhone does it".  I started with a background in math, reading the red book etc, and I honestly don't see what the hype is about.  Premultiplied seems good for a storage format, since any pixels without alphas become 0 after multiplication and zip better.  But there are pretty severe drawbacks to using them during the game, because we can't altar the pixel values or do special fx without changing the opacity of the pixels, because they are not independent of the alpha byte.

Here is our code, we have texture buffers with a boolean saying whether they are premultiplied, and we do special fx by setting the draw color etc:

if( premultipliedAlpha )
{
	glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
	glColor4f( this->red*this->opacity, this->green*this->opacity, this->blue*this->opacity, this->opacity );
}
else
{
	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
	glColor4f( this->red, this->green, this->blue, this->opacity );
}

glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );

glDrawElements( GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices );

Here is a table I made of all of the modes, white means I set the 0 alpha pixels to white (1.0, 1.0, 1.0), premul means they have been multiplied by the alpha (so are 0.0, 0.0, 0.0), and black means I set them to black (0.0, 0.0, 0.0).  There are 3 sizes (small, 1:1 and full screen), and the "moved" cases are just captures where the ship is on an even pixel value or if it's moved and interpolation is happening:

http://oi52.tinypic.com/ml31jo.jpg

My question is, is glBlendFunc( GL_ONE, ... ) and premultiplied equivalent to glBlendFunc( GL_SRC_ALPHA, ... ) and the black case?  Mathematically, premultiplied and black should be equivalent.  But I swear that the GL_ONE case looks "smoother" and I can't figure out why.  My partner thinks that the GL_ONE case doesn't bother to draw the 0 alpha pixels at all, but I don't think that is possible.  There has to be something to interpolate out to.  You can see what happens most visibly in the lower left white case.

To understand what causes the halos, imagine you have 2 pixels, a red and a clear in RRGGBBAA hex:

[red][clear]:

[FF0000FF][00000000]

And you stretch it up to 3 pixels:

[FF0000FF][7F00007F][00000000]

The middle pixel that is interpolated has to stretch across both color and alpha.  So you get a dark red pixel at half opacity (which looks dark over a white background).  The strange thing is, I swear I'm not seeing those dark pixels in premultiplied mode with GL_ONE, and I don't understand why?

I personally prefer to keep the color and alpha values independent, so I store my graphics unadulterated, where the clear pixel still contains the color info of its nearest neighbor (so there is something to interpolate to), and use non-premultiplied:

[red][clear]:

[FF0000FF][FF000000]

Stretched:

[FF0000FF][FF00007F][FF000000]

This way the middle pixel is still red but at half opacity, which looks correct over any background.

P.S. this all started because there is a bug in photoshop where it's not storing the 0 alpha pixels properly, so they come out undefined.  When we stretch them in our games, we see edge artifacts of random colors if we don't use premultiplied.  There are plugins that supposedly bleed out the edge pixel colors into their 0 alpha neighbors, but they don't seem to save properly either.

So as a fix to get us by and allow us to still use special fx on our graphics without affecting their opacity, I wrote a loop that fills in any 0 alpha pixels with an average of their nonzero alpha neighbors weighted by their alphas at load time.  It actually works great, but I hate that I have to do this.  Photoshop should be saving better.

I know this is a long email and I'm sorry, but this has caused a great deal of strife with my partner.  I need to know mathematically what is happening, and if GL_ONE has some kind of special case happening to ignore the 0 alpha pixels.  He won't believe me and frankly doesn't care about the math, he just wants something that "works".  I consider the premultiplied mode a special case that mostly saves file space, but if it really can draw over any background and completely ignore the 0 alpha pixels, then I would like to know why.  I want a general case where I can apply fx to any texture without having to worry about what format I am loading.  If GL_ONE is equivalent to the black case, then the raw mode with bled edges is actually better, and I have some evidence to provide to him as to why it's a better solution than premultiplied.

Thanx for any insights,

--Zack

"Go to the edge of the cliff and jump off. Build your wings on the way down."

- Ray Bradbury _______________________________________________
Do not post admin requests to the list. They will be ignored.
Mac-opengl mailing list      (email@hidden)
Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden
原文地址:https://www.cnblogs.com/senior-engineer/p/15665708.html