如何从一个向量到另一个向量找到正确的旋转?

时间:2014-02-17 12:12:59

标签: c++ opengl rotation quaternions

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

  • 法向量
  • up vector

喜欢这张图片:

enter image description here

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

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

以下是查找最短轮换的代码:

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;
}

我应该更改/添加到此代码中,以找到正确的旋转?

4 个答案:

答案 0 :(得分:3)

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

让我们说你要旋转你的黄色盘子与玫瑰(红色?)盘子对齐。因此,我们的参考将是来自黄板的矢量,我们将坐标系称为XYZ,其中Z - >正常黄色矢量,Y - >黄色矢量和X - &gt; YxZ(交叉产品)。

同样地,对于玫瑰板,旋转的坐标系称为X&#39; Y&#39; Z&#39;其中Z&#39; - &GT;正常的玫瑰矢量,Y&#39; - &GT;玫瑰矢量和X&#39; - &GT; Ÿ&#39; XZ&#39; (交叉产品)。

好的找到旋转矩阵,我们只需要确保我们的正常黄色矢量将成为正常的玫瑰矢量;我们的黄色向量将在向上的玫瑰向量中变换,依此类推,即:

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

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

如果向上和法线向量不正交,则可以轻松纠正其中一个向量。只需在正常和向上之间生成交叉乘积(为方便起见,生成一个名为C的向量)并再次使用C和正常之间的交叉乘积,以纠正向上向量。

答案 1 :(得分:2)

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

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

  1. 归一化(单位)方向向量
  2. 规范化(单位)向上载体
  3. 方向和向上矢量的交叉乘积。
  4. 在两种情况下,您将有R1和R2矩阵(3x3)表示对象的旋转。

    要查找从R1到R2的旋转,只需执行

     R1_to_R2 = R2 * R1.inversed()
    

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

答案 2 :(得分:1)

让我再次使用你图中的矢量来解决问题。

<强>问题:

假设您有两个向量blue_1green_1(它们是正交的),并且您正在寻找旋转以将这些向量移动到blue_2和{{1} (他们是正交的)。此外,您希望green_2green_2平行。

<强>解决方案:

正如我所看到的,这里的问题是这些轮换仅存在于某些情况下。您的向量green_1应该已经与blue_2正交。如果green_1blue_2不正交,则您的轮换不存在。

<强>为什么吗

让R成为轮换,即

green_1

我们知道green_2与blue_2正交,所以

blue_2 = R*blue_1

green_2 = R*green_1

同样,green_2和green_1只有在等于不等于零的常数因子时才会是平行的,让我们说dot(blue_2,green_2) = 0 ,这是一个实数。

a

把事情放在一起,你得到了

green_2 = a*green_1

因为a不是零,我们得到

0 = dot(blue_2,green_2) = a*dot(blue_2,green_1)

示例:

如果你的载体是

blue_1 =(1,0,0)

green_1 =(0,1,0)

并且你的新矢量蓝色是

blue_2 =(sqrt(2)/ 2,sqrt(2)/ 2,0)

然后不存在满足您的正交性的向量dot(blue_2,green_1) = 0 存在的可能性,然后您将找不到移动green_2但不移动blue_1的旋转。

答案 3 :(得分:1)

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

让将要旋转的对象称为a,并调用保持静止的对象b。让xy分别为a的正常和向上向量,同样让uv成为b的这些向量。我假设xyuv是单位长度,xy正交,{ {1}}与u正交。如果不是这种情况,可以编写代码来纠正这个问题(通过平面投影和标准化)。

现在让我们构造矩阵,将“世界空间”定义为va的方向。 (让b表示交叉产品)将^构建为z,并将x ^ y构建为c。将a ^ bxyzab写入每个矩阵的列会为我们提供两个矩阵,称之为{分别为{1}}和c。 (这里的叉积给出了单位长度和相互正交的向量,因为操作数也是如此)

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

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

B