3
\$\begingroup\$

I've got a normalized vec3 that represents an orientation.

Each frame of animation, an object's orientation changes slightly, so I add a delta vector to the orientation vector and then normalize to find the new orientation.

I'd like to convert the vec3 that represents an orientation into a rotation matrix that I can use to orient my object.

If it helps, my object is a cone, and I'd like to rotate it about the pointy end, not from its center :)

PS I know I should use quaternions because of the gimbal lock problem. If someone can explain quats too, that'd be great :)

\$\endgroup\$

2 Answers 2

5
\$\begingroup\$

Your problem is under-constrained, so there are a lot of possible solutions.

My suggestion is to see your vec3 as the result of rotating vector [1 0 0] by φ around axis Y then by θ around axis Z. This is the latitude/longitude notation. The corresponding transformation matrix is:

|cosθ cosφ   -sinθ   -cosθ sinφ|
|sinθ cosφ    cosθ   -sinθ sinφ|
|   sinφ       0         cosφ  |

See the first column? That’s your vec3, since it’s the image of [1 0 0]. So the good thing is that we already know a lot of the matrix values.

The following code computes the remaining values:

mat3 rotation_matrix(vec3 v)
{
    /* Find cosφ and sinφ */
    float c1 = sqrt(v.x * v.x + v.y * v.y);
    float s1 = v.z;
    /* Find cosθ and sinθ; if gimbal lock, choose (1,0) arbitrarily */
    float c2 = c1 ? v1.x / c1 : 1.0;
    float s2 = c1 ? v1.y / c1 : 0.0;

    return mat3(v.x, -s2, -s1*c2,
                v.y,  c2, -s1*s2,
                v.z,   0,     c1);
}

Be careful with the last line, it may need a transposition depending on how your matrix class works.

\$\endgroup\$
3
  • \$\begingroup\$ thanks sam, I have some questions about this that I hope you can comment on later :) \$\endgroup\$
    – lapin
    Dec 10, 2012 at 16:14
  • \$\begingroup\$ I get that you're combining axis angle rotations around the Y & Z axes, so I understand how you've got the transformation matrix. How (if at all) would the calculations for c1, s1 and c2, s2 change for rotations of vec3(0,1,0) around the x and z axes? \$\endgroup\$
    – lapin
    Dec 12, 2012 at 3:14
  • 1
    \$\begingroup\$ @lapin I think you need to 1) shift the final matrix one column right and one line down, 2) replace v.x with v.y, v.y with v.z and v.z with v.x. Let me know if it works. \$\endgroup\$ Dec 12, 2012 at 23:12
4
\$\begingroup\$

A single vector only represents a direction. It sounds like gimbal lock will not be a problem in your case.

First you need to select an up vector to really define an orientation instead of a direction. You can start with the world's up vector and than use the last frames up vector from there on. Now you can calculate a side vector using the cross product and correct the up vector to ensure you have an orthonormal basis. To get the rotation matrix you just put these three vectors into a matrix's rows or columns depending on your coordinate system and used matrix convention.

Vec3 forward = your_rotation;
Vec3 up;
Vec3 side;

side = cross(forward, last_up);
if( side.GetLengthSq() < 0.001f )
{
  side = cross(forward, world_up);
  if( side.GetLengthSq() < 0.001f )
    side = cross(forward, world_side);
}

side.Normalize();
up = cross( forward, side );

// example, depends solely on the matrix format and coordinate space used
Matrix3 rotation( forward, side, up );

The easier way is to use a lookat function which does exactly the same and is provided with most engines and render APIs.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks Archy, this answer is also useful. I may have questions about it later :) \$\endgroup\$
    – lapin
    Dec 10, 2012 at 16:15
  • 1
    \$\begingroup\$ No problem, @SamHocevar's solution is probably better suited for your problem. :) \$\endgroup\$
    – Archy
    Dec 10, 2012 at 16:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .