Conversion euler to matrix and matrix to euler
Firstly, should:
sinP = -matrix.M32
EDIT: Full solution follows
My derivation:
Rx(P)=| 1 0 0 |
| 0 cos P -sin P |
| 0 sin P cos P |
Ry(H)=| cos H 0 sin H |
| 0 1 0 |
| -sin H 0 cos H |
Rz(B)=| cos B -sin B 0 |
| sin B cos B 0 |
| 0 0 1 |
Multiplied with your ordering:
R = Ry(H)*Rx(P)*Rz(B)
= | cos H*cos B+sin H*sin P*sin B cos B*sin H*sin P-sin B*cos H cos P*sin H |
| cos P*sin B cos B*cos P -sin P |
| sin B*cos H*sin P-sin H*cos B sin H*sin B+cos B*cos H*sin P cos P*cos H |
Which gives reverse derivations:
tan B = M12/M22
sin P = -M32
tan H = M31/M33
There are a huge number of combinations of these functions as the answer changes depending on your conventions. I'm typically using DirectX and the same conventions as Unity. Plus my background is flightsims, space and maps, so yaw then pitch then roll matches lat/lon style too.
Being unclear on the conventions or having mismatched compose/decompose functions can lead to very odd bugs. Also worth bearing in mind that multiple sets of euler angles can produce the same orientation.
Conventions (as above):
- Euler angles: X = Pitch, Y = Yaw, Z = Roll
- Euler order: Rotation applied, yaw then pitch then roll
- Axes: +X Right, +Y Up, +Z Forward
- Matrices: DirectX conventions (using SimpleMath.h from MS DirectXTK)
To convert to OpenGL version, take a look at this.
I've taken Mike Tunnicliffe's answer and converted it to C++ code and added it to my library. I hope other people will save some time by using it.
Worth noting that the compose function clears the 4th column and the translation component to identity, and the decompose function assumes the 3x3 rotation element contains pure rotation (ie no scale etc).
Firstly the code to generate a matrix from Eulers:
//====================================================================================================
// MatrixFromYawPitchRoll
//
// Create matrix based on provided yaw (heading), pitch and roll (bank).
//
// Assumptions:
// Euler: X = Pitch, Y = Yaw, Z = Roll
// Applied: Yaw then pitch then roll
// Axes: X = Right, Y = Up, Z = Forward
// DirectX: Matrices are row major (http://www.mindcontrol.org/~hplus/graphics/matrix-layout.html)
//
// Code is based on Mike Tunnicliffe's answer to this question:
// https://stackoverflow.com/questions/1996957/conversion-euler-to-matrix-and-matrix-to-euler
inline void MatrixFromYawPitchRoll(
const DirectX::SimpleMath::Vector3& euler,
DirectX::SimpleMath::Matrix& mat)
{
float cosY = cosf(euler.y); // Yaw
float sinY = sinf(euler.y);
float cosP = cosf(euler.x); // Pitch
float sinP = sinf(euler.x);
float cosR = cosf(euler.z); // Roll
float sinR = sinf(euler.z);
mat = DirectX::SimpleMath::Matrix::Identity;
mat._11 = cosY * cosR + sinY * sinP * sinR;
mat._21 = cosR * sinY * sinP - sinR * cosY;
mat._31 = cosP * sinY;
mat._12 = cosP * sinR;
mat._22 = cosR * cosP;
mat._32 = -sinP;
mat._13 = sinR * cosY * sinP - sinY * cosR;
mat._23 = sinY * sinR + cosR * cosY * sinP;
mat._33 = cosP * cosY;
}
Then code to get back Euler angles from matrix:
//====================================================================================================
// MatrixDecomposeYawPitchRoll
//
// Extract the rotation contained in the provided matrix as yaw (heading), pitch and roll (bank) in
// radiuans.
//
// Assumptions:
// Euler: X = Pitch, Y = Yaw, Z = Roll
// Applied: Yaw then pitch then roll
// Axes: X = Right, Y = Up, Z = Forward
// DirectX: Matrices are row major (http://www.mindcontrol.org/~hplus/graphics/matrix-layout.html)
//
// Code is based on Mike Tunnicliffe's answer to this question:
// https://stackoverflow.com/questions/1996957/conversion-euler-to-matrix-and-matrix-to-euler
inline void MatrixDecomposeYawPitchRoll(
const DirectX::SimpleMath::Matrix& mat,
DirectX::SimpleMath::Vector3& euler)
{
euler.x = asinf(-mat._32); // Pitch
if (cosf(euler.x) > 0.0001) // Not at poles
{
euler.y = atan2f(mat._31, mat._33); // Yaw
euler.z = atan2f(mat._12, mat._22); // Roll
}
else
{
euler.y = 0.0f; // Yaw
euler.z = atan2f(-mat._21, mat._11); // Roll
}
}