I have a simple rectangle i have drawn on screen in opengl.
My target is to draw this rectangle in 3D so the left side of it is deeper (z-axis) than the right side.
Look at this pic so you can see what i mean:
http://www.battleteam.net/tech/fis/docs/images/metroid_hud1.png
This is the code i use to draw a rectangle which uses different colors and i moved both points on left side up a bit.
glColor4f( 1.0, 1.0, 1.0, 1.0 );
glVertex3f( 0, -20, z_left );
glColor4f( 0.0, 1.0, 1.0, 1.0 );
glVertex3f( SQUARE_WIDTH, 0, 0 );
glColor4f( 1.0, 0.0, 1.0, 1.0 );
glVertex3f( SQUARE_WIDTH, SQUARE_HEIGHT, 0 );
glColor4f( 1.0, 1.0, 0.0, 1.0 );
glVertex3f( 0, SQUARE_HEIGHT-20, z_left );
I use the z_left variable to dynamically change the z-value for the both points on the left side to move these points on the z-axis. But what happens is that the rectangle gets cut off from the left side. This happens when the z_left value reaches the zFar or zNear Variable defined via the "glOrtho" function call.
My glOrtho looks like this:
glOrtho( 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -100, 100 );
So if the z_left gets higher than 100 or less than -100 then that strange cutting off begins. I dont know why. I expected to get the left side of the rectangle to be moved on z-axis, means moving it deeper (away from eye) or closer.
Can somebody tell me whats wrong here? The rest of the code is pretty simple and standard.
A simple rectangle in a 3D environment being changed a bit to have a "3d panel" like rectangle.
My OpenGL init looks like this.
glClearColor( 0, 0, 0, 0 );
glMatrixMode( GL_PROJECTION );
glLoadIdentity(); glOrtho( 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -100, 100 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
Thanks for any help.
Ortographic projections have that property, you can move them in the Z axis, but the object looks the same. Switch to a perspective projection, on which objects get smaller with distance to the camera.
About the culling, you're drawing outside the viewing cube (when Z < -100 or Z > 100). The projection will cull away anything outside it's view.
Related
I am using C++, OpenGL and glut. I am trying to make 5 houses that are rotated properly like this:
However, whenever I try to implement the glRotatef function, I seem to not be able to either get the proper coordinates or something is off somewhere in my code. Furthermore, I set the background color to white but it's still all black, how come? For now I have the houses set to white to counter this for now. Here is my code:
#include <GL/glut.h>
typedef int vert2D[2];
void initialize()
{
glClearColor(1.0, 1.0, 1.0, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(10.0, 215.0, 0.0, 250.0);
glMatrixMode(GL_MODELVIEW);
}
void drawHouse(vert2D* sq, vert2D* tri)
{
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINE_LOOP);
glVertex2iv(sq[0]);
glVertex2iv(sq[1]);
glVertex2iv(sq[2]);
glVertex2iv(sq[3]);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex2iv(tri[0]);
glVertex2iv(tri[1]);
glVertex2iv(tri[2]);
glEnd();
}
void render()
{
vert2D sqPts[4] = { {115, 150}, {115, 125}, {100,125}, {100,150} };
vert2D triPts[3] = { {120, 150}, {95,150}, {108,160} };
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glMatrixMode(GL_MODELVIEW);
drawHouse(sqPts, triPts);
glPushMatrix();
glTranslatef(1.0, 0.0, 0.0);
glRotatef(-10.0, 0.0, 0.0, 1.0);
drawHouse(sqPts, triPts);
glTranslatef(1.0, 0.0, 0.0);
glRotatef(-10.0, 0.0, 0.0, -1.0);
drawHouse(sqPts, triPts);
glPopMatrix();
glPushMatrix();
glTranslatef(-1.0, 0.0, 0.0);
glRotatef(10.0, 0.0, 0.0, 1.0);
drawHouse(sqPts, triPts);
glTranslatef(-1.0, 0.0, 0.0);
glRotatef(10.0, 0.0, 0.0, 1.0);
drawHouse(sqPts, triPts);
glPopMatrix();
glFlush();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(100, 100);
glutInitWindowSize(640, 480);
glutCreateWindow("TestMeOut");
initialize();
glutDisplayFunc(render);
glutMainLoop();
}
Let's answer the simpler question of why your background is still black, first:
You simply never glClear(GL_COLOR_BUFFER_BIT) the color buffer. You tell OpenGL "hey, the next time I call glClear with (at least) the GL_COLOR_BUFFER_BIT, I want the color buffer to be cleared to white." but you never actually clear the buffer.
Now, onto how we can draw the houses with their correct locations and orientations:
You should first start by defining your house's vertices in a sensible local coordinate system/frame that is suitable for transforming them in further steps. Currently, with how you define your house's vertices, it is hard to do any transformations on those (mainly because linear transformations like rotation are always relative to the coordinate system's origin).
So, let's change that. Let's define the origin (0, 0) for your house to be the center of the bottom/base line of the house. And let's also define that your house's quad has a side length of 10 "units":
vert2D sqPts[4] = {
{-5, 0}, // <- bottom left
{ 5, 0}, // <- bottom right
{ 5,10}, // <- top right
{-5,10} // <- top left
};
Now, for the roof of the house, we assume the same coordinate system (with (0, 0) being the center of the house's base/bottom line), so we start at Y=10:
vert2D triPts[3] = {
{-6, 10}, // <- left
{ 6, 10}, // <- right
{ 0, 12} // <- top
};
Next, we need to define where (0, 0) should be in our "world", so to speak. One definition could be: (0, 0) should be the center of the bottom of the viewport/screen and the viewport should have a length of 100 "units". Right now, we don't care about a correct aspect ratio when the viewport's width does not equal the viewport's height. This can be added later.
Starting from the clip space coordinate system, we can transform this clip space into our own "world space" by using these transformations:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glTranslatef(0.0, -1.0, 0.0); // <- move the origin down to the bottom of the viewport
glScalef(1.0 / 50.0, 1.0 / 50.0, 1.0); // <- "scale down" the clip space to cover more space in the viewport
Now, the above part is essentially what gluOrtho2D() does as well, but highlighting the actual coordinate system transformation steps is useful here.
Now that we defined our house's local coordinate system and our "world" coordinate system, we can rotate and translate the world coordinate system such that the houses appear at their correct locations and orientations in our world.
In order to draw 5 houses, we just use a for-loop:
glMatrixMode(GL_MODELVIEW);
for (int i = -2; i <= 2; i++) { // <- 5 steps
glPushMatrix();
glRotatef(i * 20.0, 0.0, 0.0, 1.0);
glTranslatef(0.0, 50.0, 0.0);
drawHouse(sqPts, triPts);
glPopMatrix();
}
So, starting from our world coordinate system, we transform it by rotating the appropriate amount around its origin (0, 0) for the house with index i to have the correct rotation, and then translate the coordinate system by 50 units along its (now rotated) Y axis.
These two transformations will now result in a house to be drawn at the desired location. So, repeat that 5 times in total with differing rotation angles, and you're done.
I am trying to create a project in OpenGL C++ that has 3 sides of a cube showing at run time. No rotation needed to see the 3 sides. I'm very new to OpenGL, my plan of attack right now has been changing the x, y, and z values. I am fine working in 2d but adding z to mix is what I think is tripping me up. I know using a negative value will bring the image closer to the camera and positive further away, but in my code below when I change the Z value it does nothing to the object.
I only have the front and right side showing(running) just to attempt to get those 2 in the right position in the window first before the whole cube is drawn. Originally I drew them out in terms of 0.5 or -0.5 but that only produces a rectangle on the screen.
So my main question is, is there an easier way to predict the behavior of each of the vertices? Yes I know i'm working in a graphical space, but why are some of my points not even moving when the value is changed?
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <stdlib.h> //For exit function
void exit(int); //To Exit Program
void init(void)
{
glClearColor (0.0, 0.0, 0.0, 1.0);
glColor3f(1.0, 1.0, 1.0);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
}
void cube()
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glBegin(GL_QUADS);
glColor3f( 1.0, 0.0, 0.0 ); glVertex3f( 0.2, -0.3, -0.5 ); // P1 is red lb
glColor3f( 0.0, 1.0, 0.0 ); glVertex3f( 0.3, 0.2, -0.5 ); // P2 is green lt
glColor3f( 0.0, 0.0, 1.0 ); glVertex3f( -0.2, 0.3, -0.5 ); // P3 is blue tt
glColor3f( 1.0, 0.0, 1.0 ); glVertex3f( -0.3, -0.2, -0.5 ); // P4 is purple tb
glEnd();
// Green side - LEFT
glBegin(GL_QUADS);
glColor3f( 0.0, 1.0, 0.0 );
glVertex3f( -0.2, -0.3, 0.5 );
glVertex3f( -0.3, 0.2, 0.5 );
glVertex3f( -0.2, 0.3, -0.5 );
glVertex3f( -0.3, -0.2, -0.5 );
glEnd();
glFlush();
}
void myKeyboard(unsigned char theKey, int mouseX, int mouseY)
{
switch(theKey)
{
case 'Q':
case 'q':
exit(-1); //terminate the program
default:
break; // do nothing
}
}
int main(int argc, char** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(640,480);
glutInitWindowPosition(100,150);
glutCreateWindow("Shapes: Q or q to quit");
glutDisplayFunc(cube);
glutKeyboardFunc(myKeyboard);
init();
glEnable(GL_DEPTH_TEST);
glutMainLoop();
}
The problem isn't with the behavior of the vertices, but rather that you're using an orthographic projection instead of a perspective one. If you'd like to continue using ancient OpenGL, gluPerspective is what you want instead of glOrtho. If you want to move up to more modern OpenGL, all the matrix math functions are removed, so you'd have to use a library like glm to do all your math instead.
A rectangle is getting produced because in an orthographic projection, parallel lines remain parallel, so there's no horizon point or anything. If it's behind or parallel to an edge of the front face of the rectangle, you're not seeing it. A perspective projection more closely matches how a camera sees the world, with parallel points eventually converging in the distance.
A good way to think about this is to think about a really long segment of straight railroad tracks. In an orthographic projection, you would just see two rails continuing on straight forever. In a perspective projection, you would eventually see the two rails meet at a single point in the distance and would also be able to partially see the inner edge of the rail.
I am trying to test gluLookAt using this code. But I can see only a black screen. What is wrong with this code ? Is there any basic concept about glulookAt (or opengl camera) that I need to understand.
glViewport(0,0,640,480);
glEnable(GL_DEPTH_TEST);
glClearColor(0,0,0,1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluLookAt(0,0,5,0,0,0,0,0,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_POLYGON);
glColor3f(1, 0, 0);
glVertex2d(0.25, 0.25);
glVertex2d(-0.25, 0.25);
glVertex2d(-0.25, -0.25);
glVertex2d(0.25, -0.25);
glEnd();
One issue is the up vector of gluLookAt is in the same direction as the look direction.
All you need to do is set +Y up and it should work...
gluLookAt(0, 0, 0.5, //position is +0.5 along Z (NOTE: 0.5, not 5. see below),
0, 0, 0, //looking at a 0.5x0.5 X/Y quad at the origin
0, 1, 0 //rotated such that +Y is up
);
The other issue is that gluLookAt shouldn't be applied to the projection matrix. It'll work for now but will break lighting later. Move it to the modelview matrix:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(... as before ...);
Assuming the projection matrix hasn't been set, changing the from position of gluLookAt back to your 5 will make the quad disappear. This is because the default projection gives a viewing volume of an orthographic -1 to 1 cube. With the "camera" now too far away it won't see anything. This is where you'll want to investigate changing the projection matrix. Maybe increase the size of the orthographic projection with glOrtho(), or look into the more complex but natural gluPerspective().
I'm having the following problem. While glPolygonOffset works perfectly for meshes, for example when I'm trying to draw a wireframe outline on top of the object, it doesn't work for simple lines.
Here is how it works for meshes:
// draw object
mTexture.enableAndBind();
gl::color( Colorf( 1, 1, 1 ) );
gl::draw( mVboMesh );
mTexture.unbind();
// overlay wireframe
gl::enableWireframe();
glLineWidth(1);
glEnable( GL_POLYGON_OFFSET_LINE );
glPolygonOffset( -1, -1 );
glColor3f( 0, 0, 1 );
gl::draw( mVboMesh );
glDisable( GL_POLYGON_OFFSET_LINE );
gl::disableWireframe();
For some reason it doesn't work for lines. What I'm trying to achieve is to draw a coordinate frame's arrows over a grid. I'm using the very same GL_POLYGON_OFFSET_LINE mode as when I was drawing lines, just like I was doing for the wireframe over the object. However in this case glPolygonOffset( -1, -1 ); makes absolutely no difference. I've tried it with huge values like 100 and it's the same. Absolutely no effect. Here is what I'm doing:
// enable 3D rendering
gl::enable( GL_CULL_FACE );
gl::enableDepthRead();
gl::enableDepthWrite();
// drawing the grid
int size = 2000;
int step = 25;
gl::color( Colorf( 0.2f, 0.2f, 0.2f ) );
for( float i = -size; i <= size; i += step )
{
glBegin( GL_LINES );
glVertex3f( i, 0, -size );
glVertex3f( i, 0, size );
glVertex3f( -size, 0, i );
glVertex3f( size, 0, i );
glEnd( );
}
// drawing the arrows
glEnable( GL_POLYGON_OFFSET_LINE );
glPolygonOffset( -1, -1 );
glBegin( GL_LINES );
gl::color( Colorf( 1, 0, 0 ) );
glVertex3f( 0, 0, 0 );
glVertex3f( 100, 0, 0 );
gl::color( Colorf( 0, 1, 0 ) );
glVertex3f( 0, 0, 0 );
glVertex3f( 0, 100, 0 );
gl::color( Colorf( 0, 0, 1 ) );
glVertex3f( 0, 0, 0 );
glVertex3f( 0, 0, 100 );
glEnd( );
glDisable( GL_POLYGON_OFFSET_LINE );
// disable 3D rendering
gl::disableDepthWrite();
gl::disableDepthRead();
gl::disable( GL_CULL_FACE );
and an example of the Z-fighting I get:
One hack I've tried and what worked perfectly is:
disable depth read, enable depth write
draw grid
draw arrows
enable depth read
draw other objects
However this is a very special case and while it works for a flat grid and arrows, it wouldn't work for pretty much anything else with a complex shape.
My questions are:
Why does glPolygonOffset not work for lines-on-lines while it works for lines-on-polygon?
How can I fix it, without resorting to the above hack, what only works in very specific cases?
// I'm using Cinder as a framework, but it shouldn't matter since I'm using raw OpenGL commands
Update
I've checked the answer in the first comment, and tried that method as well, however that one doesn't work either, since the result depends on the distance from the camera.
//// draw coordinate frame and grid
glDepthRange (0.01, 1.0);
drawGrid( 2000.0f, 25.0f );
glDepthRange (0.0, 0.99);
gl::drawCoordinateFrame( 100.0f, 5.0f, 2.0f );
glDepthRange (0.0, 1.0);
// draw object
I guess one hack could be to draw the line just a bit closer to the view point (let's say 0.1 closer). This should avoid z-fighting.
In order to do so, you calculate the normalized directional vector from your point to the POV position. Then you scale it with a small factor, and add it to your line point coordinates
I have a simple program to use depth test. It is not working as expected. The program draws X, Y axis and a sphere near the origin.
If I don't turn on the GL_DEPTH_TEST, the sphere is drawn over the axis. If I turn on the GL_DEPTH_TEST, the axis are drawn over the sphere which I was not expecting. Can someone tell me what I did
wrong ?
void
glwid::initializeGL()
{
glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
}
void
glwid::resizeGL(int width, int height)
{
glViewport( 0, 0, (GLint)width, (GLint)height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective ( 90, (GLint)width/ (GLint)height, 0.0, 200.0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glEnable (GL_DEPTH_TEST);
}
void
glwid::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity();
gluLookAt (0, 0, 100, 0, 0, 0, 0, 1, 0);
//
// X axis
//
glBegin( GL_LINES );
qglColor( green );
glVertex3f (-100.0, 0, 0. );
glVertex3f (100.0, 0, 0. );
glEnd();
//
// Y axis
//
glBegin( GL_LINES );
qglColor( red );
glVertex3f (0.0, 100.0, 0. );
glVertex3f (0.0, -100, 0. );
glEnd();
//
// sun
//
glTranslated (5, 0, 20);
GLUquadricObj *sphere_quadric = gluNewQuadric();
glColor3ub (255, 255, 0);
gluQuadricDrawStyle(sphere_quadric, (GLenum)GLU_SMOOTH);
gluSphere(sphere_quadric, 10, 36, 36);
}
I've tried your code. The problem is in resizeGL() function.
The problem was your putting to
gluPerspective ( 90, (GLint)width/ (GLint)height, 0.0, 200.0 );
0.0 value as a third argument. Put 0.01 for example - and everything will be ok. that's because this parameter should always be positive:
http://www.opengl.org/sdk/docs/man/xhtml/gluPerspective.xml
Also change (GLint)width/ (GLint)height to (GLfloat)width/ (GLfloat)height otherwise the result will be strange.
And it's better to put glEnable(GL_DEPTH_TEST) into initializeGL() function
Your axis starts at Z location 0. The Sphere is at Z location 20 (farther away from the "camera") therefore the axis is in-front of the sphere and is being shown.
As you currently have it setup, as Z values go up they move away from the screen. As they go down, they are going closer to the screen.
You have two options: Disable depth testing while drawing your axis (therefore it will always be behind everything). Or move your axis to Z position 100 or so and scale it up to make it look the same size. Option one is probably better.
Simply wrapping your axis drawing routines in glDisable(GL_DEPTH_TEST); and glEnable (GL_DEPTH_TEST); should do the trick