{"id":7,"date":"2004-05-15T20:37:29","date_gmt":"2004-05-16T01:37:29","guid":{"rendered":"http:\/\/www.essentialmath.com\/blog\/?p=7"},"modified":"2005-11-19T09:23:42","modified_gmt":"2005-11-19T14:23:42","slug":"correction-quaternion-creation","status":"publish","type":"post","link":"https:\/\/www.essentialmath.com\/blog\/?p=7","title":{"rendered":"Correction: Quaternion Creation"},"content":{"rendered":"<p>This is both a correction, and an improvement to the creation of a quaternion from two vectors.  Or as it is commonly known, Shortest RotationArc.<\/p>\n<p>The current code doesn&#8217;t handle the case where the two vectors are opposing; there&#8217;s an if statement to detect it, and a comment, but no recovery code.   The problem is that there are an infinite number of orthogonal rotation axes &#8212; we just need to pick one.  The solution is to check to see which axis the start vector (it could be the finish vector, it doesn&#8217;t matter) is generally pointing along.  If it&#8217;s pointing generally along the <img decoding=\"async\" src=\"..\/..\/cgi-bin\/mimetex.cgi?z\" alt=\"\" border=0 align=middle\/>-axis, then we take the cross product with the <img decoding=\"async\" src=\"..\/..\/cgi-bin\/mimetex.cgi?x\" alt=\"\" border=0 align=middle\/>-axis to get our rotation axis.  Otherwise we take the cross product with the <img decoding=\"async\" src=\"..\/..\/cgi-bin\/mimetex.cgi?z\" alt=\"\" border=0 align=middle\/>-axis.<br \/>\n<!--more--><br \/>\nThe improvement is from a poster on flipcode and GameDev.net named &#8220;minorlogic&#8221; &#8212; who may have gotten it from another source that I&#8217;m not aware of.  If we take the dot product and cross product of the two vectors (call them <img decoding=\"async\" src=\"..\/..\/cgi-bin\/mimetex.cgi?\\mathbf{a}\" alt=\"\" border=0 align=middle\/> and <img decoding=\"async\" src=\"..\/..\/cgi-bin\/mimetex.cgi?\\mathbf{b}\" alt=\"\" border=0 align=middle\/>), then we end up with <img decoding=\"async\" src=\"..\/..\/cgi-bin\/mimetex.cgi?||\\mathbf{a}||\\,||\\mathbf{b}||\\cos\\theta\" alt=\"\" border=0 align=middle\/> and <img decoding=\"async\" src=\"..\/..\/cgi-bin\/mimetex.cgi?||\\mathbf{a}||\\,||\\mathbf{b}||\\sin\\theta \\hat{\\mathbf{r}}\" alt=\"\" border=0 align=middle\/>, where <img decoding=\"async\" src=\"..\/..\/cgi-bin\/mimetex.cgi?\\hat{\\mathbf{r}}\" alt=\"\" border=0 align=middle\/> is our normalized rotation axis.  Sticking this in a quaternion and normalizing gives us <img decoding=\"async\" src=\"..\/..\/cgi-bin\/mimetex.cgi?(\\cos\\theta, \\sin\\theta \\hat{\\mathbf{r}})\" alt=\"\" border=0 align=middle\/>.<\/p>\n<p>This is close to what we want, but we need <img decoding=\"async\" src=\"..\/..\/cgi-bin\/mimetex.cgi?(\\cos(\\theta\/2), \\sin(\\theta\/2) \\hat{\\mathbf{r}})\" alt=\"\" border=0 align=middle\/>.    The trick is to add 1 to the <img decoding=\"async\" src=\"..\/..\/cgi-bin\/mimetex.cgi?w\" alt=\"\" border=0 align=middle\/> value and renormalize.  This will end up dividing each element by <img decoding=\"async\" src=\"..\/..\/cgi-bin\/mimetex.cgi?\\sqrt{2(\\cos\\theta + 1)}\" alt=\"\" border=0 align=middle\/>.  From here, things should look familiar, as this is similar to Melax&#8217;s approach.  Using trigonometric identities and reducing shows that this will give us <img decoding=\"async\" src=\"..\/..\/cgi-bin\/mimetex.cgi?(\\cos(\\theta\/2), \\sin(\\theta\/2) \\hat{\\mathbf{r}})\" alt=\"\" border=0 align=middle\/>.<\/p>\n<p>The updated code looks like:<br \/>\n[cpp]<br \/>\nvoid<br \/>\nIvQuat::Set( const IvVector3&#038; from, const IvVector3&#038; to )<br \/>\n{<br \/>\n    \/\/ get axis of rotation<br \/>\n    IvVector3 axis = from.Cross( to );<br \/>\n    \/\/ get scaled cos of angle between vectors and set initial quaternion<br \/>\n    Set( axis.x, axis.y, axis.z, from.Dot( to ) ); <\/p>\n<p>    \/\/ normalize to get cos theta, sin theta r<br \/>\n    Normalize();<\/p>\n<p>    \/\/ set up for half angle calculation<br \/>\n    w += 1.0f;<\/p>\n<p>    \/\/ if vectors are opposing<br \/>\n    if ( w < = kEpsilon )\n    { \n        \/\/ find orthogonal vector\n        \/\/ take cross product with x axis\n        if ( from.z*from.z > from.x*from.x )<br \/>\n            Set( 0.0f, 0.0f, from.z, -from.y );<br \/>\n        \/\/ or take cross product with z axis<br \/>\n        else<br \/>\n            Set( 0.0f, from.y, -from.x, 0.0f );<br \/>\n    }<\/p>\n<p>    \/\/ normalize again to get rotation quaternion<br \/>\n    Normalize();<br \/>\n}<br \/>\n[\/cpp]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is both a correction, and an improvement to the creation of a quaternion from two vectors. Or as it is commonly known, Shortest RotationArc. The current code doesn&#8217;t handle the case where the two vectors are opposing; there&#8217;s an if statement to detect it, and a comment, but no recovery code. The problem is [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,3],"tags":[],"class_list":["post-7","post","type-post","status-publish","format-standard","hentry","category-erratical","category-mathematical"],"_links":{"self":[{"href":"https:\/\/www.essentialmath.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/7","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.essentialmath.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.essentialmath.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.essentialmath.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.essentialmath.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=7"}],"version-history":[{"count":0,"href":"https:\/\/www.essentialmath.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/7\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.essentialmath.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=7"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.essentialmath.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=7"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.essentialmath.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=7"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}