Get the angle from a rotated matrix using glm? - c++

I want to know how to get the angle from a rotated matrix, how do I calculate that? I am using glm c++.
For example
how do I get the angle from this matrix using c++?
[-0.01458][-2.26652][0][0]
[-1.27492][-0.02596][0][0]
[ 0 ][ 0 ][1][0]
[ x ][ y ][z][1]

This looks like an identity matrix that was rotated around Z axis. If that's always the case, you can get the angle back by applying glm::atan function on the first two elements of the first column:
float get_angle_in_rad(const glm::mat4 &matrix) {
return glm::atan(matrix[0][1], matrix[0][0]);
}
See Rotation matrix for explanation.
Note that if the matrix represents more complicated tranformation than just rotation around Z axis, the value returned by this function will be bogus. Depending on your usecase you may want to keep the euler rotation angles separately, in addition to the transformation matrix.

Related

How to rotate a vector in opengl?

I want to rotate my object,when I use glm::rotate.
It can only rotate on X,Y,Z arrows.
For example,Model = vec3(5,0,0)
if i use Model = glm::rotate(Model,glm::radians(180),glm::vec3(0, 1, 0));
it become vec3(-5,0,0)
i want a API,so i can rotate on vec3(0,4,0) 180 degree,so the Model move to vec3(3,0,0)
Any API can I use?
Yes OpenGL uses 4x4 uniform transform matrices internally. But the glRotate API uses 4 parameters instead of 3:
glMatrixMode(GL_MODELVIEW);
glRotatef(angle,x,y,z);
it will rotate selected matrix around point (0,0,0) and axis [(0,0,0),(x,y,z)] by angle angle [deg]. If you need to rotate around specific point (x0,y0,z0) then you should also translate:
glMatrixMode(GL_MODELVIEW);
glTranslatef(+x0,+y0,+z0);
glRotatef(angle,x,y,z);
glTranslatef(-x0,-y0,-z0);
This is old API however and while using modern GL you need to do the matrix stuff on your own (for example by using GLM) as there is no matrix stack anymore. GLM should have the same functionality as glRotate just find the function which mimics it (looks like glm::rotate is more or less the same). If not you can still do it on your own using Rodrigues rotation formula.
Now your examples make no sense to me:
(5,0,0) -> glm::rotate (0,1,0) -> (-5,0,0)
implies rotation around y axis by 180 degrees? well I can see the axis but I see no angle anywhere. The second (your desired API) is even more questionable:
(4,0,0) -> wanted API -> (3,0,0)
vectors should have the same magnitude after rotation which is clearly not the case (unless you want to rotate around some point other than (0,0,0) which is also nowhere mentioned. Also after rotation usually you leak some of the magnitude to other axises your y,z are all zero that is true only in special cases (while rotation by multiples of 90 deg).
So clearly you forgot to mention vital info or do not know how rotation works.
Now what you mean by you want to rotate on X,Y,Z arrows? Want incremental rotations on key hits ? or have a GUI like arrows rendered in your scene and want to select them and rotate if they are drag?
[Edit1] new example
I want a API so I can rotate vec3(0,4,0) by 180 deg and result
will be vec3(3,0,0)
This is doable only if you are talking about points not vectors. So you need center of rotation and axis of rotation and angle.
// knowns
vec3 p0 = vec3(0,4,0); // original point
vec3 p1 = vec3(3,0,0); // wanted point
float angle = 180.0*(M_PI/180.0); // deg->rad
// needed for rotation
vec3 center = 0.5*(p0+p1); // vec3(1.5,2.0,0.0) mid point due to angle = 180 deg
vec3 axis = cross((p1-p0),vec3(0,0,1)); // any perpendicular vector to `p1-p0` if `p1-p0` is parallel to (0,0,1) then use `(0,1,0)` instead
// construct transform matrix
mat4 m =GLM::identity(); // unit matrix
m = GLM::translate(m,+center);
m = GLM::rotate(m,angle,axis);
m = GLM::translate(m,-center); // here m should be your rotation matrix
// use transform matrix
p1 = m*p0; // and finaly how to rotate any point p0 into p1 ... in OpenGL notation
I do not code in GLM so there might be some little differencies.

Rotating an Object Around an Axis

I have a circular shape object, which I want to rotate like a fan along it's own axis.
I can change the rotation in any direction i.e. dx, dy, dz using my transformation matrix.
The following it's the code:
Matrix4f matrix = new Matrix4f();
matrix.setIdentity();
Matrix4f.translate(translation, matrix, matrix);
Matrix4f.rotate((float) Math.toRadians(rx), new Vector3f(1,0,0), matrix, matrix);
Matrix4f.rotate((float) Math.toRadians(ry), new Vector3f(0,1,0), matrix, matrix);
Matrix4f.rotate((float) Math.toRadians(rz), new Vector3f(0,0,1), matrix, matrix);
Matrix4f.scale(new Vector3f(scale,scale,scale), matrix, matrix);
My vertex code:
vec4 worldPosition = transformationMatrix * vec4(position,1.0);
vec4 positionRelativeToCam = viewMatrix*worldPosition;
gl_Position = projectionMatrix *positionRelativeToCam;
Main Game Loop:
Object.increaseRotation(dxf,dyf,dzf);
But, it's not rotating along it's own axis. What am I missing here?
I want something like this. Please Help
You should Get rid of Euler angles for this.
Object/mesh geometry
You need to be aware of how your object is oriented in its local space. For example let assume this:
So in this case the main rotation is around axis z. If your mesh is defined so the rotation axis is not aligned to any of the axises (x,y or z) or the center point is not (0,0,0) than that will cause you problems. The remedy is either change your mesh geometry or create a special constant transform matrix M0 that will transform all vertexes from mesh LCS (local coordinate system) to a different one that is axis aligned and center of rotation has zero in the axis which is also the axis of rotation.
In the latter case any operation on object matrix M would be done like this:
M'=M.M0.operation.Inverse(M0)
or in reverse or in inverse (depends on your matrix/vertex multiplication and row/column order conventions). If you got your mesh already centered and axis aligned then do just this instead:
M'=M.operation
The operation is transform matrix of the change increment (for example rotation matrix). The M is the object current transform matrix from #2 and M' is its new version after applying operation.
Object transform matrix
You need single Transform matrix for each object you got. This will hold the position and orientation of your object LCS so it can be converted to world/scene GCS (global coordinate system) or its parent object LCS
rotating your object around its local axis of rotation
As in the Understanding 4x4 homogenous transform matrices is mentioned for standard OpenGL matrix convetions you need to do this:
M'=M*rotation_matrix
Where M is current object transform matrix and M' is the new version of it after rotation. This is the thing you got different. You are using Euler angles rx,ry,rz instead of accumulating the rotations incrementally. You can not do this with Euler angles in any sane and robust way! Even if many modern games and apps are still trying hard to do it (and failing for years).
So what to do to get rid of Euler angles:
You must have persistent/global/static matrix M per object
instead of local instance per render so you need to init it just once instead of clearing it on per frame basis.
On animation update apply operation you need
so:
M*=rotation_around_z(angspeed*dt);
Where angspeed is in [rad/second] or [deg/second] of your fan speed and dt is time elapsed in [seconds]. For example if you do this in timer then dt is the timer interval. For variable times you can measure the time elapsed (it is platform dependent I usually use PerformanceTimers or RDTSC).
You can stack more operations on top of itself (for example your fan can also turning back and forward around y axis to cover more area.
For object direct control (by keyboard,mouse or joystick) just add things like:
if (keys.get( 38)) { redraw=true; M*=translate_z(-pos_speed*dt); }
if (keys.get( 40)) { redraw=true; M*=translate_z(+pos_speed*dt); }
if (keys.get( 37)) { redraw=true; M*=rotation_around_y(-turn_speed*dt); }
if (keys.get( 39)) { redraw=true; M*=rotation_around_y(+turn_speed*dt); }
Where keys is my key map holding on/off state for every key in the keyboard (so I can use more keys at once). This code just control object with arrows. For more info on the subject see related QA:
Computer Graphics: Moving in the world
Preserve accuracy
With incremental changes there is a risc of loosing precision due to floating point errors. So add a counter to your matrix class which counts how many times it has been changed (incremental operation applied) and if some constant count hit (for example 128 operations) Normalize your matrix.
To do that you need to ensure orthogonormality of your matrix. So eaxh axis vector X,Y,Z must be perpendicular to the other two and its size has to be unit. I do it like this:
Choose main axis which will have unchanged direction. I am choosing Z axis as that is usually my main axis in my meshes (viewing direction, rotation axis etc). so just make this vector unit Z = Z/|Z|
exploit cross product to compute the other two axises so X = (+/-) Z x Y and Y = (+/-) Z x X and also normalize them too X = X/|X| and Y = Y/|Y|. The (+/-) is there because I do not know your coordinate system conventions and the cross product can produce opposite vector to your original direction so if the direction is opposite change the multiplication order or negate the result (this is done while coding time not in runtime!).
Here example in C++ how my orthonormal normalization is done:
void reper::orto(int test)
{
double x[3],y[3],z[3];
if ((cnt>=_reper_max_cnt)||(test)) // here cnt is the operations counter and test force normalization regardless of it
{
use_rep(); // you can ignore this
_rep=1; _inv=0; // you can ignore this
axisx_get(x);
axisy_get(y);
axisz_get(z);
vector_one(z,z);
vector_mul(x,y,z); // x is perpendicular to y,z
vector_one(x,x);
vector_mul(y,z,x); // y is perpendicular to z,x
vector_one(y,y);
axisx_set(x);
axisy_set(y);
axisz_set(z);
cnt=0;
}
}
Where axis?_get/set(a) just get/set a as axis from/to your matrix. The vector_one(a,b) returns a = b/|b| and vector_mul(a,b,c) return a = b x c

How to rotate 3D camera with glm

So, I have a Camera class, witch has vectors forward, up and position. I can move camera by changing position, and I'm calculating its matrix with this:
glm::mat4 view = glm::lookAt(camera->getPos(),
camera->getTarget(), //Caclates forwards end point, starting from pos
camera->getUp());
Mu question is, how can I rotate the camera without getting gimbal lock. I haven't found any good info about glm quaternion, or even quaternion in 3d programming
glm makes quaternions relatively easy. You can initiate a quaternion with a glm::vec3 containing your Euler Angles, e.g glm::fquat(glm::vec3(x,y,z)). You can rotate a quaternion by another quaternion by multiplication, ( r = r1 * r2 ), and this does so without a gimbal lock. To use a quaternion to generate your matrix, use glm::mat_cast(yourQuat) which turns it into a rotational matrix.
So, assuming you are making a 3D app, store your orientation in a quaternion and your position in a vec4, then, to generate your View matrix, you could use a vec4(0,0,1,1) and multiply that against the matrix generated by your quaternion, then adding it to the position, which will give you the target. The up vector can be obtained by multiplying the quaternion's matrix to vec4(0,1,0,1). Tell me if you have anymore questions.
For your two other questions Assuming you are using opengl and your Z axis is the forward axis. (Positive X moves away from the user. )
1). To transform your forward vector, you can rotate about your Y and X axis on your quaternion. E.g glm::fquat(glm::vec3(rotationUpandDown, rotationLeftAndRight, 0)). and multiply that into your orientation quaternion.
2).If you want to roll, find which component your forward axis is on. Since you appear to be using openGL, this axis is most likely your positive Z axis. So if you want to roll, glm::quat(glm::vec3(0,0,rollAmt)). And multiply that into your orientation quaternion. oriention = rollquat * orientation.
Note::Here is a function that might help you, I used to use this for my Cameras.
To make a quat that transform 1 vector to another, e.g one forward vector to another.
//Creates a quat that turns U to V
glm::quat CreateQuatFromTwoVectors(cvec3 U, cvec3 V)
{
cvec3 w = glm::cross(U,V);
glm::quat q = glm::quat(glm::dot(U,V), w.x, w.y, w.z);
q.w += sqrt(q.x*q.x + q.w*q.w + q.y*q.y + q.z*q.z);
return glm::normalize(q);
}

matrix rotation multiple times

I'm having a problem understanding matrices. If I rotate my matrix 90 deg about X axis it works fine, but then, if I rotate it 90 deg about Y axis it actually rotates it on the Z axis. I guess after each rotation the axes move. How do I rotate a second time (or more) using the original axes? Is this called local and global rotation?
You don't "rotate" matrices. You apply rotation transformation matrices by multiplication. And yes, each time you call a OpenGL matrix manipulation function the outcome will be used as input for the next transformation multiplication.
A rotation by 90° about axis X will map the Y axis to Z and the Z axis to -Y, which is what you observe. So what ever transformation comes next start off with this.
Either build the whole transformation for each object anew using glLoadIdentity to reset to an identity, or use glPushMatrix / glPopMatrix to create a hierachy of "transformation blocks". Or better yet, abandon the OpenGL built-in matrix stack altogether and replace it with a proper matrix math library like GLM, Eigen or similar.
Add 'glLoadIdentity' between the rotations.
In practice best way to overcome this problem is to use quaternions, it is quite a bit math. You are right about; if you rotate it around Y 90 degrees than if you want to rotate it around Z you will be rotating around X.
Here is a nice source to convert euler angles to quaternions: http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/
And here is how to make a rotation matrix out of a quaternion:
http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/
After you have filled the matrix, you can multiply by calling glMultMatrix( qMatrix);.
Thinking about it last night I found the answer (I always seem to do this...)
I have an object called GLMatrix that holds the matrix:
class GLMatrix {
public float m[] = new float[16];
...includes many methods to deal with matrix...
}
And it has a function to add rotation:
public void addRotate2(float angle, float ax, float ay, float az) {
GLMatrix tmp = new GLMatrix();
tmp.setAA(angle, ax, ay, az);
mult4x4(tmp);
}
As you can see I use Axis Angles (AA) which is applied to a temp matrix using setAA() and then multiplied to the current matrix.
Last night I thought what if I rotate the input vector of the AA by the current matrix and then create the temp matrix and multiple.
So it would look like this:
public void addRotate4(float angle, float ax, float ay, float az) {
GLMatrix tmp = new GLMatrix();
GLVector3 vec = new GLVector3();
vec.v[0] = ax;
vec.v[1] = ay;
vec.v[2] = az;
mult(vec); //multiple vector by current matrix
tmp.setAA(angle, vec.v[0], vec.v[1], vec.v[2]);
mult4x4(tmp);
}
And it works as expected! The addRotate4() function now rotates on the original axis'es.

Orientating Figures to look at the Camera with OpenGL

In my opengl app, i want to orientate figures to look at the camera, to make this, i define for all the objects 2 vectors, front and up.
Im using gluLookAt to control the camera, so the vectors newFront and newUp i need are easily known.
The code i use to control the orientation for each figure is :
m4D orientate(v3D newFront, v3D newUp)
{
double angle = angle_between(front, newFront);
v3D cross = normalize(cross_product(front, newFront));
m4D matrix = rotate_from_axis(angle, cross);
up = normalize(up * matrix);
angle = angle_between(up, newUp);
cross = normalize(cross_product(up, newUp));
return(rotate_from_axis(angle, cross) * matrix);
}
This code works well when the matrix stack has only this matrix, but if i push a previous matrix rotation (rotating of course front and up vectors) it fails.
What's my fault?
Why always those complicated "I solve for an inverse rotation and multiply that onto the modelview" billboard/impostor solutions, when there's a much simpler method?
Let M be the modelview matrix from which a billboard matrix is to be determined. The matrix is a 4×4 real valued type. The upper left 3×3 defines rotation and scaling. For a billboard this part is to be identity.
So by replacing the upper left part of the current modelview matrix with identity, and keeping the rest as is i.e.
1 0 0 tx
0 1 0 ty
0 0 1 tz
wx wy wz ww
and using that matrix for further transformations you get exactly the desired effect. If there was a scaling applied, replace the upper left identity with a scaling matrix.