Preparing the window for a reshape
Prev: Initialization | Next: Animation |
Run the app you’ve just created. You’ll see two windows: a console window and the OpenGL window. Now resize the window so that the height no longer matches the width. The triangle gets distorted. This occurs because we’re not setting the perspective correctly. By default, the perspective assumes that the ratio width/height is 1 and draws accordingly. So when the ratio is changed, the perspective gets distorted. Therefore, every time the ratio changes the perspective needs to be recomputed.
GLUT provides a way to define which function should be called when the window is resized, i.e. to register a callback for recomputing the perspective. Furthermore, this function will also be called when the window is initially created, so that even if you’re initial window is not square things will look OK.
GLUT registers the callback functionwhen you call glutReshapeFunc.
void glutReshapeFunc(void (*func)(int width, int height));
Parameters:
- func – The name of the function that will be responsible for setting the correct perspective when the window changes size.
So what we must do is to go back to the main function we defined in the previous section, and add a call to glutReshapeFunc. Lets call our own function to take care of window resizes changeSize. The code for the main function with the call to glutReshapeFunc added in is:
int main(int argc, char **argv) { // init GLUT and create window glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(100,100); glutInitWindowSize(320,320); glutCreateWindow("Lighthouse3D- GLUT Tutorial"); // register callbacks glutDisplayFunc(renderScene); // Here is our new entry in the main function glutReshapeFunc(changeSize); // enter GLUT event processing cycle glutMainLoop(); return 1; }
The next thing we need to do, is to define the function that we’ll take care of the perspective. As seen by the syntax of glutReshapeFunc, the changeSize function has two arguments, these are the new width and height, respectively, of the client area of the window, i.e. without the window decorations.
void changeSize(int w, int h) { // Prevent a divide by zero, when window is too short // (you cant make a window of zero width). if(h == 0) h = 1; float ratio = 1.0* w / h; // Use the Projection Matrix glMatrixMode(GL_PROJECTION); // Reset Matrix glLoadIdentity(); // Set the viewport to be the entire window glViewport(0, 0, w, h); // Set the correct perspective. gluPerspective(45,ratio,1,1000); // Get Back to the Modelview glMatrixMode(GL_MODELVIEW); }
A few functions we’re introduced in this piece of code, so let’s go into a bit of detail in here before we all get lost. The first step was to compute the ratio between the width and the height. Note that, in order for this to be done correctly, we must take care of the case when the height of a window is actually zero, to prevent a division by zero.
We then set the current matrix to be the projection matrix. This is the matrix that defines the viewing volume. We then load the identity matrix to initialize it. Afterwards, we set the viewport to be the whole window, with the function glViewport. You can try with different values to see what you come up with, the first two parameters are the bottom left corner, and the last two are the width and height of the viewport. Note that these coordinates are relative to the client area of the window, not the screen. If you do try with different values then don’t forget that the ratio computed above should also use the new width and height values.
The gluPerspective function is part of another library for OpenGL, the OpenGL Utility Library, or GLU. GLU is a standard component of the implementation of OpenGL. The gluPerspective function establishes the perspective parameters. The first one defines the field of view angle in the yz plane, the ratio defines the relation between the width and height of the viewport. The last two parameters define the near and far clipping planes. Anything closer than the near value, or further away than the far value, will be clipped away from the scene. Beware with these settings, or you may end up not seeing anything at all.
Finally, we tell OpenGL that all matrix operations that follow will use the modelview matrix. This is just to be on the safe side. Most operations, such as setting the camera and transforming objects will use this matrix. The idea is to have always the modelview matrix as default.
The code so far
#ifdef __APPLE__ #include <GLUT/glut.h> #else #include <GL/glut.h> #endif void changeSize(int w, int h) { // Prevent a divide by zero, when window is too short // (you cant make a window of zero width). if (h == 0) h = 1; float ratio = w * 1.0 / h; // Use the Projection Matrix glMatrixMode(GL_PROJECTION); // Reset Matrix glLoadIdentity(); // Set the viewport to be the entire window glViewport(0, 0, w, h); // Set the correct perspective. gluPerspective(45,ratio,1,100); // Get Back to the Modelview glMatrixMode(GL_MODELVIEW); } void renderScene(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBegin(GL_TRIANGLES); glVertex3f(-2,-2,-5.0); glVertex3f(2,0.0,-5.0); glVertex3f(0.0,2,-5.0); glEnd(); glutSwapBuffers(); } int main(int argc, char **argv) { // init GLUT and create window glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(100,100); glutInitWindowSize(320,320); glutCreateWindow("Lighthouse3D - GLUT Tutorial"); // register callbacks glutDisplayFunc(renderScene); glutReshapeFunc(changeSize); // enter GLUT event processing loop glutMainLoop(); return 1; }
Prev: Initialization | Next: Animation |
47 Responses to “Preparing the window for a reshape”
Leave a Reply Cancel reply
This site uses Akismet to reduce spam. Learn how your comment data is processed.
Hi I learned that reshape function is done so that when our window is reshaped picture gets distorted but when I change height and width of my picture there is no change in object.Why this is so?
Will someone please help me.
Thanks in advance.
Hey, thanks for the tuto, I will be following that course for sure, no I have problem with the reshape function that is my triangle won’t appear on screen, while it does when I comment the glPersperctive() function; but then I got no reshape. Can you help me ?
Oh I forgot to set the z value of my vertex to -5. So how comes it gets clipped when set to 0 as 1 is the near clipping value ?
Hi,
By default the camera is at the origin, looking at the negative Z direction. Only things that are further away than the near plane are visible. The near plane specification is a distance from the camera. Hence, z=-5 is 5 units away from the camera, and it is visible, Z=1 is behind the camera because the view direction is the negative Z axis.
Hope this helps,
Antonio
Hi,
It should appear. Are you using a copy of the code provided? Try the github version and see if you get the same result.
I was running into the gluPerspective issue (not defined) and I ended up adding “-lglu32” to the end of my compilation line which fixed it. Hopefully this will help someone.
thanks man!
Hi,
I need to know how can I preserve the size of the object in the window even after the window is resized.
Hi all, I am newbie with OpenGL. Could you please tell me how the procedure changeSize defines the parameters w and h when it is called by glutReshapeFunc(changeSize) ?
If w and h are global parameters, then where did we define them after calling changeSize?
Hi,
We don’t define those parameters. That function is called by GLUT whenever the window size changes, and the function is called with the new window dimensions.
hi
i want to take all the pixel intensity values as an array what is viewed from the perspective Ie i want to store the image in an array can you please tell me how could i can make that array or obtain the image array somehow
hello
how to open picture in c language?
how to rotate picture?
Hi,
What do you mean by picture?
Hi, i tried to compile this with mingw32-gcc. This went fine:
gcc -o glutinit.o glutinit.c
but this wrong:
gcc -o glutinit.exe glutinit.o -lfreeglut -lopengl32 -Wl,–subsystem,windows
error: undefined reference to gluPerspective@32
can you please help?
I had the same problem. You just have to add “-l GLU” (or at least that’s what I had to do on Linux)
Hello,
I tryed to use glhPerspectivef2 (http://www.opengl.org/wiki/GluPerspective_code).
I don’t understand how to use vsMathLib for a replacement to gluPerspective.
Can you help me, please?
Hi,
Have looked at the code in the sample? to replace the projection matrix just do as follows:
1. Declare vsml as a global variable
VSMathLib *vsml;
2. Init VSMathLib stating which variable in your shader corresponds to the projection matrix, for instance:
vsml->setUniformName(VSMathLib::PROJECTION, “projectionMatrix”);
3. Whenever you want to build the matrix just call it as you would call gluPerspective:
vsml->loadIdentity(VSMathLib::PROJECTION);
vsml->perspective(53.13f, ratio, 0.1f, 10000.0f);
4. To send the matrices (projection and any others you are using) to the shaders, before the glDraw call invoke the method:
vsml->matricesToGL();
Hope this helps 🙂
Check out the VS*L pages, namely vsMathLib, for a replacement to gluPerspective.
The parameters to glViewport define the bottom left and top right corners. You erroneously swapped the order (cf. http://www.opengl.org/sdk/docs/man/xhtml/glViewport.xml).
Apart from that, thanks for the excellent tutorial!
well spotted. Many thanks.
in fact, the two last parameters of glViewport() aren’t the top right corner, coordinates, but the width and height of the viewport. the coordinates of top right corner are then (width-1, height-1).
Quite right. I don’t know where I got that from…
please tell me how to implement the same in opengl ES??
incredible work, thanks a lot, this is the meaning of internet sharing knowledge, making information a lot easier to access
thanks
Am I right if I say that in this case nothing is changed? I mean the triangle changes th same way after inserting the new parts. If I want to use just a triangle and I don’t want to rotate it or anything else then can I skip this part?
Hi. I had an issue. You are using VS, so it does it automatically, but on Linux systems (which I happen to be using) you probably have to compile using literal terminal commands (‘g++’ is for C++). VS should automatically add all of the required flags for adding functions starting with gl, glut, and glu. It works fine with just the ones beginning with glut, but I found an issue. My compiler warned me that there was an undefined reference to gluPerspective. It turned out that that could be fixed by adding the -lGLU tag to the compilation command. That helps.
Just thought anyone else with that issue could want that tidbit.
Even though I removed this line, the result looks the same.
Why do we need this line ?
// Get Back to the Modelview
glMatrixMode(GL_MODELVIEW);
-Sam
Good Point. Actually in the code provided its not required. But certain fixed function features, such as light and fog, rely on having the modelmatrix active. I consider switching always to the modelview to be a good practice since the modelview matrix is used in all operations except projections.
I do not see the triangle anymore, the screen is black after I added glutReshapeFunc(changeSize). It works without the reshape func, any idea what could be wrong.
I think your model is out of the (near, far) range.. Please make sure the following.
glVertex3f(-2,-2,-5.0);
glVertex3f(2,0.0,-5.0);
glVertex3f(0.0,2,-5.0);
Not sure what you mean. The near, far are set at 1 to 100 units. The view is by default located at the origin and aiming along the negative Z axis, so the model is within range, being only 5 units away from the view.
Quite enjoying the tutorial so far. However, please note that under the “The code so far” you are missing the glut include!
Thanks for the tip (previous comment) and the bug report.
Hello again. I’m a little confused as to what the 1st parameter of the gluPerspective function is for. Why did you call it a “field of view angle in the yz plane?”
I tried modifying it, and I only was able to observe that the camera moves back away from the object (or the object moves farther ahead of the camera or the object shrinks) as I increase the value of the parameter. At some point (after increasing it) increasing it further has the opposite effect, and the cycle just seems to keep on repeating as you increase the value. Please elaborate on what the first parameter actually does. Thanks. 🙂
Hi again,
the field of view determines the angle of the lens. think of it as a zoom lens. The smaller value to closer the object gets, just like zooming on an object. Large values produce a fish-eye type of image.
Hi,
You might want to mention you changed the triangle values, I was getting a black screen until I noticed they were different from the original ones you specified in your tutorial.
Also I noticed in the gluPerspective function you have one like this gluPerspective(45,ratio,0.1,1000); and the other like : gluPerspective(45,ratio,1,1000);
The only difference is the 3rd argument which is 0.1 vs 1, is this a typo, are they equal or are they values you found to be appropriate in this example?
Hi Albert,
Thanks for the feedback. The triangle values are valid for each example. However, if you try the the values from one example in the other example you may get a black screen. As for the third argument of gluPerspective, it defines the distance from which the camera can “see”, meaning that anything closer than that value won’t be displayed. In the second example you can use 1.0 and you still see the triangle.
By default the camera is placed at (0,0,0) and is pointing in the negative Z axis. Since the triangle is drawn at z = -5, the third value can have values that are as high as 5. With values greater than 5, for instance 5.1, you won’t see the triangle anymore.
Very helpful, thanks.
But doesn’t main return an int?
Well, yes. But you can also write it like this, at least in VS 🙂
You shouldn’t be able to. The operating system requires, defines, and expects a return value of (int)0 for main(). Somewhere in the code is the line
extern int main(int, char **);
Visual C++ also includes a definition:
extern void main(int, char **);
to facilitate people who do not understand that a nonzero return value indicates a zero. A void main() definition will simply return the last value loaded into memory, which could be anything. While not an issue in most cases while running Windows, if running a less stable operating system or with batch scripting files with error checking.
It’s a big problem and one that Microsoft should fix.
Yes, you’re right. Its one of those things that I keep doing the easy way, and not the correct way. When using GLUT that code won’t even get executed… 🙁
Nevertheless, I’ll take your comment into account when writing more demos 🙂
Thanks.
A void function has an undefined value in the return value location (the eax register, in the case of the standard x86 calling convention) — which is entirely different from saying that a void function returns 0.
I might not be fully understanding this example but if it is supposed to keep the aspect ratio of the view of the triangle on window resize then it doesn’t work. Anyone else having this issue?
nvm… managed to fix it… somehow 😀
Hi, nice tutorials they are very useful.
However i got to the end of this tutorial, and it is saying when i compile that
it is missing ; before type on the line float ratio = w * 1.0 / h;
and that ratio is an undeclared identifier
And it still gave these errors using the code at the end of the tutorial copied and pasted into the program, as i was writing out as myself as reading.
Sorry if these are simple to correct errors i am just doing a HND course on programming and have a unit involving C and OpenGL for 3D viewing, so trying to understand from the beginning.
Thanks.
Hi,
Just rename the c file to a cpp file and it should compile. C requires that all variable declarations are placed at the beginning of the function. C++ is more relaxed.
ARF is correct that C wants you to declare variables at the beginning of the function. So if you want to compile it as C this version of changeSize should work:
void
changeSize(int w, int h) {
float ratio;
if(h == 0)
h = 1;
ratio = ((float) w) / h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0,0,w,h);
gluPerspective(45,ratio,1,1000);
glMatrixMode(GL_MODELVIEW);
}