Math 绕x、y、z轴旋转模型,无万向节锁,输入数据始终为x、y、z轴角度旋转
我有一个输入设备,可以给我3个角度——绕x,y,z轴旋转 现在我需要使用这些角度来旋转3D空间,而不需要万向节锁。我以为我可以转换成四元数,但是 如果是这样的话,我如何才能正确地旋转空间,记住我的输入数据只是x,y,z轴的旋转角度,所以我不能只是“避免”它。类似地,围绕轴旋转的顺序移动也不会有帮助——所有轴都将被使用,因此无序移动顺序不会完成任何事情。但肯定有办法做到这一点吗 如果有帮助的话,问题几乎可以归结为实现此功能:Math 绕x、y、z轴旋转模型,无万向节锁,输入数据始终为x、y、z轴角度旋转,math,graphics,3d,rotation,quaternions,Math,Graphics,3d,Rotation,Quaternions,我有一个输入设备,可以给我3个角度——绕x,y,z轴旋转 现在我需要使用这些角度来旋转3D空间,而不需要万向节锁。我以为我可以转换成四元数,但是 如果是这样的话,我如何才能正确地旋转空间,记住我的输入数据只是x,y,z轴的旋转角度,所以我不能只是“避免”它。类似地,围绕轴旋转的顺序移动也不会有帮助——所有轴都将被使用,因此无序移动顺序不会完成任何事情。但肯定有办法做到这一点吗 如果有帮助的话,问题几乎可以归结为实现此功能: void generateVectorsFromAngles(doubl
void generateVectorsFromAngles(double &lastXRotation,
double &lastYRotation,
double &lastZRotation,
JD::Vector &up,
JD::Vector &viewing) {
JD::Vector yaxis = JD::Vector(0,0,1);
JD::Vector zaxis = JD::Vector(0,1,0);
JD::Vector xaxis = JD::Vector(1,0,0);
up.rotate(xaxis, lastXRotation);
up.rotate(yaxis, lastYRotation);
up.rotate(zaxis, lastZRotation);
viewing.rotate(xaxis, lastXRotation);
viewing.rotate(yaxis, lastYRotation);
viewing.rotate(zaxis, lastZRotation);
}
以避免万向节锁的方式。我认为“万向节锁”不是一个计算/数学问题,而是一些物理设备的问题 假设您可以通过XYZ旋转来表示任何方向,那么即使在“万向节锁定点”,对于任何可想象的方向变化,都是XYZ表示。您的物理框架可能无法以这种方式旋转,但数学仍然有效:) 这里唯一的问题是你的输入设备-如果它是万向节,那么它可以锁定,但你没有给出任何细节
编辑:好的,在你添加了一个函数之后,我想我知道你需要什么了。功能完全正确。但遗憾的是,您无法使用XYZ轴旋转获得一种简单、连续的方向编辑方式。我甚至在专业3D软件包中都没有见过这样的解决方案 我想到的唯一一件事就是把你的输入当作飞机上的方向盘——你只需要一些初始方向,你就可以绕X、Y或Z轴旋转一些。然后存储新方向并清除输入。3DMax/Maya/Blender中的旋转方式相同
如果你给我们提供更多关于你想要实现的真实世界使用的信息,我们可能会得到一些更好的想法。如果你的设备提供绝对X/Y/Z角度(这意味着类似于实际的万向节),它将有一些特定的顺序来描述旋转发生的顺序 既然你说“顺序无关紧要”,这就意味着你的设备就像(几乎可以肯定?)一个三轴速率陀螺仪,你得到的是不同的角度。在本例中,您希望将3个微分角度合并为旋转向量,并使用该向量更新方向四元数,如下所示:
given differential angles (in radians):
dXrot, dYrot, dZrot
and current orientation quaternion Q such that:
{r=0, ijk=rot(v)} = Q {r=0, ijk=v} Q*
construct an update quaternion:
dQ = {r=1, i=dXrot/2, j=dYrot/2, k=dZrot/2}
and update your orientation:
Q' = normalize( quaternion_multiply(dQ, Q) )
given differential half-angle vector (in radians):
dV = (dXrot, dYrot, dZrot)/2
compute the magnitude of the half-angle vector:
theta = |dV| = 0.5 * sqrt(dXrot^2 + dYrot^2 + dZrot^2)
then the update quaternion, as used above, is:
dQ = {r=cos(theta), ijk=dV*sin(theta)/theta}
= {r=cos(theta), ijk=normalize(dV)*sin(theta)}
请注意,dQ只是单位四元数的粗略近似值(这使得normalize()
操作比通常更重要)。然而,如果微分角不是很大,它实际上是一个很好的近似值。即使你的微分角很大,这个简单的近似也比你能做的其他事情少一些废话。如果您在使用大微分角度时遇到问题,可以尝试添加二次修正以提高精度(如第三节所述)
然而,一个更可能的问题是,任何类型的重复更新都倾向于漂移,这仅仅是由于累积的算术错误(如果没有其他原因的话)。此外,你的物理传感器会有偏差——例如,你的速率陀螺仪会有偏移,如果不进行校正,将导致你的方位估计Q
缓慢前进。如果这种漂移对您的应用程序很重要,那么如果您想要保持一个稳定的系统,您需要某种方法来检测/纠正它
如果你确实对大微分角有问题,有一个三角公式可以计算精确的更新四元数
dQ
。假设总旋转角度应与输入向量的大小成线性比例;因此,您可以按如下方式计算精确的更新四元数:
given differential angles (in radians):
dXrot, dYrot, dZrot
and current orientation quaternion Q such that:
{r=0, ijk=rot(v)} = Q {r=0, ijk=v} Q*
construct an update quaternion:
dQ = {r=1, i=dXrot/2, j=dYrot/2, k=dZrot/2}
and update your orientation:
Q' = normalize( quaternion_multiply(dQ, Q) )
given differential half-angle vector (in radians):
dV = (dXrot, dYrot, dZrot)/2
compute the magnitude of the half-angle vector:
theta = |dV| = 0.5 * sqrt(dXrot^2 + dYrot^2 + dZrot^2)
then the update quaternion, as used above, is:
dQ = {r=cos(theta), ijk=dV*sin(theta)/theta}
= {r=cos(theta), ijk=normalize(dV)*sin(theta)}
请注意,直接计算sin(θ)/theta
或normalize(dV)
在零附近是奇异的,但向量ijk
在零附近的极限值只是ijk=dV=(dXrot,dYrot,dZrot)
,与第一节的近似值相同。如果您确实以这种方式计算更新四元数,最简单的方法是检查它,并使用小的θ的近似值(这是一个非常好的近似值!)
最后,另一种方法是对cos(theta)
和sin(theta)/theta
使用泰勒展开。这是一种中间方法--一种改进的近似方法,可增加精度范围:
cos(x) ~ 1 - x^2/2 + x^4/24 - x^6/720 ...
sin(x)/x ~ 1 - x^2/6 + x^4/120 - x^6/5040 ...
因此,第一节中提到的“二次修正”是:
dQ = {r=1-theta*theta*(1.0/2), ijk=dV*(1-theta*theta*(1.0/6))}
Q' = normalize( quaternion_multiply(dQ, Q) )
附加项将扩展近似值的精确范围,但如果每次更新需要+/-90度以上,则可能应使用第二节中描述的精确trig函数。您还可以将泰勒展开与精确的三角解结合使用——这可能有助于您在近似值和精确公式之间无缝切换。更改旋转顺序会产生很大的差异;通常,围绕不同轴的旋转不会相互转换。你能给我们一个简单的例子来说明你想做什么吗?@Beta:我正在开发一种方法来控制3D可视化,使用一种设备,它可以让我以旋转角度围绕三个轴旋转。更改顺序没有帮助,因为模型可以绕所有轴旋转;AFAIK只有在一个轴的运动比另外两个轴的运动更受限制时,更改顺序才有帮助…@Beta:另外,刚刚编辑了这个问题以显示我想要实现的基本功能。所以。。。您想实现JD::Vector::rotate(JD::Vector,double)
?或者您已经有了,并且想要实现generatevectorsfromagles(…)
,以便获得与y相同的效果