How models are resized when resizing glViewport() and glFrustum()? - opengl

static void resize(int width, int height)
{
const float ar = (float) width / (float) height;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity() ;
}
We know when we resize window, this resize() is called and viewport is resized. But how models are resized when we change the window size?

What appreas on the screen of course changes when you change the projection matrix or viewport, since that is the whole point of the exercise. If you look at the end result in screen space, the models will of course appear bigger or smaller if the projection or viewport parameters are changed. And mathematically, there is a scale component involved. Since the projection matrix and viewport transform is applied to every vertex in every draw call, you could view this as the models beeing "resized". But one typically doesn't look at things that way.
That's more of a matter of how you look at things. The object space vertices of the models are not changed, neither is the world space position and size (if you like to think in such terms).

We use three different "coordinates" to make sense of a 3D world:
Models, with the positions of their vertices and whatnot, are defined in Model Space. This is the coordinate system that was originally used (for example in Blender) to create the model and define where the vertex positions are.
There can be lots of models, all with different positions, in a world. To make sense of this all, we define World Space. You have to set up a matrix that transforms every model from its Model Space to our global World Space.
Next, there's Eye Space (or Camera Space, or View Space). A matrix that transforms from World Space to Eye Space gives us the ability to easily move our camera around. Eventually, Eye Space is what we will actually "see".
But wait! There's more! Eye Space is only still a bunch of vertices, there's no concept of perspective. In the end, all OpenGL does is render all triangles that are inside a unit cube. This is known as Normalized Device Coordinate Space. To go from Eye Space to Normalized Device Coordinate Space, we apply yet again a matrix, which we usually call the projection matrix at this stage.
Old OpenGL used to have all functionality built in: you are using it yourself when you call
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);
This basically says: We want to adjust the projection matrix. Then we set it equal to the identity matrix. Then we use a convenience function called glFrustum to set up the correct projection matrix. The call to glFrustum sets up a perspective projection matrix, i.e. one where "things that are further away become smaller".

Related

Any solutions for perspective view openGL qt

I have the following problem, when I zoom in on the image. I have not been able to solve it. I am currently developing in Qt with c ++. I have a question about orthogonal projection and perspective projection. I need to zoom without traversing the image. I tried to make the glViewport bigger, but it does not work for me. The xmin, xmax... are the maximum and minimum values ​​for each axis.
void MeshViewer::resizeGL(int width, int height)
{
int side = qMin(width, height);
if ( height == 0 )
height = 1;
glViewport(((GLint)(width - side)/2.0), (GLint)((height -side)/2.0), (GLint)side, (GLint)side);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glOrtho(xmin, xmax, ymin, ymax, zmin, zmax);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
glViewport specifies the mapping of normalized device coordinates to window coordinates (pixels).
If you want that the entire geometry which is inside the clip space, is mapped to the window, then it has to be:
glViewport(0, 0, width, height)
What the window displays is a frustum, defined by six planes. Normally, these planes are parallel, as in a cube. Anything that lies outside the frustum is not displayed.
"Zoom" may be interpreted, in a generic way, as "see bigger, nearer, more detail".
There are several ways of achieve the zoom effect:
Scale the objects. This works, the flaw is that objects (or parts of them) may lie before the near plane or behind the far plane of the frustum.
Move the camera towards the object. Same matter with near/far planes. Also, take care of moving through the model, you can set a "barrier" (perhaps a box) to prevent the camera moving too deep.
For an orthogonal projection, set left/right/top/bottom planes nearer to the object. This makes the frustum smaller, thus it's normal that some objects get clipped.
For a perspective projection you can do the same trick as with orthogonal. This trick is just to reduce the FOV (field of view) angle. If objects are too far, the perspective effect may be less obvious.

How to translate the projected object in screen in opengl

I've rendered an 3d object and its 2d projection in the image is correct. However now I want to shift the 2d projected object by some pixels. How do I achieve that?
Note that simply translating the 3d object doesn't work because under perspective projection the 2d projected object could change. My goal is to just shift the 2d object in the image without changing its shape and size.
If you're using the programmable pipeline, you can apply the translation after you applied the projection transformation.
The only thing you have to be careful about is that the transformed coordinates after applying the projection matrix have a w coordinate that will be used for the perspective division. To make the additional translation amount constant in screen space, you'll have to multiply it by w. The key fragments of the vertex shader would look like this:
in vec4 Position;
uniform mat4 ModelViewProjMat;
uniform vec2 TranslationOffset;
void main() {
gl_Position = ModelViewProjMat * Position;
gl_Position.xy += TranslationOffset * gl_Position.w;
}
After the perspective division by w, this will result in a fixed offset.
Another possibility that works with both the programmable and fixed pipeline is that you shift the viewport. Say if the window size is vpWidth times vpHeight, and the offset you want to apply is (xOffset, yOffset), you can set the viewport to:
glViewport(xOffset, yOffset, vpWidth + xOffset, vpHeight + yOffset);
One caveat here is that the geometry will still be clipped by the same view volume, but only be shifted by the viewport transform after clipping was applied. If the geometry would fit completely inside the original viewport, this will work fine. But if the geometry would have been clipped originally, it will still be clipped with the same planes, even though it might actually be inside the window after the shift is applied.
As an addition to Reto Koradi's answer: You don't need shaders and you don't need to modify the viewport you use (which has the clipping issues mentioned in the answer). You can simply modifiy the projection matrix by pre-multiplying some translation (which in effect will be applied last, after the projective transformation):
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glTranstlate(x,y,z); // <- this one was added
glFrustum(...) or gluPerspective(...) or whatever you use
glFrustum and gluPerspective will multiply the current matrix with the projective transfrom matrix they build, that is why one typically loads identity first. However, it doesn't necessarily have to be identity, and this case is one of the rare cases where one should load something else.
Since you want to shift in pixels, but that transformation is applied in clip space, you need some unit conversions. Since the clip space is just the homogenous representation of the normalized device space, where the frustum is [-1,1] in all 3 dimensions (so the viewport is 2x2 units big in that space), you can use the following:
glTranslate(x * 2.0f/viewport_width, y * 2.0f/viewport_height, 0.0f);
to shift the output by (x,y) pixels.
Note that while I wrote this for fixed-function GL, the math will of course work with shaders as well, and you can simply modify the projection matrix used by the shader in the same way.

Object, world, camera and projection spaces in OpenGL

I'm trying to understand creating spaces in OpenGL:
Object space
World space
Camera space
Projection space
Is my understanding of these stages correct?
The "cube" is being created in the center of the cartesian coordinate system, directly inside the program by typing the vertices coordinates.
The coordinates are transformed into coordinates inside of the "world", which means moving it to any place on the screen.
Well, actually I'd like you to check my understanding of those two terms.
Now, I'm creating a triangle on the black screen. How does openGL code fits to these spaces?
It works on GL_MODELVIEW flag by default, but that's the second stage - world space. Does that mean that calling glVertex3f() creates a triangle in the object space?
Where is the world space part?
Also, I've read that the last two spaces are not part of the openGL pipeline (or whatever it's called).
However, OpenGL contains flags such as the GL_PROJECTION, for example:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, w, h); // w - width, h - height
gluPerspective(45, ratio, 1, 100); // radio = w/h
glMatrixMode(GL_MODELVIEW);
What does this code do? It sets the perspective. Does it create the z axis? But isn't it already the object space part?
1) Object space is the object's vertices relative to the object's origin. In the case of a 1x1x1 cube, your vertices would be:
( 0.5, 0.5, 0.5)
(-0.5, 0.5, 0.5)
( 0.5, -0.5, 0.5)
(-0.5, -0.5, 0.5)
etc.
2) World space is where the object is in your world. If you want this cube to be at (15, 10), you'd create a translation matrix that, when multiplied with each vertex, would center your vertices around (15, 10). For example, the first vertex would become (15.5, 10.5, 0.5). The matrix to go from object to world space is called the "model" matrix.
3) Eye Space (sometimes called Camera space) is the world relative to the location of the viewer. Since this has to be a matrix that each vertex is multiplied by, it's technically the inverse of the camera's orientation. That is, if you want a camera at (0, 0, -10), your "view" matrix has to be a translation of (0, 0, 10). That way all the objects in the world are forward 10 units, making it look like you are backwards 10 units.
4) Projection space is how we apply a correct perspective to a scene (assuming you're not using an orthographic projection). This is almost always represented by a frustum, and this article can explain that better than I can. Essentially you are mapping 3d space onto another skewed space.
OpenGL then handles clip space and screen space.
It works on GL_MODELVIEW flag by default, but that's the second stage - world space. Does that mean that calling glVertex3f() creates a triangle in the object space?
You set vertices with glVertex3f() in object space always. (this is actually a very old and slow way to do it, but that's not really the point of this question)
When you set GL_MODELVIEW, it's only changing the model matrix (which can be manipulated with glLoadMatrix, glTranslate, glRotate, glScale, etc.).
Line by line, your piece of code is doing the following:
All transformations will now be affecting the projection matrix.
Clear out the old projection matrix and replace it with the identity matrix.
Use the entire screen as the viewport.
Set the projection matrix to a perspective with a 45 degree vertical field of view with an aspect ratio of w/h, the near-clip plane 1 unit away, and the far-clip plane 100 units away.
All transformations are now affecting the modelview matrix again.
The Z axis already exists, this just sets the projection matrix that gives you perspective, tells OpenGL to use the entire window to render. This isn't the object space, it's the way you transform object space to projection space.
Also a side note, you're using really, really old OpenGL (1992 old). glTranslate, etc. were deprecated a long time ago and are now just removed from the API. The only reason you can still use them is because drivers keep them there for compatibility's sake. I'd recommend you look into using modern (3.0+) OpenGL. Modern graphics pipelines are several orders of magnitude faster than immediate mode (glBegin, glVertex, glEnd).

glOrtho in a 3D scene isn't working

I made a 3D scene and I used glOrtho and gluOrtho2D to get things to stay on my screen when I move the camera to look around in my 3D scene. But when I start to look around the characters disappear.
How do you get the characters to stay on your screen.
The projection matrix kind of defines your lens. But no matter what lens you use, if you turn the scene or move the camera, the view will change.
How do you get the characters to stay on your screen.
Well, by keeping the "camera" in place.
OpenGL actually doesn't have a camera. It doesn't even have a scene. The only thing it sees are points, lines and triangles it draws one after another to the screen. What OpenGL has are transformation matrices. And in your case, all you have to do is set a projection and modelview, that will draw the characters at the desired place on the screen. And since OpenGL does not maintain a scene, you can change the transformation matrices anytime you want.
You probably forgot a "glLoadIdentity();" somewhere...
After your calls to glOrtho...
glOrtho(0.0, windowWidth, 0.0, windowHeight, -10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
Hope this helps.
-kropcke

Creating a tiled world with OpenGL

I'm planning to create a tiled world with OpenGL, with slightly rotated tiles and houses and building in the world will be made of models.
Can anybody suggest me what projection(Orthogonal, Perspective) should I use, and how to setup the View matrix(using OpenGL)?
If you can't figure what style of world I'm planning to create, look at this game:
http://www.youtube.com/watch?v=i6eYtLjFu-Y&feature=PlayList&p=00E63EDCF757EADF&index=2
Using Orhtogonal vs Perspective projection is entirely an art style choice. The Pokemon serious you're talking about is orthogonal -- in fact, it's entirely layered 2D sprites (no 3D involved).
OpenGL has no VIEW matrix. It has a MODELVIEW matrix and a PROJECTION matrix. For Pokemon-style levels, I suggest using simple glOrtho for the projection.
Let's assume your world is in XY space (coordinates for tiles, cameras, and other objects are of the form [x, y, 0]). If a single tile is sized 1,1, then something like glOrtho(12, 9, -10, 10) would be a good projection matrix (12 wide, 9 tall, and Z=0 is the ground plane).
For MODELVIEW, you can start by loading identity, glTranslate() by the tile position, and then glTranslate() by the negative of the camera position, before you draw your geometry. If you want to be able to rotate the camera, you glRotate() by the negative (inverse) of the camera rotation between the two Translate()s. In the end, you end up with the following matrix chain:
output = Projection × (CameraTranslation-1 × CameraRotation-1 × ModelLocation × ModelRotation) × input
The parts in parens are MODELVIEW, and the "-1" means "inverse" which really is negative for translation and transpose for rotation.
If you want to rotate your models, too, you generally do that first of all (before the first glTranslate().
Finally, I suggest the OpenGL forums (www.opengl.org) or the OpenGL subforums of www.gamedev.net might be a better place to ask this question :-)
The projection used by that video game looks Oblique to me. There are many different projections, not just perspective and orthographic. See here for a list of the most common ones: http://en.wikipedia.org/wiki/File:Graphical_projection_comparison.png
You definitely want perspective, with a fixed rotation around the X-axis only. Around 45-60 degrees or thereof. If you don't care about setting up the projection code yourself, the gluPerspective function from the GLU library is handy.
Assuming OpenGL 2.1:
glMatrixMode(GL_PROJECTION); //clip matrix
glLoadIdentity();
gluPerspective(90.0, width/height, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW); //world/object matrix
glLoadIdentity();
glRotatef(45.0f, 1.0f, 0.0f, 0.0f);
/* render */
The last two parameters to gluPerspective is the distance to the near and far clipping planes. Their values depend on the scale you use for the environment.