Why does my Quaternion lookat goes wrong? - MathOverflow [closed] most recent 30 from http://mathoverflow.net 2013-05-23T21:13:32Z http://mathoverflow.net/feeds/question/19710 http://www.creativecommons.org/licenses/by-nc/2.5/rdf http://mathoverflow.net/questions/19710/why-does-my-quaternion-lookat-goes-wrong Why does my Quaternion lookat goes wrong? Cheery 2010-03-29T08:16:19Z 2010-03-29T14:03:17Z <p>The algorithm takes two inputs: direction, upvector and returns the rotation that is needed to make an object or camera 'look at' along those vectors.</p> <p>Before I calculated this directly, I used to make a matrix from lookat vectors and transform it into quaternion. I've used the old algorithm and it's output to test that this new algorithm behaves similarly.</p> <p>Because matrix->quaternion isn't needed often otherwise, I decided to solve the lookat -quaternion directly from direction and upvector. This was my startpoint:</p> <pre><code>right = cross(up, front) Q.conjugation * (1, 0, 0, 0) * Q = right = R Q.conjugation * (0, 1, 0, 0) * Q = up = U Q.conjugation * (0, 0, 1, 0) * Q = front = F when you use the quaternion to rotate X axis, you should get R -vector Y axis U -vector Z axis F -vector Solve Q </code></pre> <p>From simplifying the expressions you'll get this:</p> <pre><code>Ux = 2*(Qx*Qy + Qz*Qw) Uy = -Qx² + Qy² - Qz² + Qw² Uz = 2*(Qy*Qz - Qx*Qw) Fx = 2*(Qx*Qz - Qy*Qw) Fy = 2*(Qx*Qw + Qy*Qz) Fz = -Qx² - Qy² + Qz² + Qw² Rx = +Qx² - Qy² - Qz² + Qw² Ry = 2*(Qx*Qy - Qz*Qw) Rz = 2*(Qx*Qz + Qy*Qw) </code></pre> <p>When I combine and shuffle some of these, I'll get:</p> <pre><code>substitute to clarify: Qx = x, Qy = y, Qz = z Ux + Ry = 4xy Rz + Fx = 4xz Fy + Uz = 4yz Ux - Ry = 4zw Rz - Fx = 4yw Fy - Uz = 4xw </code></pre> <p>Which suggested to do this:</p> <pre><code>(Rz - Fx)/4w = y (Fy - Uz)/4w = x Ux + Ry = 4 * ((Rz - Fx)/4w) * ((Fy - Uz)/4w) Ux + Ry = 4 * (Rz - Fx) * (Fy - Uz)/4w Ux + Ry = (Rz - Fx) * (Fy - Uz)/w w = (Rz - Fx) * (Fy - Uz) / (Ux + Ry) (Ux - Ry) / 4w = z (Rz - Fx) / 4w = y (Fy - Uz) / 4w = x </code></pre> <p>Ok, so because I now know w, I thought I'd be able to solve the lookat this way:</p> <pre><code>@classmethod def from_direction(cls, direction, up): up = (up - direction * up.dot(direction)).normal right = up.cross(direction) a = right.z - direction.x b = direction.y - up.z c = up.x + right.y d = up.x - right.y w = a*b / c return Quaternion(x = b / (4*w), y = a / (4*w), z = d / (4*w), w = w) </code></pre> <p>That one is not working though. But this one does:</p> <pre><code>@classmethod def from_direction(cls, direction, up): up = (up - direction * up.dot(direction)).normal right = up.cross(direction) a = right.z - direction.x b = direction.y - up.z c = up.x + right.y d = up.x - right.y w = a*b / c return Quaternion(x = b, y = a, z = d, w = w).normal # for reference: @property def magnitude(self): return math.sqrt(self.x**2 + self.y**2 + self.z**2 + self.w**2) @property def normal(self): l = self.magnitude return Quaternion(self.x/l, self.y/l, self.z/l, self.w/l) </code></pre> <p>Calculation I did doesn't exactly explain how this could work. and I'm a bit baffled why it works.</p> <p>Update: my quaternion algorithm is not entirely working. At least special case where c == 0.0 fails.</p> <p>Update: I found quite many cases for proper lookat vectors (0, 1, 0), (1, 0, 0) etc. where this algorithm should return a quaternion but just fails instead. Question updated accordingly.</p>