【问题标题】:What I came up with by trial and error works, could you explain why?我通过反复试验得出的结论,您能解释一下原因吗?
【发布时间】:2013-04-30 09:02:14
【问题描述】:

首先,我不确定这里是否欢迎这个问题,我检查了FAQ,发现“我希望其他人解释”的问题是。

主要问题是我需要在我的应用程序中存储所有对象的旋转两次。这是因为一方面,我使用Bullet Physics 的物理模拟存储了它的表示。另一方面,我自己存储所有对象共有的旋转,无论它们是否在物理模拟中,例如灯光、任务目标等。除了物理库之外,我还使用了 GLM 数学库。

我必须同步两种表示。顺便说一句,位置和规模不会造成任何问题。困难在于物理模拟任何我自己的表示都是不同的,所以我不能只是复制值。我还没有发现所有这些差异,但它可能与左手坐标系与右手坐标系、度数与弧度以及 Y 坐标向上与 Z 向上有关。

我自己的表示只是将欧拉角存储在glm::vec3 向量中。由于我使用 OpenGL 进行绘图,我猜空间是右手的。对于欧拉角,顺序很重要。我计算旋转矩阵的方法是首先创建每个分量的矩阵,然后以X * Y * Z 的顺序将它们相乘。此外,在我自己的表示中,正 Y 坐标指向上方。

物理模拟使用四元数来存储旋转。经过一些研究,我读到了这个库中空间是左手的假设。我不知道哪个坐标是向上的,也不知道返回欧拉角的顺序。

这里有代码将旋转从物理模拟转换为我自己的表示,反之亦然。

#include <GLM/glm.hpp>
#include <GLM/gtc/quaternion.hpp>
#include <BULLET/btBulletDynamicsCommon.h>

/*******************************************************************
 * euler angles "glm::vec3 input" from my own representation
 * to quaternion "btQuaternion output" of physics simulation
 *******************************************************************/
glm::quat quaternion(glm::vec3(input.x, input.z, input.y) * 3.14159f / 180.f);
btQuaternion output(quaternion.x, quaternion.y, quaternion.z, quaternion.w);

/*******************************************************************
 * quaternion "btQuaternion input" from physics simulation
 * to euler angles "glm::vec3 output" of my own representation
 *******************************************************************/
glm::quat quaternion(input.getW(), -input.getX(), -input.getY(), -input.getZ());
glm::vec3 angles = glm::eulerAngles(quaternion);
glm::vec3 output(-angles.x, -angles.y, -angles.z);

我通过反复试验发现了这个肮脏的代码,它可以工作。但正如您所看到的,通过不同的四元数类型进行否定、组件混合和类型转换。我想其中许多是不必要的,并且可以更简单地执行任务。

您能否解释一下为什么我的转换有效以及如何简化它们?顺便说一句,如果转换不起作用,我想看看它的外观,这里是screenshot...

【问题讨论】:

  • 转换是否可逆?即,如果您将欧拉角转换为四元数并再次返回而不修改它们会发生什么?另外,第一行参数的顺序是否有错误?不应该是input.x, input.y, input.z吗?
  • 这似乎是一个错误,但这是我随机想到的。您认为正确的顺序不起作用。我检查了转换是否可逆,但不是。例如,欧拉角2, 5, 52 返回为-3.15, 51.9, 5.56。但不知道这是否代表相同的旋转。据我所知,用欧拉角表示相同的旋转有无数种不同的方式。

标签: quaternions glm-math bulletphysics euler-angles


【解决方案1】:

显然Euler angles 有很多不同的定义,而且您的两个库使用不同的约定。

来自GLM's source,他们使用俯仰、偏航、滚动

template <typename T> 
GLM_FUNC_QUALIFIER detail::tvec3<T> eulerAngles
(
    detail::tquat<T> const & x
)
{
    return detail::tvec3<T>(pitch(x), yaw(x), roll(x));
}

...在Bullet's documentation 中,他们使用Yaw、Pitch、Roll

我没有检查,但是组合旋转绝对是不是可交换的,这可以解释取某些坐标的负值——与取逆旋转相同。

【讨论】:

  • 所以欧拉角顺序绝对是一个原因。你知道如何简化转换吗?
  • 嗯,老实说,这似乎很简单。只需编写一些单元测试,以确保您之后不会过多地搞乱它;)
  • 你觉得我的代码合理吗?我自己不明白它为什么会起作用。
  • 对于第一次转换,如果两个坐标轴具有不同的手性是有意义的,即您使用的是XYZ,那么您必须转换为不同的手性(XZY)然后创建一个四元数那些角度。
  • 其实,回头看我的回答可能并不准确。这里还有其他东西在起作用,我不知道是什么。有什么理由不能一直使用四元数,因为它们不依赖于惯用手?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-07
  • 1970-01-01
  • 2011-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-23
相关资源
最近更新 更多