Related
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.
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...)
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 am loading an object through an obj file in opengl using GLM Library but it comes out on the screen upside down. Also i am providing a capability to user so he can rotate all the objects accordingly by mouse too. e.g. zoom and zoom in and rotate with y axis.
Problem is i dont know how to rotate the object first to make its face according to what i need. After that i want to draw this object and offcourse at that time mouse can play its role to rotate it.
my draw function contain the following code
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
glTranslatef(m_fPosX, m_fPosY,-m_fZoom);
glRotatef(m_fRotX, 1.0f, 0.0f, 0.0f);//these two for mouse movement
glRotatef(m_fRotY, 0.0f, 1.0f, 0.0f);
glRotated(180,0.0f, 0.0f, -1.0f);
glDisable(GL_TEXTURE_2D);
glColor3f(0.90f,0.90f,0.90f);
glmDraw(m_p3dModel,GLM_SMOOTH | GLM_MATERIAL);
glPopMatrix();
here rotate functions are all dependent on mouse movement but if it get load upside down i dont know how to first make my object face right direction and then allow it in this draw function...Which means i need to set its face before calling this draw function.
glRotatef(m_fRotY, 1.0f, 0.0f, 0.0f);
should be
glRotatef(m_fRotY, 0.0f, 1.0f, 0.0f);
copy/paste is the mother of many evils :o)
For transformation / projection / model view tutorial : check link
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.