- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在研究平面运动的模拟。现在,我使用欧拉角将“ body 框架”转换为“世界框架”并且效果很好。
最近我了解了四元数及其相对于旋转矩阵(万向节锁)的优势,并尝试使用模拟器中的偏航/俯仰/滚动角度来实现它。
如果我理解正确的话,四元数代表两件事。它有一个 x, y, 和 z 组件,代表将发生旋转的轴。它还有一个 w 分量,表示围绕该轴发生的旋转量。简而言之,一个 vector 和一个 float 。四元数可以表示为 4 元素 vector :
q=[w,x,y,z]
要计算结果(完全旋转后),方程使用:
p'=qpq'
地点:
p=[0,x,y,z]-方向 vector
q=[w,x,y,z]-旋转
q'=[w,-x,-y,-z]
使用 wikipedia我通过围绕 3 个轴 (q) 旋转来创建四元数:
Quaterniond toQuaternion(double yaw, double pitch, double roll) // yaw (Z), pitch (Y), roll (X)
{
//Degree to radius:
yaw = yaw * M_PI / 180;
pitch = pitch * M_PI / 180;
roll = roll * M_PI / 180;
// Abbreviations for the various angular functions
double cy = cos(yaw * 0.5);
double sy = sin(yaw * 0.5);
double cp = cos(pitch * 0.5);
double sp = sin(pitch * 0.5);
double cr = cos(roll * 0.5);
double sr = sin(roll * 0.5);
Quaterniond q;
q.w = cy * cp * cr + sy * sp * sr;
q.x = cy * cp * sr - sy * sp * cr;
q.y = sy * cp * sr + cy * sp * cr;
q.z = sy * cp * cr - cy * sp * sr;
return q;
}
定义平面方向(航向) vector :
p = [0,1,0,0]
计算 Hamilton product :
p'=qpq'
q'= [w, -qx, -qy, -qz]
p' = (H(H(q, p), q')
Quaterniond HamiltonProduct(Quaterniond u, Quaterniond v)
{
Quaterniond result;
result.w = u.w*v.w - u.x*v.x - u.y*v.y - u.z*v.z;
result.x = u.w*v.x + u.x*v.w + u.y*v.z - u.z*v.y;
result.y = u.w*v.y - u.x*v.z + u.y*v.w + u.z*v.x;
result.z = u.w*v.z + u.x*v.y - u.y*v.x + u.z*v.w;
return result;
}
我的结果将是一个 vector :
v=[p'x,p'y,p'z]
它工作正常但与欧拉角旋转(万向节锁定)相同。是因为我在这里也使用了欧拉角吗?如果不绕 3 个轴旋转,我真的不知道它应该如何工作。我应该分别绕每个轴旋转吗?
对于理解这个问题的任何建议和帮助,我将不胜感激。
<强>1。我的应用程序基于数据流,这意味着每 1 毫秒检查一次是否有新数据(平面的新方向)。
示例:
在开始时 pitch/roll/yaw = 0,在 1ms 偏航改变 10 度后,应用程序读取 pitch=0,roll=0,偏航 = 10。在接下来的 1 毫秒后,偏航再次改变 20 度。因此输入数据将如下所示:pitch=0, roll=0, yaw = 30。
<强>2。创建方向四元数 - p
在开始时,我定义了我的飞机的方向(头部)在 X 轴上。所以我本地的方向是v=[1,0,0]四元数 (my p) 是p=[0,1,0,0]
Vector3 LocalDirection, GlobalDirection; //head
Quaterniond p,P,q, Q, pq; //P = p', Q=q'
LocalDirection.x = 1;
LocalDirection.y = 0;
LocalDirection.z = 0;
p.w = 0;
p.x = direction.x;
p.y = direction.y;
p.z = direction.z;
<强>3。创建旋转
在每 1 毫秒 之后,我检查来自数据流的旋转角度 (Euler),并使用 toQuaternion 计算 q
q = toQuaternion(yaw, pitch, roll); // create quaternion after rotation
Q.w = q.w;
Q.x = -q.x;
Q.y = -q.y;
Q.z = -q.z;
<强>4。计算“世界方向”
使用 Hamilton 积 我计算旋转后的四元数,这是我的全局方向:
pq = HamiltonProduct(q, p);
P = HamiltonProduct(pq, Q);
GlobalDirection.x = P.x;
GlobalDirection.y = P.y;
GlobalDirection.z = P.z;
<强>5。每 1 毫秒
重复 3-4 次最佳答案
您的模拟似乎每帧都使用欧拉角来旋转对象。然后将这些角度转换为四元数。这不会解决万向节锁定问题。
当您将欧拉角添加到欧拉角时,万向节锁随时可能发生。从本地空间到世界空间时,仅仅解决这个问题是不够的。您还需要您的模拟在帧之间使用四元数。
基本上每次您的对象改变其旋转时,将当前旋转转换为四元数,乘以新的旋转增量,并将结果转换回欧拉角或您用来存储旋转的任何值。
我建议重写您的应用程序以仅使用四元数。每当用户进行输入或您的游戏的某些其他逻辑想要旋转某些内容时,您会立即将该输入转换为四元数并将其输入模拟。
有了 toQuaternion
和 HamiltonProduct
,您就拥有了所需的所有工具。
EDIT 作为对您解释应用程序工作原理的编辑的回应。
At the begging pitch/roll/yaw = 0, after 1ms yaw is changed by 10 degree so application reads pitch=0, roll=0, yaw = 10. After next 1ms yaw is changed again by 20 degrees. So input data will look like this: pitch=0, roll=0, yaw = 30.
这就是万向节锁定发生的地方。在计算旋转后您转换为四元数。那是错的。您需要在这第一步中使用四元数。不要在 1ms yaw 改变 10 度后,应用程序读取 pitch=0,roll=0,yaw = 10
,执行此操作:
澄清一下:您的第 2、3 和 4 步没问题。问题出在第 1 步。
旁注,这是:
It has an x, y, and z component, which represents the axis about which a rotation will occur. It also has a w component, which represents the amount of rotation which will occur about this axis
不完全正确。四元数的分量不是直接的轴和角度,它们是 sin(angle/2) * axis
和 cos(angle/2)
(这是你的 toQuaternion
方法产生)。这很重要,因为它为您提供了构成 4D sphere 的漂亮单位四元数。表面上的每个点(表面空间?)代表 3D 空间中的旋转,完美地允许在任意两个旋转之间进行平滑插值。
关于c++ - 从欧拉角到四元数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56576403/
我有一个第一人称相机 Controller 实现如下: float rotSpeed = 20.0f; xRotation += deltaPos.y * rotSpeed * Time.deltaT
我正在编写一个程序,它加载一个包含场景描述的文件,然后使用 OpenGL 显示它。我将 GLM 用于我的所有数学运算。场景文件中的旋转以四元数格式存储。我的场景管理系统以欧拉角的形式对对象进行旋转,这
我想要实现的效果是从相机的 pointOfView 位置指向一个箭头,在 x 和 z 轴上与场景(和重力)对齐,但指向与相机相同的方向。它可能看起来像这样: 现在,我将其欧拉角 x 和 z 设置为 0
我是一名优秀的程序员,十分优秀!