1

I just started trying to folow simple "draw cube" openGl tutorial. After final victory over getting OpenGL to work, I still have very veird results. My problem is that the objects tend to resize themselves to match the window size. Instead, I'd like the window size determine the rendering area - the larger the window is, the more you may see.

Here are some screenshots of the resizing:
Normal size
Resized
Images kept as links intentionally!

This auto-resizing behavior brings a question what the coordinates used in OpenGL are.

Community
  • 1
  • 1
Tomáš Zato
  • 50,171
  • 52
  • 268
  • 778
  • Have a look at this [question](http://stackoverflow.com/questions/15536333/keeping-a-square-clipping-volume-square-regardless-of-viewport-size-in-opengl/15536710#15536710). I think it addresses what you're asking. – radical7 Mar 31 '13 at 00:56

2 Answers2

2

First thing to keep in mind: OpenGL is a drawing API. It doesn't maintain a scene or something like that.

So what OpenGL does is, it maps geometry input coordinates in the form of vertex attributes to screen space. In the old fixed function there's a special vertex attribute called "vertex position" or just short "vertex" (the actual vertex is more than just position).

The position is transformed to what's usually called "screen" space (but depending on where the viewport is placed, it might as well be called "window" or "viewport) space) in a three step process:

1. Transformation into view/eye space: This is done by multiplying the vertex position with the modelview matrix.

Certain further calculations, like illumination calculation are done in view space.

2. Transformation to clip space: The view space position is transformed into clip space. This is usually called the projection and aptly the matrix describing this transformation is called the projection matrix

In clip space some special things happen, summarized as clipping, you don't have to worry about yet.

3. In the final step transformed the clipped geometry into normalized device coordinates (NDC). NDC space is practically a 1:1 mapping toward the viewport, i.e. the limits of the NDC volume directly correspond to the offset and dimension of the viewport set with glViewport.

You can't change the way the 3rd step happens, and the 1st step is reserved for transforming stuff into view space. So any adjustments must happen in the 2nd step.

So here's what you have to do: The projection limits must be directly proportional to the viewport extents. Like this for example

glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-width/2, width/2, -height/2, height/2, -1, 1);

Oh, and just on a general note: You should always set the viewport and projection setup in the drawing function, too. If you see a tutorial that puts those statements in a window resize handler, just disregard it and just do it in the drawing code anyway. On the long term this really simplifies things.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • I like your general note, but my problem is that I hav absoluely no idea, how to get the window dimensions (will google that, but I'm scared of new evil functions that are ready to show me how lame I am) and also how to apply that on gluPerspective (found that on the internet while waiting for reply) which just takes widht/height - so resizing will cause zoom (maybe some translating can be used, but is that correct?). – Tomáš Zato Mar 31 '13 at 01:19
  • well, genpfault posted what you've explained, so my resources are complete. Thank you :) – Tomáš Zato Mar 31 '13 at 01:22
  • 1
    @TomášZato: Window dimensions are outside the scope of OpenGL. You're probably using a framework like GLFW, GLUT or SDL (the tutorial you linked uses GLUT). glutGet(GLUT_WINDOW_WIDTH) and glutGet(GLUT_WINDOW_HEIGHT) are what you're looking for. – datenwolf Mar 31 '13 at 11:05
1

The interesting part:

glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH ) / 300.0;
double h = glutGet( GLUT_WINDOW_HEIGHT ) / 300.0;
glOrtho( -1 * w, 1 * w, -1 * h, 1 * h, 10, -10);

glMatrixMode( GL_MODELVIEW );
glLoadIdentity(); 

In context:

#include <GL/glut.h>

void display();
void specialKeys();

double rotate_y=0; 
double rotate_x=0;

void display(){
   //  Clear screen and Z-buffer
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

  glMatrixMode( GL_PROJECTION );
  glLoadIdentity();
  double w = glutGet( GLUT_WINDOW_WIDTH ) / 300.0;
  double h = glutGet( GLUT_WINDOW_HEIGHT ) / 300.0;
  glOrtho( -1 * w, 1 * w, -1 * h, 1 * h, 10, -10);

  glMatrixMode( GL_MODELVIEW );
  glLoadIdentity(); 

  // Rotate when user changes rotate_x and rotate_y
  glRotatef( rotate_x, 1.0, 0.0, 0.0 );
  glRotatef( rotate_y, 0.0, 1.0, 0.0 );

  //Multi-colored side - FRONT
  glBegin(GL_POLYGON);

  glColor3f( 1.0, 0.0, 0.0 );     glVertex3f(  0.5, -0.5, -0.5 );      // P1 is red
  glColor3f( 0.0, 1.0, 0.0 );     glVertex3f(  0.5,  0.5, -0.5 );      // P2 is green
  glColor3f( 0.0, 0.0, 1.0 );     glVertex3f( -0.5,  0.5, -0.5 );      // P3 is blue
  glColor3f( 1.0, 0.0, 1.0 );     glVertex3f( -0.5, -0.5, -0.5 );      // P4 is purple

  glEnd();

  // White side - BACK
  glBegin(GL_POLYGON);
  glColor3f(   1.0,  1.0, 1.0 );
  glVertex3f(  0.5, -0.5, 0.5 );
  glVertex3f(  0.5,  0.5, 0.5 );
  glVertex3f( -0.5,  0.5, 0.5 );
  glVertex3f( -0.5, -0.5, 0.5 );
  glEnd();

  // Purple side - RIGHT
  glBegin(GL_POLYGON);
  glColor3f(  1.0,  0.0,  1.0 );
  glVertex3f( 0.5, -0.5, -0.5 );
  glVertex3f( 0.5,  0.5, -0.5 );
  glVertex3f( 0.5,  0.5,  0.5 );
  glVertex3f( 0.5, -0.5,  0.5 );
  glEnd();

  // Green side - LEFT
  glBegin(GL_POLYGON);
  glColor3f(   0.0,  1.0,  0.0 );
  glVertex3f( -0.5, -0.5,  0.5 );
  glVertex3f( -0.5,  0.5,  0.5 );
  glVertex3f( -0.5,  0.5, -0.5 );
  glVertex3f( -0.5, -0.5, -0.5 );
  glEnd();

  // Blue side - TOP
  glBegin(GL_POLYGON);
  glColor3f(   0.0,  0.0,  1.0 );
  glVertex3f(  0.5,  0.5,  0.5 );
  glVertex3f(  0.5,  0.5, -0.5 );
  glVertex3f( -0.5,  0.5, -0.5 );
  glVertex3f( -0.5,  0.5,  0.5 );
  glEnd();

  // Red side - BOTTOM
  glBegin(GL_POLYGON);
  glColor3f(   1.0,  0.0,  0.0 );
  glVertex3f(  0.5, -0.5, -0.5 );
  glVertex3f(  0.5, -0.5,  0.5 );
  glVertex3f( -0.5, -0.5,  0.5 );
  glVertex3f( -0.5, -0.5, -0.5 );
  glEnd();

  glFlush();
  glutSwapBuffers();
}

void specialKeys( int key, int x, int y ) {
   //  Right arrow - increase rotation by 5 degree
  if (key == GLUT_KEY_RIGHT)
    rotate_y += 5;

  //  Left arrow - decrease rotation by 5 degree
  else if (key == GLUT_KEY_LEFT)
    rotate_y -= 5;

  else if (key == GLUT_KEY_UP)
    rotate_x += 5;

  else if (key == GLUT_KEY_DOWN)
    rotate_x -= 5;

  //  Request display update
  glutPostRedisplay();
}

int main(int argc, char* argv[]){
  //  Initialize GLUT and process user parameters
  glutInit(&argc,argv);

  //  Request double buffered true color window with Z-buffer
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

  // Create window
  glutCreateWindow("Awesome Cube");

  //  Enable Z-buffer depth test
  glEnable(GL_DEPTH_TEST);

  // Callback functions
  glutDisplayFunc(display);
  glutSpecialFunc(specialKeys);

  //  Pass control to GLUT for events
  glutMainLoop();

  //  Return to OS
  return 0;
}
genpfault
  • 51,148
  • 11
  • 85
  • 139
  • Thank you! There is a lot of inspiration for me in this code :) I will try to apply it. – Tomáš Zato Mar 31 '13 at 01:20
  • May I ask why glMatrixMode is called twice? And why the window size is divided by 300? – Tomáš Zato Mar 31 '13 at 01:21
  • Once to switch to the projection matrix stack and once to switch to the modelview stack. You technically could get by with one [but you really shouldn't do that](http://sjbaker.org/steve/omniv/projection_abuse.html). GLUT defaults to 300x300 pixel windows (and you didn't override via `glutInitWindowSize()`) so I figured that's the size you wanted to stick with. – genpfault Mar 31 '13 at 01:45