The order of transformed-matrix multiplication in OpenGL - opengl

Here I have a point P(x,y,z,1). Then I rotated the P around a known angel and a vector to point P1(x1,y1,z1,1). And according to P1's coordinates, I can translate P1 to point P2 (0,0,z1,1). Now I want to get only one matrix that can transform P to P2 directly So, my code is below:
GLfloat P[4] ={5,-0.6,3.8,1};
GLfloat m[16]; //This is the rotation matrix to calculate P1 from P
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glRotatef(theta, v1,v2,v3);//theta and (v1,v2,v3) is constant
glGetFloatv(GL_MODELVIEW_MATRIX, m);
glPopMatrix();
//calculate P1 from P and matrix m
GLfloat P1;
P1[0] = P[0]*m[0]+P[1]*m[4]+P[2]*m[8]+m[12];
P1[1] = P[0]*m[1]+P[1]*m[5]+P[2]*m[9]+m[13];
P1[2] = P[0]*m[2]+P[1]*m[6]+P[2]*m[10]+m[14];
P1[3] = P[0]*m[3]+P[1]*m[7]+P[2]*m[11]+m[15];
//after calculation P1 = {0.15,-3.51,-5.24,1}
GLfloat m1[16]; //P multiply m1 can get P2 directly
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glRotatef(theta, v1,v2,v3);//theta and (v1,v2,v3) is constant as above
glTranslatef(-P1[0], -P1[1], 0);// after rotation we get P1, then translation to P2
glGetFloatv(GL_MODELVIEW_MATRIX, m1);
glPopMatrix();
//calculate P2 from P and matrix m1
GLfloat P2[4];
P2[0] = P[0]*m1[0]+P[1]*m1[4]+P[2]*m1[8]+m1[12];
P2[1] = P[0]*m1[1]+P[1]*m1[5]+P[2]*m1[9]+m1[13];
P2[2] = P[0]*m1[2]+P[1]*m1[6]+P[2]*m1[10]+m1[14];
P2[3] = P[0]*m1[3]+P[1]*m1[7]+P[2]*m1[11]+m1[15];
//after this calculation, I expect P2 should be (0,0,-5.24) that is (0,0,p1[2])
//however, the real result is not my expectation! Where I do wrong???
Actually, I analyzed this problem. I found the order of matrix multiplication is weird.
After I do glRotatef(theta, v1,v2,v3), I get the matrix m. That's OK.
m is
m[0] m[1] m[2] 0
m[4] m[5] m[6] 0
m[8] m[9] m[10] 0
0 0 0 1
And if I do glTranslatef(-P1[0], -P1[1], 0) alone, I get the translation matrix m'.
m' is
1 0 0 0
0 1 0 0
0 0 0 1
-P1[0] -P1[1] 0 1
So I think after do glRotatef(theta, v1,v2,v3) and glTranslatef(-P1[0], -P1[1], 0),
the m1 = m*m', that is
m[0] m[1] m[2] 0
m[4] m[5] m[6] 0
m[8] m[9] m[10] 0
-P1[0] -P2[0] 0 1
However, in the actual program, m1 = m'*m, so the P2 is not my expected result!
I know doing the translate first and then doing the rotation that can get my right result, but why I cannot do the rotation first?

Rotation and translation are not commutable. (Matrix multiplication in general is not commutable, but in some special cases, such as all translations, all 2D rotations, all scalings, one rotation mixed with uniform scalings, the actions/matrices are commutable).
If you rotate first, then the translation will be in the direction of the rotated coordinate.
As an example, translate by (1, 0), then rotate by 90 degree, will give the origin at (1, 0), (assuming starting from identity matrix). As opposed to rotate by 90 degree first, will give the origin at (0, 1).
On the mathematical side, since this is coordinate transformation, any new transformation will be left multiply to the current coordinate transformation matrix. e.g. If T is matrix of a new transformation action, C is the current transformation matrix, then after the transformation, the current transformation matrix will become TC.

Related

gluLookAt specification

I have some problems understanding the specification for gluLookAt.
For example the z-axis is defined as:
F = ( centerX - eyeX, centerY - eyeY, centerZ - eyeZ )
with center being the point the camera looks at and eye being the position the camera is at.
f = F / |F|
and the View-Matrix M is defined as:
( x[0] x[1] x[2] 0 )
( y[0] y[1] y[2] 0 )
(-f[0] -f[1] -f[2] 0 )
( 0 0 0 1 )
with x and y being the x,y-axis and f being the z-axis
If my camera is positioned at (0, 0, 5) and the camera looks at the center. Then f would look along the negative z-axis because of the first equation (center - eye) the f-vector would be: (0,0,0) - (0,0,5) = (0,0,-5)
So far everything makes sense to me, but then the f-vector is multiplied by -1 in the M-Matrix above.
That way the f-vector looks along the positive z-axis and away from the center.
I found that the perspective matrix gluPerspective will also multiply the z-axis of the camrea with -1 which turns the z-axis again and makes it look toward the world's negative z-axis.
So what is the point of multiplying it with -1?
Because gluLookAt is a View Matrix for a right-handed system. In this space, Z-coordinate increments as it goes out of screen, or behind the camera. So all objects that the camera can see have negative Z in view space.
EDIT
You should review your maths. The matrix you exposed lacks the translation to camera position.
Following this notation let's do:
Obtain f normalized, up normalized, s normalized, and u=sn x f. Notice that s must be normalized because f and up may be not be perpendicular and then their cross-product is not a vector of length=1. This is not mentioned in the link above.
Form the matrix and pre-multiply by the translation to camera position, L= M ยท T
The resulting lookAt matrix is:
s.x s.y s.z -dot(s, eye)
u.x u.y u.z -dot(u, eye)
-f.x -f.y -f.z dot(f, eye)
0 0 0 1
With your data: camera=(0,0,5), target=(0,0,0), and up=(0,1,0), the matrix is:
1 0 0 0
0 -1 0 0
0 0 1 -5
0 0 0 1
Let's apply this transformation a the point A=(0,0,4). We get A'=(0,0,-1).
Again for B=(0,0,20), B'=(0,0,15).
A' has a negative Z, so the camera sees it. B' has a positive value, the camera can not see it.
I know this isn't a direct answer to the question but it might help someone who is looking for an equivalent function without using GLU, for example, if they are porting old OpenGL2 code to modern OpenGL.
Here is an equivalent function to gluLookAt(...):
void gluLookAt(float eyeX, float eyeY, float eyeZ,
float centreX, float centreY, float centreZ,
float upX, float upY, float upZ) {
GLfloat mat[16];
float forwardX = centreX - eyeX;
float forwardY = centreY - eyeY;
float forwardZ = centreZ - eyeZ;
glm::vec3 forward = glm::normalize(glm::vec3(forwardX, forwardY, forwardZ));
glm::vec3 right = glm::cross(glm::vec3(forwardX, forwardY, forwardZ),
glm::vec3(upX, upY, upZ));
right = glm::normalize(right);
mat[0] = right.x;
mat[1] = right.y;
mat[2] = right.z;
mat[3] = 0.0f;
mat[4] = upX;
mat[5] = upY;
mat[6] = upZ;
mat[7] = 0.0f;
mat[8] = -forward.x;
mat[9] = -forward.y;
mat[10] = -forward.z;
mat[11] = 0.0f;
mat[12] = 0.0f;
mat[13] = 0.0f;
mat[14] = 0.0f;
mat[15] = 1.0f;
glMultMatrixf(mat);
glTranslatef (-eyeX, -eyeY, -eyeZ);
}

How to create glClipPlanes matching the current projection matrix?

I'm rendering a collection of points in space which the user has manually rotated, panned, zoomed, and finally drawn a selection rectangle over a desired section. When they do this I call gluPickMatrix and then gluPerspective to construct the projection matrix, before using the GL_SELECT render mode to find the points in their selected area.
I want to only show the points in the selected area. For testing each point has a boolean isSelected, and I know selection works because the correct ones are getting selected. There are too many points for this to be feasible, though, so I'd like to use glClipPlane to construct four planes corresponding to the rectangular prism (edit: I mean the frustum) defined by the user's selection rectangle. How can I derive the coefficients to pass to glClipPlane after setting up the projection matrix?
Right now I'm doing this, but it ends up clipping all the points:
// Set up projection matrix
int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
gluPickMatrix(x, y, w, h, viewport);
gluPerspective(FOV_Y, ASPECT_RATIO, NEAR_PLANE, FAR_PLANE);
// Derive clip planes - this doesn't work
// Based on the paper "Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix"
// http://graphics.cs.ucf.edu/cap4720/fall2008/plane_extraction.pdf
double t[4], r[4], b[4], l[4];
double m[16];
glGetDoublev(GL_PROJECTION_MATRIX, m);
t[0] = m[3] - m[1]; t[1] = m[7] - m[5]; t[2] = m[11] - m[9]; t[3] = m[15] - m[13];
r[0] = m[3] - m[0]; r[1] = m[7] - m[4]; r[2] = m[11] - m[8]; r[3] = m[15] - m[12];
b[0] = m[3] + m[1]; b[1] = m[7] + m[5]; b[2] = m[11] + m[9]; b[3] = m[15] + m[13];
l[0] = m[3] + m[0]; l[1] = m[7] + m[4]; l[2] = m[11] + m[8]; l[3] = m[15] + m[12];
// ... Render points in GL_SELECT mode, then go back to GL_RENDER mode ...
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// ... Apply user's pan/rotate/zoom choices here ...
// Apply clip planes
glEnable(GL_CLIP_PLANE0);
glClipPlane(GL_CLIP_PLANE0, t);
glEnable(GL_CLIP_PLANE1);
glClipPlane(GL_CLIP_PLANE1, r);
glEnable(GL_CLIP_PLANE2);
glClipPlane(GL_CLIP_PLANE2, b);
glEnable(GL_CLIP_PLANE3);
glClipPlane(GL_CLIP_PLANE3, l);
I also tried normalizing and/or negating the plane coordinates, which still seems to end up clipping all the points.
After reading that paper more carefully, I found the problem. I wasn't taking the model view matrix into account.
This:
double m[16];
glGetDoublev(GL_PROJECTION_MATRIX, m);
// ... derive t, r, b, and l from m
Should be this:
double vm[16], pm[16], m[16];
glGetDoublev(GL_MODELVIEW_MATRIX, vm);
glGetDoublev(GL_PROJECTION_MATRIX, pm);
matrix_mul(vm, pm, m); // m = vm * pm
// ... derive t, r, b, and l from m

Current coordinates of an object in OpenGL

I need to perform a static collision detection between two objects using C++/OpenGL. I have written the code for the collision detection but this code uses the vertices of the two models as given in their .obj files and not the coords of their current positions (which is what I want).
I have performed to both models a Translate and a Scale transformation and I need to know what are these coordinates right now. I guess it has something to do with transformation matrices etc but how is this combined to the initial coordinates?
Can anyone help me?
OpenGL doesn't know what a model or a scene is, it just draws points, lines and triangles to a pixel framebuffer.
It's time for you to abandon some or all of the fixed function pipeline. You should no longer build your modelview matrix using glRotate, glTranslate and glScale. Instead you should maintain the matrix yourself, using some math library like GLM or Eigen. This gives you a single instance of the model transformation matrix which you can apply on your original model coordinates for collision testing, but also can be loaded into the modelview matrix using glLoadMatrix (if you also have the view transformation applied) or glMultMatrix in the GL_MODELVIEW matrix mode. Or you go for shaders and use uniforms.
If you just have translation t and scaling s, you can simply calculate the actual positions with:
world_position = s * model_position + t
If you have an arbitrary transformation given as a matrix M, you calculate the position with:
world_position = M * model_position
//where model_position should be a 4d vector with w-coordinate 1
I recommend you first draw your objects whith their centroid in the origin (0, 0 , 0)
So when you call the funcion
GLfloat matrixMV[16];
glGetFloatv(GL_MODELVIEW_MATRIX, matrixMV);
the coordinates x, y, z
will be respectively matrixMV[12] matrixMV[13] matrixMV[14]
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(-25.0, 0.0, 1.0, 0.0);
glTranslatef(100.0, 50.0, 0.0);
/*Draw a triangle with centroid in the orign*/
glBegin(GL_POLYGON);
glVertex2f(0.0 , 1.0 );
glVertex2f(-1.0,-0.27 );
glVertex2f(1.0 ,-0.27 );
glEnd();
GLfloat matrixMV[16];
glGetFloatv(GL_MODELVIEW_MATRIX, matrixMV);
double xCenterTriangle = matrixMV[12];
double yCenterTriangle = matrixMV[13];
double zCenterTriangle = matrixMV[14];
You would actually need to perform the same transformations you did to your coordinates.
If you are using fixed function pipline you might just get the current ModelView Matrix before you start to paint one object via glGetFloatv(GL_MODELVIEW_MATRIX, m) into some GLfloat m[16] and store the matrices to later apply them to your objects.
To get the multiplication right, here's the way the matrix elements are ordered, when multiplied from the left.
| m[0] m[4] m[8] m[12] | v[0]
| m[1] m[5] m[9] m[13] | x v[1]
| m[2] m[6] m[10] m[14] | v[2]
| m[3] m[7] m[11] m[15] | v[3]

Calculating AABB from Box (center, halfSize, rotation)

I want to calculate AABB (axis aligned bounding box) from my Box class.
The box class:
Box{
Point3D center; //x,y,z
Point3D halfSize; //x,y,z
Point3D rotation; //x,y,z rotation
};
The AABB class (Box, but without rotation):
BoundingBox{
Point3D center; //x,y,z
Point3D halfSize; //x,y,z
};
Ofc, when rotation = (0,0,0), BoundingBox = Box. But how to calculate minimum BoundingBox that contains everything from Box when rotation = (rx,ry,rz)?
If somebody asks: the rotation is in radians and I use it in DirectX matrix rotation:
XMMATRIX rotX = XMMatrixRotationX( rotation.getX() );
XMMATRIX rotY = XMMatrixRotationY( rotation.getY() );
XMMATRIX rotZ = XMMatrixRotationZ( rotation.getZ() );
XMMATRIX scale = XMMatrixScaling( 1.0f, 1.0f, 1.0f );
XMMATRIX translate = XMMatrixTranslation( center.getX(), center.getY(), center.getZ() );
XMMATRIX worldM = scale * rotX * rotY * rotZ * translate;
You can use matrix rotations in Cartesian coordinates. A rotation of an angle A around the x axis is defined by the matrix:
1 0 0
Rx(A) = 0 cos(A) -sin(A)
0 sin(A) cos(A)
If you do the same for an angle B around y and C around z you have:
cos(B) 0 sin(B)
Ry(B) = 0 1 0
-sin(B) 0 cos(A)
and
cos(C) -sin(C) 0
Rz(C) = sin(C) cos(C) 0
0 0 1
With this you can calculate (even analytically) the final rotation matrix. Let's say that you rotate (in that order) along z, then along y then along x (note that the axis x,y,z are fixed in space, they do not rotate at each rotation). The final matrix is the product:
R = Rx(A) Ry(B) Rz(C)
Now you can construct vectors with the positions of the six corners and apply the full rotation matrix to these vectors. This will give the positions of the six corners in the rotated version. Then just calculate the distance between opposing corners and you have the new bounding box dimensions.
Well, you should apply the rotation on the vertices of the original bounding box (for the purposes of the calculation), then iterate over all of them to find the min and max x, y and z of all the vertices. That would define your axis-aligned bounding box. That's it at its most basic form, you should try and figure out the details. I hope that's a good start. :)

Howto convert transformed coordinates to world coordinates in OpenGL?

I have a transformation set up in Opengl like this:
glPushMatrix();
glTranslated(pntPos.X(), pntPos.Y(), pntPos.Z());
glRotated(dx, 1, 0, 0);
glRotated(dy, 0, 1, 0);
glRotated(dz, 0, 0, 1);
//I use this to Render a freely placeable textbox in 3d
//space which is based on the FTGL-Toolkit [1] (for TTF support).
m_FTLayout.Render(m_wcCaption, m_iCaptionSize);
glPopMatrix();
This works as expected.
However, i would like to calculate the 3d-Boundingbox wich bounds my text in word space. I know the coordinates of this bounding-box relative to my GL-Transformation.
But i have a hard time calculating their world coordinates from these.
Could you give me some insight on how to retrieve the respective World coordinates of the four vertexes in the bounding Box?
[1] http://sourceforge.net/projects/ftgl/
The simplest way is to ask the GL what its current modelview matrix is glGetFloatv(GL_MODELVIEW_MATRIX, m), and transform your bounding box vertices by the resulting matrix.
m[0] m[4] m[8] m[12] v[0]
m[1] m[5] m[9] m[13] v[1]
M(v) = m[2] m[6] m[10] m[14] X v[2]
m[3] m[7] m[11] m[15] v[3]
That will give you the view-space 4-D homogeneous position of your vertex.
Or, you could compute the modelview yourself, based on the math that is available in the man pages of glTranslated and glRotated