Blending problems (OpenGL) - opengl

A have a question, maybe someone can help me.
I am trying to make a mirror effect using OpenGL. I draw a transparent plane, a "reflected" scene cut by stencil, and an original one.
But I have a completely non-transparent "wall" instead of the mirror. I know it happens because of the first mirror plane rendering (to get a stencil buffer). But I don't know what to do with this:(
Here is the code:
void CMirror::draw(CSceneObject * curscene)
{
glPushMatrix();
glClearStencil(0.0f);
glClear(GL_STENCIL_BUFFER_BIT);
//Draw into the stencil buffer
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glStencilFunc(GL_ALWAYS, 1, 0);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glEnable(GL_STENCIL_TEST);
glPushMatrix();
glTranslatef(this->coords[0], this->coords[1], this->coords[2]);
glScalef(this->size, this->size, this->size);
glColor4f(1, 0, 1, 0);
glBegin(GL_QUADS);
glVertex3f(0.0f, this->height / 2.0f, this->width / 2.0f);
glVertex3f(0.0f, this->height / -2.0f, this->width / 2.0f);
glVertex3f(0.0f, this->height / -2.0f, this->width / -2.0f);
glVertex3f(0.0f, this->height / 2.0f, this->width / -2.0f);
glEnd();
glPopMatrix();
glDisable(GL_STENCIL_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
//glClear(GL_COLOR_BUFFER_BIT);
//Draw the scene
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 1, 255);
glPushMatrix();
glTranslatef( 2*this->coords[0], 2*this->coords[1], 2*this->coords[2]);
glScalef(-1.0f, 1.0f, 1.0f);
((CScene*)curscene)->draw();
glColor4f(0.0f, 0.30f, 0, 0.9);
((CScene*)curscene)->spline->draw();
((CScene*)curscene)->morph->draw();
glPopMatrix();
glDisable(GL_STENCIL_TEST);
//the mirror itself:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glPushMatrix();
glTranslatef(this->coords[0], this->coords[1], this->coords[2]);
glScalef(this->size, this->size, this->size);
glColor4f(0, 0, 0, 0.9);
glBegin(GL_QUADS);
glVertex3f(0.0f, this->height / 2.0f, this->width / 2.0f);
glVertex3f(0.0f, this->height / -2.0f, this->width / 2.0f);
glVertex3f(0.0f, this->height / -2.0f, this->width / -2.0f);
glVertex3f(0.0f, this->height / 2.0f, this->width / -2.0f);
glEnd();
glPopMatrix();
glDisable(GL_BLEND);
glPopMatrix();
}

What happens if you don't do that last draw (i.e. if the problem is still there, remove it as it complicates the example)?
One thing that's clear is that you don't seem to handle anything Z-buffer related.
When you draw your first quad to set the stencil, assuming Z-write is on, you end up setting the Z-values to your mirror Z. Drawing the scene that is supposed to be reflected in the mirror will be Z-rejected.
You need to clear the Z buffer for that region of the screen somehow. Obviously, a full Clear(DEPTH_BIT) can work but it depends on what you've already drawn on your screen.
Likewise, not updating the Z-buffer when updating the stencil can work depending on whether anything has been drawn there before.

Related

Image cropping for non standard aspect ratio format

I am facing the problem of rendering the correct image with some portion of the edges cropped out. I can observe this only for non-standard aspect ratio.
In my case width is 1228 and height is 972 which is yielding an aspect ratio of 1.26.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glClearColor(0.0, 0.0, 0.0, 1.0);
float vx = float(m_uiImageWidth) / float(m_uiImageWidth);
float vy = float(m_uiImageHeight) / float(m_uiImageWidth);
glEnable(GL_TEXTURE_2D);
glTexImage2D(GL_TEXTURE_2D, 0, 3, m_uiImageWidth, m_uiImageHeight, 0, GL_BGR, GL_UNSIGNED_BYTE, m_arrayBufferVS1);
glLoadIdentity();
glBindTexture(GL_TEXTURE_2D, m_texture);
//glTranslatef(0.0f, 0.0f, -1.36f);
glTranslatef(0.0f, 0.0f, -1.358f);
//Normal
if(m_bContextMenuNormal)
glRotatef(180, 1, 0, 0);
else if (m_bContextMenuRotate180 && m_bContextMenuMirror)
{
//do nothing
}
else if(m_bContextMenuMirror)
glRotatef(180, 0, 0, 0);
else if(m_bContextMenuRotate180)
glRotatef(180, 0, 1, 0);
glScalef(1, -1, 1);
glBegin(GL_QUADS);
glTexCoord2f(1.0f, 1.0f); //top right
glVertex3f(vx, vy, 0.0f);
glTexCoord2f(0.0f, 1.0f); // left top
glVertex3f(-vx, vy, 0.0f);
glTexCoord2f(0.0f, 0.0f); //left bottom
glVertex3f(-vx, -vy, 0.0f);
glTexCoord2f(1.0f, 0.0f); //right bottom
glVertex3f(vx, -vy, 0.0f);
glEnd();
glDisable(GL_TEXTURE_2D);
This is my code snippet. It would be a great help if anyone points out the mistake I have made and suggestions to fix.
modify your calls to glTexCoord2f, the decimal values are interpolated between the four vertexes and then multiplied by the width and height of the image to calculate the coordinates of each pixel from the texture to draw to the screen. if you want to crop the left and right of your image with an aspect ratio of 1.26 into a square you would use the following texture coordinates:
glTexCoord2f(1.0f - 0.13f, 1.0f); //top right
glTexCoord2f(0.0f + 0.13f, 1.0f); // left top
glTexCoord2f(0.0f + 0.13f, 0.0f); //left bottom
glTexCoord2f(1.0f - 0.13f, 0.0f); //right bottom
0.13 * 1228 is 159.64 pixels, and when you remove 159.64 pixels from either side of your 1228 pixel wide texture the remaining portion of the image is 972 pixels wide, meaning the aspect ratio of the pixels drawn will be 1:1 because your texture is 972 pixels tall

Text color is not correct

void text(string str)
{
for (int i = 0; i < str.length(); i++)
{
glColor3f(0.0f, 0.0f, 0.0f);
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, str[i]);
}
}
void render(void)
{
int width = glutGet(GLUT_WINDOW_WIDTH);
int height = glutGet(GLUT_WINDOW_HEIGHT);
if (height == 0) height = 1;
GLfloat aspect = (GLfloat)width / (GLfloat)height;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_SCISSOR_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, aspect, 0.1f, 100.0f);
// Top view - top left
glViewport(0, 0, width/2, height/2);
glScissor(0, 0, width/2, height/2);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
PilotView(0.0f, 0.0f, -5.0f, 0.0f, 0.0f, 0.0f, 1.0f);
glRasterPos3f(-0.1f, -0.1f, 4.0f);
text("Front");
diode();
// Corner view - top right
glViewport(width/2, 0, width/2, height/2);
glScissor(width/2, 0, width/2, height/2);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
PilotView(0.0f, 0.0f, -5.0f, 0.0f, -90.0f, 0.0f, 1.0f);
glRasterPos3f(4.0f, -0.1f, 0.1f);
text("Right");
diode();
// Front view - bottom left
glViewport(0, height/2, width/2, height/2);
glScissor(0, height/2, width/2, height/2);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
PilotView(0.0f, 0.0f, -5.0f, 90.0f, 0.0f, 0.0f, 1.0f);
glRasterPos3f(-0.1f, 4.0f, 0.0f);
text("Top");
diode();
// Right view - bottom right
glViewport(width/2, height/2, width/2, height/2);
glScissor(width/2, height/2, width/2, height/2);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
PilotView(0.0f, 0.0f, -5.0f, 20.0f, 0.0f, 0.0f, 1.0f);
glRasterPos3f(-0.1f, 4.0f, 0.0f);
text("Fro4nt");
diode();
glDisable(GL_SCISSOR_TEST);
glutSwapBuffers();
}
I'm not sure where the white "Front" and the yellow "Top"/"Right" is coming from (in terms of color). They all should be black. Does anyone know what the issue is?
Here is what the output looks like:
As suspected, this may come as a shock but glRasterPos (...) actually tracks the "current" color when you call that function. That is, whatever color was set before glRasterPos (...) was called, applies as the "current color" for drawing operations at that position. Think of it almost as the rasterizer's analog to glVertex (...), as I will explain below.
You need to set the current color before you call glRasterPos (...), to that end you should remove the glColor3f (...) call completely from your text (...) function, or perhaps modify that function to do both - set the color and then the raster pos, then draw the text.
glRasterPos — specify the raster position for pixel operations:
The current raster position consists of three window coordinates (x, y, z), a clip coordinate value (w), an eye coordinate distance, a valid bit, and associated color data and texture coordinates.

OpenGL Drawing Axis in Corner

I've been searching on how to draw an Indicator-Axis in my OpenGL scene. The project's nested in a Qt OpenGL widget, but I think the problem is independent of Qt.
I have found on here and forums from years ago that suggest storing the viewport and data, loading new ones for the botttom corner, apply my rotations and draw, then restore the matrices. This seems the most beneficial to me, but I'm guessing I'm still missing some critical info in my OpenGL knowledge.
For now I just have it drawing a red line from -x to x, so I expected to have a red square in the bottom left of the screen:
void GLWidget::drawAxis()
{
float tempPro[16];
float tempMod[16];
glGetFloatv(GL_PROJECTION_MATRIX, &tempPro[0]);
glGetFloatv(GL_MODELVIEW_MATRIX, &tempMod[0]);
glViewport(0, 0, 50, 50);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, 1.0f, 0.1f, 20.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
glBegin(GL_LINES);
glColor3f(1.0f, 0.0f, 0.0f);
glEnable( GL_LINE_SMOOTH );
glLineWidth( 1.5 );
glVertex3f(-1000, 0, 0);
glVertex3f(1000, 0, 0);
glEnd();
glPopMatrix();
glViewport(0, 0, 960, 600);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(tempPro);
gluPerspective(45.0f, (960.0/600.0), 0.1f, 400.0f);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(tempMod);
}
Instead I get nothing, just a large empty scene, and I'm unsure how to proceed. My paintGL is essentially:
void GLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
Camera.Render();
glTranslatef(0.0, 0.0, 0.0);
glBegin(GL_QUADS);
glColor3f(1.0f, 1.0f, 1.0f);
glVertex3f(50.0f, 0.0f, 50.0f);
glVertex3f(50.0f, 0.0f, -50.0f);
glVertex3f(-50.0f, 0.0f, -50.0f);
glVertex3f(-50.0f, 0.0f, 50.0f);
glEnd();
drawAxis();
}
Not calling the draw-axis function still gives me my plane, with it, I get a large blank scene. Am I missing something in how I'm implementing the drawAxis? Should I setup another camera for the function or something like that?
You can use glPushMatrix() and glPopMatrix() to save and restore the state of your Projection and ModelView matrices.
Your not setting up your ModelView matrix to anything useful.
Try something like this:
void GLWidget::drawAxis()
{
glViewport(0, 0, 50, 50);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
gluPerspective(45.0f, 1.0f, 0.1f, 20.0f);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
//This really has to come from your camera....
gluLookAt(10.0f,10.0f,10.0f, 0.0f,0.0f,0.0f, 0.0f,0.1f,0.0f);
glColor3f(1.0f, 0.0f, 0.0f);
glEnable( GL_LINE_SMOOTH );
glLineWidth( 1.5 );
glBegin(GL_LINES);
glVertex3f(-1000, 0, 0);
glVertex3f(1000, 0, 0);
glEnd();
//Restore View
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glViewport(0, 0, 960, 600);
}

Alphablending not resulting in desired image

I grab images from two cameras (each image 8bit grayscale), and upload those images to a texture. I then want to draw those textures overlayed, to result in 50% from one image, and 50% from the other image, but I don't know why it wouldn't result in what I need.
Below is my setup for alpha blending:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Alpha Blending
To update my textures:
glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY, g_Image[g_iCounter].GetCols(), g_Image[g_iCounter].GetRows(), 0, GL_RED, GL_UNSIGNED_BYTE, g_Image[g_iCounter].GetData());
g_Image is a FlyCapture2 Image (Point Grey SDK), GetCols() / GetRows() returns the size of the image, GetData() the raw data pointer. This works fine, if I want to display the images side by side this does exactly what I want.
My drawing code:
glBindTexture(GL_TEXTURE_2D, texture2);
glBegin(GL_QUADS);
// Front Face
glTexCoord2f(left, bottom); glVertex3f(-1.0f, -1.0f, 0.5f);
glTexCoord2f(right, bottom); glVertex3f( 0.0f, -1.0f, 0.5f);
glTexCoord2f(right, top); glVertex3f( 0.0f, 1.0f, 0.5f);
glTexCoord2f(left, top); glVertex3f(-1.0f, 1.0f, 0.5f);
glEnd();
if(interleaved)
{
top = 0.0f;
bottom = 1.0f;
left = 0.0f;
right = 1.0f;
glColor4f(1.0, 1.0, 1.0, 0.5);
switch(flags1)
{
case 0: break;
case 1: left = 1.0f; right = 0.0f; break;
case 2: top = 1.0f; bottom = 0.0f; break;
case 3: top = 1.0f; bottom = 0.0f; left = 1.0f; right = 0.0f; break;
default: break;
}
glEnable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, texture);
glBegin(GL_QUADS);
// Front Face
glTexCoord2f(left, bottom); glVertex3f(-1.0f, -1.0f, 0.5f);
glTexCoord2f(right, bottom); glVertex3f( 0.0f, -1.0f, 0.5f);
glTexCoord2f(right, top); glVertex3f( 0.0f, 1.0f, 0.5f);
glTexCoord2f(left, top); glVertex3f(-1.0f, 1.0f, 0.5f);
glEnd();
glDisable(GL_BLEND);
}
}
This though will always result in me seeing both images, but the first image drawn will always the better visible one, and it's no 50/50 blend. What do I need to alter to get it to do 50/50?
Don't draw them on top of each other. Move the second slightly closer to the camera, just by a whisker. A difference of about 0.000001 ought to do it.

OpenGL Depth Spaz Attack

I've begun learning OpenGL today, and it's just plain fantastic. However I cannot for the life of me make objects draw according to depth, instead of drawing order, so I hope someone can tell me what I'm doing wrong.
Here's the extremely simple code I'm using to create a cube:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
//Simple translation
glBegin(GL_QUADS);
glColor3f(0.0f,1.0f,0.0f);
glVertex3f( 1.0f, 1.0f,-1.0f);
glVertex3f(-1.0f, 1.0f,-1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
glColor3f(1.0f,0.5f,0.0f);
glVertex3f( 1.0f,-1.0f, 1.0f);
glVertex3f(-1.0f,-1.0f, 1.0f);
glVertex3f(-1.0f,-1.0f,-1.0f);
glVertex3f( 1.0f,-1.0f,-1.0f);
glColor3f(1.0f,0.0f,0.0f);
//You get the point, continue with all sides
glEnd(); // End Drawing The Cube
SDL_GL_SwapBuffers();
Here's the set up code:
if (SDL_Init(SDL_INIT_EVERYTHING)<0)
return -1;
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2);
SDL_Surface* screen = SDL_SetVideoMode(screen_x,screen_y,32,SDL_HWSURFACE|SDL_GL_DOUBLEBUFFER|SDL_OPENGL);
if (screen == NULL)
return -2;
//glEnable(GL_DEPTH_TEST); //<-If this is uncommented look at figure 1
glDepthFunc(GL_LESS);
glClearColor(0, 0, 0, 0);
glClearDepth(1.0f);
glViewport(0, 0, screen_x, screen_y);
glMatrixMode(GL_PROJECTION); //projection with ortho, model otherwise
glLoadIdentity();
gluPerspective(60.0,1.0,0.0,10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
Well, when I
glEnable(GL_DEPTH_TEST);
...
And if I don't enable it
So what am I supposed to do? I must be missing ... something? How do I fix my depth issue?
I found the answer!
http://www.opengl.org/resources/faq/technical/depthbuffer.htm
Here's where I found the answer, My near frame was at exactly 0, it needs to be slightly away from 0 in order for the depth buffer's precision to take effect. (If I read that correctly)
All is well.