Search code examples
vectorrotationglsl

Get xyz angles between vectors?


How can i get the x, y and z rotation values between two unit vectors? I can't use the dot product, because that gives me only one value. I want to use rotation matrices for rotating on each axis,and for those i need the angular differences on each axis. I have tried the dot product of only two components, but i got a little confused. Is there a quick and easy way for doing this? Maybe i was doing it wrong with the two component thing, but i don't know. Best would be, if anyone knows a glsl method to do this exact thing!


Solution

  • If you want to get the x, y, and z angles between two vectors, take the dot product of the projections of the two vectors onto the orthogonal plane of the axis you want.

    That is, if you want the z-angle between the two vectors, create xy-plane vectors of the originals. To do this, make a vector that ignores the z-component of the vectors.

    vec3 u = vec3( ... ); // your input vector
    vec3 v = vec3( ... ); // your other input vector
    float x_angle = acos( dot( u.yz, v.yz ) );
    float y_angle = acos( dot( u.xz, v.xz ) );
    float z_angle = acos( dot( u.xy, v.xy ) );
    

    Note that it doesn't matter if you use u.xz or u.zx since you would be using the dot product. Just be sure to use the same order for both vectors within the dot product. Also, lines 3 - 5 of the code here assume unit vectors as there is no mention of vector lengths in the expression.

    It should also be noted that the use of acos can lead to errors for small values of the argument. To avoid this, the difference between the 2D projection vectors can be taken, and used with the atan2 function.

    Edit

    At the suggestion that the ultimate goal is to construct a rotation matrix to reorient other vectors with the same transformation, I suggest using the axis-angle approach (otherwise known as arbitrary axis rotations). The method involves finding the angle between the two vectors (dot product) and an appropriate rotation axis about which this angle is subtended (cross product).

    First step, you want to find the angle between the two vectors using the dot product.

    float angle = acos( dot( u, v ) ); // for unit vectors
    

    Next, to find the axis of rotation, use the cross product. Knowing that the cross product will yield a vector perpendicular to both u and v, crossing them in either order will give an appropriate axis.

    vec3 axis = cross( u, v ); // again, for unit vectors
    // normalize this if need be
    

    The form of the matrix you will want to use can be found under the heading of Rotation matrix from axis and angle on this Wikipedia article. I recommend storing some temporary values to make the calculation run faster.

    float c = cos(angle);
    float s = sin(angle);
    float t = 1 - c;
    

    Once you have this matrix constructed, simply multiply it by any vector to reapply the original transform.