当前位置: 首页 > 知识库问答 >
问题:

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

幸弘光
2023-03-14

我在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个答案

邓子濯
2023-03-14

让我们假设您想要的四元数描述了玩家相对于某个参考态度的态度。因此,有必要了解参考态度是什么。

此外,你需要理解,一个物体的姿态不仅仅包括它的面向——它还包括物体围绕该面向的方向。例如,想象玩家直接面对位置坐标系的正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)

在这一点上,我提醒你们,我们从四元数系统的参考姿态的假设开始,这个结果取决于这个选择。我还提醒你,我对被通缉者的态度做了一个假设,这也会影响这个结果。

最后,我观察到,当目标对象非常接近玩家正上方或正下方时(对应于值非常接近零的半半径),当玩家非常接近目标顶部时(对应于值非常接近零的hyp)。如果您完全按照给定的公式使用这些公式,则导致被零除的可能性为非零,因此您需要考虑如何处理。)

 类似资料:
  • 本文向大家介绍Python面向对象实现一个对象调用另一个对象操作示例,包括了Python面向对象实现一个对象调用另一个对象操作示例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Python面向对象实现一个对象调用另一个对象操作。分享给大家供大家参考,具体如下: 我先总结一下python中的类的特点: 1.类中所有的方法的参数中都必须加self,并且是第一个参数 2.__init__方法用

  • 我有一个组件订阅服务中的一个可观察对象。该方法反过来订阅另一个服务中的可观察对象。我想将一个数组从最后一个服务传递回第一个服务,然后第一个服务将该数组传递回组件。更具体地说,该组件调用其本地服务,然后调用一个数据服务,该数据服务通过http客户端访问我的数据库。http客户端正在工作,数据服务将数组返回给本地服务。本地服务接收数组,但我不知道如何将该数组作为可观察对象传递回组件。以下是简短的代码块

  • 面向对象 下面列出了面向对象软件开发的优点: (1) 代码开发模块化,更易维护和修改。 (2) 代码复用。 (3) 增强代码的可靠性和灵活性。 (4) 增加代码的可理解性。 面向对象编程有很多重要的特性,比如:封装,继承,多态和抽象 Java面向对象的三个特征与含义 一、继承: 概念:继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力. 好处:提高代码的复用,缩短

  • 面向对象是一种符合人类思维习惯的编程思想。现实生活中存在各种形态不同的事物,这些事物之间存在着各种各样的联系。在程序中使用对象来映射现实中的事物,使用对象的关系来描述事物之间的联系,这种思想就是面向对象。 提到面向对象,自然会想到面向过程,面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一一实现,使用的时候依次调用就可以了。面向对象则是把构成问题的事务按照一定规则划分为多个独立的对象,

  • 我在Quarkus的PanacheRepositories工作。目前,我想实现函数。基本上,我想要做的函数是检查一个实体是否存在,该实体具有并将其更新为,但是如果不将每个属性从深度复制到中,我无法确定这是否可能。我不想那样,因为物体很大。 有没有什么方法可以做像这样的事情

  • 打完电话后 我只填充了的和。列表始终保持。我怎么才能修好这个?