Order of matrix multiplications in OpenGL - c++

glDisable(GL_DEPTH_TEST);
glViewport(0/*left*/, 0/*botton*/, 200/*width*/, 200/*height*/); //T4
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90 /*fov*/, 1/*aspect*/, 1/*fp*/, 1000/*bp*/); //T3
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0/*eyex*/,0/*eyey*/,0/*eyez*/, 0/*lax*/,0/*lay*/,-1/*laz*/, 0/*upx*/,1/*upy*/,0/*upz*/); //T2
glTranslatef(-15.0, -10.0, -49.0); //T1
glBegin(GL_POINTS);
glVertex4f(0, 0, -1, 1);
glEnd();
Given this code, in what order does the matrix multiplication happen? What do I have to know to follow and verify the calculations on paper?
I suspect to following order, but haven't figured out a way to verify it:
v=[0,0,-1,1]
T4 * T3 * T2 * T1 * v
Is this correct?

This is mostly correct, however glViewport (...) by itself does not define a matrix. It is a simple bias and scale operation. It defines the total width, height and offset in X and Y. There is another component you are missing, which is the depth range.
The multiplication occurs in that order, but since these are column-major matrices and post-multiplied, you conceptually start on the right and then work your way to the left. Cross out T4 because it alone is not a matrix, and the end result of all this is a clip-space vertex coordinate. You still need to divide v.xyz by v.w and then do the viewport transformation to fully replicate what GL does.
You can implement the viewport transform using a matrix, but you also need to factor in glDepthRange (...) which biases and scales the Z coordinate from NDC space to window space.
Here is what such a matrix would look like:
The whole process is discussed in better detail here, under 4.1 Coordinates Transformation.

Related

OpenGL capture 6 cube face images

How to move camera in OpenGL to capture 6 cube face images and save into files (like image below)?
What does "plugin" means?
I'm confused that you need how to calculate camera position&direction vectors for capture each side of dice or how to implement lookat&perspective functions.
for lookat&perspective functions, there are many resources to refer :
Can't understand gluLookAt arguments
gluPerspective parameters- what do they mean?
these functions are usually provided on many libraries, but if you need, then I will post my implementation.
Camera position and direction/up vector is calculated for viewing each side of dice squarely. to do this, you have to care about perspective FOV(field of view) with respect to distance between camera and dice.
If you read above posts carefully, you can determine arguments for these functions.
If once you see each side on screen, I think you need the method combining the result scene of each dice into one screen(or FBO) and save it.
If once you obtain 6 sets of arguments for lookat and perspective, you can use glViewPort.
// if pixel per each side : 10
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
//back side draw
glViewPort(0, 10, 10, 10);
//call glulookat & gluperspective or equivalent functions with arguments so that back side of dice drew on your Viewport fully
gluLookAt(...);
gluPerpective(...);
glDrawElements(...);
//up side draw
glViewPort(10, 0, 10, 10);
gluLookAt(...);
gluPerpective(...);
glDrawElements(...);
//left side draw
glViewPort(10, 10, 10, 10);
gluLookAt(...);
gluPerpective(...);
glDrawElements(...);
...
The above code draw 6 times in each selected viewport of your result FBO.
An example using PyQt5 for making an image of a plane with size X, Y in the z=0 plane.
Xt = X/2 #center of your camera in X
Yt = Y/2 #center of your camera in Y
dist = math.tan(math.radians(60))*Y/2 #Compute the distance of the campera from plane
#assuming a 60 degree projection
aspect = float(self.width)/float(self.height) #aspect ratio of display
center = QtGui.QVector3D(Xt, Yt, 0) #look at this point
eye = QtGui.QVector3D(Xt, Yt, dist) #Point of Camera in space
up = QtGui.QVector3D(0, 1, 0)
self.modelview = QtGui.QMatrix4x4()
self.modelview.lookAt(eye,center,up) #build modelview matrix with given parameters
self.projection = QtGui.QMatrix4x4()
self.projection.perspective(60.0, aspect, dist*0.0001, dist*10000.0) #build projection matrix
repeating this process for each side + adjusting the z distance to your cube should yield the desired result. The you can just write your results to a framebuffer and read that buffer into an array.

Z value always 1 or -1 when using `glm::perspective`

I'm trying to teach myself the ways for 3D programming with OpenGL, however I am struggling with some things, especially projection matrices.
I defined some vertices for a cube and successfully handed them to my graphics processor. The cube goes from xyz -0.5 to xyz 0.5 respectively, which gets rendered fine.
To move it into my world coordinate system, I am using this model matrix:
auto model = glm::mat4(
glm::vec4(1, 0, 0, 0),
glm::vec4(0, 1, 0, 0),
glm::vec4(0, 0, 1, 0),
glm::vec4(0, 0, 0, 1)
);
model = glm::translate(model, glm::vec3(0.f, 0.f, 495.f));
model = glm::scale(model, glm::vec3(100.f, 100.f, 100.f));
This successfully moves my cube to (-50, -50, 445) -> (50, 50, 545) so its now centered in the 200x200x1000 world coordinates I defined for myself.
My camera / view matrix is
auto view = glm::lookAt(
glm::vec3(0.f, 0.f, 5.f),
glm::vec3(0.f, 0.f, 0.f),
glm::vec3(0.f, 1.f, 0.f)
);
which moves the cube slightly closer, changing the z coordinate to 440 and 540 respectively. I don't understand why this is happening but I guess it has something to do with glm expecting a right hand coordinate system while I am working with a left handed one? While this is not why I am posting this question, I would be happy if someone would clear it up for me.
Now to my actual problem: I am trying to make use of glm::perspective. I call it like this:
auto perspective = glm::perspective(glm::radians(55.f), 1.f, 0.f, 1000.f);
If I'm not mistaken, at a z value of 440 I can expect the clipping area to go from roughly -229 to 229, so I would expect that bottom right cube vertex at (-50,-50) is visible. I calculated this by drawing the frustum in 2D, when I noticed that I should be able to calculate the height of any distance to the camera using tan(alpha / 2) * distToCamera = maxVisibleCoordinate (working with a 1:1 aspect ratio). Is this a correct assumption? Here is my terrible drawing, maybe you can tell that I have a wrong understanding of something with it:
In the final step I am trying to get all this together in my vertex shader using
gl_Position = projection * view * model * vec4(pos.x, pos.y, pos.z, 1.0);
which yields a perfectly reasonable result for the x and y value but the z value is always -1 which is, as far as I know, just right for not being displayed.
For my front-bottom-left vertex of the cube (-0.5, -0.5, -0.5) the result is (-96.04, -96.04, -440, -440), normalized to (-0.218, -0.218, -1).
For my back-top-right vertex of the cube (0.5, 0.5, 0.5) the result is (96.04, 96.04, -550, -550), normalized to (0.218, 0.218, -1).
What am I getting wrong, that my z value is lost and just set to -1 instead? When playing around with the camera position, the best I can get is getting it to 1, which also results in an empty window and is definitely not what I would expect.
A projection matrix is like this:
In the picture, f is for zfar and n is for znear.
As you can see, if you put znear = 0, the term at the 4th column become zero, which is incorrect. Also, -(f+n)/(f-n) = -1, which is incorrect too.
So, the conclusion is, znear cannot be zero. It is usually a small value, for example, 0.1
Since Amadeus already answered the question correctly, I'm going to just use this space to add some clarifying information about why it's correct.
We can refer back to the diagram you provided to explain what the problem is: You have two planes, the near plane and the far plane, representing the range at which you may view objects. What the Perspective Matrix does is it takes everything in between those two planes, within the Frustrum that you've defined (mathematically a cone, but our monitors are rectangular, so...) and maps them onto the flat Near-plane to create the final image. In a sense, you can think of the Near Plane as representing the monitor.
So given this context, if you were to set the Near Plane's distance to 0, meaning it was identical to the camera, what would happen? Well, in a cone it would set the plane to a single point, and in a frustrum, it's the same. You cannot view objects drawn onto a single point. You need a surface with actual surface area to draw onto.
That is why it is inappropriate to set the near value to 0. It would turn the drawing surface into a single point, and you cannot mathematically render any objects on a single point. Hence why the essential mathematical formulas backing the matrix will break down and result in bad outcomes if you try to do so anyways.

How to correctly represent 3D rotation in games

In most 3D platform games, only rotation around the Y axis is needed since the player is always positioned upright.
However, for a 3D space game where the player needs to be rotated on all axises, what is the best way to represent the rotation?
I first tried using Euler angles:
glRotatef(anglex, 1.0f, 0.0f, 0.0f);
glRotatef(angley, 0.0f, 1.0f, 0.0f);
glRotatef(anglez, 0.0f, 0.0f, 1.0f);
The problem I had with this approach is that after each rotation, the axises change. For example, when anglex and angley are 0, anglez rotates the ship around its wings, however if anglex or angley are non zero, this is no longer true. I want anglez to always rotate around the wings, irrelevant of anglex and angley.
I read that quaternions can be used to exhibit this desired behavior however was unable to achieve it in practice.
I assume my issue is due to the fact that I am basically still using Euler angles, but am converting the rotation to its quaternion representation before usage.
struct quaternion q = eulerToQuaternion(anglex, angley, anglez);
struct matrix m = quaternionToMatrix(q);
glMultMatrix(&m);
However, if storing each X, Y, and Z angle directly is incorrect, how do I say "Rotate the ship around the wings (or any consistent axis) by 1 degree" when my rotation is stored as a quaternion?
Additionally, I want to be able to translate the model at the angle that it is rotated by. Say I have just a quaternion with q.x, q.y, q.z, and q.w, how can I move it?
Quaternions are very good way to represent rotations, because they are efficient, but I prefer to represent the full state "position and orientation" by 4x4 matrices.
So, imagine you have a 4x4 matrix for every object in the scene. Initially, when the object is unrotated and untraslated, this matrix is the identity matrix, this is what I will call "original state". Suppose, for instance, the nose of your ship points towards -z in its original state, so a rotation matrix that spin the ship along the z axis is:
Matrix4 around_z(radian angle) {
c = cos(angle);
s = sin(angle);
return Matrix4(c, -s, 0, 0,
s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
}
now, if your ship is anywhere in space and rotated to any direction, and lets call this state t, if you want to spin the ship around z axis for an angle amount as if it was on its "original state", it would be:
t = t * around_z(angle);
And when drawing with OpenGL, t is what you multiply for every vertex of that ship. This assumes you are using column vectors (as OpenGL does), and be aware that matrices in OpenGL are stored columns first.
Basically, your problem seems to be with the order you are applying your rotations. See, quaternions and matrices multiplication are non-commutative. So, if instead, you write:
t = around_z(angle) * t;
You will have the around_z rotation applied not to the "original state" z, but to global coordinate z, with the ship already affected by the initial transformation (roatated and translated). This is the same thing when you call the glRotate and glTranslate functions. The order they are called matters.
Being a little more specific for your problem: you have the absolute translation trans, and the rotation around its center rot. You would update each object in your scene with something like:
void update(quaternion delta_rot, vector delta_trans) {
rot = rot * delta_rot;
trans = trans + rot.apply(delta_trans);
}
Where delta_rot and delta_trans are both expressed in coordinates relative to the original state, so, if you want to propel your ship forward 0.5 units, your delta_trans would be (0, 0, -0.5). To draw, it would be something like:
void draw() {
// Apply the absolute translation first
glLoadIdentity();
glTranslatevf(&trans);
// Apply the absolute rotation last
struct matrix m = quaternionToMatrix(q);
glMultMatrix(&m);
// This sequence is equivalent to:
// final_vertex_position = translation_matrix * rotation_matrix * vertex;
// ... draw stuff
}
The order of the calls I choose by reading the manual for glTranslate and glMultMatrix, to guarantee the order the transformations are applied.
About rot.apply()
As explained at Wikipedia article Quaternions and spatial rotation, to apply a rotation described by quaternion q on a vector p, it would be rp = q * p * q^(-1), where rp is the newly rotated vector. If you have a working quaternion library implemented on your game, you should either already have this operation implemented, or should implement it now, because this is the core of using quaternions as rotations.
For instance, if you have a quaternion that describes a rotation of 90° around (0,0,1), if you apply it to (1,0,0), you will have the vector (0,1,0), i.e. you have the original vector rotated by the quaternion. This is equivalent to converting your quaternion to matrix, and doing a matrix to colum-vector multiplication (by matrix multiplication rules, it yields another column-vector, the rotated vector).

Cant load and save matrix Opengl

I have the following code:
void setupCamera() {
// Clear the screen buffer
glClear(GL_COLOR_BUFFER_BIT);
// reset the projection matrix //
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// and set the perspective with the current field of view,
// and the current height and width
gluPerspective(fov, ratio, objDepth - objRadius * 2,
objDepth + objRadius * 2);
glViewport(0, 0, WINDOW_SIZE, WINDOW_SIZE);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if(first){
glMultMatrixf(rotMatrix);
}
first = true;
//translate everything to be in objDepth//
glTranslatef(initX * 0.01, initY * 0.01, (-1) * objDepth);
glRotatef(200 * angle, rotationVector[0], rotationVector[1],
rotationVector[2]);
glutWireTeapot(1.5);
glGetFloatv (GL_MODELVIEW_MATRIX, rotMatrix);
}
The rotation vector holds the rotation axis,
translate is used for moving all to the correct position.
the thing is, I am using glMultMatrixf in order to use the last matrix saved,
do rotation and then translation, and then save the matrix again with glGetFloatv.
this function is constantly called with timer, but for some reason
I can't figure out, the matrix wont save anything and always be initialized over and over,
meaning rotation is always used with small angles(because matrix isn't saved).
the saved matrix is not being used anywhere else in the code.
Any idea's?
Are you calling setupCamera() every tick? If you are, you may want to stop. You don't need to reset your projection matrix every frame and unless you NEED to, you don't need to reset your model view matrix either. Consider incrementing angle and your translation by itself rather than storing the whole matrix.
The steps you might want to take are:
1) Init matrices. Initialize projection to identity and use gluPerspective. Then switch to modelview and initialize it to identity as well. This should really only be done once.
2) In your update loop, increment your angle and translation on their representative variables.
3) In your draw loop, use glPushMatrix() to push the modelview matrix. Apply your matrix changes with gltranslate and glrotate then draw whatever it is you're drawing. After that, glPopMatrix() in order to return to identity.
I still don't really understand if you're trying to draw something and think that you need to read and store and restore the current glMatrix every frame or if you are actually trying to evaluate what OpenGL does to matrices and really DO need to read it out.

OpenGL: draw line between two elements

I need to draw a line between two meshes I've created. Each mesh is associated with a different model matrix. I've been thinking on how to do this and I thought of this:
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(first_object_model_matrix);
glBegin(GL_LINES);
glVertex3f(0, 0, 0); // object coord
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(first_object_model_matrix);
glVertex3f(0, 0, 0); // ending point of the line
glEnd( );
But the problem is that I can't call glMatrixMode and glLoadMatrixf between glBegin and glEnd. I'm also using shaders and the programmable pipeline, so the idea of turning back to the fixed pipeline with my scene rendered isn't exciting.
Can you:
Suggest me precisely how to draw a line between two meshes (I have their model matrix) with shaders.
or
Suggest me how to write code similar to the one above to draw a line having two meshes model matrices.
Calculate the line's two points by multiplying each one with one of your model matrices. The following is pseudo-code. Since you're using Qt, you could use its built-in maths libraries to accomplish this effect.
vec3 line_point_1 = model_matrix_object1 * vec4(0, 0, 0, 1);
vec3 line_point_2 = model_matrix_object2 * vec4(0, 0, 0, 1);
// Draw Lines
The position of the second point can simply be taken from the w vector of the model_matrix_object2. No need to multiply with (0,0,0,1).
This is because a 4x4 matrix in OpenGL is usually an ortho matrix consisting of a 3x3 rotational part and a translational vector. The last row is then padded with 0,0,0,1. If you want to know where a 4x4 matrix would translate simply get the vector in the right-most column.
See Given a 4x4 homogeneous matrix, how can i get 3D world coords? for more info.