当仅需要X-Y旋转时,3D对象沿所有三个轴旋转

时间:2013-01-19 01:38:56

标签: c++ math opengl rotation quaternions

所以我在OpenGL场景中为我的3D对象实现旋转,到目前为止,基本旋转本身(使用四元数)工作正常。我也主要解决了“看”问题,这样我现在可以让任何3D物体(包括相机)完全毫无困难地面对3D空间中的任何一点。

然而,当命令一个物体面对一个给定的点时,它会经常沿着它的局部Z轴滚动;看到这张图片,小船正在看红色,绿色和蓝色线汇合的点。您可以看到它看起来不像人们可能期望的那样,例如,沿着Y轴旋转以面向绿线,然后沿着X轴向下倾斜以面向三条线的会合点。

enter image description here

我不一定要这个。我希望它直接看到那一点,但是顺时针稍微倾斜(从前面看),这样它的翅膀的尖端处于相同的Y水平。由于面向点的整个点是局部Z轴穿过该点,因此对象围绕其局部Z轴旋转无关紧要,但是所得到的旋转始终是倾斜的,尽管偏斜似乎取决于物体的相对位置及其焦点。

在任何情况下,这是我的LookAt()代码,我想修改它,以便我可以更好地控制最终的Z旋转。

void Thing::LookAt(sf::Vector3<float> Target)
{
    ///Derived from pseudocode found here:
    ///http://stackoverflow.com/questions/13014973/quaternion-rotate-to
    //Reset the rotation to default
    m_Orientation = Quaternion();

    //Get the normalized vector from the camera position to Target
    sf::Vector3<double> VectorTo(Target.x - m_Position.x,
                                 Target.y - m_Position.y,
                                 Target.z - m_Position.z);
    //Get the length of VectorTo
    double VectorLength = sqrt(VectorTo.x*VectorTo.x +
                               VectorTo.y*VectorTo.y +
                               VectorTo.z*VectorTo.z);
    //Normalize VectorTo
    VectorTo.x /= VectorLength;
    VectorTo.y /= VectorLength;
    VectorTo.z /= VectorLength;

    //Straight-ahead vector
    sf::Vector3<double> LocalVector = m_Orientation.MultVect(sf::Vector3<double>(0, 0, -1));

    //Get the cross product as the axis of rotation
    sf::Vector3<double> Axis(VectorTo.y*LocalVector.z - VectorTo.z*LocalVector.y,
                             VectorTo.z*LocalVector.x - VectorTo.x*LocalVector.z,
                             VectorTo.x*LocalVector.y - VectorTo.y*LocalVector.x);
    //Normalize the axis
    //Get the length of VectorTo
    double AxisLength = sqrt(Axis.x*Axis.x +
                             Axis.y*Axis.y +
                             Axis.z*Axis.z);
    //Normalize VectorTo
    Axis.x /= AxisLength;
    Axis.y /= AxisLength;
    Axis.z /= AxisLength;

    //Get the dot product to find the angle
    double DotProduct = (VectorTo.x*LocalVector.x +
                        VectorTo.y*LocalVector.y +
                        VectorTo.z*LocalVector.z);
    double Angle = acos(DotProduct);

    //Determine whether or not the angle is positive
    //Get the cross product of the axis and the local vector
    sf::Vector3<double> ThirdVect(Axis.y*LocalVector.z - Axis.z*LocalVector.y,
                                  Axis.z*LocalVector.x - Axis.x*LocalVector.z,
                                  Axis.x*LocalVector.y - Axis.y*LocalVector.x);
    //If the dot product of that and the local vector is negative, so is the angle
    if (ThirdVect.x*VectorTo.x + ThirdVect.y*VectorTo.y + ThirdVect.z*VectorTo.z < 0)
    {
        Angle = -Angle;
    }

    //Finally, create a quaternion
    //Quaternion AxisAngle;
    m_Orientation.FromAxisAngle(Angle, Axis.x, Axis.y, Axis.z);
    m_Orientation.RotationMatrix(m_RotationMatrix);
}

我的问题是我不知道如何控制绕Z轴的最终旋转。请注意,当我从m_Orientation四元数中提取Z角时,它告诉我上面描绘的船绕其Z轴旋转0弧度。我尝试手动将Z组件设置为0并重新规范化四元数,但(显然我认为)不起作用。

目前,可以计算船舶“自上而下”旋转所需的特定Z分量,即使其两个翼尖处于相同的Y水平且其Y轴如同陡峭一样可能,但我想更清楚地了解如何操纵最终的Z旋转。任何想法或资源?

1 个答案:

答案 0 :(得分:2)

如果围绕任意轴执行单次旋转,则很自然地得到此结果。你有没有想过转型?

但是,有一种更简单的方法来构造旋转矩阵。您只需要找到轴映射到的矢量。

所以,例如如果模型指向-z,则z轴(正向)映射到z = VectorToz = -VectorTo。要保留向上方向,您需要定义它。我们说up = (0, 1, 0)。然后x轴被映射到x = z x up的叉积。最后,您需要重新计算向上矢量以使用y = x x z保持纯旋转。 (中间的x指定叉积运算符)。

计算完这些向量后,您现在可以按如下方式构建变换矩阵(使用标准化向量):

    /  x.x  y.x  z.x  0  \
    |  x.y  y.y  z.y  0  |
T = |  x.z  y.z  z.z  0  |
    \  0    0    0    1  /

根据您的API,您可能需要转置此矩阵。

如果您需要四元数,可以使用this one等方法。