Perspective Issue with 3D coordinate system in OpenGL - opengl

I'm currently facing some perspective issues when trying to render the axes of a coordinate system into my scene. For these axes I draw three orthogonal lines that go through the center of my 3D cube.
It's pretty tough to explain what the problem is, so I guess the most demonstrative way of presenting it is to post some pictures.
1) view on the whole scene: click here
2) zoomed in view on the origin of the coordinate system: click here
3) When I zoom in a tiny little bit further, two of the axes disappear and the other one seems to be displaced for some reason: click here
Why does this happen and how can I prevent it?
My modelview and projection matrices look the following:
// Set ProjectionMatrix
projectionMatrix = glm::perspective(90.0f, (GLfloat)width / (GLfloat) height, 0.0001f, 1000.f);
glBindBuffer(GL_UNIFORM_BUFFER, globalMatricesUBO);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(glm::mat4), glm::value_ptr(projectionMatrix));
glBindBuffer(GL_UNIFORM_BUFFER, 0);
// Set ModelViewMatrix
glm::mat4 identity = glm::mat4(1.0); // Start with the identity as the transformation matrix
glm::mat4 pointTranslateZ = glm::translate(identity, glm::vec3(0.0f, 0.0f, -translate_z)); // Zoom in or out by translating in z-direction based on user input
glm::mat4 viewRotateX = glm::rotate(pointTranslateZ, rotate_x, glm::vec3(1.0f, 0.0f, 0.0f)); // Rotate the whole szene in x-direction based on user input
glm::mat4 viewRotateY = glm::rotate(viewRotateX, rotate_y, glm::vec3(0.0f, 1.0f, 0.0f)); // Rotate the whole szene in y-direction based on user input
glm::mat4 pointRotateX = glm::rotate(viewRotateY, -90.0f, glm::vec3(1.0f, 0.0f, 0.0f)); // Rotate the camera by 90 degrees in negative x-direction to get a frontal look on the szene
glm::mat4 viewTranslate = glm::translate(pointRotateX, glm::vec3(-dimensionX/2.0f, -dimensionY/2.0f, -dimensionZ/2.0f)); // Translate the origin to be the center of the cube

That's called "clipping". The axis is hitting the near-clip plane and thus is being clipped. The third axis is not "displaced"; it is simply partially clipped. Take your second image and cover up most of it, so that you only see part of the diagonal axis; that's what you're getting.
There are a few general solutions to this. First, you could just not allow the user to zoom in that far. Or you could adjust the near clip plane inward as the camera is moved closer to the target object. This will also cause precision problems for far away objects, so you'll probably want to adjust your far clip plane inward too.
Alternatively, you can just turn on depth clamping (assuming you have GL 3.x+, or access to ARB_depth_clamp or NV_depth_clamp). This isn't a perfect solution, as things will still be clipped when they get behind the camera. And things that intersect the near clip plane will no longer have proper depth buffering if two such objects overlap. But it's generally good enough.

Related

OpenGL glm rotate model around a point issue

I have a model and some helper cubes which are located on its axes, three on each axis for transformations, I used them for rotate the model around its local axes.
I want to make those cubes rotate around the model center with its rotation so I translate them to the model center, rotate them by the same angle on the same axis the translate them back.
This is the code:
//Rotation around X axis
GLfloat theta=glm::radians(xoffset);
glm::quat Qx(glm::angleAxis(theta, glm::vec3(1.0f, 0.0f, 0.0f)));
glm::mat4 rotX = glm::mat4_cast(Qx);
pickedObject->Transform(rotX);//Multiply the model matrix by the transformation matrix
glm::vec3 op(pickedObject->getMatrix()[3]);//model position
for(TransformationHelper* h:pickedObject->GetTransformationHelpers()){//the small cubes
glm::mat4 m,it,t;
glm::vec3 hp(h->getMatrix()[3]);//the cube position
t=glm::translate(m,op);//m is a unit matrix
it=glm::translate(m,-op);
m=t*rotX*it;
h->Transform(m);
}
The result is unexpected
Update:
after updating the translation matrix I got this result:
The translation is in the wrong direction; the correct offset should be hp-op, i.e. the matrix t should restore the cube's position after rotating.
t=glm::translate(glm::mat(1.f),hp-op);
Also there is no need to use inverse since it is costly (and numerically less stable):
it=glm::translate(glm::mat(1.f),op-hp);
(Note: here translate was called with an explicitly constructed identity matrix. See this post for a similar problem. See here for why this is necessary.)

Understanding how glm::ortho()'s arguments affect vertex location after projection

After searching many pages, glm documentation, tutorials...etc, I'm still confused on some things.
I'm trying to understand why I need to apply the following transformations to get my 800x600 (fullscreen square, assume the screen of the user is 800x600 for this minimal example) image to draw over everything. Assume I'm only drawing CCW triangles. Everything renders fine in my code, but I have to do the following:
// Vertex data (x/y/z), using EBOs
0.0f, 600.0f, 1.0f,
800.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
800.0f, 600.0f, 1.0f
// Later on...
glm::mat4 m, v, p;
m = scale(m, glm::vec3(-1.0, 1.0, 1.0));
v = rotate(v, glm::radians(180.0f), glm::vec3(0.0f, 1.0f, 0.0f));
p = glm::ortho(0.0f, 800.0f, 600.0f, 0.0f, 0.5f, 1.5f);
(Note that just since I used the variable names m, v, and p doesn't mean they're actually the proper transformation for that name, the above just does what I want it to)
I'm confused on the following:
Where is the orthographic bounds? I assume it's pointing down the negative z-axis, but where do the left/right bounds come in? Does that mean [-400, 400] on the x-axis maps to [-1.0, 1.0] NDC, or that [0, 800] maps to it? (I assume whatever answer here applies to the y-axis). Then documentation just says Creates a matrix for an orthographic parallel viewing volume.
What happens if you flip the following third and fourth arguments (I ask because I see people doing this and I don't know if it's a mistake/typo or it works by a fluke... or if it properly works regardless):
Args three and four here:
_____________
| These two |
p1 = glm::ortho(0.0f, 800.0f, 600.0f, 0.0f, 0.5f, 1.5f);
p2 = glm::ortho(0.0f, 800.0f, 0.0f, 600.0f, 0.5f, 1.5f);
Now I assume this third question will be answered with the above two, but I'm trying to figure out if this is why my first piece of code requires me flipping everything on the x-axis to work... which I will admit I was just messing around with it and it happened to work. I figure I need a 180 degree rotation to turn my plane around so it's on the -z side however... so that just leaves me with figuring out the -1.0, 1.0, 1.0 scaling.
The code provided in this example (minus the variable names) is the only stuff I use and the rendering works perfectly... it's just my lack of knowledge as to why it works that I'm unhappy with.
EDIT: Was trying to understand it from here by using the images and descriptions on the site as a single example of reference. I may have missed the point.
EDIT2: As a random question, since I always draw my plane at z = 1.0, should I restrict my orthographic projection near/far plane to be as close to 1.0 as possible (ex: 0.99, 1.01) for any reason? Assume nothing else is drawn or will be drawn.
You can assume the visible area in a orthographic projection to be a cube given in view space. This cube is then mapped to the [-1,1] cube in NDC coordinates, such that everything inside the cube is visible and everything outside will be clipped away. Generally, the viewer looks along the negative Z-axis, while +x is right and +Y is up.
How are the orthographic bounds mapped to NDC space?
The side length of the cube are given by the parameters passed to glOrtho. In the first example, parameters for left and right are [0, 800], thus the space from 0 to 800 along the X axis is mapped to [-1, 1] along the NDC X axis. Similar logic happens along the other two axes (top/bottom along y, near/far along -z).
What happens when the top and bottom parameters are exchanged?
Interchanging, for example, top and bottom is equivalent to mirroring the scene along this axis. If you look at second diagonal element of a orthographic matrix, this is defined as 2 / (top - bottom). By exchanging top and bottom only the sign of this element changes. The same also works for exchanging left with right or near with far. Sometimes this is used when the screen-space origin should be the lower left corner instead of upper left.
Why do you have to rotate the quad by 180° and mirror it?
As described above, near and far values are along the negative Z-axis. Values of [0.5, 1.5] along -Z mean [-0.5, -1.5] in world space coordinates. Since the plane is defined a z=1.0 this is outside the visible area. By rotating it around the origin by 180 degrees moves it to z=-1.0, but now you are looking at it from the back, which means back-face culling strikes. By mirroring it along X, the winding order is changed and thus back and front side are changed.
Since I always draw my plane at Z = 1.0, should I restrict my orthographic projection near/far plane to be as close to 1.0 as possible?
As long as you don't draw anything else, you can basically choose whatever you want. When multiple objects are drawn, then the range between near and far defines how precise differences in depth can be stored.

Setup Orthographic projection correctly?

Recently I need to use orthographic projection using glm library. But with orthographic projection my scene is not rendering at the center of my viewport.
My Scene is simply a cube, It was rendering well by using glm::perspective. I don't understand too much mathematical stuff, I just using glm::ortho function.
So how do I need to do to correctly setup the orthographic projection?
Here is the code I did:
mat4 projection=ortho(0.0f, 800.0f, 600.0f, 0.0f,-1000.0f, 1000.0f);
mat4 view=lookAt(vec3(0,0,1),vec3(0,0,0),vec3(0,1,0));
mat4 model=mat4();
Then I sent these three matrices to shader which is same as perspective projection did.It should be a quad in the center of my screen, but in my program it is lied on the top left corner of the screen,turns out like the a quarter.
Your cube appears in the top-left corner of the screen because that's the origin (0,0,0) of the coordinate space specified by your orthographic projection.
With your previous perspective projection you probably had an origin at the center of the screen. You can get back to that by changing the values in your orthographic projection:
ortho(-(800.0f / 2.0f), 800.0f / 2.0f,
600.0f / 2.0f, -(600.0f / 2.0f),
-1000.0f, 1000.0f);

OpenGL/GLSL/GLM - Skybox rotates as if in 3rd person

I have just gotten into implementing skyboxes and am doing so with OpenGL/GLSL and GLM as my math library. I assume the problem is matrix related and I haven't been able to find an implementation that utilizes the GLM library:
The model for the skybox loads just fine, the camera however circles it as if it is rotating around it in 3d third person camera.
For my skybox matrix, I am updating it every time my camera updates. Because I use glm::lookAt, it is essentially created the same way as my view matrix except I use 0, 0, 0 for the direction.
Here is my view matrix creation. It works fine in rendering of objects and geometry:
direction = glm::vec3(cos(anglePitch) * sin(angleYaw), sin(anglePitch), cos(anglePitch) * cos(angleYaw));
right = glm::vec3(sin(angleYaw - 3.14f/2.0f), 0, cos(angleYaw - 3.14f/2.0f));
up = glm::cross(right, direction);
glm::mat4 viewMatrix = glm::lookAt(position, position+direction, up);
Similarly, my sky matrix is created in the same way with only one change:
glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f);
glm::mat4 skyView = glm::lookAt(position, position + direction, up);
I know a skybox does not apply translation and only considers rotations so I am not sure what the issue is. Is there an easier way to do this?
Visual aids:
Straight on without any movement yet
When I rotate the camera:
My question is this: how do I set up the correct matrix for rendering a skybox using glm:lookAt?
Aesthete is right skybox/skydome is only object that means you do not change projection matrix !!!
your render should be something like this:
clear screen/buffers
set camera
set modelview to identity and then translate it to position of camera you can get the position directly from projection matrix (if my memory serves at array positions 12,13,14) to obtain the matrix see this https://stackoverflow.com/a/18039707/2521214
draw skybox/skydome (do not cross your z_far plane,or disable Depth Test)
optionaly clear Z-buffer or re-enable Depth Test
draw your scene stuf .... ( do not forget to set modelview matrix for each of your drawed model)
of course you can temporary set your camera position (projection matrix) to (0,0,0) and leave modelview matrix with identity, it is sometimes more precise approach but do not forget to set the camera position back after skybox draw.
hope it helps.

OpenGL - drawing GUI

I use glm::perspective(80.0f, 4.0f/3.0f, 1.0f, 120.0f); and multiply it by
glm::mat4 view = glm::lookAt(
glm::vec3(0.0f, 0.0f, 60.5f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f)
);
My question touches the subject of OpenGL and Maths. It relates to drawing GUI on my viewport. I do not know how to get proper coordinates in order to draw, e.g. a square that covers ¼ of the window. If I don't use perspectives and glm::lookAt(...) (matrix indentity), I will be able to draw my GUI by setting coords from X,Y in <-1.0, 1.0>. And when I put a vertex on (-1.0, -1.0), it will be localized at the bottom left corner of the window.
How to gain the same effect using perspective and lookAt?
Don't try to fiddle things into one certain projection. Just switch your projection to something that better suits your GUI drawing needs. OpenGL is a state machine, and it's perfectly normal to switch the parameters multiple times throughout rendering a single image.