Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find correct rotation from one vector to another?

I have two objects, and each object has two vectors:

  • normal vector
  • up vector

Like on this image:

enter image description here

Up vector is perpendicular to normal vector. Now I want to find unique rotation from one object to another, how to do that?

I have one method to find rotation between one vector to another, and it works. The problem is that I need to take care the two vectors: normal vector and up vector. If I use this method to rotate normal vector from object one to normal from object two, the up vector could be pointing wrong way, and they needs to be parallel.

Here is the code for finding the shortest rotation:

GE::Quat GE::Quat::fromTo(const Vector3 &v1, const Vector3 &v2)
{
    Vector3 a = Vector3::cross(v1, v2);
    Quat q;

    float dot = Vector3::dot(v1, v2);

    if ( dot >= 1 ) 
    {
        q = Quat(0,0,0,1);

    }
    else if ( dot < -0.999999 )
    {
        Vector3 axis = Vector3::cross(Vector3(1,0,0),v2);

        if (axis.length() == 0) // pick another if colinear
                axis = Vector3::cross(Vector3(0,1,0),v2);
        axis.normalize();
        q = Quat::axisToQuat(axis,180);
    }
    else
    {
        float s = sqrt( (1+dot)*2 );
        float invs = 1 / s;

        Vector3 c = Vector3::cross(v1, v2);

        q.x = c.x * invs;
        q.y = c.y * invs;
        q.z = c.z * invs;
        q.w = s * 0.5f;
    }
    q.normalize();
    return q;
}

What should I change/add to this code, to find the correct rotation?

like image 455
Tom Avatar asked Feb 17 '14 12:02

Tom


1 Answers

Before we begin, I will assume that both UP vector and normal vector are normalized and orthogonal (dot product is zero) between them.

Let's say that you want to rotate your yellow plate to be aligned with the rose (red?) plate. So, our reference will be the vectors from yellow plate and we will call our coordinate system as XYZ, where Z -> normal yellow vector, Y -> Up yellow vector and X -> YxZ (cross product).

In the same way, for rose plate, the rotated coordinate system will be called X'Y'Z' where Z' -> normal rose vector, Y' -> up rose vector and X' -> Y'xZ' (cross product).

Ok to find the rotation matrix, we only need to make sure that our normal yellow vector will become normal rose vector; that our up yellow vector will be transfomed in the up rose vector, and so on, i.e.:

RyellowTOrose = |X'x   Y'x   Z'x|
                |X'y   Y'y   Z'y|
                |X'z   Y'z   Z'z|

in other words, after you have any primitives transformed to be in coordinates of yellow system, applying this transformation, will rotate it to be aligned with rose coordinates system

If your up and normal vector aren't orthogonal, you can correct one of them easily. Just make the cross product between normal and up (results in a vector called C, for convenience) and do again the cross product between with C and normal, to correct the up vector.

like image 148
Amadeus Avatar answered Sep 28 '22 00:09

Amadeus