C# 欧拉到矩阵和矩阵到欧拉的转换
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1996957/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Conversion euler to matrix and matrix to euler
提问by Mike
I'm trying to convert a 3D rotation described in term of euler angles into a matrix and then back, using .NET/C#. My conventions are:
我正在尝试使用 .NET/C# 将根据欧拉角描述的 3D 旋转转换为矩阵,然后返回。我的约定是:
- left handed system (x right, y top, z forward)
- order of rotations: heading around y, pitch around x, bank around z
- rotations are positive using the left hand rule (thumb pointing to +infinity)
- 左手系统(x 右,y 上,z 向前)
- 旋转顺序:绕y,绕x俯仰,绕z倾斜
- 使用左手规则(拇指指向+无穷大)旋转为正
My trial is:
我的试验是:
Euler to matrix(I've removed the x,y,z translation part for simplification)
欧拉到矩阵(为了简化,我删除了 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,
};
Matrix to 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; }
It must be wrong. If I take 3 angles, convert them into a matrix and convert the matrix back into angles, the result if different than the intial values.
一定是错的。如果我取 3 个角度,将它们转换为矩阵并将矩阵转换回角度,结果与初始值不同。
I have browsed several sites with different formulas, starting with euclideanspace.com, but I'm now completely lost, and can't find the right computations. I' appreciate a little help. Is there a mathematician onboard?
我用不同的公式浏览了几个站点,从 euclideanspace.com 开始,但我现在完全迷失了,找不到正确的计算。我很感激一点帮助。机上有数学家吗?
采纳答案by Mike Tunnicliffe
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
棕褐色 B = M12/M22
sin P = -M32
罪 P = -M32
tan H = M31/M33
棕褐色 H = M31/M33
回答by AndrewBloom
Your idea is wrong: "It must be wrong. If I take 3 angles, convert them into a matrix and convert the matrix back into angles, the result if different than the intial values." It would have been beautiful, but is not necessarily true. In general, more than one triplet of Euler Angles (fixed the convention) leads to the same orientation in the space. This doesn't mean that in your calculation there isn't an error, though. From Wikipedia:
你的想法是错误的:“它一定是错误的。如果我取 3 个角度,将它们转换为矩阵,然后将矩阵转换回角度,结果与初始值不同。” 它会很美,但不一定是真的。一般来说,超过一个欧拉角三元组(固定惯例)导致空间中的相同方向。但这并不意味着在您的计算中没有错误。来自维基百科:
"For example, suppose we use the zyz convention above; then we have the following equivalent pairs:
(90°, 45°, ?105°) ≡ (?270°, ?315°, 255°) ? multiples of 360°
(72°, 0°, 0°) ≡ (40°, 0°, 32°) ? singular alignment
(45°, 60°, ?30°) ≡ (?135°, ?60°, 150°) ? bistable flip "
“例如,假设我们使用上面的 zyz 约定;那么我们有以下等效对:
(90°, 45°, ?105°) ≡ (?270°, ?315°, 255°) ? 360°的倍数
(72°, 0°, 0°) ≡ (40°, 0°, 32°) ? 单一对齐
(45°, 60°, ?30°) ≡ (?135°, ?60°, 150°) ? 双稳态翻转"
回答by Jules
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.
这些函数有大量组合,因为答案会根据您的约定而变化。我通常使用 DirectX 和与 Unity 相同的约定。另外我的背景是飞行模拟、空间和地图,所以偏航然后俯仰然后滚动匹配纬度/经度风格。
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)
- 欧拉角:X = 俯仰,Y = 偏航,Z = 滚动
- 欧拉顺序:应用旋转,偏航然后俯仰然后滚动
- 轴:+X 向右,+Y 向上,+Z 向前
- 矩阵:DirectX 约定(使用 MS DirectXTK 中的 SimpleMath.h)
To convert to OpenGL version, take a look at this.
要转换为 OpenGL 版本,请查看此.
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.
我采用了Mike Tunnicliffe的答案并将其转换为 C++ 代码并将其添加到我的库中。我希望其他人可以通过使用它来节省一些时间。
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).
值得注意的是,compose 函数将第 4 列和平移分量清除为同一,分解函数假定 3x3 旋转元素包含纯旋转(即没有缩放等)。
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
}
}