Blending textures hav a shadow on the border. Why?

Hi,

I render clouds using glBlendFunc(src_alpha, one_minus_src_alpha)
Clouds are white textures.

The clouds have transparent borders. Rendering on the background works good.

But when a cloud border is rendered on top of another cloud I get a shadow. The shadow is along the border of the topmost cloud.

I want to have just “white” as an result when a cloud pixel with any alpha is rendered on another solid white cloud pixel.

Any ideas where this could come from?

Sound like you have depth test enabled.
Try without.
But of course you will need to render the clouds back to front.

Do you have a picture ?

I suggest you to read about “pre-multiplied alpha” here:
http://home.comcast.net/~tom_forsyth/blog.wiki.html#[[Premultiplied%20alpha]]

Thx for the article and the hint with depthbuffer.

While trying to understand what the arcticle is saying
I disabled depthbuffer without any change.

Attached you can find a generated result I get.

cloud.png: I am drawing them in the order back-to-front.
coudresult.png: result I get after drawing with blending described above.

I have
SDL_CurrentVideo->glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
SDL_CurrentVideo->glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
SDL_CurrentVideo->glShadeModel(GL_FLAT);
SDL_CurrentVideo->glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
SDL_CurrentVideo->glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
SDL_CurrentVideo->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
SDL_CurrentVideo->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
GLfloat environmentColor[4] = { 0.0, 0.0, 0.0, 1.0 };
SDL_CurrentVideo->glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, environmentColor );
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glColor4f( 1.0, 1.0, 1.0, 1.0 );
SDL_CurrentVideo->glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
SDL_CurrentVideo->glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE);
SDL_CurrentVideo->glDisable(GL_DITHER);

Skynet is right, this will be fixed just with a change of glBlendFunc.
From your description I thought the cloud texture was all white, with alpha used to define the cloud silhouette, which works with classic alpha.
But the kind of artefact you have if exactly caused by having black over transparent regions : the interpolation between black+transparent and white+opaque gives grey+semitransparent.
This is a case best handled by premultiplied alpha, with
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

ZBuffer, thanks!! That works like charm!

Now I have another challenge. Clouds get drawn correct.

My program has another function which sets the alpha for a image. So when I reduce the alpha of a cloud nothing happens.
Even a alpha value of 0 still shows the cloud.

According to that equation I expected a change when changing source alpha:
(RsSr+RdDr, GsSg+GdDg, BsSb+BdDb, AsSa+AdDa)

…this will be fixed just with a change of glBlendFunc.

You forgot about the “pre-multiplied” part :slight_smile: The texture data needs to be prepared as well!

I did not forgot, I tried to give the minimum information to fix the described problem :slight_smile:

I assume that after reading Tom’s page, Andreas K would get a high level grasp of how pre-multiplied alpha works… I guess he did not.

@Andreas K: To avoid rebuilding the texture for each alpha change, you can either :

  • in fragment shader, divide color by default alpha (the one from the texture), then multiply by alpha modulation, keeping premultiplied alpha blend func.
  • put all white instead of black in the cloud texture, and go back to classic blend func

Gents thanks a lot for the fast replies!
The software is a 2D game engine. Will get back to the user
who provided me the cloud image and ask to change black to white.
In parallel I will try to understand option a). Have no experience with the fragment shader and how to configure.

Doing GLSL seem complex at first, but it allows a lot of freedom to do complex stuff easily.

Anyway, you can do solution b) from within your code, whithout having to change the cloud file.
At load time, for each texel, divide color by its alpha (putting black for alpha=0 of course).

In fact it is good practice to know for each image file if it has premultiplied alpha or not.

At load time, for each texel, divide color by its alpha (putting black for alpha=0 of course).

Why divide? Its “pre-multiplied” alpha. Presumed he is using 255 as opaque and 0 for fully transparent pixels, he needs to divide the alpha by 255 and then use that as factor to multiply RGB with. The alpha channel of the texture remains as is.

Sorry I am wrong, it is not possible to properly un-premultiply when alpha=0, black is not a good value obviously… This works only post-interpolation, ie on the fragment shader.

@skynet : this is to go from “premultiplied alpha” texture, to “classic blending” rendering.

So we tried to replace the pixels as described above without success.

Any new ideas how can can get this rendered properly?

Am working with SDL. Maybe I can find a SDL function after loading before rendering starts.

If not, whats the suggested way we should change images?

If we cannot find a blending which fits all situations I might
introduce two blendings in the game engine.

The classic blending is default and used in the game-editor and by default in the engine.
Per script command blending can be changed to the one u proposed.

This is then for in-game-mode only.

Does that make sense?

Well it should work.

Can you put the RGBA cloud files online ?
Both the original version, and the all white one ?

Here is the result:

Original clouds in my post above: clouds.png.

Will try to get the modified clouds from user.

Here is the modified cloud.

Fine but where is gone your alpha channel ?

And the resulting image looks like color-key transparency, where the first pixel of an image is considered transparent.

Instead you should use the RGB color data from the modified ‘cloud.bmp’ with the alpha from the original ‘cloud.png’ for ‘classic blending’ to work.