Translucent, blending question

I need a little help to get me pointed in the right direction. I apologize if this is a common question… I haven’t been able to find answers by searching these forums or the web. I suspect this is because I don’t know exactly what to search for. I am attempting to enhance an OpenGL application that I did not originally write, and I’m far from an OpenGL expert.

I have a number of objects in my scene. Some objects have parts that are translucent, handled by manual back-to-front sorting and GL_BLEND/glBlendFunc()… there is no shader support in this app. Each object is contained in it’s own display list.

At run time, I want to control the translucency of entire objects (as in a ghost car). The degree of an object’s translucency is dynamic, and may change from one frame to the next.

What I would like to do is to leave as much of the existing code in place, but somehow tell OpenGL “draw the entire next object with 0.50 alpha.” I would prefer to use the simplest and most compatible method to do this (some customers that use this software have VERY old hardware).

Here are some specific questions I have:

  1. Is there a way to apply translucency to a display list?
  2. If shaders are required, can this be done w/ a vertex shader (modifying each vert’s alpha), or is a pixel shader required?
  3. Can a pixel shader directly blend into the frame buffer? Something like: gl_FragColor = 0.5 * gl_FragColor + 0.5 * newColor; (I know that gl_FragColor is read-only, but this expresses what I would like to do).
  4. If I must use shaders, can I leave the existing fixed-pipeline code and just use the shader when I draw the dynamically-translucent objects, or do I need to re-write my code to use shaders for all drawing?

Thanks,
-Brad

If your display list does not have texturing, and your target hardware support texturing (please define “very old hardware”), you can solve your problem easily :

//bind transparent texture (only alpha, 1 texel, you update it each frame according to your ghosting mode)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // it is the default, so maybe not needed
//Draw list

If the DL already use texture, you may use multitexture combine modes, but it may be tricky.

Using shaders will require you to reimplement quite a lot of existing stuff.

If you are targeting low end hardware, I would use:

http://www.opengl.org/sdk/docs/man/xhtml/glBlendColor.xml

And change the blend function to GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA

Note that there is a bug in the man pages above, this feature became core in OpenGL 1.4 (previously you needed the ARB_imaging subset - which has been present on Nvidia since original TNT days)

ZbuffeR, yes the display lists do include textures. By “very old hardware”, I suppose I’m referring to hardware accelerated cards without shader support (GeForce2 level, or so). If it wasn’t too much work, I wouldn’t mind implementing this using shaders (or other more recent extensions) so long as the code would still run on older hardware (without the effect being visible, of course). But this sounds to me like more work than I need to do.

It sounds like glBlendColor may be just what I’m looking for. I’ll have to look into it a bit more. I’m guessing that this will lead to two problems. “Problems” is an overstatement in my case… let’s say “less than ideal results”:

  1. The alpha values on the already-transparent parts of the object (car windows) will be rendered with the same alpha as everything in else in the display list (they won’t be appropriately more translucent).
  2. Normally occluded polys will be visible (the car’s dashboard will be visible through the car’s roof).

Neither of these is a deal-breaker… it’s just less than ideal. I suppose to get “perfect” results, I would have to render the object normally to an off-screen buffer and then blend the result into the frame buffer… which would be much more complex (read “work”).

Thanks for your help!

Well, if you wanted to get around problem 1, you could use texture combiners instead (OpenGL 1.3 - pre cursor to shaders - widely supported)

Something like:

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);

glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);

glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_COLOR);

float AlphaValue[4] = {0.0f, 0.0f, 0.0f, 0.5f};
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, AlphaValue);

This does:

output.rgb = srcColor.rgb * texture .rgb;
output.a = yourConstant.a * texture.a;

This assumes that the alpha you want to keep is coming from the texture. If it is coming from the vertex color, do this:

glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_COLOR);

When you are done, don’t forget to reset the combine mode to the default of:

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );

(I have not actually tested the above, so there may be bugs as my texture combiner knowledge is a bit rusty)
See:

http://www.opengl.org/sdk/docs/man/xhtml/glTexEnv.xml