2
\$\begingroup\$

I have a unit vector (direction) which represent a rotation around Y axis,

and would like to turn this into a quaternion to represent the same rotation.

I use GLM library, but interested any library agnostic solution.

Should I pack the direction vector to a matrix then convert to quaternion? Is there a better way?

UPDATE: As I said the matrix solution works already, but there must be a shorter way, as i don't need all dimension only one (around Y):

glm::quat q = glm::conjugate(glm::toQuat(
    glm::lookAt(glm::vec3(from.getX(), from.getY(), from.getZ()),
                glm::vec3(from.getX(), from.getY(), from.getZ()) + direction,
                glm::vec3(0, 1, 0)
    )
));
\$\endgroup\$
  • \$\begingroup\$ Is the unit vector in the xz plane? (ie. y = 0, only its x & z components might be non-zero) \$\endgroup\$ – DMGregory Sep 30 '17 at 21:16
  • \$\begingroup\$ @DMGregory yes, correct \$\endgroup\$ – Avithohol Oct 1 '17 at 19:41
3
\$\begingroup\$

From http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/

qx = ax * sin(angle/2)
qy = ay * sin(angle/2)
qz = az * sin(angle/2)
qw = cos(angle/2)

But since your vector represents the rotation, and is not the axis of rotation, we need to compute the angle. Your axis of rotation is just 0,1,0

angle = atan2( vector.x, vector.z ) // Note: I expected atan2(z,x) but OP reported success with atan2(x,z) instead! Switch around if you see 90° off.
qx = 0
qy = 1 * sin( angle/2 )
qz = 0
qw = cos( angle/2 )

NOTE: this even works for non-unit vectors, as atan2 will compute the correct angle for any length vector, as long as it is not zero.

\$\endgroup\$
  • \$\begingroup\$ We can do one better and skip computing the angle directly, by noting that x & z already encode the sine and cosines we need to use the half-angle trig identities... \$\endgroup\$ – DMGregory Sep 30 '17 at 23:29
  • \$\begingroup\$ If you know cos(a), how does that help you to know cos(a/2) then, without doing cos( acos(a) / 2 ) which seems costly, and also would require unit vector. \$\endgroup\$ – Bram Oct 1 '17 at 3:31
  • \$\begingroup\$ By using the half-angle trig identities I mention in the second half of my comment. eg. cos(a/2) = sqrt((1 + cos(a))/2) for angles in the range (-π...+π) — still need two square roots instead of two trig and one inverse trig, so it's not a gigantic savings by any means, it's just kind if a cute pattern. ;) \$\endgroup\$ – DMGregory Oct 1 '17 at 10:35
  • \$\begingroup\$ @Bram thanks, it works and much shorter than my matrix solution ... one minor thing: if i rotate a model with the resulting quaternion, it seems to always add extra 90 to the correct rotation... my model is originally facing +Z axis ... but i can fix that substracting a constant -90 degree \$\endgroup\$ – Avithohol Oct 1 '17 at 19:48
  • 1
    \$\begingroup\$ @Bram that did it, angle should be angle = atan2( vector.x, vector.z) ... thank you very much, this is a beautiful whole answer! \$\endgroup\$ – Avithohol Oct 2 '17 at 18:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.