Immediate mode not drawing alpha texture correctly - c++

As the title says, whenever i enable blending like this:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
I cannot draw any texture using immediate mode. It is an RGBA texture. I confirmed that image loading and generating works correctly, as when i "downloaded" the pixel from the GPU to debug this, the alpha values seemed to be correct (not all of them were 255, for example.). However, the texture just disappears when drawing it like this with blending enabled:
glColor4ub(255, 255, 255, 0);
_texture->setActive(0);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(_x, _y);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(_x + _width, _y);
glTexCoord2f(1.0f, 1.0f);
glVertex2f(_x + _width, _y + _height);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(_x, _y + _height);
glEnd();
Where _texture->setActive() simply calls this:
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, m_ID);
Without blending, i get the following result:
But with blending it simply draws nothing (again, alpha values of the texture are confirmed to be correct!):
When it should look something like this:
What is the issue here?
Update
After applying glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);, i now get the expected output:

I think I found it:
glColor4ub(255, 255, 255, 0);
Assuming you apply texture using GL_MODULATE the alpha will be mixed with the "primitive" color. If setting alpha of the primitive to 0 then any mix with texture will end up 0 alpha.
I´m not sure what you want to do so I propose doing one of the following:
Apply texture using GL_REPLACE instead. Call glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE). Texture environment is part of your (active) texture unit config. From https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml
For OpenGL versions 1.3 and greater, or when the ARB_multitexture
extension is supported, glTexEnv controls the texture environment for
the current active texture unit, selected by glActiveTexture
Set primitive color to (255, 255, 255, 255)ub.

Related

OpenGL texture doesn't show correctly - strange behaviour

I want to detect a marker with OpenCV, and then I want to overlay it with an image, with OpenGL. First part is ok (I achieve detection marker perfectly), but I have some problems with the second.
marker is:
and image is:
but the result is this:
code to generate the texture of image is:
GLuint *textures = new GLuint[2];
glGenTextures(2, textures);
Mat image = imread("Immagine.png");
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 4,image.cols, image.rows, 0, GL_RGB,GL_UNSIGNED_BYTE, image.data);
and to show the texture i use:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, WIDTH, HEIGHT, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBindTexture(GL_TEXTURE_2D, textures[1]);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex2f((GLfloat)(coord[1].x),(GLfloat)(coord[1].y));
glTexCoord2f(1.0f, 0.0f); glVertex2f((GLfloat)(coord[2].x),(GLfloat)(coord[2].y));
glTexCoord2f(1.0f, 1.0f); glVertex2f((GLfloat)(coord[3].x),(GLfloat)(coord[3].y));
glTexCoord2f(0.0f, 1.0f); glVertex2f((GLfloat)(coord[0].x),(GLfloat)(coord[0].y));
glEnd();
I don't know why textured image is so strange. Also, I use the same code to show (on opengl window) captured frames from webcam and I have no problem.
I've noted also that if I use the same image without numbers at corners, it works correctly (even if it isn't in the same place/coordinates of marker).
Does anyone have any idea?
This is a padding/alignment issue.
You're loading a format which has different padding requirements to GL (which by default expects rows of pixels to be padded to a multiple of 4 bytes).
Possible fixes for this are:
Tell GL how your texture is packed, using (for example) glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
Change the dimensions of your texture, such that the padding matches without changing anything
Change the loading of your texture, such that the padding is consistent with what GL expects

3d cube opengl - overlapping sides

I want to create a 3d cube with openGL. Also, I want to cover each side with an image that I transform in a texture.
I find cube coordinates in 2D, and I create a QUADS for each side.
My problem is that when I render textures corresponding cube sides, I see these textures overlap each other, as you can see in this image:
my code is:
Initialization:
glGenTextures(2, textures);
glClearColor (0.0, 0.0, 0.0, 0.0);
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_ALWAYS);
Transform image in thexture:
up = imread("up.png");
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, up.cols, up.rows, GL_RGB, GL_UNSIGNED_BYTE, up.data);
Display cube:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
// Set Projection Matrix
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, WIDTH, HEIGHT, 0);
// Switch to Model View Matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBindTexture(GL_TEXTURE_2D, textures[1]);
glBegin(GL_QUADS);
//sopra
glTexCoord2f(0.0f, 0.0f); glVertex2f((GLfloat)((coord[6].x)),(GLfloat)(coord[6].y));
glTexCoord2f(1.0f, 0.0f); glVertex2f((GLfloat)((coord[5].x)),(GLfloat)(coord[5].y));
glTexCoord2f(1.0f, 1.0f); glVertex2f((GLfloat)((coord[4].x)),(GLfloat)(coord[4].y));
glTexCoord2f(0.0f, 1.0f); glVertex2f((GLfloat)((coord[7].x)),(GLfloat)(coord[7].y));
glEnd();
I do the same for the other sides of the cube.
The order in which I render textures is:
bottom (ground) side
up side
behind side
front side
left side
right side
what is wrong or what am I missing? Or, Maybe cannot create a 3d cube with 2d coordinates (glVertex2f (...))?
Thanks for your help!
You can't create a cube with 2d coordinates. The sides are overlapping because they are all on the same plane in space. A cube is in 3d space so needs 3 coordinates, x, y, and z.
So try using:
glVertex3f(x, y, z);
and use some appropriate z values depending on where you want each face.
For the texture you can still use:
glTexCoord2f(x, y);
since the textures are in 2 dimensional space.
If you are still confused about what to use for your coordinates I suggest you read this to help you understand 3d space in openGL:
http://www.falloutsoftware.com/tutorials/gl/gl0.htm

Draw polygons above background image

My question is to draw a polygon or some other OpenGL primitives above or over a background image. Summarizing like paint in different layers, but in OpenGL i think there is no layers.
Now i'm doing some test trying to draw a triangle and a line over the background image.
To draw the background i use a square with OpenGL window size and then apply the png image in this square as a texture.
After that I try to paint the triangle and the line with different colors but I don't see anything except the background image.
I play with the alpha channel but i don't see anything.
Code:
void init()
{
// glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);
// The following two lines enable semi transparent
glEnable(GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
int width, height;
bool hasAlpha;
char filename[] = "prueba-luz.png";
bool success = loadPngImage(filename, width, height, hasAlpha, &textureImage);
if (!success)
{
cout << "Unable to load png file" << endl;
return;
}
cout << "Image loaded " << width << " " << height << " alpha " << hasAlpha << endl;
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, hasAlpha ? 4 : 3, width,
height, 0, hasAlpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE,
textureImage);
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
void display(void)
{
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // Igual que GL_REPLACE pero se le puede aplicar transparencias a la textura
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPushMatrix();
glColor4f(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_QUADS);
glTexCoord2i(0,0); glVertex2i(10, -10);
glTexCoord2i(1,0); glVertex2i(-10, -10);
glTexCoord2i(1,1); glVertex2i(-10, 10);
glTexCoord2i(0,1); glVertex2i(10, 10);
glEnd();
glPopMatrix();
glDisable(GL_TEXTURE_2D);
glBegin(GL_POLYGON);
glColor4f(1.0, 1.0, 1.0, 0.8);
glVertex3f(-1.0f, -3.0f, 0.0f); // A
glVertex3f( 1.0f, -3.5f, 0.0f); // B
glVertex3f( 0.0f, 0.5f, 0.0f); // C
glEnd();
glBegin(GL_LINES);
glColor4f( 1.0, 0.0, 0.0, 0.8 );
glVertex2f(-8.0, 6.0);
glVertex2f (5.0, -3.0);
glEnd();
glutSwapBuffers();
}
How can i draw one image over the background image ???
Some things spotted :
Try to disable depth test. You are drawing everything at Z=0 and your application is definitely writing to the depth buffer. I'm not sure why you enable depth testing here since everything you draw is on Z=0.
By default all fragments written to the same or higher Z value will be discarded when depth testing is enabled. This can be changed with glDepthFunc (Default value GL_LESS). This is probably why your geometry is discarded in this example.
Drawing 2D geometry do not mean that the depth buffer will not be affected. OpenGL will draw this geometry with Z=0 and write that to your depth buffer.
Currently there is no reason for your application to use depth testing unless you draw your geometry on different z positions. You can use depth testing in 2D drawing to make "layers" by assigning different z values to each object.
A good practice for 2D drawing with z-culling is to draw the closes layer first, then draw the layers further in. This makes sure your write fewer fragments.
For example :
Z = 0 : Draw non-transparent overlays
Z = -1 : Draw stuff hidden behind the overlays
Z = -2 : Draw background
However, transparent objects need special rules.
You need to get control over your depth buffer. There are options :
glEnable/Disable(GL_DEPTH_TEST) : Enable or disable z-culling
glDepthMask(GL_TRUE/GL_FALSE) : Enable or disable writing to the the depth buffer
(glDepthFunc can be used to define how fragments are discarded)
Note here that the two first functions give you way more options than you might think
Depth culling and depth write when drawing objects
Depth culling, but your object do not affect the depth buffer
No depth culling, but your object will write to the depth buffer
No depth culling and no depth write
If you want to draw all your transparent objects in a last pass you can for example enable depth testing so the objects are not drawn on top your your overlays, but you disable depth writes because you want to be able to draw several overlapping objects in that layer.
Use your creativity and learn to love the depth buffer :D

problem blending properly in openGL

I'm trying to draw a 2d character sprite on top of a 2d tilemap, but when I draw the character he's got odd stuff behind him. This isn't in the sprite, so I think its the blending.
This is how my openGL is set up:
void InitGL(int Width, int Height) // We call this right after our OpenGL window is created.
{
glViewport(0, 0, Width, Height);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // This Will Clear The Background Color To Black
glClearDepth(1.0); // Enables Clearing Of The Depth Buffer
glDepthFunc(GL_LESS); // The Type Of Depth Test To Do
glDisable(GL_DEPTH_TEST); // Enables Depth Testing
//glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping ( NEW )
glShadeModel(GL_FLAT);
glMatrixMode(GL_PROJECTION);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glAlphaFunc(GL_GREATER, 0.5f);
glMatrixMode(GL_PROJECTION);//configuring projection matrix now
glLoadIdentity();//reset matrix
glOrtho(0, Width, 0, Height, 0.0f, 100.0f);//set a 2d projection matrix
}
How should I set this up to work properly (i.e. drawing the sprite without odd stuff behind him.
This is what I am talking about: http://i.stack.imgur.com/cmotJ.png
PS: I need to be able to put transparent/semi-transparent images on top of each other and have whats behind them visible too
Does your sprite have premultiplied alpha? Your glBlendFunc setup is a little unusual, if you don't have premultiplied alpha it could definitely be causing the issue.

Lightmap with multitexturing, disabling lighting for one of the textures?

How i can disable lighting for only one of the textures in this multitexturing scheme? I tried to use glDisable(GL_LIGHTING) and glEnable(GL_LIGHTING) but it doesnt remember the settings when i render the quad.
Here is the code snippet:
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glDisable(GL_TEXTURE_RECTANGLE_ARB);
glDisable(GL_TEXTURE_2D);
//------------------------
glActiveTextureARB(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, LIGHT_MAP); // texture with black/white
//------------------------
glActiveTextureARB(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, MY_TEXTURE); // normal texture
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);
glColor4f(1, 1, 1, 1);
glBegin(GL_QUADS);
glNormal3f(0,0,1);
glMultiTexCoord2fARB(GL_TEXTURE0, 0.0f, 0.0f);
glMultiTexCoord2fARB(GL_TEXTURE1, 0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);
glMultiTexCoord2fARB(GL_TEXTURE0, 0.0f, 1.0f);
glMultiTexCoord2fARB(GL_TEXTURE1, 0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 0.0f);
glMultiTexCoord2fARB(GL_TEXTURE0, 1.0f, 1.0f);
glMultiTexCoord2fARB(GL_TEXTURE1, 1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 0.0f);
glMultiTexCoord2fARB(GL_TEXTURE0, 1.0f, 0.0f);
glMultiTexCoord2fARB(GL_TEXTURE1, 1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 0.0f);
glEnd();
glActiveTextureARB(GL_TEXTURE0);
glDisable(GL_TEXTURE_2D);
glActiveTextureARB(GL_TEXTURE1);
glDisable(GL_TEXTURE_2D);
Edit: the texture loading:
glGenTextures(1, &LIGHT_MAP);
glBindTexture(GL_TEXTURE_2D, LIGHT_MAP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
Weird thing is that when i enable lighting at the first line of code, i cant see the light_map texture rendered at all in the multitexture quad. Also the lighting doesnt seem to affect that quad at all, it works on other quads (which arent multitextured) in my app.
Any help appreciated.
Your first sentence does not make sense. GL Lighting happens at the vertex level. texturing, be it single texture or multitexture. happens way after. In more details:
The lighting that got computed per vertex is interpolated to each fragment, and that value is input to the texturing pipeline stage 0.
So... The lit color L comes in and gets combined with the texture on the texture stage 0 (your light map here), according to the texture environment of stage 0. You don't show how you set up the Texture environment for texture stage 0, so I can't tell you how it will pass down.
Then your output from stage 0 (computed from lighting and texture 0) get sent to the texture stage 1 input (where your "normal" texture is bound. That's called a diffuse texture). You use an environment of COMBINE with ADD on both RGB and ALPHA here, which is not typical of lightmapping: You're adding your lighting+lightmap to the diffuse color. Usually you want to multiply them (GL_TEXTURE_ENV_MODE=GL_MODULATE rather than GL_COMBINE).
Also, you did not set the SOURCE0_ALPHA and SOURCE1_ALPHA, so I'm not sure what exactly you add to generate the stage 1 ALPHA output.
All in all, I'd advise to write down exactly what you want as a result first (as math), and try to map that to the GL multitexturing pipeline.
Edit: Following your comments, if you don't specify stage 0 TexEnv, then you get the default:
GL_TEXTURE_ENV_MODE defaults to GL_MODULATE and GL_TEXTURE_ENV_COLOR
defaults to (0, 0, 0, 0).
So your color coming from the lighting is modulated with your lightmap (which may make sense depending on what you're trying to achieve). That gets added to your diffuse (where, as I said, it should probably get modulated instead).
None of these change what I said earlier: write down exactly what math you would like for your result. From that we can help find which texture environment you may need. But you did not say what result you want to achieve.