"看着"具有四元数的对象

时间:2013-01-15 12:11:23

标签: c++ opengl rotation sfml quaternions

所以我目前正在尝试创建一个将需要两个3D点A和B的函数,并为我提供表示点A要求“旋转”点B所需的旋转的四元数(这样点A的局部Z如果你愿意,轴会通过B点。

我最初找到this post,其中最重要的答案似乎为我提供了一个很好的起点。我继续实现以下代码;而不是假定默认(0,0,-1)方向,正如原始答案所示,我尝试提取表示相机实际方向的单位向量。

void Camera::LookAt(sf::Vector3<float> Target)
{
    ///Derived from pseudocode found here:
    ///https://stackoverflow.com/questions/13014973/quaternion-rotate-to

    //Get the normalized vector from the camera position to Target
    sf::Vector3<float> VectorTo(Target.x - m_Position.x,
                                Target.y - m_Position.y,
                                Target.z - m_Position.z);
    //Get the length of VectorTo
    float 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<float> LocalVector = m_Orientation.MultVect(sf::Vector3<float>(0, 0, -1));

    //Get the cross product as the axis of rotation
    sf::Vector3<float> 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);

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

    //Determine whether or not the angle is positive
    //Get the cross product of the axis and the local vector
    sf::Vector3<float> 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;
    AxisAngle.FromAxisAngle(Angle, Axis.x, Axis.y, Axis.z);

    //And multiply it into the current orientation
    m_Orientation = AxisAngle * m_Orientation;
}

几乎有效。发生的事情是相机似乎向目标点旋转了一半的距离。如果我再次尝试旋转,它会无限制地执行剩余旋转的一半,这样如果我按住“Look-At-Button”,相机的方向会越来越接近直接看目标,但也会不断放慢它的旋转速度,这样就不会完全到达那里。

请注意,我不想求助于gluLookAt(),因为我最终还需要使用此代码将对象其他指向彼此的相机,并且我的对象已经使用了四元数他们的方向。例如,我可能想创建一个跟踪前方移动物体位置的眼球,或者更新其方向以寻找其目标的抛射物。

2 个答案:

答案 0 :(得分:4)

在将Axis传递给FromAxisAngle之前将其归一化。

答案 1 :(得分:1)

为什么使用四元数?在这种情况下,你只是让事情变得更复杂,需要更多的计算。要设置矩阵: -

calculate vector from observer to observed (which you're doing already)
normalise it (again, doing it already) = at
cross product this with the observer's up direction = right
normalise right
cross product at and right to get up

你已经完成了。右边,向上和向量是矩阵的第一行,第二行和第三行(或列,取决于你如何设置)。最后一行/列是对象位置。

但看起来你想在几帧上将现有矩阵转换为这个新矩阵。 SLERP对matricies和四元数这样做(当你研究数学时这并不奇怪)。对于变换,存储初始和目标基质,然后存储它们之间的SLERP,将每个帧的数量更改为SLERP(例如0,0.25,0.5,0.75,1.0-尽管非线性进展看起来更好)。

不要忘记您正在将四元数转换回矩阵,以便将其传递给渲染管道(除非着色器中有一些新功能可以本机处理四元数)。因此,使用四元数的任何效率也必须考虑到转换过程。