角度到四元数 - 使对象面​​向另一个对象

时间:2017-03-23 18:35:28

标签: c angle

我在3D世界中有两个对象,并希望使一个对象面向另一个对象。我已经计算了所有的角度和东西(俯仰角和偏航角)。 问题是我没有单独设置偏航或俯仰的功能,这意味着我必须通过四元数来完成。作为我唯一的函数是:SetEnetyQuaternion(float x,float y,float z,float w)。这是我的伪代码:

float px, py, pz;
float tx, ty, tz;           
float distance;
GetEnetyCoordinates(ObjectMe, &px, &py, &pz);
GetEnetyCoordinates(TargetObject, &tx, &ty, &tz);

float yaw, pitch;
float deltaX, deltaY, deltaZ;

deltaX = tx - px;
deltaY = ty - py;
deltaZ = tz - pz;

float hyp = SQRT((deltaX*deltaX) + (deltaY*deltaY) + (deltaZ*deltaZ));

yaw = (ATAN2(deltaY, deltaX));
if(yaw < 0) { yaw += 360; }


pitch = ATAN2(-deltaZ, hyp);
if (pitch < 0) { pitch += 360; }

//here is the part where i need to do a calculation to convert the angles

SetEnetyQuaternion(ObjectMe, pitch, 0, yaw, 0);

我试过的是从那些与2分开的角度计算窦但是这没有用 - 我认为这是针对欧拉角或类似的东西,但没有帮助我。滚动(y轴)和w参数可以省略我认为因为我不希望我的对象有滚动。这就是为什么我把0加入。

如果有人有任何想法我真的很感激帮助。 提前谢谢你:)

1 个答案:

答案 0 :(得分:0)

让我们假设您想要的四元数描述了玩家相对于某些参考态度的态度。然后必须知道参考态度是什么。

此外,您需要了解对象的态度不仅仅包含面对 - 它还包含对象围绕该对象的方向。例如,假设玩家直接面向位置坐标系的正 x 方向。这提供了许多不同的态度,从玩家站直的那个到左侧或右侧水平的,到他站在他头上的那个,以及其间的所有人。

让我们假设适当的参考姿态是面向正 x 方向的那个,并且“向上”平行于正 z 方向(我们将称之为“垂直”)。让我们假设在玩家面对目标的态度中,你想要一个“向上”最接近垂直的人。我们可以想象通过两个步骤执行所需的姿态变化:绕坐标 y 轴旋转,然后围绕坐标 z 轴旋转。我们可以为这些中的每一个写出一个单位四元数,并且整个旋转的所需四元数是这些四元数的汉密尔顿乘积。

围绕由坐标( x y z )描述的单位矢量旋转角度θ的四元数是(cosθ / 2, x sinθ/ 2, y sinθ/ 2, z sinθ/ 2)。那么,考虑一下你想要的第一个四元数,对应于音高。

double semiRadius = sqrt(deltaX * deltaX + deltaY * deltaY);
double cosPitch = semiRadius / hyp;
double sinPitch = deltaZ / hyp;  // but note that we don't actually need this

。但是你需要那个角度一半的正弦和余弦。半角公式在这里派上用场:

double sinHalfPitch = sqrt((1 - cosPitch) / 2) * ((deltaZ < 0) ? -1 : 1);
double cosHalfPitch = sqrt((1 + cosPitch) / 2);

余弦总是非负的,因为俯仰角必须在第一或第四象限;如果对象在玩家之上,则正弦将为正,如果在对象之下则为负。完成所有这些后,第一个四元数就是

(cosHalfPitch, 0, sinHalfPitch, 0)

类似的分析适用于第二个四元数。完整旋转角度的余弦和正弦

double cosYaw = deltaX / semiRadius;
double sinYaw = deltaY / semiRadius;  // again, we don't actually need this

我们可以再次应用半角公式,但现在我们需要考虑任何象限中的全角。然而,半角只能在象限1或2中,所以它的正弦必然是非负的:

double sinHalfYaw = sqrt((1 - cosYaw) / 2);
double cosHalfYaw = sqrt((1 + cosYaw) / 2) * ((deltaY < 0) ? -1 : 1);

这给了我们一个整体的第二个四元数

(cosHalfYaw, 0, 0, sinHalfYaw)

你想要的四元数是这两个的汉密尔顿乘积,你必须注意用正确的操作数顺序(qYaw * qPitch)计算它,因为汉密尔顿产品不是可交换的。这两个因素中的所有零使得整体表达比其他情况简单得多,但是:

(cosHalfYaw * cosHalfPitch,
-sinHalfYaw * sinHalfPitch,
 cosHalfYaw * sinHalfPitch,
 sinHalfYaw * cosHalfPitch)

此时我提醒您,我们首先假设四元数系统的参考态度,这个结果取决于该选择。我还提醒你,我对想要的态度做了一个假设,这也影响了这个结果。

最后,我观察到这种方法在目标物体几乎直接位于玩家正上方或直接位于玩家之下(相当于semiRadius取值非常接近于零)并且玩家几乎位于最顶层的地方发生故障目标(对应于hyp取值非常接近零)。如果您完全按照给定的方式使用这些公式,则将零除零的可能性非常小,因此您需要考虑如何处理它。)