I have the following code that takes snapshots to the framebuffer. I verified the framebuffer works correctly and the camera is facing the object correctly. I used to get pictures done correctly, but it was based on faulty code, using the wrong frustum. So I decided to start fresh (with the frustums).
The object is centered at the middle and is 32*32 blocks with each block 2*2, so 64 * 64.
My distance is 100 and my viewport is 128x256. My frustum is 1 to 1000.0.
I'm relatively new to Opengl so I'm having trouble understanding the concepts of frustrums and perspectives fully.
I do not get a picture at all.
saveGLState();
const int nrPics = 360 / DEGREES_BETWEEN_PICTURES;
for (int i = 0; i < nrPics; i++) {
catchFbo->bind();
glViewport(0, 0, PICTURE_WIDTH, PICTURE_HEIGHT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
float rat = PICTURE_WIDTH / PICTURE_HEIGHT;
glFrustum(- 1.0, + 1.0, - rat, + rat, 1.0, 1000.0);
gluPerspective(90.0f,rat,CAPT_FRUSTRUM_NEAR,CAPT_FRUSTRUM_FAR);
glColorMask(true, true, true, true);
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_MULTISAMPLE);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
drawScreenshot(i);
catchFbo->release();
QImage catchImage = catchFbo->toImage();
catchImage.save("object/test" + QString::number(i) + ".png");
}
glDisable(GL_MULTISAMPLE);
restoreGLState();
void VoxelEditor::saveGLState()
{
glPushAttrib(GL_ALL_ATTRIB_BITS);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
}
void VoxelEditor::restoreGLState()
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glPopAttrib();
}
EDIT: I tried using only glFrustum or glPerspective. No luck.
You shouldn't use both glFrustum and gluProjection. They both are operations which setup the projection matrix, and if you use them together you'll multiply them together and get a weird result. Generally you'd just apply glFrustum OR gluProjection on an identity matrix, not both.
If that doesn't solve the problem, what are your values of NEAR, FAR, WIDTH, and HEIGHT?
Also make sure you're not doing integer divide for your screen ratio (a common bug).
Related
So I draw an 'I' and use gluLookAt(0.f,0.f,3.f,0.f,0.f,0.f,0.f,1.f,0.f), and the I is moderate size. Then I add a drawScene() function which draw the background with gradient color, and then the 'I' becomes super big. I guess it is because I change matrix mode to GL_PROJECTION and GL_MODELVIEW in drawScene(), and those change the perspective maybe? I guess glPushMatrix() and glPopMatrix() are needed to reserve matrix status, but I have hard time finding where to put them. So how can I make the 'I' look normal size? Here are my drawI() and drawScene():
void drawI(int format)
{
glBegin(format);
glColor3f(0, 0, 1);
glVertex2f(point[3][0], point[3][1]);
glVertex2f(point[2][0], point[2][1]);
glVertex2f(point[1][0], point[1][1]);
glVertex2f(point[12][0], point[12][1]);
glVertex2f(point[10][0], point[10][1]);
glEnd();
glBegin(format);
glVertex2f(point[10][0], point[10][1]);
glVertex2f(point[11][0], point[11][1]);
glVertex2f(point[12][0], point[12][1]);
glEnd();
glBegin(format);
glVertex2f(point[9][0], point[9][1]);
glVertex2f(point[10][0], point[10][1]);
glVertex2f(point[3][0], point[3][1]);
glVertex2f(point[4][0], point[4][1]);
glVertex2f(point[6][0], point[6][1]);
glColor3f(1, 0.5, 0);
glVertex2f(point[7][0], point[7][1]);
glVertex2f(point[8][0], point[8][1]);
glEnd();
glBegin(format);
glColor3f(0, 0, 1);
glVertex2f(point[5][0], point[5][1]);
glVertex2f(point[6][0], point[6][1]);
glVertex2f(point[4][0], point[4][1]);
glEnd();
}
void drawScene()
{
glBegin(GL_QUADS);
//red color
glColor3f(1.0,0.0,0.0);
glVertex2f(-1.0,-1.0);
glVertex2f(1.0,-1.0);
//blue color
glColor3f(0.0,0.0,1.0);
glVertex2f(1.0, 1.0);
glVertex2f(-1.0, 1.0);
glEnd();
}
Thanks a lot!
So I take glMatrixMode() and glLoadIdentity() out of drawScene() and drawI() and put them in display(). I changed drawScene() and drawI() above, and here is my display()
void display()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(70.f,1.f,0.001f,30.f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
drawScene();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.f,0.f,3.f,0.f,0.f,0.f,0.f,1.f,0.f);
drawI(GL_TRIANGLE_FAN);
glutSwapBuffers();
}
The normal way to do this (in a 3D mode) is in your code, before you call drawI or drawScene would be:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fov, aspect, near, far); // fov is camera angle in degrees, aspect is width/height of your viewing area, near and far are your near and far clipping planes.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0,0.0,3.0,0.0,0.0,0.0,0.0,1.0,0.0)
In your 2D rendering, you probably don't need the call to gluPerspective, but these calls should be done in your code before you call drawI or drawScene. Do this and delete the glMatrixMode() and glLoadIdentity() calls from drawI and drawScene.
Edit:
If your "I" is still too big, there are a number of things you could do, but you should probably be operating in 3D (giving a Z coordinate also).
You could scale the object:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0,0.0,3.0,0.0,0.0,0.0,0.0,1.0,0.0)
glScalef(0.5, 0.5, 0.5);
You could move the camera further back (you'll need to include the gluPerspective() call as well):
gluLookAt(0.0,0.0,50.0,0.0,0.0,0.0,0.0,1.0,0.0);
Perhaps the easiest way to control the rendered image size in a 3D mode is to both move the camera (eye) back a way and then control the image size by changing the camera aperture angle (fov in the gluPerspective() call). A wider fov will shrink the rendered image; a smaller fov will enlarge it.
I don't know what the values for your coordinates are in drawI since they're variables, but a camera position of 3.0, an fov of 70.0 and an aspect of 1 should give you left, right, top and bottom clipping planes of about +/- 2.1 at Z = 0.
If you kept everything else the same and moved the camera to 50.0, the clipping planes would be at about +/- 35.0, so your "I" would occupy a much smaller portion of the viewing area.
If you then left the camera position at 50.0, but changed the fov to 40.0, the clipping planes would be at about +/- 18.2. Your "I" would fill a larger area than it did at cameraZ = 50.0, fov = 70.0, but a smaller area than cameraZ = 3.0, fov = 70.0.
You can play with camera position and fov to get the image size you want, or you could just scale the image. I like to keep camera position constant and change the fov. If I provide a function that changes the fov based on user input (maybe a mouse scroll), it's a good way to provide a zoom in/out effect.
BTW, in your original code, if you called:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0,0.0,3.0,0.0,0.0,0.0,0.0,1.0,0.0)
Then later in DrawI or drawScene call:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
You've trashed the matrix loaded by your earlier call to gluLookAt().
I need to draw a cube and project it with the default projection matrix. Also, I want to draw a hud controlling the orientation of the sphere. The hud is projected with another projection matrix.
render()
{
DrawGUI(); // project GUI with another projection matrix
glPushMatrix();
glutSolidCube(); // project the cube with the default projection matrix
glPopMatrix();
glutSwapBuffers();
}
reshape()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(...);
...
}
DrawGUI()
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(...); // project the GUI with this matrix
glMatrixMode(GL_MODELVEIW);
glPushMatrix();
glLoadIdentity();
glBegin();
//... drawing GUI
glEnd();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
#define BUFFER_LENGTH 64
void processSelection(int xPos, int yPos)
{
static GLuint selectBuff[BUFFER_LENGTH];
GLint hits, viewport[4];
glSelectBuffer(BUFFER_LENGTH, selectBuff);
glGetIntegerv(GL_VIEWPORT, viewport);
// Switch to projection and save the matrix
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glRenderMode(GL_SELECT);
glLoadIdentity();
gluPickMatrix(xPos, viewport[3] - yPos, 2,2, viewport);
glOrtho (-100, 100, -100, 100, -100, 100); // this line of code is the most
glMatrixMode(GL_MODELVIEW);
render();
hits = glRenderMode(GL_RENDER);
//...process hits
// Restore the projection matrix
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
The render part works well. Both the GUI and the cube are drawn without problem. However, the selection does not work as intended.
My question is: Since I project 3D models with different projection matrix, how should I deal with selection? I try to implement the typical selection buffer approach, but every time I click in the window, the selection buffer always contains the GUI even if I do not click on the GUI. Also, if I click on the cube, the selection buffer ends up with both the cube and the GUI.
If you use the selection buffer approach, you render with mixed projections as you do when doing the usual render. The only difference, is, that you apply that pick matrix as well. Also don't try to be too clever with the matrix pushing / poping. It rarely makes sense to use that in the projection matrix stack (hence it requires to have only 2 push levels, instead of the 32 for the modelview). Also don't use the reshape function to define the projection matrix.
DrawCube()
{
glMatrixMode(GL_MODELVEIW);
glLoadIdentity();
glutSolidCube();
}
DrawGUI()
{
glMatrixMode(GL_MODELVEIW);
glLoadIdentity();
glBegin();
//... drawing GUI
glEnd();
}
void render()
{
// base the projection on whats already in the projection
// matrix stack. For normal render this is identity, for
// selection it is a pick matrix.
glMatrixMode(GL_PROJECTION);
glPushMatrix();
gluOrtho2D(...); // project the GUI with this matrix
DrawGUI();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
gluPerspective(...);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
}
void display()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
render();
glutSwapBuffers();
}
#define BUFFER_LENGTH 64
void select(int xPos, int yPos)
{
static GLuint selectBuff[BUFFER_LENGTH];
GLint hits, viewport[4];
glSelectBuffer(BUFFER_LENGTH, selectBuff);
glGetIntegerv(GL_VIEWPORT, viewport);
// Switch to projection and augment it with a picking matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPickMatrix(xPos, viewport[3] - yPos, 2,2, viewport);
glRenderMode(GL_SELECT);
render();
hits = glRenderMode(GL_RENDER);
//...process hits
}
Note that OpenGL selection mode is usually not GPU accelerated and hence very slow. Also it's been deprecated and removed from modern OpenGL versions. It's highly recommended to use either index buffer selection (i.e. render each object with a dedicated index "color") or perform manual ray-intersection picking into the scene data.
I am attempting to make a simple drawing using openGL. However, the depth buffer doesn't appear to be working.
Other people with a similar problem are typically doing one of two things wrong:
Not including glEnable(GL_DEPTH_TEST)
Bad clipping values
However, my code does not have either of these problems.
...
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gluPerspective(25.0,1.0,10.0,200.0);
// Set the camera location
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(20.0, 10.0, 50.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
// Enable depth test
glEnable(GL_DEPTH_TEST);
// Cull backfacing polygons
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE)
drawCoordinateAxis();
drawBox(5.0,2.0,5.0,0.8,0.0,0.0);
glTranslated(1.0,-1.0,1.0); //The box is 5x2x5, it is shifted 1 unit down and 1 in the x and z directions
drawBox(5.0,2.0,5.0,0.0,1.0,1.0);
...
When I execute my code, this is drawn. http://imgur.com/G9y41O1
Note that the blue box and the red box collide, so the red box should be covering part of the blue box.
The functions drawCoordinateAxis() and drawBox() just draw a few primitives, nothing fancy inside.
I am running this on Debian squeeze.
void reshape(GLint width, GLint height)
{
g_Width = width;
g_Height = height;
glViewport(0, 0, g_Width, g_Height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(65.0, (float)g_Width / g_Height, g_nearPlane, g_farPlane);
glMatrixMode(GL_MODELVIEW);
}
So set Matrix Mode to GL_PROJECTION first, then gluPerspective.... and then back to MODELVIEW mode.
Been integrating this camera tutorial http://www.swiftless.com/tutorials/opengl/camera2.html and having a bit of trouble centering the camera in the skybox.
Using this code below makes my camera inside the box:
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-1.0, 1.0, -1.0*(GLfloat)h/(GLfloat)w,
1.0*(GLfloat)h/(GLfloat)w, -10.0, 10.0);
else
glOrtho(-1.0*(GLfloat)w/(GLfloat)h,
1.0*(GLfloat)w/(GLfloat)h, -1.0, 1.0, -10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
}
To draw the skybox, I followed this tutorial: http://sidvind.com/wiki/Skybox_tutorial
I've been trying to translate objects closer to the camera, but didn't work as I expected. Now I'm not sure what I need to do.
Appreciate any help.
First: Don'y apply the projection in the reshape handler. Otherwise simple things appear impossible (like doing a skybox). Second: For a skybox to work you must use the very same projection like for the rendering of the rest of the scene. What you should change is the translation of the modelview to 0, yet keeping the camera orientation.
You can do this by setting the last column of the modelview matrix to (0,0,0,1).
So this makes your rendering code like this:
void render_skybox()
{
push_modelview();
set_modelview_column(3, 0, 0, 1);
draw_skybox();
pop_modelview();
}
void render()
{
set_viewport();
set_projection();
apply_camera_transform();
render_skybox();
render_scene();
}
While attempting to render a 3D object using OpenGL (and the GLFW library), the model experiences lots of flickering. Im reading the .obj file using a library that I've written on my own.
Written below is my render function:
Unfortunately, in order to understand how faces and vertices are being inputted, I will have to provide all my code, which is linked:
Zipped code along with executable and sample .obj:
Source
Im using .obj files from here to test the program. Right now, the program doesn't support normals and textures, which isnt an issue since most of the models on the site dont have them. Also, (right now) it only reads from "123.obj" so the file should'nt be named anything else. And it only accepts a single space, not more than that.
float render()
{
glfwSetTime(0.0f);
int win_width;
int win_height;
glfwGetWindowSize(&win_width, &win_height);
float win_aspect = (float)win_width / (float)win_height;
glViewport(0, 0, win_width, win_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90, win_aspect, 0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, 50.0, 0, 0, 0, 0.0, 1.0, 0.0);
glEnable(GL_DEPTH);
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_NORMALIZE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glRotatef(angle , 0 , 1, 0);
glColor3f(0.0f, 0.0f, 0.0f);
int index = 0;
for(int a = 0; a < faces.size(); a++)
{
if(faces[a].vertices.size() == 3)
{
glBegin(GL_TRIANGLES);
}
else
{
glBegin(GL_QUADS);
}
for(int b = 0; b < faces[a].vertices.size(); b++)
{
index = faces[a].vertices[b];
glVertex3f(vertices[index].Dimensions[_x], vertices[index].Dimensions[_y], vertices[index].Dimensions[_z]);
}
glEnd();
}
glfwSwapBuffers();
return (float)glfwGetTime();
Here's the problem
gluPerspective(90, win_aspect, 0, 100.0);
You cannot set 0 as your nearclip, set it to something larger like 0.1, or 1.0.
gluPerspective(90, win_aspect, 1.0, 100.0);
With nearclip at 0, all of your depths get mapped to z = 1, and you get z fighting.
EDIT : if you're interested, here's some theory on perspective depth:
For a given distance from the camera x, your perspective transform outputs a certian depth value z. At the farclip, this value will be the maximum of 1, and at nearclip it will be 0.
Between these values however, relationship is not linear like you may expect. The curve looks similar to the following diagrams:
Diagram
When you go to the extreme of setting your nearclip to 0, your curve is heavily warped, so now all distances map to z = 1.
Because of all this, you should also try to keep the ratio far:near smaller than 10000:1