There are a huge number of combinations of these functions, since the answer varies depending on your agreements. I usually use DirectX and the same conventions as Unity. In addition, my background is flights, space and maps, so yawing is then performed and then collapses lat / lon style matches.
Unclear conventions or inconsistent layout / decomposition functions can lead to very strange errors. It is also worth keeping in mind that multiple sets of Euler angles can create the same orientation.
Agreements (as indicated above):
- Euler Angle: X = Pitch, Y = Yaw, Z = Roll
- Euler order: apply rotation, yaw then step and then roll
- Axes: + X Right, + Y Up, + Z Forward
- Matrices: DirectX conventions (using SimpleMath.h from MS DirectXTK )
To convert to OpenGL version, see this .
I accepted Mike Tunnikliff and converted it to C ++ code and added it to my library. I hope other people save time using it.
It is worth noting that the layout function clears the 4th column and translation component from identity, and the decomposition function assumes that the 3x3 rotation element contains pure rotation (i.e., without scaling, etc.).
Firstly, the code for generating the matrix from Euler:
//==================================================================================================== // 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 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 the code to return the Euler angles from the 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 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 } }