如何防止相机矢量中的浮点错误

时间:2011-03-15 01:30:28

标签: c++ opengl vector floating-point

different question上,回答(Ricky)的用户我也说了以下内容(我仍然觉得有些混乱):

  

当我说他们必须留下来时   垂直,我只是说,如果你   由...独立旋转矢量   同样的转变,一遍又一遍,   浮点错误可能会蔓延到   他们可能会偏离   垂直。点(x,y),点(y,z)和   dot(x,z)应非常接近零。   如果没有,你需要做一些交叉   产品并重新整合它们。   它就像覆盖一样简单   z = cross(x,y),然后y = cross(z,x)。

我的相机系统上有3个相关矢量,这些矢量是浮点数并且始终标准化。参考矢量指向摄像机正在看的方向,UpVector和RightVector是不言自明的。

任何知道如何回答的人,当然应该回答,但Ricky,如果你在那里,请帮帮我......

1)究竟是什么意思是点(x,y),点(y,z)和点(x,z)?这是这些载体之间的点积吗?我想......但是哪些(x,y,z)对应我的Reference,UpVector和RightVector?我有点困惑......

2)然后,这些点积应该非常接近于零,我应该如何检查?我已经看到这样的代码在类似的上下文中实现了相同的东西:

const float Math::EPSILON = 1e-6f;

Math::closeEnough(<floating_point_variable_to_check>, 0.0f);

static bool closeEnough(float f1, float f2) {
    // Determines whether the two floating-point values f1 and f2 are
    // close enough together that they can be considered equal.

    return fabsf((f1 - f2) / ((f2 == 0.0f) ? 1.0f : f2)) < EPSILON;
}

我认为它足够好了吗?

3)我应该在哪里执行所有这些检查并重新确定向量?我有3个旋转相机的功能,Pitch,Yaw和Roll(最后一个我没有那么多使用它),只有这些功能改变了那些单位矢量。每当我调用其中一个旋转功能时,我应该执行检查和修复还是会过多?那时何时何地?

4)最后但并非最不重要的是,为了修复它们,我需要用十字产品覆盖矢量,这是有意义的,因为我希望它们彼此垂直。但上面的引用是不是缺少一个交叉产品?我执行这些修复的顺序是否很重要?

3 个答案:

答案 0 :(得分:5)

希望当前的两个答案是充分的,所以我只是添加一个理论上的注释,它产生的原因以及它处理它的不太重要的原因是形成3x3旋转矩阵的九个数字并描述你的相机如何定位是不必要的。

旋转矩阵只是具有三个向量(例如,向上,向右,向前)作为三列的矩阵。考虑具有三个向量的矩阵e1 =右,e2 =向上,e3 =向后。然后,要将一个点转换为与矩阵相同的参考帧,您可以通过

预先计算列向量
[ e1_x  e2_x  e3_x ]
[ e1_y  e2_y  e3_y ]
[ e1_z  e2_z  e3_z ]

(或反过来......我总是把语言混淆,这取决于你如何看待它。另外,OpenGL使用4x4矩阵作为一个技巧来应用翻译甚至透视只有一个矩阵。)无论如何,你可以得到三个向量中的任何一个通过交叉两个向量。即e1 = e2 x e3e2 = e3 x e1e3 = e1 x e2这意味着不需要一个向量。少一个向量留下六个数字。剩下的两个向量的长度是无关紧要的 - 只有方向很重要 - 这留下了描述变换所需的四个数字。输入四元数。它们是一种数学工具,恰好以稳定,稳健的方式处理其余四个数字。如果你使用全部九个数字,你只需要确保向量总是长度为1,任何一个都垂直于另外两个。否则它不是一个真正的旋转矩阵。向上可能不是90度。这就是我建议的原因:

e1 = Normalize(e1);
e3 = Normalize(Cross(e1,e2));  // e3 is now perpendicular to e1 and e2, and
                               // probably hasn't changed much.  It will also 
                               // have length 1.
e2 = Normalize(Cross(e3,e1));  // e2 was perpendicular to e3 from the previous
                               // step, but now it's also perpendicular to e1.

只要能达到同样的效果,您就可以按任何顺序或组合执行此操作。每次迭代或每千次。如果完全忽略它,相机很可能会开始扭曲图像。经过几次相机旋转后,只会修改最后几个数字,所以把它想象成一个可以避免长时间漂移的软糖因素。

答案 1 :(得分:1)

  1. 是的,矢量之间的矢量点积。 x 。如果 x y 垂直,则 y = 0。你选择哪一对并不重要,因为每个对都需要与另外两对垂直。

  2. 是的,就是这样

  3. 无论你喜欢什么地方。渲染前每帧一次,这是一个好地方。这个想法只是为了防止累积错误失控。

  4. 不,你只需要修复两个相对于另一个(和彼此)的向量,因此只需要更改两个向量。无论您选择向前矢量还是向上矢量,甚至是右矢量都是您的选择。选择“向上”对于您总是希望相机竖立的情况是有意义的。申请顺序无关紧要,因为更正应该很小。

答案 2 :(得分:1)

1)Dot(x,z)表示(例如)参考矢量和侧矢量之间的点积。由于这些矢量应该都是垂直的,因此任何其中两个的点积应为零。

2)由于你的所有载体都在(理论上)标准化,你应该只能测试fabs(Dot(a,b))&lt; EPSILON。

3)坦率地说,如果只有一台摄像机,我只是每帧都重新规范它们 - 为什么不呢?

这是一种方法:

基本上,前向矢量是你真正关心的唯一一个,如果你知道你的相机永远不会颠倒,你可以每帧导出另外两个矢量。

使用向上矢量(0,1,0)获取前向(参考)向量的叉积。这为您提供了一个保证垂直于前向矢量的侧向量。现在将这个新向量的交叉积与前向向量相乘。这为你提供了“真实”相机的向上 - 即。它将以相机所处的任何俯仰角度向前倾斜。