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

C++ 如何找到从一个向量到另一个向量的正确旋转?,c++,opengl,rotation,quaternions,C++,Opengl,Rotation,Quaternions,我有两个对象,每个对象有两个向量: 法向量 上向量 如图所示: 上方向向量垂直于法向量。现在我想找到从一个物体到另一个物体的唯一旋转,怎么做 我有一种方法可以找到一个向量到另一个向量之间的旋转,它是有效的。问题是我需要考虑两个向量:法向量和上向量。如果我使用这种方法将法向量从对象1旋转到对象2的法向量,上向量可能指向错误的方向,它们需要平行 以下是查找最短旋转的代码: GE::Quat GE::Quat::fromTo(const Vector3 &v1, const Vector

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

  • 法向量
  • 上向量
如图所示:

上方向向量垂直于法向量。现在我想找到从一个物体到另一个物体的唯一旋转,怎么做

我有一种方法可以找到一个向量到另一个向量之间的旋转,它是有效的。问题是我需要考虑两个向量:法向量和上向量。如果我使用这种方法将法向量从对象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;
}
GE::Quat GE::Quat::fromTo(常量向量3和v1,常量向量3和v2)
{
向量3 a=向量3::交叉(v1,v2);
quatq;
浮点点=矢量3::点(v1,v2);
如果(点>=1)
{
q=Quat(0,0,0,1);
}
否则如果(dot<-0.999999)
{
向量3轴=向量3::交叉(向量3(1,0,0),v2);
if(axis.length()==0)//选择另一个if共线
轴=向量3::交叉(向量3(0,1,0),v2);
axis.normalize();
q=Quat::axisToQuat(轴,180);
}
其他的
{
浮点数s=sqrt((1+点)*2);
浮动库存=1/s;
向量3 c=向量3::交叉(v1,v2);
q、 x=c.x*invs;
q、 y=c.y*invs;
q、 z=c.z*invs;
q、 w=s*0.5f;
}
q、 规范化();
返回q;
}

为了找到正确的旋转方向,我应该对该代码进行哪些更改/添加?

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

假设您希望旋转黄色盘子,使其与玫瑰色(红色?)盘子对齐。所以,我们的参考是来自黄色板块的向量,我们将坐标系称为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|
换句话说,在将任何基本体转换为黄色系统的坐标后,应用此转换将旋转它,使其与玫瑰坐标系对齐


如果上方向向量和法向量不正交,可以很容易地纠正其中一个。只需在法线和法线之间做叉积(为了方便起见,生成一个称为C的向量),然后再做一次C和法线之间的叉积,以纠正上向量。

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

将要旋转的对象称为
a
,并将保持静止的对象称为
b
。设
x
y
分别为
a
的法向量和上向量,同样地,设
u
v
b
的向量。我将假定
x
y
u
v
是单位长度,也就是说
x
y
正交,
u
v
正交。如果其中任何一个不是这样,可以编写案例代码来纠正这一点(通过平面投影和标准化)

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

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

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


四元数代码只将一个矢量旋转到另一个矢量,而不使用“向上”矢量

在您的例子中,只需从3个正交向量构建旋转矩阵

  • 归一化(单位)方向向量
  • 归一化(单位)上向量
  • 方向向量和上方向向量的叉积 在两种情况下,R1和R2矩阵(3x3)表示对象的旋转

    要找到从R1到R2的旋转,只需执行以下操作

     R1_to_R2 = R2 * R1.inversed()
    

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

    如果这是一个愚蠢的问题,很抱歉,但是“最短旋转”和“唯一旋转”之间的区别是什么?也许我没有说清楚,很抱歉。我只想把法向量旋转到另一个法向量,但上方向向量也必须是正确的。如果我使用这个方法,
     R1_to_R2 = R2 * R1.inversed()