So I'm pretty new to openGL programming and am just going over the basics for now. I know I should be using VBOs and stuff but wanted to get a little foundation first. I wont present you with all the code just the stuff that draws and sets the scene.
Heres a little code for setting up my camera:
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(70, width / height, 1, 1000);
glEnable(GL_DEPTH_TEST);
// Move the camera back to view the scene
glTranslatef(0.0f, 0.0f, -5.0f);
I tried to create it around the origin like so (also I never draw the bottom face) :
void drawtetrahedron(GLfloat angle)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(angle, 0.0f, 1.0f, 0.0f);
glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f); //FRONT
glVertex3f(0.0f, 1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 1.0f);
glVertex3f(-1.0f, -1.0f, 1.0f);
glColor3f(0.0f, 1.0f, 0.0f); //RIGHT
glVertex3f(0.0f, 1.0f, 0.0f);
glVertex3f(0.0f, -1.0f, -1.0f);
glVertex3f(1.0f, -1.0f, 1.0f);
glColor3f(0.0f, 0.0f, 1.0f); //LEFT
glVertex3f(0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 1.0f);
glVertex3f(0.0f, -1.0f, -1.0f);
glEnd();
}
When my window first comes up the red triangle looks fine, but as I rotate it the shape looks a little distorted. If I rotate all the way around (where I cant see the red face at all) it looks normal... What am I missing here?
Heres where it starts to look weird
Also any pointers on openGL stuff I'm doing incorrectly (or in general) are greatly appreciated! :D
I don't know if this is what you consider a wierd looking shape, but your shape doesn't seem to be a regular Tetrahedron:
The 3 Corners of the base don't have the same distance to the top corner (the two front corners have a distance of sqrt(6) to the top corner, while the back corner has a distance of sqrt(5)).
the distance on the base is off too: the front corners have a distance of sqrt(2) while the distance between any front corner and the back corner is sqrt(3).
An example for a regular tetrahedron would be:
(Please note that these coordinates don't have a base parallel to the xz plane)
(1,1,1)(1,-1,-1)(-1,1,-1)(-1,-1,1)
Your code itself looks to be ok. (Except for the translating the projection matrix) I, myself prefer to create code blocks after push/popmatrix and glbegin/end (these things { ... }), but that's just to keep my code easy to read.
Also, as a general rule of thumb, in opengl you don't move the camera: you move everything else. (That's why translating negative z moves objects away from you, translating positive x makes them move right and so on...)
Related
I read similar suggested questions and their solutions, but could not find an answer.
I'm trying to draw a scene with an isometric view in OpenGL.
Draw func:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glRotatef(atan(0.5f) * 180.0f / PI, 1.0f, 0.0f, 0.0f);
glRotatef(-45.0f, 0.0f, 1.0f, 0.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBegin(GL_QUADS);
glColor3f(1.0f, 1.0f, 1.0f);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 1.0f);
glVertex3f(0.0f, 0.0f, 1.0f);
glEnd();
glPopMatrix();
In the end, I get this result. The camera does have an isometric projection, but for some reason polygons are clipped.
If I add glTranslatef(-0.8f, 0, -0.8f) before drawing the quad, the result is as follows:
The problem is that I don't apply any optimization to OpenGL render. But why do polygons have to be cut off?
The polygons are clipped by the near or far plane of the viewing volume.
When you do not set a projection matrix, then view space, clip space and normalized device space are the same. The normalized device space is a unique cube with the left, bottom, near of (-1, -1, -1) and right, top, far of (1, 1, 1). All the geometry which is not inside this cube is clipped.
Actually you draw a quad with a side length of 1. One vertex of the quad is at the origin of the view (0, 0, 0). The quad is rotated around the origin by glRotate. Since the length of the diagonal of the quad is sqrt(2.0), one vertex of the rotated quad is clipped by either the near plane or the far plane.
If you construct and rotate a quad whose center is (0, 0 ,0), it will not be clipped, because the length form the center to each vertex is sqrt(2.0)/2.0. That is less than 1 (distance to near and far plane form the center of the viewing volume)
glBegin(GL_QUADS);
glColor3f(1.0f, 1.0f, 1.0f);
glVertex3f(-0.5f, 0.0f, -0.5f);
glVertex3f( 0.5f, 0.0f, -0.5f);
glVertex3f( 0.5f, 0.0f, 0.5f);
glVertex3f(-0.5f, 0.0f, 0.5f);
glEnd();
respectively
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(atan(0.5f) * 180.0f / PI, 1.0f, 0.0f, 0.0f);
glRotatef(-45.0f, 0.0f, 1.0f, 0.0f);
glTranslate(-0.5f, 0.0f, -0.5f);
glBegin(GL_QUADS);
glColor3f(1.0f, 1.0f, 1.0f);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 1.0f);
glVertex3f(0.0f, 0.0f, 1.0f);
glEnd();
Alternatively you can set an Orthographic projection, which enlarges the viewing volume by glOrtho:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -2.0, 2.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(atan(0.5f) * 180.0f / PI, 1.0f, 0.0f, 0.0f);
glRotatef(-45.0f, 0.0f, 1.0f, 0.0f);
glBegin(GL_QUADS);
glColor3f(1.0f, 1.0f, 1.0f);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 1.0f);
glVertex3f(0.0f, 0.0f, 1.0f);
glEnd();
I'm pretty sure this is due to my lack of understanding of how the GL_MODELVIEW matrix works. Here is a screen recording of what's happening: http://youtu.be/3F7FLkVI7kA
As you can see, the bottom-most triangle is the first triangle being drawn, and moves as I expect the other 2 triangles to move. The second triangle is moved and rotated relative to the first, and the third is moved and rotated relative to that combination.
What I want is for all three triangles to be stationary in 3D space, but spinning (like the first triangle).
Source:
// Main loop
do {
// Clear Screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Update camera
glfwGetCursorPos(window, &cursorX, &cursorY);
cam.update(0.001f, (int)cursorX, (int)cursorY);
// Reset Matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// move camera
glRotatef(cam.rotation.x, 1.0f, 0.0f, 0.0f);
glRotatef(cam.rotation.y, 0.0f, 1.0f, 0.0f);
// translate modelview matrix to position of the camera - everything should now draw relative to camera position
glTranslatef(-cam.position.x, cam.position.y, -cam.position.z);
// Draw ground
drawGroundGrid(-25.0f);
drawSpinningTriangle(0.0f, 0.0f, -5.0f);
drawSpinningTriangle(3.14f, 3.0f, -6.0f);
drawSpinningTriangle(-6.0f, 12.0f, -5.0f);
// Swap buffers - back buffer is now front buffer to be rendered to next frame
glfwSwapBuffers(window);
glfwPollEvents();
calcFPS();
} while (!glfwGetKey(window, GLFW_KEY_ESCAPE) && !glfwWindowShouldClose(window));// Main Loop End
[...]
void drawSpinningTriangle(float x, float y, float z) {
glMatrixMode(GL_MODELVIEW);
glTranslatef(x, y, z);
glRotatef(glfwGetTime() * 50.0f, 0.0f, 1.0f, 0.0f);
glBegin(GL_TRIANGLES);
{
// Red vertex
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 1.0f, 0.0f);
// Yellow vertex
glColor3f(1.0f, 1.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);
// White vertex
glColor3f(1.0f, 1.0f, 1.0f);
glVertex3f(1.0f, -1.0f, 0.0f);
}
glEnd();
}
First using the matrix stack is deprecated. It's much better to manage your own matrices
Second you should pushMatrix and popMatrix before the transformations and after drawing:
void drawSpinningTriangle(float x, float y, float z) {
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(x, y, z);
glRotatef(glfwGetTime() * 50.0f, 0.0f, 1.0f, 0.0f);
glBegin(GL_TRIANGLES);
{
// Red vertex
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 1.0f, 0.0f);
// Yellow vertex
glColor3f(1.0f, 1.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);
// White vertex
glColor3f(1.0f, 1.0f, 1.0f);
glVertex3f(1.0f, -1.0f, 0.0f);
}
glEnd();
glPopMatrix();
}
This will save and restore the top most matrix so any changes between the 2 calls are removed.
I have built a SDI MFC application, where the CView child is drawing a cube with OpenGL. This cube is drawn by the following function:
void CglSDI3View::setupScene()
{
wglMakeCurrent(m_hDC, m_hRC);
// Clear color and depth buffer bits
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Wireframe Mode
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBegin(GL_QUADS);
// Front Side
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);
// Back Side
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);
// Top Side
(...)
glEnd();
SwapBuffers(m_hDC);
}
I have no Timer defined. Rigth now, my OnDraw function is as follows:
void CglSDI3View::OnDraw(CDC* /*pDC*/)
{
CglSDI3Doc* pDoc = GetDocument();
wglMakeCurrent(m_hDC, m_hRC);
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -m_fZoom);
glTranslatef(m_fPosX, m_fPosY, 0.0f);
glRotatef(m_fRotX, 1.0f, 0.0f, 0.0f);
glRotatef(m_fRotY, 0.0f, 1.0f, 0.0f);
setupScene();
wglMakeCurrent(NULL, NULL);
ValidateRect(NULL);
}
where m_fRotX, m_fRotY, m_fPosX, etc. are scaling and translation factors. My question is: do I need to call setupScene() on every OnDraw() call? Or can this be optimized? In other words, does the cube have to be redrawn on every OnDraw() call or is there a way to do this only once and then apply only transformations?
Please note that in the future, the setupScene() function will draw a huge point cloud with millions of colored points, so this needs to be optimized as much as possible.
The name "setupScene" is misleading. OpenGL has no scenes. OpenGL has no models. OpenGL is not a scene graph.
OpenGL is a "dumb" drawing API. It draws points, lines and triangles, one at a time. And after drawing something it already forgets about it.
So yes, you have to redraw if you want to have some changes in the drawing to happen, because, well, it's just a drawing and nothing more. There's no retained scene OpenGL could manipulate.
So rename "setupScene" to "drawScene" and use it as the thereby apt name suggests.
Aha! It seems my problem was that my zNear value given to gluPerspective had to be greater than 0, and I had to enable the depth buffer to get it working. Ive updated the code below to be working.
I've tried to do this a lot, and always thought I was defining my quad vertices in the wrong order, but now, I know its something else.
I've tried enabling Culling, changing frontFace to clockwise, disabling Blending, adding normals, but I always get a cube that looks like this;
Hopefully, you won't even have to look at my code to know what the problem is, as it wasn't too hard to get it like this.
If you don't immediately know what the problem is, here's the code used to set up and draw the cube.
// FIXED CODE.
// reshape, called on init, and window resize
void reshape(int w, int h) {
scrw=w;
scrh=h;
glClearColor(0.8,0.8,0.8,1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(cfov,(float) scrw/ (float) scrh,1,1000); // this is also a part of the fix.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_BLEND);
glEnable(GL_DEPTH_TEST); // this is a part of the fix
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glViewport(0,0,scrw,scrh);
}
// drawQuadCube(), called every frame.
void drawQuadCube() {
glPushMatrix();
glTranslated(0.5,0.5,0.5);
glRotated(xangle,0,1,0);
glRotated(yangle,1,0,0);
glRotated(zangle,0,0,1);
glTranslated(-0.5,-0.5,-0.5);
glBegin(GL_QUADS);
// bottom
glColor4ub(30,30,255,255);
glVertex3f(0.0f, 0.0f, 1.0f);
glVertex3f(1.0f, 0.0f, 1.0f);
glVertex3f(1.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 0.0f);
// top
glColor4ub(40,40,255,255);
glVertex3f(0.0f, 1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 0.0f);
glVertex3f(0.0f, 1.0f, 0.0f);
// left
glColor4ub(60,60,255,255);
glVertex3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 1.0f, 0.0f);
glVertex3f(0.0f, 1.0f, 1.0f);
// right
glColor4ub(60,60,200,255);
glVertex3f(1.0f, 0.0f, 1.0f);
glVertex3f(1.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 1.0f, 0.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
// near
glColor4ub(70,70,100,255);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 1.0f, 0.0f);
glVertex3f(0.0f, 1.0f, 0.0f);
// far
glColor4ub(20,20,90,255);
glVertex3f(0.0f, 0.0f, 1.0f);
glVertex3f(1.0f, 0.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
glVertex3f(0.0f, 1.0f, 1.0f);
glNormal3f(0,0,0);
glNormal3f(0,0,1);
glNormal3f(0,1,0);
glNormal3f(1,0,0);
glNormal3f(1,0,1);
glNormal3f(1,1,0);
glNormal3f(1,1,1);
glNormal3f(0,1,1);
glEnd();
glPopMatrix();
}
// if that isn't enough, this is the function used to set up the view.
void setView(void) {
glLoadIdentity();
gluLookAt(0.5,0.5,-5,0.5,0.5,0.5,0,1,0);
}
Your winding mode is incorrect.
glFrontFace defaults to GL_CCW, but your "front-facing quad", in this example the "near" one, is wound clockwise (from the frame of reference of your camera position; note that it's at negative Z, and looking along positive Z). glCullFace defaults to GL_BACK, so it's getting culled. Set it correctly with:
glFrontFace(GL_CW);
See also http://www.opengl.org/sdk/docs/man/xhtml/glFrontFace.xml
Once you've got that setup, then you'll want to enable depth-buffering, so your quads overpaint correctly without relying on paint ordering. See: http://www.opengl.org/archives/resources/faq/technical/depthbuffer.htm
Try:
glCullFace(GL_FRONT);
See http://www.opengl.org/sdk/docs/man/xhtml/glCullFace.xml
or:
glEnable(GL_CULL_FACE);
See http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml
You didn't specify what windowing mechanism you were using but incase you are using glut, don't forget to set the GLUT_DEPTH flag while creating the window. Thats a simple common error frequently overlooked.
I have a scene with a bunch of shapes, drawn like this:
glBegin(GL_QUADS);
glVertex3f(-0.7f, -0.5f, 0.0f);
glVertex3f(0.7f, -0.5f, 0.0f);
glVertex3f(0.4f, 0.5f, 0.0f);
glVertex3f(-0.4f, 0.5f, 0.0f);
glEnd();
How do I make all of the shapes half as small, without individually going through and changing each coordinate?
The question is a little bit ambiguous. You asked to make the quads be half their original size, but you didn't stipulate where they should be once their size is changed. The standard way would be to apply a scaling factor:
glPushMatrix();
glScaled(.5,.5,.5);
glBegin(GL_QUADS);
glVertex3f(-0.7f, -0.5f, 0.0f);
glVertex3f(0.7f, -0.5f, 0.0f);
glVertex3f(0.4f, 0.5f, 0.0f);
glVertex3f(-0.4f, 0.5f, 0.0f);
glEnd();
...
glBegin(GL_QUADS);
...
glEnd();
glPopMatrix();
This will scale everything after the glScale call until the glPopMatrix(). Consequently, the quads will be half the size, but will also be half the distance from the origin (not a problem here where it's centered at the origin). If you want to apply the scaling factor to the quads, but not to their location, you'd probably need something like this:
glPushMatrix();
glTranslated(xx,yy,zz);
glBegin(GL_QUADS);
glVertex3d( ww*ss, hh*ss,0);
glVertex3d(-ww*ss, hh*ss,0);
glVertex3d(-ww*ss,-hh*ss,0);
glVertex3d( ww*ss,-hh*ss,0);
glEnd();
glPopMatrix();
Then you would just set ss to your desired value and use xx,yy,zz to place the quad where you want it. Of course it's a bit silly to do things just this way, at very least, you should multiply the values once each and remember them, but you get the idea.