我在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方向的参考姿态,并且"向上"平行于正z方向(我们称之为"垂直")。 我们还假设,在玩家面对目标的态度中,您希望玩家的"向上"最接近垂直。 我们可以想象所需的姿态变化分两步执行:围绕坐标y轴旋转,然后绕坐标z轴旋转。 我们可以为它们中的每一个写一个单位四元数,整个旋转所需的四元数是这些四元数的汉密尔顿乘积。
由坐标 (x, y,z) 描述的单位向量旋转角度 θ 的四元数为 (cos θ/2,xsin θ/2,ysin θ/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
. 但是你需要这个角度的一半正弦和余弦。 半角公式在这里派上用场:
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
获取非常接近零的值)。 如果您完全按照给定的公式使用这些公式,则有非零的可能性导致除以零,因此您需要考虑如何处理它。