I've been studying Computer Graphics and I'm very confused about the role of the viewport, gluortho and when to use GL_MatrixMode and GL_Projection.
Here is a sample code I wrote that confuses me.
void init()
{
glClearColor(1.0,1.0,1.0,1.0);//Background Color of Viewport
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-200,200,-200,200,-50,50);
glMatrixMode(GL_MODELVIEW);
}
void wheel()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1,0.2,0.2);
glLoadIdentity();
glViewport(0,0,200,200);
glutSolidCube(100);
glFlush();
}
void main(int argc,char** argv)
{
glutInit(&argc,argv);
glutInitWindowSize(400,400);
glutInitWindowPosition(400,400);//Position from the top left corner
glutCreateWindow("Car");
init();
glutDisplayFunc(wheel);//Shape to draw
glutMainLoop();
}
When I change the Cube's size to 200 it disappears, why? Is that because it's larger than the z clipping?
When I remove glMatrixMode(GL_MODELVIEW) the cube disappears why?
If I don't flush at the end of the display function the cube disappears as well,why?
When I make the viewport smaller the object get smaller does that mean the object coordinates are relative to the viewport and not the world coordinates?
When you change the cubes size to 200, its faces extend beyond the near and far clipping planes, which you've set in your glOrtho call to -50 and 50. Technically you'd then be viewing the inside of the cube, but the far side of the cube is also outside of the far clipping plane, so you can't see its backface.
Removing the call to set the matrix mode to GL_MODELVIEW means your glLoadIdentity call operates on the fixed functionality projection matrix (I'm pretty sure), and so the cube is directly translated into Normalized Device Coordinates, and it once again extends beyond all the clipping planes.
Finally, glViewport defines the size of the buffer you should be rendering to, and therefore usually matches your screen size. Making it smaller effectively makes your screen size smaller, but does not change the actual GLUT window size. In mathematical terms, it changes the way fragments are projected from normalized device coordinates into screen coordinates.
Related
I am not able to understand the correct way of transforming primitive coordinate values to the screen coordinates.
If I use the following code (where w and h are width and height of my window 640 X 480)
glViewport(0,0,w,h);
// set up the projection matrix
glMatrixMode(GL_PROJECTION);
// clear any previous transform and set to the identity matrix
glLoadIdentity();
// just use an orthographic projection
glOrtho(0,w,h,0,1,-1);
and my primitives are
glBegin(GL_TRIANGLES);
glColor3f(1,0,0);
glVertex3f(-10,-10,0);
glColor3f(0,1,0);
glVertex3f(10,-10,0);
glColor3f(0,0,1);
glVertex3f(0,10,0);
glEnd();
The triangle becomes too big to fit the window. Most of the tutorials have the primitives in the range[-1,1] and their ortho projection between [-1,1], so the triangle comes correctly at the centre.
So, if the coordinates are generated by a 3rd party software (or lies above the range [-1,1], how would I transform them correctly so that the coordinates fit the screen?
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.
I need to draw case/ spare which are Rectangle.
but the problem is that glTranslated()doesn't work. When I call it my rectangle isn't draw anymore.
my rectangle: glRectf(-0.032f, 0.032f, 0.032f, -0.032f);
(I don't understand values but working)
full code:
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3ub(254,128,1);
//glTranslated(50, 20, 0); when I remove the comment, my rectangle doesn't appear.
glRectf(-0.032f, 0.032f, 0.032f, -0.032f);
glFlush();
SDL_GL_SwapBuffers();
}
glRectf(x1,y1,x2,y2) means draw a rectangle from point (-0.032,0.032) to the diagonally opposite corner at (0.032,-0.032).
glTranslated(50,20,0) is applying a vector to move it. Those are pretty big numbers since you are saying you can see the rectangle (square) of size 0.064 wide. It may be drawing out of your viewport so you can't see it.
Try some small numbers and also glTranslated requires doubles (so I would cast them too).
Read more here...
http://www.cprogramming.com/tutorial/opengl_first_opengl_program.html
Assuming I use Orhographic Projection, and have a reshape function like this:
void reshape(f32 width, f32 height){
aspect = width/height;
glViewport(0, 0, width, height);
// guaranted 960x640 HUD canvas
if(640*aspect>=960){
ortho.x = 640*aspect;
ortho.y = 640;
}else{
ortho.x = 960;
ortho.y = 960/aspect;
}
glOrtho(0, ortho.x, ortho.y, 0, -1.0f, 1.0f);
}
How can I make sure, that all vertices >ortho.x or >ortho.y (normally offscreen) are didn't drawn?
Because if I scale the windows to something with a bigger aspect ratio than 1.5f (960/640) I see the objects, that schouldn't be full visible (because the viewport is so big like the window).
Is there something like a clipping pane in orthographic projection?
What you want is to use [glScissor][1] to ensure that the rendered area never goes beyond a certain size. glScissor takes a rectangle in window coordinates (remember: window coordinates have the origin at the bottom-left). The scissor test prevents the generation of fragments outside of this area.
To activate the scissor test, you must use glEnable(GL_SCISSOR). Unless you do that, the above call won't actually do anything.
Use constant values for the limit parameters of glOrtho, but use glViewport and glScissor (enable with glEnable(GL_SCISSOR_TEST)) to limit rendering to a sub-portion of your window.
BTW: You should set the projection and viewport in the rendering function. Doing it in the reshape handler makes not much sense. In any serious OpenGL application you'll switch projection modes several times during a full render, so just do it that way from the very beginning.
I have a main scene centered on the center of the viewport
in addition to that I want another small object to be displayed on the corner of the viewport.
The trouble is that when I draw the small object, it is transformed by the main projection transformation and appears slanted. I want the small object to have its own vanishing point centered in its center.
Is this possible which just transformations?
You want your main scene to be projected in one way and your corner object to be projected in another way. This directly leads you to the solution:
void render() {
glMatrixMode(GL_PROJECTION);
setUpMainProjection();
glMatrixMode(GL_MODELVIEW);
drawMainObject();
glMatrixMode(GL_PROJECTION);
setUpCornerProjection();
glMatrixMode(GL_MODELVIEW);
drawCornerObject();
}
Perhaps you're wondering how to implement setUpCornerProjection. It would look something like this:
// let's say r is a rect, which, in eye space, contains the corner object and is
// centered on it
glFrustum(r.left, r.right, r.bottom, r.top, nearVal, farVal);
// let's say p is the rect in screen-space where you want to
// place the corner object
glViewport(p.x, p.y, p.width, p.height);
And then in setUpMainProjection() you'd need to also call glFrustum and glViewport.