将euler转换为矩阵,将矩阵转换为euler

我正在尝试使用.NET / C#将使用欧拉角度描述的3D旋转转换为矩阵然后返回。 我的约定是:

  • 左撇子系统(x右,y上,z前进)
  • 旋转顺序:绕y前进,绕x旋转,绕z倾斜
  • 使用左手规则(拇指指向+无穷大)旋转是正的

我的试用期是:

Euler到矩阵 (为了简化,我删除了x,y,z平移部分)

Matrix3D matrix = new Matrix3D() { M11 = cosH * cosB - sinH * sinP * sinB, M12 = - sinB * cosP, M13 = sinH * cosB + cosH * sinP * sinB, M21 = cosH * sinB + sinH * sinP * cosB, M22 = cosB * cosP, M23 = sinB * sinH - cosH * sinP * cosB, M31 = - sinH * cosP, M32 = - sinP, M33 = cosH * cosP, }; 

矩阵到欧拉

 const double RD_TO_DEG = 180 / Math.PI; double h, p, b; // angles in degrees // extract pitch double sinP = -matrix.M23; if (sinP >= 1) { p = 90; } // pole else if (sinP <= -1) { p = -90; } // pole else { p = Math.Asin(sinP) * RD_TO_DEG; } // extract heading and bank if (sinP  0.9999) { // account for small angle errors h = Math.Atan2(-matrix.M31, matrix.M11) * RD_TO_DEG; b = 0; } else { h = Math.Atan2(matrix.M13, matrix.M33) * RD_TO_DEG; b = Math.Atan2(matrix.M21, matrix.M22) * RD_TO_DEG; } 

一定是错的。 如果我采用3个角度,将它们转换为矩阵并将矩阵转换回角度,结果如果与初始值不同。

我从euclideanspace.com开始浏览了几个具有不同公式的网站,但我现在完全迷失了,无法找到合适的计算方法。 我很感激一点帮助。 船上有数学家吗?

首先,应该:

 sinP = -matrix.M32 

编辑:完整的解决方案如下

我的推导:

 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 | 

乘以您的订购:

 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 | 

这给出了反向推导:

tan B = M12 / M22

sin P = -M32

tan H = M31 / M33

你的想法是错误的:“它一定是错的。如果我采用3个角度,将它们转换成矩阵并将矩阵转换回角度,结果如果与初始值不同。” 它会很漂亮,但不一定是真的。 一般来说,不止一个欧拉角的三重态(固定惯例)导致空间中的相同方向。 但这并不意味着在您的计算中没有错误。 来自维基百科:“例如,假设我们使用上面的zyz约定;那么我们有以下等效对:(90°,45°,-105°)≡(-270°,-315°,255°)360的倍数°(72°,0°,0°)≡(40°,0°,32°)单一对齐(45°,60°,-30°)≡(-135°,-60°,150°)双稳态翻转“

这些function有很多组合,因为答案会根据您的惯例而变化。 我通常使用DirectX和Unity相同的约定。 加上我的背景是flightims,space和maps,所以yaw然后音高然后滚动匹配lat / lon风格。

不清楚约定或具有不匹配的组合/分解function可能导致非常奇怪的错误。 另外值得注意的是,多组欧拉角可以产生相同的方向。

公约(如上):

  • 欧拉角:X =俯仰,Y =偏航,Z =滚动
  • 欧拉顺序:应用旋转,偏航然后俯仰然后滚动
  • 轴:+ X右,+ Y向上,+ Z向前
  • 矩阵:DirectX约定(使用MS DirectXTK中的SimpleMath.h )

要转换为OpenGL版本,请看一下。

我采用了Mike Tunnicliffe的回答并将其转换为C ++代码并将其添加到我的库中。 我希望其他人可以节省一些时间。

值得注意的是,compose函数清除第4列和转换组件以进行标识,并且分解函数假定3×3旋转元素包含纯旋转(即没有缩放等)。

首先是从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; } 

然后编码从矩阵中找回欧拉角:

 //==================================================================================================== // 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 } }