Why does my Quaternion lookat goes wrong? - MathOverflow [closed]most recent 30 from http://mathoverflow.net2013-05-23T21:13:32Zhttp://mathoverflow.net/feeds/question/19710http://www.creativecommons.org/licenses/by-nc/2.5/rdfhttp://mathoverflow.net/questions/19710/why-does-my-quaternion-lookat-goes-wrongWhy does my Quaternion lookat goes wrong?Cheery2010-03-29T08:16:19Z2010-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>