2

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);
}
KiraHoneybee
  • 495
  • 3
  • 12

1 Answers1

2

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:

Spektre
  • 49,595
  • 11
  • 110
  • 380
  • Hi... I tried switching it to your version, but I get the same effect. I believe that one condition is for an extremely rare situation that the guy who sent me the code identified-- when it produces bad results, it doesn't hit that code at all, I checked with breakpoints. I added the code for the Rotate/Axis function-- I have math functions that turn degrees to radians for simplicity, that's what gMath.Sin/Cos are. Any comment on whether that function is bad? – KiraHoneybee Feb 21 '22 at 19:19
  • One more note: The vector-to-vector function definitely WORKS-- a situation where it manifests is, if I'm rotating from Vector(-1,0,0) to Vector (0,1,0)... what I'm looking for is a nice clean rotation around the Z axis to turn x into Y, but for some reason I end up with the whole thing z-inverted. (In the past, I've only actually used this with symmetrical objects, like pointing a cone in a direction, so I never noticed the inversion effect!) – KiraHoneybee Feb 21 '22 at 19:22
  • @KiraHoneybee well vector `v1` to vector `v2` has infinite possibilities, so check the last link in my answer ... it aligns 2 triangles you can use that ... you can use `v1` and `up` as 2 edges of trianlgle, the same for `v2,up` – Spektre Feb 21 '22 at 22:45
  • 1
    I had to tweak things a little, but managed to figure it out from your answer! Thanks! – KiraHoneybee Feb 22 '22 at 01:29