矩阵函数--如何添加一个"up"向量?

Matrix function-- how to add an "up" vector?

一个朋友给了我一些代码来创建一个从一个向量旋转到另一个向量的矩阵。对于相互指点非常有用。

出现的一个问题是,矩阵在旋转时经常会做奇怪的翻转。 IE。我最终会得到一个正确旋转的结果——但在 Z 中倒置,或类似的东西。

有没有办法在这段代码中添加一个向上向量,以强制矩阵尽可能避免绕向上方向的轴旋转?

代码如下:

Matrix& Matrix::VectorToVector(Vector theV1, Vector theV2)
{
    theV1.Normalize();
    theV2.Normalize();

    float aDot=theV1.Dot(theV2);
    if (gMath.Abs(aDot)>=1.0f-gMath.mMachineEpsilon)
    {
        if (aDot<0) 
        {
            Vector aPerp=theV1.Perp(); // We don't care which perp, we just need a perp
            RotateAroundAxis3D(aPerp,180);
        }
    }
    else
    {
        Vector aAxis;
        float aAngle=0;

        aAxis=gMath.Cross(theV1,theV2);
        aAngle=gMath.Deg((float)acos(gMath.Dot(theV1,theV2)));
        RotateAroundAxis3D(aAxis,aAngle);
    }
    return *this;
    
}

编辑:添加了 RotateAroundAxis3D 函数的代码...

Matrix& Matrix::RotateAroundAxis3D(Vector theVector, float theAngle)
{
    //
    // Multiply the angle by -1 to put it into Raptis Space.
    //
    theAngle=180-theAngle;

    theVector.Normalize();

    Matrix aMat;

    float aSin=gMath.Sin(theAngle);
    float aCos=gMath.Cos(theAngle);
    aMat.m00=(1.0f - aCos) * theVector.mX * theVector.mX + aCos;
    aMat.m10=(1.0f - aCos) * theVector.mX * theVector.mY - aSin * theVector.mZ;
    aMat.m20=(1.0f - aCos) * theVector.mX * theVector.mZ + aSin * theVector.mY;
    aMat.m01=(1.0f - aCos) * theVector.mY * theVector.mX + aSin * theVector.mZ;
    aMat.m11=(1.0f - aCos) * theVector.mY * theVector.mY + aCos;
    aMat.m21=(1.0f - aCos) * theVector.mY * theVector.mZ - aSin * theVector.mX;
    aMat.m02=(1.0f - aCos) * theVector.mZ * theVector.mX - aSin * theVector.mY;
    aMat.m12=(1.0f - aCos) * theVector.mZ * theVector.mY + aSin * theVector.mX;
    aMat.m22=(1.0f - aCos) * theVector.mZ * theVector.mZ + aCos;

    return Multiply(&aMat);
}

我假设函数:

Matrix& Matrix::VectorToVector(Vector theV1, Vector theV2)

应该轮换 this,这样 theV1 就变成了 theV2。如果是这种情况,那么在我看来 if (gMath.Abs(aDot)>=1.0f-gMath.mMachineEpsilon) 这不应该做任何事情,但是你正在围绕未对齐的垂直矢量旋转 180 度到 theV1。这是完全错误的,在这种情况下我会保留矩阵而不做任何改变所以:

Matrix& Matrix::VectorToVector(Vector theV1, Vector theV2)
    {
    theV1.Normalize();
    theV2.Normalize();
    float aDot=theV1.Dot(theV2);
    if (gMath.Abs(aDot)<1.0f-gMath.mMachineEpsilon)
        {
        Vector aAxis;
        float aAngle=0;
        aAxis=gMath.Cross(theV1,theV2);
        aAngle=gMath.Deg((float)acos(gMath.Dot(theV1,theV2)));
        RotateAroundAxis3D(aAxis,aAngle);
        }
    return *this;    
    }

如果问题仍然存在,那么原因可能出在 RotateAroundAxis3D(aAxis,aAngle); 中,但是没有看到它的实现很难说。如果它使用四元数或欧拉角,则可能是原因。如果是的话,看看这个:

函数 vec3 rotate(float ang,vec3 axis,vec3 p) 旋转矢量,您可以通过旋转其 3 个基本矢量和原点将其更改为旋转

顺便说一句,还有另一种方法可以执行此对齐操作,请参阅:

  • Problem superimposing and aligning 3D triangles