Convert pitch rotation to roll rotation in OpenGL matrix - opengl

I have OpenGL (Right handed coordinates, Y-up, -Z forward) 4x4 transformation matrix that rotates the yaw correctly, but pitch and roll are flipped. Position is also correct.
Is there a way to flip the rotation around the z-axis to actually rotate around x-axis and vice versa?
Transformation matrix [
x1 y1 z1 w1
x2 y2 z2 w2
x3 y3 z3 w3
0 0 0 1
]
I have tried to decompose T R S out of the matrix and multiplying only the rotation matrix with coordinate system changing matrices without success. E.g. I have tried:
Identity matrix with x and z flipped [
0 0 1
0 1 0
1 0 0
]

The indices in the matrix are not corresponding to a certain axis, it might as well be labeled
[ e11 e12 e13
e21 e22 e23
e31 e32 e33 ]
check out this tutorial
http://ogldev.atspace.co.uk/www/tutorial07/tutorial07.html

Related

Why does graphics pipeline need mapping to clip coordinates and normalized device coordinates?

On perspective projection, if I use simple projection matrix like:
1 0 0 0
0 1 0 0
0 0 1 0
0 0 1/near 0
, which is just projecting onto the image plane. It can be easily get view space coordinates by discarding and normalizing, I think.
If on orthogonal projection, it even does not need the projection matrix.
But, OpenGL graphics pipeline has the above process, though the perspective projection causes a depth precision error.
Why does it need mapping to clip coordinates and normalized device coordinates?
Added
If I use the above projection matrix,
1 0 0 0
p = ( 0 1 0 0 )
0 0 1 0
0 0 1/n 0
v_eye = (x y z 1)
v_clip = p * v_eye = (x y z z/n)
v_ndc = v_clip / v_clip.w = (nx/z ny/z n 1)
Then, v_ndc can be clipped by discarding values over top, bottom, left, right.
Values over far also can be clipped in the same way before multiplying the projection matrix.
Well, it looks like silly though, I think it's easier than before.
ps. I noticed that the depth buffer can't be written in this way. Then, can't it be written before the projection?
Sorry for silly question and gibberish...
In case of orthographic projections, you are right: The perspective divide is not required, but it des not introduce any error, since it is a division by 1. (A orthographic projection matrix contains always [0, 0, 0, 1] in the last row).
For perspective projection, this is a bit more complex:
Let's look at the simplest perspective projection:
1 0 0 0
P = ( 0 1 0 0 )
0 0 1 0
0 0 1 0
Then a vector v=[x,y,z,1] (in view space) gets projected to
v_p = P * v = [x, y, z, z],
which is in projektive space.
Now the perspectve divide is needed to get the perspectve effect (objects closer to the viewer look larger):
v_ndc = v / v.w = [x'/z y'/z, z'/z, 1]
I don't see how this could be achieved without the perspective divide.
Why does it need mapping to clip coordinates and normalized device coordinates?
The space where the programmer leaves the vertices to the GL to be taken care of is the clip space. It's the 4D homogeneous space where the vertices exist before normalization / perspective division. This division, useful to perform perspective projection, is the mapping needed to transform the vertices from clip space to NDC (3D). Why? Similar triangles.
View Space Point
*
/ |
Proj /- |
Y ^ Plane /-- |
| /-- |
| *-- |y
| /-- | |
| /-- |y' |
| /--- | |
<-----+------------+------------+-------
Z O |
|-----d------| |
|------------z------------|
Perspective projection is where rays from the eye/origin cuts through a projection plane hitting the points present in the space. The point where the ray intersects the plane is the projection of the point hit. Lets say we want to project point P on to the projection plane, where all points have z = d. The projected location of P i.e. P' needs to be found. We know that z' will be d (since projection planes lies there). To find y', we know
y ⁄ z = y' ⁄ z' (similar triangles)
y ⁄ z = y' ⁄ d (z' = d by defn. of proj. plane)
y' = (d * y) ⁄ z
This division by z is called the perspective division. This shows that in perspective projection, objects farther, with larger z, appear smaller and objects closer, will smaller z, appear larger.
Another thing which convenient to perform in clip space is, obviously, clipping. In 4D, clipping is which is just checking if the points lie within a range as opposed to the costlier division.
In case of orthographic projection, the projection isn't a frustum but a cuboid — parallel rays come from infinity and not the origin. Hence for point P = (x, y, z), the Z values are just dropped, giving P' = (x, y). Thus the perspective division does nothing (divides by 1) in this case.

Reversing RotateAxisAngle back to angles

I'm trying to figure out how to reverse RotateAxisAngle to get back rotations around these arbitrary axes (or equivalent rotations that yield same net rotation, doesn't have to be identical). Does anyone know how to do it? I'm using MathGeoLib, but I don't see an opposite way, to return back the angles about axes, when all you have is the matrix.
Here's the forward direction code (RotateAxisAngle is from MathGeoLib):
float4x4 matrixRotation = float4x4::RotateAxisAngle(axisX, ToRadian(rotation.x));
matrixRotation = matrixRotation * float4x4::RotateAxisAngle(axisY, ToRadian(rotation.y));
matrixRotation = matrixRotation * float4x4::RotateAxisAngle(axisZ, ToRadian(rotation.z));
Now I want to get back to the degrees, about these arbitrary axes, in the same order (well, pull off Z, then Y, then X), so if I did it again, forward direction, would yield the same net rotations.
Here's the sample/matrix corresponding to that set of rotations I posted above, if it helps, on reversing back to it:
axisX:
x 0.80878228 float
y -0.58810818 float
z 0.00000000 float
Rot about that axis:
30.000000 float
axisY:
x 0.58811820 float
y 0.80877501 float
z 0.00000000 float
Rot about that axis:
60.000000 float
axisZ:
x 0.00000000 float
y 0.00000000 float
z 1.0000000 float
Rot about that axis:
40.000000 float
That forms this matrix, which is stored to a file, and need to retrieve the rotations about above axes (without any info about rotations originally used)
[4][4]
[0x0] 0.65342271 float
[0x1] -0.51652151 float
[0x2] 0.55339342 float
[0x3] 0.00000000 float
[0x0] 0.69324547 float
[0x1] 0.11467478 float
[0x2] -0.71151978 float
[0x3] 0.00000000 float
[0x0] 0.30405501 float
[0x1] 0.84856069 float
[0x2] 0.43300733 float
[0x3] 0.00000000 float
[0x0] 0.00000000 float
[0x1] 0.00000000 float
[0x2] 0.00000000 float
[0x3] 1.0000000 float
OK, I'm going to take another stab at this. My first answer was for XYZ order of rotations. This answer is for ZYX order, now that I know more about how MathGeoLib works.
MathGeoLib represents position vectors as column vectors v = [x y z 1]^T where ^T is the transpose operator which flips rows to columns (and vice versa). Rotation matrices pre-multiply column vectors. So if we have a matrix Rx(s) representing a rotation around the x-axis by s degrees, then a rotation Ry(t) representing a rotation about the y-axis by t degrees, then rotation Rz(u) representing a rotation about the z-axis by u degrees, and we combine them and multiply with v as Rx(s) Ry(t) Rz(u) v, we're actually applying the z rotation first. But we can still work out the angles from the combined matrix, it's just that the formulas are going to be different from the more common XYZ order.
We have the upper left blocks of the rotation matrices as follows. (The fourth row and column are all 0s except for the diagonal element which is 1; that never changes in the calculations that follow so we can safely ignore.) MathGeoLib appears to use left-handed coordinates, so the rotation matrices are:
[1 0 0] [ cos t 0 sin t] [ cos u -sin u 0]
Rx(s) = [0 cos s -sin s], Ry(t) = [ 0 1 0], Rz(u) = [ sin u cos u 0]
[0 sin s cos s] [-sin t 0 cos t] [ 0 0 1]
(Note the position of the - sign in Ry(t); it's there because we think of the coordinates in cyclic order. Rx(s) rotates y and z; Ry(t) rotates z and x; Rz(u) rotates x and y. Since Ry(t) rotates z and x not in alphabetical order but in cyclic order, the rotation is opposite in direction from what you expect for alphabetical order.
Now we multiply the matrices in the correct order. Rx(s) Ry(t) is
[1 0 0][ cos t 0 sin t] [ cos t 0 sin t]
[0 cos s -sin s][ 0 1 0] = [ sin s*sin t cos s -sin s*cos t]
[0 sin s cos s][-sin t 0 cos t] [-cos s*sin t sin s cos s*cos t]
The product of that with Rz(u) is
[ cos t 0 sin t][ cos u -sin u 0]
[ sin s*sin t cos s -sin s*cos t][ sin u cos u 0] =
[-cos s*sin t sin s cos s*cos t][ 0 0 1]
[ cos t*cos u -cos t*sin u sin t]
[ sin s*sin t*cos u+cos s*sin u -sin s*sin t*sin u+cos s*cos u -sin s*cos t]
[-cos s*sin t*cos u+sin s*sin u cos s*sin t*sin u+sin s*cos u cos s*cos t]
So we can figure out the angles as follows:
tan s = -(-sin s * cos t)/(cos s * cos t) = M23/M33 => s = -arctan2(M23,M33)
sin t = M13 => t = arcsin(M13)
tan u = -(-cos t * sin u)/(cos t * cos u) = M12/M11 => u = -arctan2(M12,M11)
If we are to implement those calculations, we need understand how the matrix is indexed in MathGeoLib. The indexing is row major, just like the mathematical notation, but indexing starts at 0 (computer style) rather than at 1 (math style) so the C++ formulas you want are
s = -atan2(M[1][2],M[2][2]);
t = asin(M[0][2]);
u = -atan2(M[0][1],M[0][0]);
The angles are returned in radians so will need to be converted to degrees if desired. You should test that result in the case when axes for the rotations Z, Y, and X are in standard position (001), (010), and (100).
If we are to reverse a rotation about non-standard axes, as in your example, the problem becomes more difficult. However, I think it can be done by a "change of coordinates". So if our rotation mystery matrix is matrixRotation, I believe you can just form the "conjugate" matrix
M = coordinateChangeMatrix*matrixRotation*coordinateChangeMatrix^{-1}
and then use the above formulas. Here coordinateChangeMatrix would be the matrix
[Xaxis0 Xaxis1 Xaxis2 0]
[Yaxis0 Yaxis1 Yaxis2 0]
[Zaxis0 Zaxis1 Zaxis2 0]
[ 0 0 0 1]
where the rotation X-axis is (Xaxis0,Xaxis1,Xaxis2). In your example those numbers would be (0.808...,-0.588...,0). You should make sure that the rotation matrix is orthonormal, i.e., the dot product of Xaxis with itself is 1, the dot product of Xaxis with another axis is 0, and the same for any other axis. If the coordinate change matrix is not orthonormal, the calculation might still work, but I don't know for sure.
The inverse of the coordinate change matrix can be calculated using float4x4::inverseOrthonormal or if it's not orthonormal you can use float4x4::inverse but as I mentioned I don't know how well that will work.
If you just want a rotation that reverses the rotation you've got in one step, you can invert the rotation matrix. float4x4::InverseOrthonormal should work, and it's fast and accurate. float4x4::Inverse will also work but it's slower and less accurate.
If you really want to recover the angles, it goes something like this. (There are numerous different conventions, even for X-Y-Z; I think this one matches, but you may have to take the transpose of the matrix or make some other modification. If this doesn't work I can suggest alternatives.) First we follow the Wikipedia article for a description of the Euler Angles to Matrix conversion. In the resulting matrix, we have
A11 = cos theta cos psi
A21 = -cos theta sin psi
A31 = sin theta
A32 = -sin phi cos theta
A33 = cos phi cos theta
where phi is the rotation around the x-axis, theta is the rotation around the y-axis, and psi is rotation around the z-axis. To recover the angles, we do
phi = -arctan2(A32,A33)
theta = arcsin(A31)
psi = -arctan2(A21,A11)
The angles may not match the original angles exactly, but the rotations should match. arctan2 is the two-argument form of the arctan function, which takes into account the quadrant of the point represented by the argument, and deals correctly with 90 degree angles.
Given the way your rotations are represented, I think you may have to use the transpose instead. That's easy: you just swap the indices in the above formulas:
phi = -arctan2(A23,A33)
theta = arcsin(A13)
psi = -arctan2(A12,A11)
If neither of those work, I could take a closer look at the MathGeoLib library and figure out what they're doing.
Update
I neglected to take into account information about the axes of rotation in my previous answer. Now I think I have a plan for dealing with them.
The idea is to "change coordinates" then do the operations as above in the new coordinates. I'm a little hazy on the details, so the process is a little "alchemical" at the moment. The OP should try various combinations of my suggestions and see if any of them work ... there aren't too many (just 4 ... for the time being).
The idea is to form a coordinate change matrix using the coordinates of the rotation axes. We do it like this:
axisX: 0.80878228 -0.58810818 0.00000000 0.00000000
axisY: 0.58811820 0.80877501 0.00000000 0.00000000
axisZ: 0.00000000 0.00000000 1.0000000 0.00000000
and..: 0.00000000 0.00000000 0.00000000 1.0000000
I have just taken the three 3-vectors axisX, axisY, axisZ, padded them with 0 at the end, and added the row [0 0 0 1] at the bottom.
I also need the inverse of that matrix. Since the coordinate system is an orthonormal frame, the inverse is the transpose. You can use the InverseOrthonormal function in the library; all it does is form the transpose.
Now take your mystery matrix, and pre-multiply it by the coordinate change matrix, and post-multiply it by the inverse of the coordinate change matrix. Then apply one of the two calculations above using inverse trig functions. Crossing my fingers, I think that's it ...
If that doesn't work, then pre-multiply the mystery matrix by the inverse of the coordinate change matrix, and post-multiply by the coordinate change matrix. Then apply one or the other of the sets of trig formulas.
Does it work?

DirectX 3D rotate eyePt around lookAt

I'm really stuggling with the maths i need for this maths has never been my strong point once you get into Calculus and Geometry.
So how do i rotate a vector3 around another vector3
D3DXVECTOR3 lookAt = this->cam->getLookAt();
D3DXVECTOR3 eyePt = this->cam->getEyePt();
I need to rotate lookAt around eyePt how do I do this I know I need a Matrix but what I'm supposed to fill it with and how I do the rotation in it I just don't understand.
So if some one could provide code with explanations of the steps used to do it would really help
Another note is that i only want to translate on X,Z axis as i'm rotation around Y axis so here is an image of what im trying to do
Take the unit vector eyePt, which will be the axis of rotations. (I presume it's a unit vector; if not, I can show you how to turn it into a unit vector.) Let's call it E:
Ex
E = Ey
Ez
(This is the vector (Ex, Ey, Ez), but it's hard to do mathematical notation here.)
Now construct three matrices. The identity matrix I:
1 0 0
I = 0 1 0
0 0 1
the tensor product of E and E, which we'll call T:
0 -Ez Ey
T = Ez 0 -Ex
-Ey Ex 0
and the cross-product matrix of E, which we'll call P:
ExEx ExEy ExEz
P = ExEy EyEy EyEz
ExEz EyEz EzEz
Now choose an angle of rotation, theta (in radians). The rotation matrix will be:
R = cos(theta)I + (1-cos(theta))T + sin(theta)P
Now to rotate the vector v (which in this case is lookAt), just multiply R by it:
vafter = Rvbefore

Raycast a 3D pointcloud to an 2D image from a given viewpoint

What I want to do is to raycast a pointcloud to a 2D image. What I have is a 3D PointCloud and a Viewpoint which is different to the general world coordinate system. I would like to raycast from this Viewpoint to generate a 2D image of the point cloud. So, I just need a method like getintersectedvoxel which is doing the casting for the whole area and not only for a single ray.
That is a projection from 3D to a camera. You can get it with the pinhole camera model equations (as shown here).
You need first 3 parameters that define your camera: the focal length f, and the center of the projection plane: cx, cy. With this you create a 3x3 matrix (I will use matlab syntax):
A = [ f 0 cx;
0 f cy;
0 0 1 ];
You can use something like cx = 0.5 * image_width, cy = 0.5 * image_height, and some value as f = 800 (try some of them to check how the image looks better).
Then, a 3x4 matrix with the transformation from the camera frame to the point cloud frame (you say you have it):
T = [ r11 r12 r13 tx;
r21 r22 r23 ty;
r31 r32 r33 tz ];
And finally, your point cloud in homogeneous coordinates, i.e. in a 4xN matrix for a point cloud with N points:
P = [ x1 x2 ... xN;
y1 y2 ... yN;
z1 z2 ... zN;
1 1 ... 1 ];
Now you can project the points:
S = A * T * P;
S is a 3xN matrix where the pixel coordinates of each i-th 3D point are:
x = S(1, i) / S(3, i);
y = S(2, i) / S(3, i);

Model matrix in 3D graphics / OpenGL

I'm following some tutorials to learn openGL (from www.opengl-tutorial.org if it makes any difference) and there is an exercise that asks me to draw a cube and a triangle on the screen and it says as a hint that I'm supposed to calculate two MVP-matrices, one for each object. MVP matrix is given by Projection*View*Model and as far as I understand, the projection and view matrices are the same for all the objects on the screen (they are only affected by my choice of "camera" location and settings). However, the model matrix should change since it's supposed to give me the coordinates and rotation of the object in the global coordinates. Following the tutorials, for my cube the model matrix is just the unit matrix since it is located at the origin and there's no rotation or scaling. Then I draw my triangle so that its vertices are at (2,2,0), (2,3,0) and (3,2,0). Now my question is, what is the model matrix for my triangle?
My own reasoning says that if I don't want to rotate or scale it, the model matrix should be just translation matrix. But what gives the translation coordinates here? Should it include the location of one of the vertices or the center of the triangle or what? Or have I completely misunderstood what the model matrix is?
The model matrix is like the other matrices (projection, view) a 4x4 matrix with the same layout. Depending on whether you're using column or row vectors the matrix consists of the x,y,z axis of your local frame and a t1,t2,t3 vector specifying the translation part
so for a column vector p the transformation matrix (M) looks like
x1, x2, x3, t1,
y1, y2, y3, t2,
z1, z2, z3, t3,
0, 0, 0, 1
p' = M * p
so for row vectors you could try to find out how the matrix layout must be. Also note that if you have row vectors p' = p * M.
If you have no rotational component your local frame has the usual x,y,z axis as the rows of the 3x3 submatrix of the model matrix..
1 0 0 t1 -> x axis
0 1 0 t2 -> y axis
0 0 1 t3 -> z axis
0 0 0 1
the forth column specifies the translation vector (t1,t2,t3). If you have a point p =
1,
0,
0,
1
in a local coordinate system and you want it to translate +1 in z direction to place it in the world coordinate system the model matrix is simply:
1 0 0 0
0 1 0 0
0 0 1 1
0 0 0 1
p' = M * p .. p' is the transformed point in world coordinates.
For your example above you could already specify the triangle in (2,2,0), (2,3,0) and (3,2,0) in your local coordinate system. Then the model matrix is trivial. Otherwise you have to find out how you compute rotation etc.. I recommend reading the first few chapters of mathematics for 3d game programming and computer graphics. It's a very simple 3d math book, there you should get the minimal information you need to handle the most of the 3d graphics math.