PDA

View Full Version : Blending - AlphaMask - translucent Textures



Casius
10-06-2008, 09:14 AM
My first time in this forum, so "Hello everybody!"

Iīm a newbee in programming openGL, but need to set up following. Before getting trouble with my generally idea to solve the problem, i want to ask you, if my concept is generally right. Please let me know, if this way is possible or if there are better solutions.

Prolem:
1. I need 2 simple rectangles (quads), one placed in front of the other.
2. Both with an overlying texture.
3. These textures are fixed, and wonīt chance during watching them.
4. The Texture are partially invisible (parts colored with RGBA and Alpha=0)
5. I wanna mask the front rectangle with an alpha mask, to control itīs opacity by a slider, which ajust the opacity during watching it. (To be able to slide gently through the foreground quad. Untill it is total transparent and you can only see the background quad. )


My concept/idea to solve it:
- Get dimension of the image to map on the quads. (Each texture got the same dimension)
- Drawing two quads with this dimension, first the far one, then the near one. One with z=0, next with z=0.5. (Iīm drawing them with z=0 and translate the far one 0.5 back.)
- Map the texture on the backgound. (I made a little testing scenario, with texture-mapped background and a flat colored (RGBA, A=0.5) forground. Iīm already able to do this for base-of-2-textures, but without any transparent parts.)
- Slider for adjust transparency already set up. When initialize the foreground alpha value to 0.5f, itīs half transparent, but when repaint the hole foreground in case of chanced alpha, it doesnīt take effect and remains 50% transparent. Does OpenGl store this RGBA-values somewhere while initializing the scene and just read this informations when repainting it? I donīt understand why it wonīt take effect.

To do so, there are some qustions, i want to ask you:

1. My textures are not of base 2. Is it possible, to map an image as texture with e.g. 600x800 onto a quad with same size?

2. While changing the foregrounds opacity, the background must be permanent visible. But the transparent parts of the background texture needed obviously to be invisible.

3. As test iīm using
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
but then the background also gets transparent! Why? I dontīs want to change anything in the background, just make the foreground invisible step by step.

4. How to mask the hole partially-transparent-textured-quad to enable adjusting itīs tranparency?

Am i totally wrong with the idea? I dontīt hope so.
Any hints and advice are wellcome.
Thanx in advance
Casius



PS:
My english makes me nowbody so fast after. :)

ZbuffeR
10-06-2008, 11:12 AM
That is it, you are on the right way. Pretty simple stuff, more details below.

1) if the extension GL_ARB_texture_non_power_of_two is present, you can directly use non-power-of-two (NPOT) textures. Otherwise you have to partially fill a bigger POT texture and adjust the texture coordinates ranges, instead of [0;1] in both direction. exemple, you may use [0;800/1024.0][0;600/1024.0]

2) use default blending mode, activate blending :
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // the default anyway
glEnable(GL_BLEND);
Draw first the background, then the foreground, without depth testing.

3) glClear is not a test. it allows to clear one or more buffers.
you have to clear then draw both quads each time you refresh the display. You should disable any test for these operations (depth test, alpha test, stencil test can all ruin the result).

4) set glEnable(GL_COLOR_MATERIAL); then before rendering the foreground quad simply do :
glColor4f(1.0f,1.0f,1.0f,ALPHA); // tie ALPHA to slider values between 0.0 (invisiable) and 0.1 (fully opaque)
// draw foreground quad
glColor4f(1.0f,1.0f,1.0f,1.0f);// go back to normal


have fun :-)

Casius
10-06-2008, 01:18 PM
Thanks a lot, ZbuffeR, for the quick timenear answer!

1) going to check it out tomorror

2)The alpha slider throws integers as signal (Iīm using QT) - but the color was glColor4f! Slider to zero - quad disapeard! grrr Another day lost!

Draw first the background, then the foreground, without depth testing.
What is written first (LOC), getīs drawn first? [y/n]

3) The Problem, wasnīt clearing the buffer (see Point 2) - grrrr!
First line in my paintGL() func, which is called immediately if alpha changes:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
I hope you ment this buffer?
Do I need to clear second one, if GL_DEPTH_TEST is disabled?
Is GL_DEPTH_TEST enabled per default? [y/n]

4) set glEnable(GL_COLOR_MATERIAL);
Do you mean generally - when init gl, or is needed enabled just while rendering the forground?
I mean, is GL_COLOR_MATERIAL included in state of go back to nomal?

I want to use a list for each quad (using glGenLists(index, GL_COMPILE) because I need up to 10 pairs of background an foreground quads, in a role, so a foreground is also a backgroud for the next foreground and so on). Is there any to BEER in mind regarding the buffer issue?
Is it important to declare the color or map the textures within or outside these list?
Or is such kind of "list" just used as placeholder, which wonīt get stored especially?

Big thumbs up for your help! Thanks!

Fun is over for today ;-)

ZbuffeR
10-06-2008, 01:45 PM
2) yes the drawing order is kept.

3) no need to clear depth buffer is depth test is disabled.
For default values, RTFM the glEnable entry here :
http://www.opengl.org/sdk/docs/man/

4) Enable it just once after GL init. Unless you actually need to use glMaterial commands.
To go back to normal in this case only the glcolor 1111 is needed.

You probably don't need to bother with display lists, unless you have high polycount or complex opengl state changes.
But you have to handle properly your textures :
At init time ONLY, generate 10 texture "names" (actually integer IDs).
then for each one i:
- glBindTexture i
- glTexture2D it for the texture data
- do various per texture settings (interpolation mode, disable mipmaps (ON by default, and unless you generate mipmaps the texture would not work).

Afterwards in the main render loop you only need to bind i, draw the quad, etc.

Casius
10-07-2008, 01:22 PM
Thanks a lot for your help, ZbuffeR.
Itīs set up like asked in first post.

For all others, who dealing with same or simmilar stuff here my results. Works fine for me:

/* All other stuff
*
* QList<Pixmap> layerPixmaps; and layerCount=layerPixmaps.size();
* GLuint* textures;
*/

void GLWidget::initializeGL()
{
glClearColor(1.0f, 0.5f, 0.0f, 1.0f); // White Background

glMatrixMode(GL_MODELVIEW);

glDisable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glEnable(GL_TEXTURE_2D);

//to enable my_own_blend effect
glEnable(GL_COLOR_MATERIAL);

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);

textures = new GLuint[layerCount];
//bind all textures to array - with QT function provided for convenience as QT doku sais
for (int i=0; i < layerCount; ++i)
textures[i] = bindTexture(layerPixmaps[i], GL_TEXTURE_2D);
}

void GLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);

glLoadIdentity();
//translate scene in correct place for viewport
glTranslated(0.0, 0.0, -10.0);

//realize rotate scene
glRotated(xRot / 16.0, 1.0, 0.0, 0.0);
glRotated(yRot / 16.0, 0.0, 1.0, 0.0);
glRotated(zRot / 16.0, 0.0, 0.0, 1.0);

//draw each layer, from far to near ragarding blending

if (layerCount > 0)
for (int i=0; i < layerCount; ++i){
//drawing reverse incoming order to obtain "from far to near" order
drawLayer((layerCount-1)-i, sizeX, sizeY);
}
}

void GLWidget::drawLayer(int ID, float sizeX, float sizeY) //size* is temporally set up fixed. Need this later
{
GLfloat z = -ID*0.2; //just for testing
//color for material to adjust blending
glColor4f(1.0f,1.0f,1.0f,alpha[ID]); // latter are quad corresponding alpha values, selective adjustable
//bind texture to layer
glBindTexture(GL_TEXTURE_2D, textures[ID]);
//draw quad with according size
glBegin(GL_QUADS);
glTexCoord2d(0,0); glVertex3d(-sizeX, +sizeY, z);
glTexCoord2d(1,0); glVertex3d(+sizeX, +sizeY, z);
glTexCoord2d(1,1); glVertex3d(+sizeX, -sizeY, z);
glTexCoord2d(0,1); glVertex3d(-sizeX, -sizeY, z);
glEnd();
//reset color - go back to normal ;-)
glColor4f(1.0f,1.0f,1.0f,1.0f);
}
eof