I have been trying to create a hud in my OpenGL application. Having looked around, it seems the way to do it is with an ortho projection, but so far I have not been able to get the program to render correctly. What is happening is instead of rendering on top of my display, I'm getting odd graphical glitches as seen here:
If I comment out the hud code, everything renders perfectly.
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
//Set up projection matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//Using gluPerspective. It's pretty easy and looks nice.
gluPerspective(fov, aspect, zNear, zFar);
//Set up modelview matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//3D rendering
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,window_width,0,window_height); //left,right,bottom,top
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(0.0,0.0,1.0);
glBegin(GL_QUADS);
glVertex2f(50,50);
glVertex2f(50,100);
glVertex2f(100,100);
glVertex2f(100,50);
glEnd();
Once you're done rendering the HUD, you need to re-enable the depth writes
glDepthMask(GL_TRUE);
When you clear the buffers when rendering your HUD, all that has been
drawn so far (your 3D scene) will also be cleared. So don't clear the buffer twice.
Related
I am trying to draw a 2D scene with a texture as background and then ( as the program flows and does computations ) draw different primitives on the "canvas". As a test case I wanted to draw a blue quad on the background image.
I have looked at several resources and SO questions to try get the information I need to accomplish the task ( e.g. this tutorial for first primitive rendering, SOIL "example" for texture loading ).
My understanding was that the texture will be drawn on Z=0, and quad as well. Quad would thus "cover" a portion of texture - be drawn on it, which is what I want. Instead the result of my display function is my initial texture in black/blue colour, and not my texture ( in original colour ) with a blue quad drawn on it. This is the display function code :
void display (void) {
glClearColor (0.0,0.0,0.0,1.0);
glClear (GL_COLOR_BUFFER_BIT);
// background render
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, 1024.0, 512.0, 0.0, 0.0, 1.f); // window size is 1024x512
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, texture );
glBegin (GL_QUADS);
glTexCoord2d(0.0,0.0); glVertex2d(0.0,0.0);
glTexCoord2d(1.0,0.0); glVertex2d(1024.0,0.0);
glTexCoord2d(1.0,1.0); glVertex2d(1024.0,512.0);
glTexCoord2d(0.0,1.0); glVertex2d(0.0,512.0);
glEnd(); // here I get the texture properly displayed in window
glDisable(GL_TEXTURE_2D);
// foreground render
glLoadIdentity();
gluPerspective (60, (GLfloat)winWidth / (GLfloat)winHeight, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glColor3f(0.0, 0.0, 1.0);
glBegin (GL_QUADS);
glVertex2d(400.0,100.0);
glVertex2d(400.0,500.0);
glVertex2d(700.0,100.0);
glVertex2d(700.0,500.0);
glEnd(); // now instead of a rendered blue quad I get my texture coloured in blue
glutSwapBuffers(); }
I have already tried with many modifications, but since I am just beginning with OpenGL and don't yet understand a lot of it, my attempts failed. For example, I tried with pushing and popping matrices before and after drawing the quad, clearing the depth buffer, changing parameters in gluPerspective etc.
How do I have to modify my code so it will render the quad properly on top of the background texture image of my 2D scene ? Being a beginner, extra explanations of the modifications ( as well as mistakes in the present code ) and principles in general will be greatly appreciated.
EDIT - after answer by Reto Koradi :
I have tried to follow the instructions, and the modified code now looks like :
// foreground render
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glOrtho(0.0f, 1024.0, 512.0, 0.0, 0.0, 1.f);
glColor3f(0.0, 0.0, 1.0);
glBegin (GL_QUADS); // same from here on
Now I can see the blue "quad", but it is not displayed properly, it looks something like this .
Beside that, the whole scene is flashing really quickly.
What do I have to change in my code so that quad will get displayed properly and screen won't be flashing ?
You are setting up a perspective transformation before rendering the blue quad:
glLoadIdentity();
gluPerspective (60, (GLfloat)winWidth / (GLfloat)winHeight, 1.0, 100.0);
The way gluPerspective() is defined, it sets up a transformation that looks from the origin down the negative z-axis, with the near and far values specifying the distance range that will be visible. With this transformation, z-values from -1.0 to -100.0 will be visible. Which does not include your quad at z = 0.0.
If you want to draw your quad in 2D coordinate space, the easiest solution is to not use gluPerspective() at all. Just use a glOrtho() type transformation like you did for your initial drawing.
If you want perspective, you will need a GL_MODELVIEW transformation as well. You can start with a translation in the negative z-direction, within a range of 1.0 to 100.0. You may have to adjust your coordinates for the different coordinate system as well, or use additional transformations that also translate in xy-direction, and possibly scale.
The code also has the coordinates in the wrong order for drawing the blue quad. You either have to change the draw call to GL_TRIANGLE_STRIP (recommended because it at least gets you one step closer to using features that are not deprecated), or swap the order of the last two vertices:
glBegin (GL_QUADS);
glVertex2d(400.0,100.0);
glVertex2d(400.0,500.0);
glVertex2d(700.0,500.0);
glVertex2d(700.0,100.0);
glEnd(GL_QUADS);
I use the following code trying to render a partial frame of a viewport.
Start and end is a part of the frame, which is correct.
glViewport(start,0,end,SAVE_HEIGHT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90.0f, 1.0f, NEAR, FAR);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
The code seems out of order; I had it working before. From what I could find of sparse documentation, this seems the correct order however.
The visual output is that I do not see some parts, and the parts that are rendered do not have the correct perspective. As a note, I am rendering to the same FBO each time.
The expected output is that each time the code is called a part of the viewport is rendered to the same fbo.
My question: how can I render to an FBO partially each iteration?
I was looking for glScissor apparently.
I am currently working on a little toy program with OpenGL which shows a scene in clip-space view, i.e. it draws a cube to visualize the canonical view volume and inside the cube, the projectively transformed model is drawn. To show a code snippet for the model drawing:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glScalef(1.0f, 1.0f, -1.0f);
glMultMatrixd(projectionMat);
glMultMatrixd(modelviewMat);
glEnable(GL_LIGHTING);
draw_model();
glDisable(GL_LIGHTING);
So, naturally, the drawn model is "distorted" (which is the desired behaviour). However, the lighting is wrong, as the surface normals are also transformed by the projection matrix and, thus, are not orthogonal to their surfaces after transform. What I am trying to accomplish is lighting that is "correct" in the sense that the surfaces of the distorted models have correct normals.
The question is - how can I do that? I was playing with the usual transposed-inverse-matrix rule for normals, but as far as I understand, that's what OGL does with its normals by default. I think I would have to recalculate the surface normals AFTER the surfaces are transformed with the modelview matrix, but how to do that? Or is there another way?
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glScalef(1.0f, 1.0f, -1.0f);
glMultMatrixd(projectionMat);
The projection matrix goes into glMatrixMode(GL_PROJECTION);. Transforming the normals happens with the inverse transpose of the modelview. If there's a projection component in the modelview it messes up your normal transformation.
The correct code would be
glMatrixMode(GL_PROJECTION);
glLoadMatrixd(projectionMat);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glScalef(1.0f, 1.0f, -1.0f);
glMultMatrixd(modelviewMat);
glEnable(GL_LIGHTING);
draw_model();
glDisable(GL_LIGHTING);
If you're using fixed-function, you must put all of this in your projection matrix. Including the scale, translation, and rotation that happens after the projection:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glScalef(1.0f, 1.0f, -1.0f);
glMultMatrixd(projectionMat);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMultMatrixd(modelviewMat);
glEnable(GL_LIGHTING);
draw_model();
glDisable(GL_LIGHTING);
This works because the positions (ie: what you see) are transformed by both the projection and modelview matrices, but the fixed-function lighting is done only in view space (ie: after modelview but before projection).
In fact, this is exactly why fixed-function GL has a distinction between the two matrices.
Here is the thing: I want to load a picture as a background filled in the whole viewport. This background should always face to the camera no matter where the camera face to.
First I naturally think use a texture as a background, my code is below:
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0,1,0,1,0,1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glBindTexture(GL_TEXTURE_2D, myimage.GetID());
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2f(0, 0);
glTexCoord2f(1, 0); glVertex2f(1, 0);
glTexCoord2f(1, 1); glVertex2f(1, 1);
glTexCoord2f(0, 1); glVertex2f(0, 1);
glEnd();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
Believe me, myimage is a CIMAGE class that can load pics into textures, it works well.
However, for some unknown reason, my application cannot load a texture into a rectangle. (I described this problem here click) As a result, I only can see a rectangle frame around my viewport.
So, I figure out another solution.
I use the glDrawPixels instead of a texture. My code is below:
glRasterPos2i(0, 0);
glDrawPixels(myimage.GetWidth(), myimage.GetHeight(), (myimage.GetBPP() == 24)?GL_RGB:GL_RGBA, GL_UNSIGNED_BYTE,
myimage.GetData());
The picture appeared! However, the pic didn't always face to my camera. It only appears in a particular direction. You know, like a object in the scene, but not a background always face to the camera.
So anybody know how to use the glDrawPixels to implement a background?
By the way, I think this background is not a object placed in the 3D scene. So billboards may not be my solution. Again, this background filled in the whole view port and always face to camera.
One of the reasons your texture loading might not work is because it might not have power-of-two dimensions. Try a square 256x256 texture (or the like) to see if this is the problem. Look here for more info on Rectangle Textures.
Coming back to your background issue - the right way to do this would be to
Set up an orthographic projection/viewport that fills the entire screen.
glViewport(0,0,nw,nh);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,1,0,1,0,1);
glMatrixMode(GL_MODELVIEW);
Disable depth testing
Draw the fullscreen quad with the texture/texture rectangle you have loaded.
glBegin(GL_QUADS);
glVertex2f(0,0);
glVertex2f(1,0);
glVertex2f(1,1);
glVertex2f(0,1);
glEnd();
Set up your regular projection/modelview and continue.
Hope this helps!
I'm having some troubles converting a orthogonal camera to a perspective one, using OpenGL.
I currently have my orthogonal camera following a middle point of two objects, using:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,_winWidth,0,_winHeight,150,-150);
glTranslated(-_middlePoint[0]+_winWidth/2, -_middlePoint[1]+_winHeight/2, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
The above code works perfectly, now i'm trying to use it like this:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, _winWidth/_winHeight, 1.0, 1000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, 800, _middlePoint[0], _middlePoint[1], 50, 0, 0, 1);
glLoadIdentity();
And I simply get a black screen. Any thoughts? I've tried changing the up vector from 0,0,1 to 0,1,0 and it stays the same.
Any help appreciated.
If you have code working using glOrtho already, you can normally switch to a perspective projection by simply changing that to glFrustum. If you're writing new code, gluPerspective and gluLookat may be easier, but for code that already works using an orthographic projection, it's easy to switch to perspective by just calling glFrustum with the same parameters.