Any solutions for perspective view openGL qt - c++

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.

Related

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

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".

How to scale 2d world with 3d rendering?

I'm using 3d mode to render my 2d game, because the camera rotation and zooming in/out is much easier than with 2d mode.
Now i have ran into a problem i cant seem to think how to fix:
How to make the 2d plane of my world to fit the screen in a way that 1 texture pixel matches 1 pixel on my screen? In other words: how do i calculate the z-position of my camera to achieve this?
My texcoords start from 0 and ends to 1, so i can see all the pixels from one tile in the GL_NEAREST texture filter mode.
My window is resizeable in a way that my tiles are always squares but the visible area expands depending on how i resize my window.
Edit: my view port is using perspective mode, not isometric. but if its not possible in perspective mode, im willing to change to isometric.
Use an orthographic projection that maps eye space units to pixels:
glViewport(0,0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, 0, height, -1, 1);
Update due to question update:
A texel → viewport pixel matching is possible with a perspective projection, but only under a certain constraint: The textured quad must be coplanar to the perspective frustum near/far plane.
How to do it? For glFrustum(left, right, bottom, top, near, far) with Z=near, XY eye space range [left, right]×[bottom, top] maps to NDC xy[-1, 1]² and NDC xy[-1, 1]² maps to the viewport extents. So those are all affine transformations following the law
y(x) = to_lower_bound + (x - from_lower_bound) * (to_upper_bound - to_lower_bound) / (from_upper_bound - from_lower_bound)
All you have to do it map viewport to NDC to near plane and if you're Z =/= near scale by near/Z.

gluLookAt and glFrustum with a moving object

Original Question/Code
I am fine tuning the rendering for a 3D object and attempting to implement a camera following the object using gluLookAt because the object's center y position constantly increases once it reaches it's maximum height. Below is the section of code where I setup the ModelView and Projection matrices:
float diam = std::max(_framesize, _maxNumRows);
float centerX = _framesize / 2.0f;
float centerY = _maxNumRows / 2.0f + _cameraOffset;
float centerZ = 0.0f;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(centerX - diam,
centerX + diam,
centerY - diam,
centerY + diam,
diam,
40 * diam);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0., 0., 2. * diam, centerX, centerY, centerZ, 0, 1.0, 0.0);
Currently the object displays very far away and appears to move further back into the screen (-z) and down (-y) until it eventually disappears.
What am I doing wrong? How can I get my surface to appear in the center of the screen, taking up the full view, and the camera moving with the object as it is updated?
Updated Code and Current Issue
This is my current code, which is now putting the object dead center and filling up my window.
float diam = std::max(_framesize, _maxNumRows);
float centerX = _framesize / 2.0f;
float centerY = _maxNumRows / 2.0f + _cameraOffset;
float centerZ = 0.0f;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(centerX - diam,
centerX,
centerY - diam,
centerY,
1.0,
1.0 + 4 * diam);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(centerX, _cameraOffset, diam, centerX, centerY, centerZ, 0, 1.0, 0.0);
I still have one problem when the object being viewed starts moving it does not stay perfectly centered. It appears to almost jitter up by a pixel and then down by 2 pixels when it updates. Eventually the object leaves the current view. How can I solve this jitter?
Your problem is with the understanding what the projection does. In your case glFrustum. I think the best way to explain glFrustum is by a picture (I just drew -- by hand). You start of a space called Eye Space. It's the space your vertices are in after they have been transformed by the modelview matrix. This space needs to be transformed to a space called Normalized Device Coordinates space. This happens in a two fold process:
The Eye Space is transformed to Clip Space by the projection (matrix)
The perspective divide {X,Y,Z} = {x,y,z}/w is applied, taking it into Normalized Device Coordinate space.
The visible effect of this is that of kind of a "lens" of OpenGL. In the below picture you can see a green highlighted area (technically it's a 3 volume) in eye space that, is the NDC space backprojected into it. In the upper case the effect of a symmetric frustum, i.e. left = -right, top = -bottom is shown. In the bottom picture an asymmetric frustum, i.e. left ≠ -right, top ≠ -bottom is shown.
Take note, that applying such an asymmetry (by your center offset) will not turn, i.e. rotate your frustum, but skew it. The "camera" however will stay at the origin, still pointing down the -Z axis. Of course the center of image projection will shift, but that's not what you want in your case.
Skewing the frustum like that has applications. Most importantly it's the correct method to implement the different views of left and right eye an a stereoscopic rendering setup.
The answer by Nicol Bolas pretty much tells what you're doing wrong so I'll skip that. You are looking for an solution rather than telling you what is wrong, so let's step right into it.
This is code I use for projection matrix:
glViewport(0, 0, mySize.x, mySize.y);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fovy, (float)mySize.x/(float)mySize.y, nearPlane, farPlane);
Some words to describe it:
glViewport sets the size and position of display place for openGL inside window. Dunno why, I alsways include this for projection update. If you use it like me, where mySize is 2D vector specifying window dimensions, openGL render region will ocuppy whole window. You should be familiar with 2 next calls and finaly that gluPerspective. First parameter is your "field of view on Y axis". It specifies the angle in degrees how much you will see and I never used anything else than 45. It can be used for zooming though, but I prefer to leave that to camera operating. Second parameter is aspect. It handles that if you render square and your window sizes aren't in 1:1 ratio, it will be still square. Third is near clipping plane, geometry closer than this to camera won't get rendered, same with farPlane but on contrary it sets maximum distance in what geometry gets rendered.
This is code for modelview matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt( camera.GetEye().x,camera.GetEye().y,camera.GetEye().z,
camera.GetLookAt().x,camera.GetLookAt().y,camera.GetLookAt().z,
camera.GetUp().x,camera.GetUp().y,camera.GetUp().z);
And again something you should know: Again, you can use first 2 calls so we skip to gluLookAt. I have camera class that handles all the movement, rotations, things like that. Eye, LookAt and Up are 3D vectors and these 3 are really everything that camera is specified by. Eye is the position of camera, where in space it is. LookAt is the position of object you're looking at or better the point in 3D space at which you're looking because it can be really anywhere not just center object. And if you are worried about what's Up vector, it's really simple. It's vector perpedicular to vector(LookAt-Eye), but becuase there's infinite number of such vectors, you must specify one. If your camera is at (0,0,0) and you are looking at (0,0,-1) and you want to be standing on your legs, up vector will be (0,1,0). If you'd like to stand on your head instead, use (0,-1,0). If you don't get the idea, just write in comment.
As you don't have any camera class, you need to store these 3 vectors separately by yourself. I believe you have something like center of 3D object you're moving. Set that position as LookAt after every update. Also in initialization stage(when you're making the 3D object) choose position of camera and up vector. After every update to object position, update the camera position the same way. If you move your object 1 point up at Y axis, do the same to camera position. The up vectors remains constant if you don't want to rotate camera. And after every such update, call gluLookAt with updated vectors.
For updated post:
I don't really get what's happening without bigger frame of reference (but I don't want to know it anyway). There are few things I get curious about. If center is 3D vector that stores your object position, why are you setting the center of this object to be in right top corner of your window? If it's center, you should have those +diam also in 2nd and 4th parameter of glOrtho, and if things get bad by doing this, you are using wrong names for variables or doing something somewhere before this wrong. You're setting the LookAt position right in your updated post, but I don't find why you are using those parameters for Eye. You should have something more like: centerX, centerY, centerZ-diam as first 3 parameters in gluLookAt. That gives you the camera on the same X and Y position as your object, but you will be looking on it along Z axis from distance diam
The perspective projection matrix generated by glFrustum defines a camera space (the space of vertices that it takes as input) with the camera at the origin. You are trying to create a perspective matrix with a camera that is not at the origin. glFrustum can't do that, so the way you're attempting to do it simply will not work.
There are ways to generate a perspective matrix where the camera is not at the origin. But there's really no point in doing that.
The way a moving camera is generally handled is by simply adding a transform from the world space to the camera space of the perspective projection. This just rotates and translates the world to be relative to the camera. That's the job of gluLookAt. But your parameters to that are wrong too.
The first three values are the world space location of the camera. The next three should be the world-space location that the camera should look at (the position of your object).

OpenGL coordinates question

I have a simple OpenGL drawing. When the user changes the window's size, I want the drawing to maintain it's aspect ration. I accomplished that by setting the glViewport to the maximum rectangle with the appropriate aspect ration whenever the reshape method is called.
My problem is that I want to draw a square that will always remain in the top right corner of the window, no matter what the size or shape of the window is. Right now, that square moves around the screen whenever the window is reshaped.
Can anyone please explain how to do this?
Thank you,
You need to move/size the square when the screen is re-sized. You can fix a square to the top left by using device coordinates but it won't necessarily be square of the aspect ratio changes. Therefore you need to resize the square to keep it square.
One way of doing this would be to create a new ortho matrix that maps to pixel coordinates (left = 0, bottom = 0, right = window-width, top = window-height) and set the gl-viewport to cover the entire window whenever the window changes. That way, you can draw a square by specifying pixel coordinates, if you make sure you have an identity model-view matrix set up.
It's not the only way, though. No matter what non-singular transformation you have, you should be able to come up with a way of hitting the correct pixels as long as the gl-viewport covers those, it's just easier this way.
If I understand correctly, you wish to draw a square at the top right corner of the window, regardless of where your scene viewport is positioned.
The easiest way to do this is to, after having rendered your normal scene with desired aspect, change the gl viewport to the square you want to draw in the top corner. Then draw a "full-screen" quad to fill the square, with full-screen in-fact becoming full-viewport in this case.
Untested semi-pseudo code would go something like this:
// Draw normal scene
glViewport(x, y, w, h);
drawScene();
// Draw top-right red square
glViewport( windowWidth - squareWidth, windowHeight - squareHeight,
squareWidth, squareHeight );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glColor3f(1.f, 0.f, 0.f);
glRectf(-1.f, -1.f, 1.f, 1.f);
Making sure that the winding of the glRectf matches your current gl cull face configuration. Alternatively, just temporarily disable culling by glDisable(GL_CULL_FACE) / glEnable(GL_CULL_FACE).
To draw a square in the top-right corner of the window, you need the viewport to cover this area. Having a viewport smaller than the window won't allow drawing in the corner.
You want your viewport to cover all the window (as done usually), and your square coordinates should be mapped to something like:
X0 = 1-2*s/width
X1 = 1
Y0 = 1-2*s/height
Y1 = 1
where s is the side of the square (pix), and width, height the dimensions of the window (pix).

How to declare gluPerspective in OpenGL?

How can I actually declare gluPerspective?
I mean I am drawing a spiral and I am setting z = -50 in the beginning and looping until the circle is complete. So what will be the declaration of gluPerspective?
Somewhere at the top of the source file you want to use gluPerspective in:
#include <GL/glu.h>
and then you can use gluPerspective with no problem.
I'm not really sure what you mean.gluPerspective() is typically used once when the program starts, then whenever the window is resized, to define the way primitives are projected to the screen.
You do that as so:
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
gluPerspective(60,screenWidth/screenHeight,0.1,1000);
I strongly recommend that you have a look at the official OpenGL red book chapter 3, Viewing. There you'll find a good introduction to perspective projection.
Edit after comment:
Well if you would read the chapter carefully you would read this:
You can manufacture a viewing transformation in any of several ways, as described next. You can also choose to use the default location and orientation of the viewpoint, which is at the origin, looking down the negative z-axis.
and
void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble near, GLdouble far);
Creates a matrix for a symmetric perspective-view frustum and multiplies the current matrix by it. fovy is the angle of the field of view in the x-z plane; its value must be in the range [0.0,180.0]. aspect is the aspect ratio of the frustum, its width divided by its height. near and far values the distances between the viewpoint and the clipping planes, along the negative z-axis. They should always be positive.