Tuesday, March 1, 2011

Direct3D Geometry: Rotation Matrix from Two Vectors

Given two 3D vectors A and B, I need to derive a rotation matrix which rotates from A to B.

This is what I came up with:

  1. Derive cosine from acos(A . B)
  2. Derive sine from asin(|A x B| / (|A| * |B|))
  3. Use A x B as axis of rotation
  4. Use matrix given near the bottom of this page (axis angle)

This works fine except for rotations of 0° (which I ignore) and 180° (which I treat as a special case). Is there a more graceful way to do this using the Direct3D library? I am looking for a Direct3D specific answer.

Edit: Removed acos and asin (see Hugh Allen's post)

From stackoverflow
  • No, you're pretty much doing it the best way possible. I don't think there is a built-in DirectX function that does what you want. For step 4, you can use D3DXMatrixRotationAxis(). Just be careful about the edge cases, such as when |A| or |B| is zero, or when the angle is 0° or 180°.

  • It's probably more of a typo than a thinko, but acos(A.B) is the angle, not its cosine. Similarly for point 2.

    You can calculate the sin from the cos using sin^2 + cos^2 = 1. That is, sin = sqrt(1-cos*cos). This would be cheaper than the vector expression you are using, and also eliminate the special cases for 0/180 degrees.

    Vulcan Eager : I am not sure that calculating the sine from sqrt(1-cosine*cosine) will work. This is because cosine*cosine will cause us to lose the sign of the cosine
    Hugh Allen : You don't "lose the sign of cosine" because you use the cosine as-is in the rotation matrix. What you should really ask is do you get the right sign for sin? In this case (0-180 degrees) you only want the positive square root, so it's all good.
    Vulcan Eager : I agree completely!
    Vulcan Eager : Hugh, What about the 0 to -180 range?
    Hugh Allen : Negative angles aren't necessary for this particular application. When rotating from B to A the axis vector will be negated rather than the rotation angle.
    Vulcan Eager : That's how things ended. Thanks again for a very prompt reply.
  • You might look at the following article from siggraph link text

  • Maybe you can use D3DXMatrixLookAtLH ?

0 comments:

Post a Comment