Currently working on steering behavior for my AI and just hit a little mathematical bump.

I'm in the process of writing an align function, which basically tries to match the agent's orientation with a target orientation. I've got a good source material for implementing this behavior but it uses euler angles to calculate the rotational delta, acceleration, and so on. This is nice, however I store orientation as a quaternion and the math library I'm using doesn't provide any functionality for deriving the euler angles. But if it helps I also have rotational matrices at my disposal too.

What would be the best way to decompose the quaternion or rotational matrix to get the euler information?

I found one source for decomposing the matrix, but I'm not quite getting the correct results. I'm thinking it may be a difference of column/row ordering of my matrices but then again, math isn't my strong point. http://nghiaho.com/?page_id=846

  • 1
    \$\begingroup\$ Do you really need an Euler-angle decomposition, or do you need a way to implement your target-facing behavior directly in terms of quaternions? \$\endgroup\$ Commented Sep 3, 2012 at 22:02
  • \$\begingroup\$ Well, if you have a source for a quaternion based implementation I'm all ears. Don't want to derail the original question though. \$\endgroup\$ Commented Sep 3, 2012 at 22:25
  • \$\begingroup\$ You could post a new question about it if you like. I would need to know more details of the desired behavior to be specific, but the general idea is just to lerp from the current quaternion toward the target quaternion. \$\endgroup\$ Commented Sep 3, 2012 at 22:33
  • \$\begingroup\$ Ah yeah, interpolating would be an easy solution. However, I'm not directly moving the entities but updating acceleration to meet rotational velocity targets which is probably naturally easier with euler angles. \$\endgroup\$ Commented Sep 4, 2012 at 12:42

2 Answers 2


You should really be storing the component vectors (rotation, translation, scale, velocity, etc.) in addition to the matrix and quaternion forms. Not only does that eliminate the problem your having, it reduces compound numerical errors that come up over time from floating point limits.

  • \$\begingroup\$ Ended up just doing this for simplicity sake. Going to leave the question open a bit longer though since it doesn't quite answer the original question. \$\endgroup\$ Commented Sep 3, 2012 at 22:33
  • \$\begingroup\$ +1, not only numerical accuracy, but there's quite a frequent issue of having two quats (q and -q) representing the exact same orientation. Most libraries give randomly either of the two as a result from a matrix-to-quat and vice-versa conversion. So one more reason not to use plain quats.. also, use them only for special reasons (e.g. slerp, multiple slerp, etc.) \$\endgroup\$
    – teodron
    Commented Sep 4, 2012 at 8:32

Here's the code from pyeuclid:

class Quaternion:
    def get_euler(self):
        t = self.x * self.y + self.z * self.w
        if t > 0.4999:
            heading = 2 * math.atan2(self.x, self.w)
            attitude = math.pi / 2
            bank = 0
        elif t < -0.4999:
            heading = -2 * math.atan2(self.x, self.w)
            attitude = -math.pi / 2
            bank = 0
            sqx = self.x ** 2
            sqy = self.y ** 2
            sqz = self.z ** 2
            heading = math.atan2(2 * self.y * self.w - 2 * self.x * self.z,
                                 1 - 2 * sqy - 2 * sqz)
            attitude = math.asin(2 * t)
            bank = math.atan2(2 * self.x * self.w - 2 * self.y * self.z,
                              1 - 2 * sqx - 2 * sqz)
        return heading, attitude, bank
  • \$\begingroup\$ For some reason, I don't quite get the same angles back. I'm using the new DirectXMath library so maybe there is a difference in computing the quaternion from the yaw, pitch, and roll values. Anywho, ended up going with the other answer though since I can just keep the euler cached instead of recomputing it for AI queries. \$\endgroup\$ Commented Sep 3, 2012 at 22:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .