【问题标题】:How to find correct rotation from one vector to another?如何找到从一个向量到另一个向量的正确旋转?
【发布时间】:2014-02-17 12:12:58
【问题描述】:

我有两个对象,每个对象都有两个向量:

  • 法线向量
  • 向上向量

喜欢这张图片:

上向量垂直于法向量。现在我想找到从一个对象到另一个对象的唯一旋转,该怎么做?

我有一种方法可以找到一个向量到另一个向量之间的旋转,并且它有效。问题是我需要注意两个向量:法线向量和向上向量。如果我使用这种方法将法线向量从对象一旋转到法线从对象二,向上向量可能指向错误的方向,它们需要平行。

这是寻找最短旋转的代码:

GE::Quat GE::Quat::fromTo(const Vector3 &v1, const Vector3 &v2)
{
    Vector3 a = Vector3::cross(v1, v2);
    Quat q;

    float dot = Vector3::dot(v1, v2);

    if ( dot >= 1 ) 
    {
        q = Quat(0,0,0,1);

    }
    else if ( dot < -0.999999 )
    {
        Vector3 axis = Vector3::cross(Vector3(1,0,0),v2);

        if (axis.length() == 0) // pick another if colinear
                axis = Vector3::cross(Vector3(0,1,0),v2);
        axis.normalize();
        q = Quat::axisToQuat(axis,180);
    }
    else
    {
        float s = sqrt( (1+dot)*2 );
        float invs = 1 / s;

        Vector3 c = Vector3::cross(v1, v2);

        q.x = c.x * invs;
        q.y = c.y * invs;
        q.z = c.z * invs;
        q.w = s * 0.5f;
    }
    q.normalize();
    return q;
}

为了找到正确的旋转,我应该更改/添加到此代码中的哪些内容?

【问题讨论】:

  • 对不起,如果这是一个愚蠢的问题,但“最短轮换”和“唯一轮换”有什么区别?
  • 也许我没有说清楚,抱歉。我只想将法线向量旋转到其他法线向量,但向上向量也必须正确。如果我使用发布的这个方法,它只会旋转一个向量,因此向上的向量可能指向错误的方向,但我需要它是相同的方向。对不起我的英语
  • @Proxy 我编辑了我的问题,也许现在更清楚了
  • 您是否希望生成的旋转 (a) 旋转一个对象,使其与另一个对象平行,或者 (b) 将第一个对象位置旋转到围绕某个原点的第二个对象位置?
  • 我只想要一个旋转对象一的法线向量将平行于对象二的法线向量,并且对象一的向量向上将平行于对象二的向量:) 所以选项(a )

标签: c++ opengl rotation quaternions


【解决方案1】:

在我们开始之前,我将假设 UP 向量和法线向量都是标准化并且它们之间正交(点积为零)。

假设您想旋转黄色盘子以与玫瑰(红色?)盘子对齐。因此,我们的参考将是来自黄色板的向量,我们将坐标系称为 XYZ,其中 Z -> 正常黄色向量,Y -> 向上黄色向量和 X -> YxZ(叉积)。

同理,对于玫瑰板,旋转后的坐标系将被称为 X'Y'Z' 其中 Z' -> 正常玫瑰矢量,Y' -> 向上玫瑰矢量和 X' -> Y'xZ' (交叉产品)。

确定旋转矩阵就可以了,我们只需要保证我们正常的黄色向量会变成正常的玫瑰向量即可;我们的向上黄色向量将转换为向上玫瑰向量,依此类推,即:

RyellowTOrose = |X'x   Y'x   Z'x|
                |X'y   Y'y   Z'y|
                |X'z   Y'z   Z'z|

换句话说,在将任何图元转换为黄色系统坐标后,应用此转换,将旋转它以与玫瑰坐标系统对齐

如果您的向上和法线向量不是正交的,您可以轻松地纠正其中一个。只需在 normal 和 up 之间进行叉积(为方便起见,得到一个称为 C 的向量),然后再次在 C 和 normal 之间进行叉积,以校正 up 向量。

【讨论】:

  • 这么简单...谢谢你的回答,我现在感觉自己像个白痴:)
  • 还有一个小问题——不应该是 cross(Y,Z) 而不是 cross(Z,Y)?
  • @Tom 这遵循右手定则,坐标系为 XYZ,或 X = YxZ、Z = XxY 和 Y = ZxX。如果您遵循另一个约定,只需更改它
【解决方案2】:

首先,我声称只有一个这样的变换可以对齐两个对象的方向。所以我们不必担心找到最短的那个。

将要旋转的对象称为a,将保持静止的对象称为b。让xy 分别为a 的法线和向上向量,同样让uvb 的这些向量。我将假设xyuv 是单位长度,即xy 正交,uv 正交。如果不是这种情况,可以编写代码来纠正这个问题(通过平面投影和归一化)。

现在让我们构造矩阵来定义“世界空间”ab 的方向。 (让^ 表示叉积)将z 构造为x ^ y,并将c 构造为a ^ b。将xyzabc 写入每个矩阵的列会得到两个矩阵,分别称为AB。 (这里的叉积给了我们一个单位长度和相互正交的向量,因为操作数也是如此)

根据A 得到B 的坐标系变换是A^-1(矩阵A 的倒数,其中^ 表示指数的推广),在这种情况下@987654357 @ 可以计算为A^T,即转置,因为A 通过构造是正交矩阵。那么到B 的物理转换就是矩阵B 本身。因此,通过A^-1 转换对象,然后通过B 将得到所需的结果。但是,这些转换可以通过将右侧的 B 乘以左侧的 A^-1 来连接成一个转换。

你最终得到这个矩阵(假设没有算术错误):

 _                                                                                                                                                                                             _
| x0*u0+x1*u1+x2*u2                                    x0*v0+x1*v1+x2*v2                                    x0*(u1*v2-u2*v1)+x1*(u2*v0-u0*v2)+x2*(u0*v1-u1*v0)                                  |
|                                                                                                                                                                                               |
| y0*u0+y1*u1+y2*u2                                    y0*v0+y1*v1+y2*v2                                    y0*(u1*v2-u2*v1)+y1*(u2*v0-u0*v2)+y2*(u0*v1-u1*v0)                                  |
|                                                                                                                                                                                               |
| (x0*y2-x2*y1)*u0+(x2*y0-x0*y2)*u1+(x0*y1-x1*y0)*u2   (x0*y2-x2*y1)*v0+(x2*y0-x0*y2)*v1+(x0*y1-x1*y0)*v2   (x0*y2-x2*y1)*(u1*v2-u2*v1)+(x2*y0-x0*y2)*(u2*v0-u0*v2)+(x0*y1-x1*y0)*(u0*v1-u1*v0) |
|_                                                                                                                                                                                             _|

【讨论】:

  • 谢谢,我会在 2 小时内奖励你
  • @Tom,没问题。谢谢汤姆。
【解决方案3】:

四元数代码仅将一个向量旋转到另一个没有“向上”向量的向量。

在您的情况下,只需从 3 个正交向量构建旋转矩阵

  1. 归一化(单位)方向向量
  2. 归一化(单位)向上向量
  3. 方向向量和上向量的叉积。

在两种情况下,您将拥有表示对象旋转的 R1 和 R2 矩阵 (3x3)。

要找到从 R1 到 R2 的旋转,只需这样做

 R1_to_R2 = R2 * R1.inversed()

矩阵 R1_to_R2 是从一个方向到另一个方向的变换矩阵。注意:这里的 R1.inversed() 可以替换为 R1.transposed()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-18
    相关资源
    最近更新 更多