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

Angle to Quaternion - Making an object facing another object

我在 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 的角度计算正弦,但这没有用 - 我认为这是欧拉角或类似的角度,但对我没有帮助。 roll(y 轴) 和 w 参数我认为可以省略,因为我不希望我的对象有一个滚动。这就是为什么我输入 0。

如果有人有任何想法,我将不胜感激。 提前谢谢你:)

假设您想要的四元数描述了玩家相对于某种参考态度的态度。那么有必要知道参考态度是什么。

此外,您需要了解物体的姿态不仅包括其 面向 - 它还包括物体围绕该面向的方向。例如,假设玩家直接面向位置坐标系的正 x 方向。这提供了许多不同的姿势,从玩家直立的姿势到他在左侧或右侧水平站立的姿势,再到他倒立的姿势,以及介于两者之间的所有姿势。

假设合适的参考姿态是面向x正方向,"up"平行z正方向 方向(我们称之为 "vertical")。我们还假设在玩家面对目标的姿态中,您想要 "up" 最接近垂直的姿态。我们可以想象所需的姿态改变分两步执行:绕坐标 y 轴旋转,然后绕坐标 z 轴旋转。我们可以为其中的每一个写一个单位四元数,而整体旋转所需的四元数就是这些四元数的哈密顿积。

围绕坐标描述的单位向量旋转角度 θ 的四元数 (x, y, z) 是 (cos θ/2, x sin θ/2, y sin θ/2, zsinθ/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

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

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 取一个非常接近于零的值)。如果您完全按照给定的方式使用这些公式,则导致被零除的可能性不为零,因此您需要考虑如何处理。)