Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 欧拉到矩阵和矩阵到欧拉的转换_C#_Math_Matrix_3d_Euler Angles - Fatal编程技术网

C# 欧拉到矩阵和矩阵到欧拉的转换

C# 欧拉到矩阵和矩阵到欧拉的转换,c#,math,matrix,3d,euler-angles,C#,Math,Matrix,3d,Euler Angles,我正在尝试使用.NET/C#将用euler角度描述的3D旋转转换为矩阵,然后再转换回来。我的惯例是: 左手系统(x右,y上,z向前) 旋转顺序:绕y航向,绕x俯仰,绕z倾斜 使用左手法则旋转为正(拇指指向+无穷大) 我的审判是: 欧拉到矩阵(为了简化,我删除了x、y、z平移部分) 矩阵到Euler const double RD_TO_DEG = 180 / Math.PI; double h, p, b; // angles in degrees // extra

我正在尝试使用.NET/C#将用euler角度描述的3D旋转转换为矩阵,然后再转换回来。我的惯例是:

  • 左手系统(x右,y上,z向前)
  • 旋转顺序:绕y航向,绕x俯仰,绕z倾斜
  • 使用左手法则旋转为正(拇指指向+无穷大)
我的审判是:

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

矩阵到Euler

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 || 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; }
const double RD_TO_DEG=180/Math.PI;
双h,p,b;//角度(度)
//提取沥青
双sinP=-matrix.M23;
如果(sinP>=1){
p=90;}//极
否则,如果(sinP 0.9999){//说明小角度误差
h=数学Atan2(-matrix.M31,matrix.M11)*RD_至_度;
b=0;}
否则{
h=数学Atan2(矩阵M13,矩阵M33)*RD_至_度;
b=数学Atan2(矩阵M21,矩阵M22)*RD_至_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

sinp=-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°)   双稳态翻转 "


这些函数有大量的组合,因为答案根据您的约定而变化。我通常使用DirectX和与Unity相同的约定。再加上我的背景是飞行模拟、太空和地图,所以偏航、俯仰和滚转也符合lat/lon风格

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

公约(如上所述):

  • 欧拉角:X=俯仰,Y=偏航,Z=横摇
  • 欧拉顺序:应用旋转,偏航,俯仰,然后滚动
  • 轴:+X向右,+Y向上,+Z向前
  • 矩阵:DirectX约定(使用MS中的SimpleMath.h)
要转换为OpenGL版本,请查看

我已经把答案转换成C++代码并把它添加到我的库中。我希望其他人使用它能节省一些时间

值得注意的是,compose函数将第4列和translation组件清除为identity,decompose函数假定3x3旋转元素包含纯旋转(即无缩放等)

首先,从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'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;
}
然后编写代码从矩阵中获取Euler角度:

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

我试过了,但还是不行。目前在euler->matrix->euler的过程中,如果我在HPB中使用一个角度(例如h,0,0),那么符号在结果中是变化的(-h,0,0)。我想知道是否可以分别调试每个转换,例如,网络上是否有一个页面,上面有转换示例和矩阵元素的值。我发现了一些,但不是在左手系统/左手旋转中。我推导了原始旋转矩阵,并得出了不同的答案tbh,我认为我的数学是错误的(或只是等效的)尽管如此:| cosHcosB+sinhsimpsinb | cosshinp sinBcosH | cosssinh | cosssinb | cosscosp | sinbcossinp sinHcosB | cosshinp sinBcosH | cosPcosH |根据我在上述评论中的矩阵,颠倒如下:tan B=M12/M22,sin P=-M32,tan H=M31/m33是的,这太完美了!我不是一个数学家,虽然我理解这些原理,但这对我来说绝对不是一件容易的事,因为我无法区分不同的处理方式和变体,也无法重用不是为我所使用的代码而编写的代码。但你确实在几分钟内得到了确切的答案,只需要在我这边粘贴一份副本。非常感谢,先生!对此我非常感激。我已经重新做了我的回答,包括上面的评论。很高兴它既有帮助又是正确的(自从我获得数学学位已经有几年了):)大多数文献都会用右手坐标系和旋转角度来表达这些操作。您最好翻转一些符号,将数据放入右手系统,执行矩阵运算,然后转换回左手系统。这可能需要一些额外的操作,但会更容易理解!这是一个具有连续“关节”的系统,可以通过旋转来移动相机。实际上,我必须在左手系统中维护HPB值,因为必须以这种方式输入和查看。最后,我将它们转换成右手系统,使用不同的航向原点,以便能够使用WPF 3D绘制,这是右手的。请参阅
//====================================================================================================
// 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
    }
}