5

I've found 5349574673 pages on alpha blending and I still can't get the desired result. I'm trying to make gif/png files display properly (WITH transparency/translucency) using opengl.

Here's my initialization bit:

glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); //I've seen this on most tutorials
glDisable(GL_DEPTH_TEST); //it's a 2D game
//...loading matrices and so on

I am SURE the images have transparency, and are loaded properly.
glBlendFunc(GL_ONE, GL_ONE); works but I can't tell if it's doing anything on the alpha channel since it would render as black => blending works
glColor4f(1f,1f,1f,0.3f); works fine, I can draw transparent stuff

P.S. I'm using this example http://lwjgl.org/wiki/index.php?title=Space_Invaders_Example_Game for learning

EDIT I used other textures made encoded with GIMP and other texture loaders and it now works fine.

adrianton3
  • 2,258
  • 3
  • 20
  • 33

2 Answers2

6

Your blending setup is correct. However for blending to work the texture must contain an alpha channel, properly valued of course. And then the alpha channel data must be preserved by the image loading process. May we see the image loading and texture generation code, please?

datenwolf
  • 159,371
  • 13
  • 185
  • 298
1

The main problem with alpha blending formula is how source/destination/result colors are stored. We have 2 cases: alpha-premultiplied (r,g,b channels are multiplied by alpha channel); not-alpha-premultiplied (r,g,b are not multiplied). You have to ensure which formats are used to use correct blending formulas. alpha-premultiplication is often used when rendering something to the screen, it allows to use simpler and faster blending formula.

I gathered all basic cases below, but first some informations:

  • what is source/destination: if you think in "Photoshop" way you can treat destination as bottom layer, and source and top layer.
  • mix functions: it is shader linear interpolation function (also know as lerp). From OpenGL reference: mix performs a linear interpolation between X and Y using A to weight between them: mix(x, y, a) = x * (1 - a) + y * a. From my experience i can say mix version is a bit faster than standard formula when using it in gpu fragment shaders.
  • all formulas are for float color values (from 0.0 to 1.0)
  • if you want to use opacity for source color you have to just multiply src.a by the opacity src.a *= opacity
  • in formulas where division by 0 can happen you probably have to add an "if" condition like this:
result.a = <formula for alpha>;
if (result.a == 0.0) {
    result.rgb = dest.rgb;
} else {
    result.rgb = <formula for rgb>;
}

So here are the formulas:

1. Source, Destination, Result are not premultiplied

result.a = dest.a * (1.0 - src.a) + src.a;
result.rgb = (dest.rgb * dest.a * (1.0 - src.a) + src.rgb * src.a) / result.a;  // division by 0

or using mix function:

result.a = mix(dest.rgb, 1.0, src.a);
result.rgb = mix(dest.rgb * dest.a, src.rgb, src.a) / result.a;  // division by 0!!!!

OpenGL blend functions:

not possible

2. Source, Destination, Result are all premultiplied

result.a = dest.a * (1.0 - src.a) + src.a;
result.rgb = dest.rgb * (1.0 - src.a) + src.rgb;

mix version:

result.a = mix(dest.rgb, 1.0, src.a);
result.rgb = dest.rgb * (1.0 - src.a) + src.rgb; // "mix" version not available

OpenGL blend functions:

glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);

3. Destination, Result premultiplied, Source not premultiplied

result.a = dest.a * (1.0 - src.a) + src.a;
result.rgb = dest.rgb * (1.0 - src.a) + src.rgb * src.a;

mix version:

result.a = mix(dest.rgb, 1.0, src.a);
result.rgb = mix(dest.rgb, src.rgb, src.a);

OpenGL blend functions:

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);

4. Destination is opaque (dest.a = 1.0) so Result is opaque, Source non premultiplied

result.rgb = dest.rgb * (1.0 - src.a) + src.rgb * src.a;
result.a = 1.0;

mix version:

result.rgb = mix(dest.rgb, src.rgb, src.a);
result.a = 1.0;

OpenGL blend functions:

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
Slyv
  • 421
  • 3
  • 8