I have a tile engine using orthographic projection in immediate mode and I'm just trying to draw a 3d cube on top of my tile scene, in hopes that I can eventually incorporate 3d models into my engine instead of just sprites / textured quads. I would also like to make the tiles 3d for that slight bit of extra eye candy.. Hopefully I can eventually convert this to use modern OpenGL so I can take advantage of those extra features. Not on the top of my priority list at the moment. So on to the question.
I'm initializing OpenGL with this:
void initGL()
{
glDisable(GL_DEPTH_TEST);
glViewport( 0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
//Initialize Projection Matrix
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
//Initialize Modelview Matrix
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glOrtho(0,SCREEN_WIDTH,SCREEN_HEIGHT,0,0,1);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
//...setting some various other attributes, omitted for brevity...
glEnable(GL_TEXTURE_2D);
glClearColor( 0, 0, 0, 0 );
}
I have a function for drawing a cube that works.
void draw_cube()
{
/* position object */
glRotatef(30.0F, 1.0F, 0.0F, 0.0F);
glRotatef(30.0F, 0.0F, 1.0F, 0.0F);
/* draw six faces of a cube */
glBegin(GL_QUADS);
...vertices... (removed for brevity)
glEnd();
}
I made 2 functions for setting the 2d and 3d projection modes.
void set3d()
{
glEnable(GL_DEPTH_TEST);
glClear(GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(0,SCREEN_WIDTH,0,SCREEN_HEIGHT, 0,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void set2d()
{
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,SCREEN_WIDTH,SCREEN_HEIGHT,0,0,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
For the sake of completeness, some pseudocode of my textured quad drawing..
pushmatrix();
translate();
rotate();
-translate();
glbegin();
...vertices
glend();
popmatrix();
So far I have managed to get the cube to draw on top of the tiles, but it disappears after approximately 1 second to never be seen again until I run the program again.
Basically what I'm doing in the main loop is this:
move objects around, process collisions, etc.
set2d();
draw textured quads, lines, text, etc. in 2d mode.
set3d();
draw_cube();
My question is: Why is the cube disappearing, and are there any errors in my set2d() and set3d() functions?
You have quite a few problems in this code, too many to list in comments in fact.
Your projection matrices are changing the handedness of your post-projected coordinate space, which will affect polygon winding.
Stick to a single handedness, unless you want to reverse the direction used for front- / back-facing polygon facets (glFrontFace (...)) - it is CCW by default, but you will have to change it to CW when you use set3d (...) to maintain consistent behavior.
This problem arises because you have the Y-axis going different directions
The behavior your are describing, where the object appears briefly and then disappears is indicative of an issue with your matrix stack.
Are you calling initGL (...) more than once in your software? You will run into a stack overflow if you do this enough times since you needlessly push the current matrix onto the stack and never pop it off.
You cannot use 0.0 for zNear with a perspective projection matrix, this will result in wonky math during the perspective divide step that comes after transformation to clip-space; the depth buffer will not work correctly.
In fact, glFrustum (...) will generate a GL_INVALID_VALUE error and do exactly nothing if you pass a value ≤ 0.0 for zNear. On a related note, gluPerspective (...) will not do this since it is not actually part of OpenGL, but it is equally invalid behavior to pass such a value to gluPerspective (...).
Related
I want to draw an oval by projection the sphere on the screen (like rasterize). Here is my code but it doesn't show anything on the screen. Should I use more functions to initialize the projection? Is this way possible to draw oval on screen by using sphere?
GLfloat xRotated, yRotated, zRotated;
GLdouble radius=1;
void display(void);
void reshape(int x, int y);
int main (int argc, char **argv)
{
glutInit(&argc, argv);
glutInitWindowSize(800,800);
glutCreateWindow("OVAL");
zRotated = 30.0;
xRotated=43;
yRotated=50;
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
void display(void)
{
glMatrixMode(GL_PROJECTION);
glOrtho(0.1, 1.0, 0.1, 1.0, -1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0,0.0,-5.0);
glColor3f(0.9, 0.3, 0.2);
glRotatef(xRotated,1.0,0.0,0.0);
glRotatef(yRotated,0.0,1.0,0.0);
glRotatef(zRotated,0.0,0.0,1.0);
glScalef(1.0,1.0,1.0);glutSolidSphere(radius,20,20);
glFlush();
}
void reshape(int x, int y)
{
if (y == 0 || x == 0) return;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(39.0,(GLdouble)x/(GLdouble)y,0.6,21.0);
glMatrixMode(GL_MODELVIEW);
glViewport(0,0,x,y);
}
You are drawing a sphere compltely outside of the viewing volume, so it should be no surprise that it can't be seen.
There are a couple of issues with your code:
All OpenGL matrix functions besides glLoadIndentity and glLoadMatrix always post-multiply a matrix to the current top element of the current matrix stack. In your display function, you call glOrtho without resetting the projection matrix to identity before. This will result in totally weird - and different - results if the display callback is called more than once.
You should add a call to glLoadIdentity() right before calling glOrtho.
You set up the model view transformations so that the sphere's center will always end up at (0,0,-5) in eye space. However, you set a projectiom matrix which defines a viewing volume which goes from z=1 (near plane) to z=-1 (far plane) in eye space, so your spehre is actually behind the far plane.
There are several ways this could be fixed. Changing the viewing frustum by modifying the parameters of glOrtho might be the easisest. You could for example try (-2, 2, -2, 2, 1, 10) to be able to see the sphere.
It is not really clear what
I want to draw an oval by projection the sphere on the screen (like rasterize).
exactly means. If you just want the sphere to be distorted to an ellipsoid, you could just apply some non-uniform scaling. This in principle could be done in the projection matrix (if no other objects are to be shown), but this would make much more sense to apply it to the model matrix of the sphere - you already have the glScale call there, you could try something like glScalef(1.0f, 0.5f, 1.0f);.
Also note that the ortho parameters I suggested previously will result in some distortion if your viewport is not exactly square. In a real world, one wants to incorporate the aspect ratio of the viewport into the projection matrix.
If you want to see the sphere deformed as by a perspective projection, you would have to skip the glOrtho altogheter and switch to a perspective projection matrix.
The code you are using is totally outdated. The OpenGL matrix stack has been deprecated in OpenGL 3.0 (2008) and is not available in core profiles of modern OpenGL. The same applies for builtin vertex attributes like glColor or immediate mode drawing and client-side vertex arrays. As a result, GLUT's drawing functions can also not be used with modern GL any more.
If you really intend learning OpenGL nowadays, I stronly advise you to ignore this old cruft and star learning the modern way.
So, I've been trying to rotate a single object in an OpenGL/GLUT environment.
After going through several questions on SO and the like, I've written what appears to be correct code, but no dice. Does anyone know how to make this work?
PS: I've tried changing the GLMatrixmode to Projection, but that just shows a black screen. Same thing happens if I use glLoadIdentity().
Here's my rendering code
void display()
{
preProcessEvents();
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(Camera::position.x, Camera::position.y, Camera::position.z,
Camera::position.x+Math::sind(Camera::rotationAngles.x)*Math::cosd(Camera::rotationAngles.y),
Camera::position.y+Math::cosd(Camera::rotationAngles.x),
Camera::position.z+Math::sind(Camera::rotationAngles.x)*Math::sind(Camera::rotationAngles.y),
0.0, 1.0, 0.0);
glBegin(GL_TRIANGLES);
glColor3f(1, 0, 0);
glVertex3f(-1, 0,-3);
glColor3f(0, 1, 0);
glVertex3f(0.0f, 2.0f,-3);
glColor3f(0, 0, 1);
glVertex3f(1.0f, 0.0f,-3);
glEnd();
glBindTexture(GL_TEXTURE_2D, tex->textureID);
glBegin(GL_QUADS);
glColor3f(1, 1, 1);
glTexCoord2f(100, 100);
glVertex3f(100,0,100);
glTexCoord2f(-100, 100);
glVertex3f(-100,0,100);
glTexCoord2f(-100,-100);
glVertex3f(-100,0,-100);
glTexCoord2f(100,-100);
glVertex3f(100,0,-100);
glEnd();
glBindTexture(GL_TEXTURE_2D, 0);
object1.draw();
glTranslatef(-10.0, 10.0, 0.0);
glBindTexture(GL_TEXTURE_2D, tex2->textureID);
gluQuadricTexture(quad,1);
gluSphere(quad,10,20,20);
glBindTexture(GL_TEXTURE_2D, 0);
//RELEVANT CODE STARTS HERE
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
glRotatef(190, 0.0, 0.0, 1.0);
glPopMatrix();
glutSwapBuffers();
}
Are you aware what glPushMatrix and glPopMatrix do? They save and restore the "current" matrix.
By enclosing your rotation in that and then doing no actual drawing operation before restoring the matrix the entire sequence of code beginning with //RELEVANT CODE STARTS HERE is completely pointless.
Even if you did not push/pop, your rotation would only be applied the next time you draw something. Logically you might think that would mean the next time you call display (...), but one of the first things you do in display (...) is replace the current matrix with an identity matrix (line 3).
In all honesty, you should consider abandoning whatever resource you are currently using to learn OpenGL. You are using deprecated functionality and missing a few fundamentals. A good OpenGL 3.0 tutorial will usually touch on the basics of transformation matrices.
As for why changing the matrix mode to projection produces a black screen, that is because the next time you call display (...), gluLookAt operates on the projection matrix. In effect, you wind up applying the camera transformation twice. You should really add glMatrixMode (GL_MODELVIEW) to the beginning of display (...) to avoid this.
You do the rotation (and reset it with glPopMatrix) after you draw, do the rotation code before the glBegin/glEnd calls.
Or just move to the shader based pipeline and manage you own transformation matrices.
I'm trying to draw a square on the screen but it clearly draws a rectangle.
This is my render code:
glClear(GL_COLOR_BUFFER_BIT);
glTranslatef(0,0,-0.1);
glBegin(GL_QUADS);
glVertex3f(0,0,0);
glVertex3f(1,0,0);
glVertex3f(1,1,0);
glVertex3f(0,1,0);
glEnd();
SDL_GL_SwapBuffers();
And OpenGL Init code:
glClearColor(0,0,0,0.6f);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(30,640.0/480.0,.3f,200.0);
glMatrixMode(GL_MODELVIEW);
Why is this happening?
I don't see anywhere in your code where you have set-up the glViewport. I will rather write something like this in your init method:
glViewport(0,0,640,480); // Reset The Current Viewport
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(30.0f,(GLfloat)640/(GLfloat)480,0.3f,200.0f);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity();
also check the second Nehe tutorial it will help you to start with OpenGL for very basic stuff like drawing primitives such as triangle, square etc...
Try using gluOrtho2D to generate a correct orthogonal projection matrix, in your case gluOrtho2D(0,640,0,480), this is assuming you want a square in 2D and not 3D.
This will of course change your coordinate system from (0,1),(0,1) to (0,640),(0,480).
I just started working with OpenGL, but I ran into a problem after implementing a Font system.
My plan is to simply visualize several Pathfinding Algorithms.
Currently OpenGL gets set up like this (OnSize gets called once on window creation manually):
void GLWindow::OnSize(GLsizei width, GLsizei height)
{
// set size
glViewport(0,0,width,height);
// orthographic projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0,width,height,0.0,-1.0,1.0);
glMatrixMode(GL_MODELVIEW);
m_uiWidth = width;
m_uiHeight = height;
}
void GLWindow::InitGL()
{
// enable 2D texturing
glEnable(GL_TEXTURE_2D);
// choose a smooth shading model
glShadeModel(GL_SMOOTH);
// set the clear color to black
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.0f);
}
In theory I don't need blending, because I will only use untextured Quads to visualize obstacles and line etc to draw paths... So everything will be untextured, except the fonts...
The Font Class has a push and pop function, that look like this (if I remember right my Font system is based on a NeHe Tutorial that I was following quite a while ago):
inline void GLFont::pushScreenMatrix()
{
glPushAttrib(GL_TRANSFORM_BIT);
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(viewport[0],viewport[2],viewport[1],viewport[3], -1.0, 1.0);
glPopAttrib();
}
inline void GLFont::popProjectionMatrix()
{
glPushAttrib(GL_TRANSFORM_BIT);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib();
}
So the Problem:
If I don't draw a Text I can see the Quads I want to draw, but they are quite dark, so there must be something wrong with my general OpenGL Matrix Properties.
If I draw Text (so the font related push and pop functions get called) I can't see any Quads.
The question:
How do I solve this problem and some background information why this happened would also be nice, because I am still a beginner/student, who just started.
If your quads are untextured, you will run into undefined behaviour. What will probably happen is that any previous texture will be used, and the colour at point (0,0) will be used, which could be what is causing them to be invisible.
Really, you need to disable texturing before trying to draw untextured quads using glDisable(GL_TEXTURE_2D). Again, if you don't, it'll just use the previous texture and texture co-ordinates, which without seeing your draw() loop, I'm assuming to be undefined.
I know how to speed up rendering in 3d by simply rendering the nearest planes first.
But how do i get advantage of this type of method in 2d mode? I cant use depth testing because they are all in the same z-level.
So i was thinking if it could be speed up when i dont need to render the invisible parts of the layers "below". Is this possible?
Note that i am rendering in 3d mode, there may be 3d objects and 2d objects at the same time. So i cant switch to 2d render only, i always use 3d coordinates for everything. And i may rotate the camera as i wish, so camera-specific tricks arent acceptable.
Edit: i tried the method Ville suggested:
( http://img815.imageshack.us/img815/7857/zfighting.png )
but as you see, it will result in z-fighting.
The code i used for rendering that is here:
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glDisable(GL_ALPHA_TEST);
glDisable(GL_POLYGON_OFFSET_FILL);
glColor4f(1,0,0,1);
DrawQuad(0, 0, 10, 10);
glColor4f(0,0,1,1);
DrawQuad(5, 5, 15, 15);
glDepthFunc(GL_LEQUAL);
It sounds like you are rendering all your "2D" objects on the same plane. You could render your 2D parts into an off-screen framebuffer with an orthographic projection and give them different Z values as datenwolf suggested. Then render the framebuffer texture into your main 3D scene.
What do you understand by 2D mode? Do you mean orthographic projection? Then I have good news: Depth testing works there perfectly as well. gluOrtho2D is basically the same like glOrtho(..., -1, 1); i.e. you have the Z range -1 ... 1 to spend.
EDIT due to comment:
It is perfectly possible to combine rendering several projections in one single frame:
void render_perspective_scene(void);
void render_ortho_scene(void);
void render_HUD();
void display()
{
float const aspect = (float)win_width/(float)win_height;
glViewport(0,0,win_width,win_height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-aspect*near/lens, aspect*near/lens, -near/lens, near/lens, near, far);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
render_perspective_scene();
// just clear the depth buffer, so that everything that's
// drawn next will overlay the previously rendered scene.
glClear(GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-aspect*scale, aspect*scale, -scale, scale, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
render_ortho_scene();
// Same for the HUD, only that we render
// that one in pixel coordinates.
glClear(GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, win_width, 0, win_height, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
render_HUD();
}
Of course if you've fallen for those bad tutorials that place the projection matrix setup in the reshape handler you're of course mind blocked, to see that obvious solution.