Say I have a Rotation Matrix, which is used to rotate a 3D model.
Is it possible to set the yaw of the rotation matrix to zero before applying it to the model?
Regards, Adam.
RotMatrix=R(yaw)*R(pitch)*R(roll)
to eliminate yaw factor, we can left-multiply this matrix on negative yaw matrix
RotMatrixNew=R(-yaw)*R(yaw)*R(pitch)*R(roll) = I**R*(pitch)*R(roll) = R(pitch)*R(roll)
If yaw angle isn't known before, then it could be calculated as
yaw = ArcTan2(RotMatrix[2][1], RotMatrix[1][1])
Related
I am currently working on block-breaking in a Minecraft clone. In order to do so, I want use the camera's Euler angles to determine the direction vector of the camera's ray.
I have 2 angles: pitch and yaw.
Pitch rotates along the X axis and is positive when the player looks down, and negative when the player looks up. It cannot be greater than 90 degrees (looking straight down) and cannot be smaller than -90 degrees (looking straight up)
Yaw rotates along the Y axis. It can be a negative number and a positive number, depending on how many times the player turned and in which direction. For example, the player spawns in (yaw = 0) and instantly spins counter-clockwise 360 degrees. In such a case, yaw = -360.
As stated in the question, I am using OpenGL, so when yaw = 0, the player is looking down the negative Z-axis.
How can I generate a direction vector (must be a unit-vector) using only the Euler angles with the restrictions described above?
From your description of Pitch and Yaw, I am assuming that you are using a left-hand reference (pitch=0 and yaw=0 gives a camera vector (0.0, 0.0, 1.0).
The Pitch parameter moves the camera vector in the YZ plane :
Y = cos(pitchInRadians)
Z = sin(pitchInRadians)
The Yaw parameter moves the camera vector in the XZ plane :
X = sin(yawInRadians)
Z = cos(yawInRadians)
Combining the two would give you your final camera vector :
Cv = (sin(yaw), cos(pitch), sin(pitch)*cos(yaw))
As you should have noted, the angles are in radians. Since your post mentions angles in degrees, you will have to convert your degree angles to radians first :
radians = (degrees * PI) /180
I need to compare the relative angle of the wrist between two IMUs with the angle obtain from the Vicon but I have a problem. The relative angle obtained from the two IMUs is in the form 'roll, pitch and yaw' but from the Vicon Cameras I obtained only one absolute angle. In order to obtain the angle from the Vicon, I calculated the forearm plane and the hand plane, then I calculated the normal vectors of these planes and at the end from the two normals I obtain the relative angle between the hand and the forearm planes. How I can obtain three values (roll, pitch, yaw) from the relative Vicon angle in order to compare the two systems?
Thanks a lot for the help:)
I'm currently trying to finish my camera orientation and have ran into a problem where I will need to compute the angle between two vectors in order to rotate my camera to look in my desired direction. Currently my camera always looks at 0,0,0 regardless of whether I specify a camera 'lookat'. I have found out that my camera will only rotate by increasing/decreasing the floats that I have stored (which is used when creating the rotation matrix).
I am trying to rotate around the Y axis only and for rotation I am using XMMatrixRotationAxisY(vector, #);
I have VectorA and VectorB.
VectorA = the current lookat position of the camera and VectorB = the desired lookat position of the camera
How do I compute the angle to pass into XMVectorRotationY, based on the two vectors above?
XMFLOAT3 currentDirection = XMFLOAT3(1.0f, 0.0f, 1.0f);
XMFLOAT3 destinationDirection = XMFLOAT3(200.0f, 0.0f, 200.0f);
rotationY = ?
XMMatrixRotationAxisY(vector, rotationY);
? being the angle we wish to rotate by
The cross product of two vectors v1, v2, produces another vector (v) perpendicular to the plane defined by the two other vectors. This (v) is the axis of your rotation.
The angle for rotation is arccosine of the dot product of vectors v1, v2.
You can compute the decomposition of (v) projecting into the plane needed, which can be easy with the dot product again.
First, project these two vectors on XOZ (
v_proj = {dot(v,X),0,dot(v,Z)} where X,Y,Z are basis vectors and dot is dot product). Since you get current and destination vectors projected on XOZ,. normalize projections. Then find cos(theta) = dot(cur_proj, dest_proj). Call acos for angle. Or you can construct rotation matrix by yourself.
Rot_y =
cos(theta); 0; sin(theta);
0; 1; 0;
-sin(theta); 0; cos(theta)
where sin(theta) = |cur_proj X dest_proj| - cross product. To get the sign you need to look at Y component of cross vector
How can I efficiently limit camera pitch when I have only camera quaternion? Do I have to convert to euler angles and then back to quaternion or is there any other way?
If the camera never has any roll (as is common in lots of games, such as first person shooters), then the solution is simple. If there is roll, then there's an additional step involved. I'll start with what to do if there is no roll, and generalize the solution to what to do if there is.
Let qc be the camera rotation. Let qy a rotation with the same yaw as qc, but with zero pitch. If there is no roll, the camera rotation is a yaw rotation followed by a pitch rotation:
qc = qp * qy
We can recover the pitch rotation qp as the rotation from qy to qc:
qp = qc * qy^-1
The trick, then, is to construct qy, so we can plug it into the above equation to solve for qp. Let vc be the unit vector pointing out of the lens of the camera, or the "forward vector". Let vy be the same vector, but projected to the horizontal plane and normalized. Finally, let v0 be the forward vector when the camera rotation qc is the identity rotation. The rotation that rotates v0 into vy is the yaw rotation. The angle can be given as:
yaw = asin(Norm(cross(v0, vy)))
The corresponding yaw rotation is:
qy = { cos(yaw/2), up * sin(yaw/2) }
Where "up" is the unit vector in the up direction, aka the axis for yaw rotations. Plug this into qp = qy^-1 * qc above to get pitch quaternion qp. Finally, get the pitch angle from qp as:
pitch = 2*asin(Dot(right, [qp[1], qp[2], qp[3]]))
Where "right" is the unit vector in the right direction, aka the axis for pitch rotations.
Like I said, things get more complicated if the camera also has roll, but the general strategy is the same. You formulate the camera rotation as a product of rotation components, then isolate the component you want (in this case, pitch). For example, if the euler sequence you use to define "pitch" is the common yaw-pitch-roll sequence, you define qc as:
qc = qr * qp * qy
We can define a variable qx to be the combined pitch and roll rotations:
qx = qr * qp
We can now write qc as:
qc = qx * qy
We already know how to solve for qx in this form, by retracing the steps we used above to solve for qp. Rearranging the definition for qx, we get:
qp = qr^-1 * qx
We just solved for qx, so to solve for the pitch rotation qp, we only need the roll qr. We can construct it using vectors as we did previously. Let vc be the forward vector again. The roll will be a rotation around this vector. Let vu be the camera's up vector (in world coordinates), and let vu0 be the camera's up vector with zero roll. We can construct vu0 by projecting the global up vector to the plane perpendicular to vc, then normalizing. The roll rotation qr is then the rotation from vu0 to vu. The axis of this rotation is the forward vector vc. The roll angle is
roll = asin(Dot(vc, cross(vu0, vu)))
The corresponding quaternion is:
qr = { cos(roll/2), forward * sin(roll/2) }
Where "forward" is the axis of roll rotations.
The pitch is just one component of the full rotation, so if you want to think about your rotation like that, you'd better store the pitch separately, possibly using Euler angles.
Just converting to Euler angles and back when you need to limit the movement might not work too well, since you'l need to remember the last frame (if you have any) to see if you passed the limit, and in what direction.
As I see it, the main point of quaternions is that you don't need to bother with limits like that. Everything just works without any singularities. Why exactly do you want to limit the pitch?
Camera rotation quaternions can be defined as:
vector A = [x, y, z]
Q.x = A.x * sin(theta/2)
Q.y = A.y * sin(theta/2)
Q.z = A.z * sin(theta/2)
Q.w = cos(theta/2)
Where A is the position and theta is the angle you want to rotate the camera (adjust the pitch).
So if you have the quaternion available you can limit the angle of pitch by verifying each time if the rotation angle plus/minus the actual angle is ok.
I think you can avoid conversion if you set your limits as
+cos(supLim/2) < (Q.w + P.w) < -cos(infLim/2)
As cosine is an continuous function this is supposed to work.
If you could post the code you're actually using maybe we can help a little more.
I may be a little late to the party, but this is how I solved it:
// "Up" = local vector -> rotation * Vector3.UnitY
// "Forward" = local vector -> rotation * Vector3.UnitZ
// "Right" = local vector -> rotation * Vector3.UnitX
public void Rotate(Vector3 axis, float angle)
{
if (LerpRotation)
{
RotationTarget *= Quaternion.FromAxisAngle(axis, angle);
}
else
{
Rotation *= Quaternion.FromAxisAngle(axis, angle);
}
//Locking the Pitch in 180°
float a = Vector3.CalculateAngle(Vector3.UnitY, Up);
float sign = Math.Sign(Forward.Y);
float delta = (float)Math.PI / 2 - a;
if(delta < 0)
Rotation *= Quaternion.FromAxisAngle(Right, delta * sign);
}
I have an input 3D vector, along with the pitch and yaw of the camera. Can anyone describe or provide a link to a resource that will help me understand and implement the required transformation and matrix mapping?
The world-to-camera transformation matrix is the inverse of the camera-to-world matrix. The camera-to-world matrix is the combination of a translation to the camera's position and a rotation to the camera's orientation. Thus, if M is the 3x3 rotation matrix corresponding to the camera's orientation and t is the camera's position, then the 4x4 camera-to-world matrix is:
M00 M01 M02 tx
M10 M11 M12 ty
M20 M21 M22 tz
0 0 0 1
Note that I've assumed that vectors are column vectors which are multiplied on the right to perform transformations. If you use the opposite convention, make sure to transpose the matrix.
To find M, you can use one of the formulas listed on Wikipedia, depending on your particular convention for roll, pitch, and yaw. Keep in mind that those formulas use the convention that vectors are row vectors which are multiplied on the left.
Instead of computing the camera-to-world matrix and inverting it, a more efficient (and numerically stable) alternative is to calculate the world-to-camera matrix directly. To do so, just invert the camera's position (by negating all 3 coordinates) and its orientation (by negating the roll, pitch, and yaw angles, and adjusting them to be in their proper ranges), and then compute the matrix using the same algorithm.
If we have a structure like this to describe a 4x4 matrix:
class Matrix4x4
{
public:
union
{
struct
{
Type Xx, Xy, Xz, Xw;
Type Yx, Yy, Yz, Yw;
Type Zx, Zy, Zz, Zw;
Type Wx, Wy, Wz, Ww;
};
struct
{
Vector3<Type> Right;
Type XW;
Vector3<Type> Up;
Type YW;
Vector3<Type> Look;
Type ZW;
Vector3<Type> Pos;
Type WW;
};
Type asDoubleArray[4][4];
Type asArray[16];
};
};
If all you have is Euler angles, that is an angles representing the yaw, pitch, and roll and a point in 3d space for the position, you can calculate the Right, Up, and Look vectors. Note that Right, Up, and Look are just the X,Y,Z Vectors, but since this is a camera, I find it easier to name it so. The simplest way to apply your roations to the camera matrix is to build a series of rotation matrices and multiply our camera matrix by each rotation matrix.
A good reference for that is here: http://www.euclideanspace.com
Once you have applied all the needed rotations, you can set the vector Pos to the camera's position in the world space.
Lastly, before you apply the camera's transformation, you need to take the camera's inverse of its matrix. This is what you are going to multiply your modelview matrix by before you start drawing polygons. For the matrix class above, the inverse is calculated like this:
template <typename Type>
Matrix4x4<Type> Matrix4x4<Type>::OrthoNormalInverse(void)
{
Matrix4x4<Type> OrthInv;
OrthInv = Transpose();
OrthInv.Xw = 0;
OrthInv.Yw = 0;
OrthInv.Zw = 0;
OrthInv.Wx = -(Right*Pos);
OrthInv.Wy = -(Up*Pos);
OrthInv.Wz = -(Look*Pos);
return OrthInv;
}
So finally, with all our matrix constuction out of the way, you would be doing something like this:
Matrix4x4<float> cameraMatrix, rollRotation, pitchRotation, yawRotation;
Vector4<float> cameraPosition;
cameraMatrix = cameraMatrix * rollRotation * pitchRotation * yawRotation;
Matrix4x4<float> invCameraMat;
invCameraMat = cameraMatrix.OrthoNormalInverse();
glMultMatrixf(invCameraMat.asArray);
Hope this helps.
What you are describing is called 'Perspective Projection' and there are reams of resources on the web that explain the matrix math and give the code necessary to do this. You could start with the wikipedia page