Home > OS >  Matrix function-- how to add an "up" vector?
Matrix function-- how to add an "up" vector?

Time:02-22

A friend gave me some code that creates a matrix that rotates from one vector to another vector. Very useful for pointing things at one another.

An issue that's come up is, often the matrix will do odd flips in its rotating. I.E. I'll end up with a result that's rotated correctly-- but is upside down in Z, or something like that.

Is there a way to add an up-vector to this code, to force the matrix to avoid rotating around the axis of the up-direction if possible?

Here's the code:

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

Edit: Added the code for the RotateAroundAxis3D function...

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

CodePudding user response:

I assume the function:

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

should rotate this so theV1 becomes theV2. If the case then in my opinion the case if (gMath.Abs(aDot)>=1.0f-gMath.mMachineEpsilon) this should not do anything, but you are rotating by 180deg around unaligned perpendicular vector to theV1. That is simply wrong I would leave the matrix as is in such case without any change so:

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

If the problem persists then the cause might be in RotateAroundAxis3D(aAxis,aAngle); however without seeing its implementation its hard to say. If it uses quaternions or Euler angles it might be the reason. If the case take a look at this:

the function vec3 rotate(float ang,vec3 axis,vec3 p) rotates vector you can change it to rotate matrix by rotating its 3 basis vectors and origin.

btw there is also another option for doing this aligning see:

  • Related