将2个欧拉角与GLM相结合的问题
issue combining 2 Euler angles with GLM
我有以下代码:
#define GLM_ENABLE_EXPERIMENTAL
#include <iostream>
#include <glm/glm.hpp>
#include <glm/ext.hpp>
// combines 2 XYZ euler angles given in degrees
glm::vec3 EulerCombine(const glm::vec3& first, const glm::vec3& second)
{
glm::vec3 output;
glm::mat4 m1 = glm::eulerAngleXYZ(glm::radians(first.x), glm::radians(first.y), glm::radians(first.z));
glm::mat4 m2 = glm::eulerAngleXYZ(glm::radians(second.x), glm::radians(second.y), glm::radians(second.z));
glm::extractEulerAngleXYZ(m2 * m1, output.x, output.y, output.z);
return glm::degrees(output);
}
// applies the XYZ euler rotation on p
glm::vec3 EulerRotate(const glm::vec3& p, const glm::vec3& euler)
{
glm::vec3 output;
output = glm::rotateX(p, glm::radians(euler.x));
output = glm::rotateY(output, glm::radians(euler.y));
output = glm::rotateZ(output, glm::radians(euler.z));
return output;
}
int main(void)
{
glm::vec3 euler1(30, 20, 90); // euler angles in degrees
glm::vec3 euler2(20, 30, 10);
glm::vec3 euler3 = EulerCombine(euler1, euler2);
glm::vec3 p(-10, 7, 23);
glm::vec3 result1 = EulerRotate(EulerRotate(p, euler1), euler2);
glm::vec3 result2 = EulerRotate(p, euler3);
std::cout << result1.x << " " << result1.y << " " << result1.z << std::endl;
std::cout << result2.x << " " << result2.y << " " << result2.z << std::endl;
}
但它打印:
17.9056 -6.99702 17.5622
17.2369 4.15094 19.0699
这是一个问题,因为CCD_ 1和CCD_。
我觉得我的EulerCombine
函数必须是正确的,因为它几乎完全是glm,但这意味着EulerRotate
是不正确的——但我认为XYZ欧拉角意味着你在X轴上旋转它,然后在Y轴上旋转,然后在Z轴上旋转。
发生了什么事?
正如OP已经怀疑的那样:EulerRotate()
的实现是错误的。应该是:
glm::vec3 EulerRotate(const glm::vec3& p, const glm::vec3& euler)
{
return glm::rotateX(glm::rotateY(glm::rotateZ(p, glm::radians(euler.z)),
glm::radians(euler.y)), glm::radians(euler.x));
}
它也可以写(更可读(为:
glm::vec3 EulerRotate(const glm::vec3& p, const glm::vec3& euler)
{
const glm::vec3 p1 = glm::rotateZ(p, glm::radians(euler.z));
const glm::vec3 p2 = glm::rotateY(p1, glm::radians(euler.y));
const glm::vec3 p3 = glm::rotateX(p2, glm::radians(euler.x));
return p3;
}
对应于欧拉角的变换矩阵可以像这样分割:
MrXYZ=M
因此:
p'=MrXYZ·p=M
这是
p’=p绕Z旋转,绕Y旋转,绕X旋转。
听起来很简单——在实际工作中正确地做到这一点有时会让我发疯。三维空间中的旋转是不可交换的→秩序非常重要。
我准备了一个样品来证明这一点。由于我手头没有glm
(也不愿意将其安装在我这边(,我使用了自己的代码(我曾为另一个示例做过准备(,并试图尽可能接近OP代码:
#include <iostream>
#include "linMath.h"
double radians(double);
Vec3 degrees(Vec3 angles);
Mat4x4 eulerAngleXYZ(double rX, double rY, double rZ);
void extractEulerAngles(const Mat4x4 &mat, double &rX, double &rY, double &rZ);
Vec3 rotateX(const Vec3 &p, double angle);
Vec3 rotateY(const Vec3 &p, double angle);
Vec3 rotateZ(const Vec3 &p, double angle);
// combines 2 XYZ euler angles given in degrees
Vec3 eulerCombine(const Vec3 &first, const Vec3 &second)
{
const Mat4x4 mat1 = eulerAngleXYZ(radians(first.x), radians(first.y), radians(first.z));
const Mat4x4 mat2 = eulerAngleXYZ(radians(second.x), radians(second.y), radians(second.z));
Vec3 output;
extractEulerAngles(mat2 * mat1, output.x, output.y, output.z);
return degrees(output);
}
// applies the XYZ euler rotation on p
Vec3 eulerRotate(const Vec3 &p, const Vec3 &euler)
{
#ifndef FIX // Theo:
Vec3 output;
output = rotateX(p, radians(euler.x));
output = rotateY(output, radians(euler.y));
output = rotateZ(output, radians(euler.z));
return output;
#else // Dirk:
return rotateX(rotateY(rotateZ(p, radians(euler.z)), radians(euler.y)), radians(euler.x));
#endif // FIX
}
int main()
{
Vec3 euler1(30, 20, 90); // euler angles in degrees
Vec3 euler2(20, 30, 10);
Vec3 euler3 = eulerCombine(euler1, euler2);
Vec3 p(-10, 7, 23);
Vec3 result1 = eulerRotate(eulerRotate(p, euler1), euler2);
Vec3 result2 = eulerRotate(p, euler3);
std::cout << result1.x << " " << result1.y << " " << result1.z << std::endl;
std::cout << result2.x << " " << result2.y << " " << result2.z << std::endl;
// done
return 0;
}
double radians(double angle) { return degToRad(angle); }
Vec3 degrees(Vec3 angles)
{
return Vec3(radToDeg(angles.x), radToDeg(angles.y), radToDeg(angles.z));
}
Mat4x4 eulerAngleXYZ(double rX, double rY, double rZ)
{
return Mat4x4(InitRotX, rX) * Mat4x4(InitRotY, rY) * Mat4x4(InitRotZ, rZ);
}
void extractEulerAngles(const Mat4x4 &mat, double &rX, double &rY, double &rZ)
{
decompose(mat, RotX, RotY, RotZ, rX, rY, rZ);
}
Vec3 rotateX(const Vec3 &p, double angle)
{
const Vec4 p_ = Mat4x4(InitRotX, angle) * Vec4(p, 1.0);
return Vec3(p_.x, p_.y, p_.z);
}
Vec3 rotateY(const Vec3 &p, double angle)
{
const Vec4 p_ = Mat4x4(InitRotY, angle) * Vec4(p, 1.0);
return Vec3(p_.x, p_.y, p_.z);
}
Vec3 rotateZ(const Vec3 &p, double angle)
{
const Vec4 p_ = Mat4x4(InitRotZ, angle) * Vec4(p, 1.0);
return Vec3(p_.x, p_.y, p_.z);
}
首先,我尝试了使用类似于OP转换顺序的eulerRotate()
函数的代码,得到了以下输出:
17.9056 -6.99702 17.5622
17.2369 4.15094 19.0698
我似乎正确地再现了OP的问题。现在,我定义FIX
以使用正确的转换顺序,并得到以下输出:
12.1019 -22.7589 3.68476
12.1019 -22.7589 3.68476
Wandbox上的实时演示
现在,两种计算都提供了与预期相同的结果。
我认为XYZ欧拉角意味着你在X轴上旋转它,然后是Y轴,然后是Z轴。
不完全是。如上所示,它必须从右到左进行解释。
相关文章:
- C++ 将函数指针与最佳性能相结合
- 将2个欧拉角与GLM相结合的问题
- 抽象和派生与std::list相结合
- 想要将 CGAL 与四元数相结合是否合乎逻辑
- 可变参数模板与默认模板参数相结合
- 是否可以将C++与任何语言相结合?
- 如何将Back_inserter与转换组合C 相结合
- C 操纵器,可以将SetPrecision Manip与SetFill Manip相结合
- 如何将Boost.Spirit自定义点与Nabialek相结合?
- 将可选与reference_wrapper相结合是否有意义?
- 好的设计?用于分配的智能指针与用于访问的原始指针相结合
- 用户定义的文字与UINT64_T参数相结合
- 前向迭代器与多个绑定相结合的迭代速度太快
- 有问题使循环工作与功能相结合
- 如何在C++中将惰性计算与自动计算相结合
- 在Visual Studio中将调试与C .lib的发行版相结合
- 将声明和初始化与超载`=`相结合
- Mac OS X上的MetaTrader 4与C++或R相结合
- CUDA与OpenMP相结合
- 是否可以将Windows 8(Metro)C++/DDirectX游戏与(Metro)C#/XAML启动器相结合