如何从前向矢量计算俯仰和偏航值

时间:2020-02-24 08:36:43

标签: opengl camera glm-math euler-angles

我想根据相机实例化时获得的位置和目标点来计算相机的俯仰和偏航值。如果我将音高初始化为0,并将偏航角初始化为-90(如LearnOpenGL Camera Tutorial),则在第一次旋转时,相机突然跳动;旋转后可以正常工作。因此,首先,从该教程中给出的方程式开始,我尝试从正向矢量获取俯仰和偏航值:

float pitch = glm::degrees(glm::asin(forward.y));
float yaw = glm::degreees(glm::acos((float)x/glm::cos(glm::asin(y))));

而且

float yaw = glm::degreees(glm::asin((float)z/glm::cos(glm::asin(y))));

并且cos(sin(y))不应为0,因此y不应为0或-1。 我尝试实现这些功能,但是偏航的2个值不相同,偏航的第一个值似乎也是我想要的,但音高却不同。 之后,我尝试了一种简单的方法,知道间距是前向矢量与y轴之间的夹角,而偏航是前向矢量与x轴之间的夹角,我尝试(在纸上)计算以下内容:

const glm::vec3 yUnit(0, 1, 0);
const glm::vec3 xUnit(1, 0, 0);
float pitch = glm::degrees(glm::acos(glm::dot(forward, yUnit)));
float yaw = glm::degrees(glm::acos(glm::dot(forward, xUnit)));

具有以下2个输入:位置=(0,0,0),目标=(0,1,2,5),正向=目标-位置=(0,1,2.5),标准化正向〜(0 ,0.37,0.926),结果是俯仰〜68度,偏航= 90度。 另外,我在应用程序内部打印了俯仰和偏航值,期望值应该为pitch = -20和yaw = -90。

如果我做错了,为什么我在哪里做错,你能解释一下我吗?

2 个答案:

答案 0 :(得分:1)

无法指向要更改的任何一行,但建议:

第一次旋转时,相机突然跳动

这表明某些内容未初始化为您认为的样子。在这种情况下,俯仰和偏航是可以从前向矢量计算得出的值,对吧?当您导出值时,永远不要直接初始化它们,因为有可能会弄错它。如果两个假定为“相同”的值不同,则会发生奇怪的事情。而是初始化前向矢量,并立即从中计算出俯仰和偏航。

并且cos(sin(y))不应为0

我们都会不时犯此错误。但是在这种情况下,我认为这并不重要,因为以后的原因。

但是,您可能需要测试正向向量为(0,0,0)时会发生什么。在图形编程中以某种方式获得全零向量是令人惊讶的普遍现象。

float yaw = glm :: degreees(glm :: acos((float)x / glm :: cos(glm :: asin(y))));

您是否已确定要使用哪种欧拉角表示形式?在简单的情况下,您不需要使用多个轴坐标值来计算角度,但是这里使用的是两个。

最简单的情况是偏航(航向),俯仰和横滚是独立的角度,因此,如果俯仰不变,则偏航不会改变,反之亦然。带有xUnit和yUnit向量的最后一个代码块似乎正在执行此操作。

但是,在飞行模拟器和航空航天计算中,偏航-俯仰-侧倾有些复杂,因为它们不是独立的。偏航角可以在俯仰平面上测量,而不是绝对XZ。航空偏航通常是从“北” Z轴而不是X方向测量的。因此,您需要清楚要测量的偏航和俯仰角,并且始终保持一致。而且,您需要研究任何教科书示例或代码,以弄清它们如何使用俯仰-偏航-横滚以及是否与您的俯仰一致。

我建议暂时使用简单的单坐标测量。

浮点距= glm :: degrees(glm :: acos(glm :: dot(forward,yUnit)));

再次,您确定前进方向正常吗?通常,将LookAt编码为比数学库更宽容的代码,这是一个容易犯的错误。

而且,您是否检查过-180至180度以外的机智值是什么数学库?还有一件事要担心。

希望这会有所帮助。如果您发现欧拉角很烦人,那么您并不孤单!这就是为什么许多3D书籍和教程建议学习四元数的原因。

答案 1 :(得分:1)

根据您的期望值,您的音高似乎应该在-90到90度之间变化,因此您应该使用asin而不是acos来获得音高。

在计算偏航时,您需要将前向矢量投影到xz平面上。您可以通过将y分量设置为零然后对其进行归一化来实现。

偏航将需要在0到360度之间变化,但acos仅返回0到180度之间。偏航在前180度是正确的,但是随着偏航从180增加到360,aco将从180减小到零。 当正向向量与(0,0,1)之间的点积大于零时,偏航角将大于180度,因此应通过从360中减去它来调整acos值。

根据您的期望值,我对正确的偏航和俯仰值的猜测是

pitch = degrees(-asin(dot(forward, y_unit)))
forward.y = 0
forward = normalize(forward)
yaw = degrees(acos(dot(forward, x_unit)))
if(dot(forward, z_unit) > 0)
    yaw = 360 - yaw