Three.js: THREE.Matrix4 makeRotationFromEuler function is wrong.

Created on 30 Dec 2016  路  7Comments  路  Source: mrdoob/three.js

(* This section is for bug reports and feature requests only. This is NOT a help site. Do not ask help questions here. If you need help, please use stackoverflow. *)

Description of the problem

For the matrix is column major and right multiplication in three js, which means column elements are placed in adjacent memory address, the matrix made from euler order 'XYZ' is actually that of 'ZYX'. I didn't check other euler orders yet. I found this because the euler angles which I exported from FBX file is 'XYZ' order, but I have to set them to 'ZYX' to get the right result in three js. Or I was wrong, if three js rotation is based on the local coordination of object instead of that of it's parent.

Three.js version
  • [ ] Dev
  • [ ] r82
  • [ ] ...
Browser
  • [x] All of them
  • [ ] Chrome
  • [ ] Firefox
  • [ ] Internet Explorer
OS
  • [x] All of them
  • [ ] Windows
  • [ ] Linux
  • [ ] Android
  • [ ] IOS
Hardware Requirements (graphics card, VR Device, ...)

Most helpful comment

In three.js, Euler angles are of the _intrinsic_ Tait-Bryan type. Rotations are performed with respect to the _local_ coordinate system. That is, for order XYZ, the rotation is first around X, then around local-Y (which may now be different from the world Y-axis), then local-Z (which may be different from the world Z-axis).

If the rotations are performed with respect to the static _world_ coordinate system, instead of the _local_ coordinate system, then the angles are referred to as _extrinsic_ Euler angles. In that case, for order XYZ, the rotations are around world-X, world-Y, and world-Z.

Euler order XYZ when the angles are interpreted as intrinsic angles is equivalent to order ZYX when the same angles are interpreted as extrinsic angles.

So a reasonable assumption would be that the FBX Euler angles are extrinsic. To convert to three.js angles, reverse the order.

All 7 comments

In three.js, Euler angles are of the _intrinsic_ Tait-Bryan type. Rotations are performed with respect to the _local_ coordinate system. That is, for order XYZ, the rotation is first around X, then around local-Y (which may now be different from the world Y-axis), then local-Z (which may be different from the world Z-axis).

If the rotations are performed with respect to the static _world_ coordinate system, instead of the _local_ coordinate system, then the angles are referred to as _extrinsic_ Euler angles. In that case, for order XYZ, the rotations are around world-X, world-Y, and world-Z.

Euler order XYZ when the angles are interpreted as intrinsic angles is equivalent to order ZYX when the same angles are interpreted as extrinsic angles.

So a reasonable assumption would be that the FBX Euler angles are extrinsic. To convert to three.js angles, reverse the order.

I'll add a note on this to the docs.

@WestLangley actually there is quite a bit of useful info in your responses and StackOverflow posts - do you mind if I plagiarise some of it?

@looeee OK

@WestLangley @looeee

Euler order XYZ when the angles are interpreted as intrinsic angles is equivalent to order ZYX when the same angles are interpreted as extrinsic angles.

That doesn't sound right to me. Care to provide a proof link?

Also, Wiki says:

Here we present the results for the two most commonly used conventions: ZXZ for proper Euler angles and ZYX for Tait-Bryan.

And three.js defaults to XYZ for Tait-Bryan... What is the reason for not going with a "commonly used convention"?

The two most commonly used conventions

Three.js uses one of the two most commonly used conventions. Actually Tait-Bryan are probably more commonly used than 'proper' Euler angles. Intrinsic Tait-Bryan Euler angles are also known as yaw, pitch, and roll.

Euler order XYZ when the angles are interpreted as intrinsic angles is equivalent to order ZYX when the same angles are interpreted as extrinsic angles.

Hmm, this could be written a bit better, as the initial XYZ should be XY'Z'' to show that these are local axes rather than world axes. Something like:

An intrinsic Euler rotation XY'Z'' about the angles a, b, c is equivalent to an extrinsic Euler rotation ZYX about the angles c, b, a.

You can find proofs of the intrinsic to extrinsic transform online. Here's one discussion. Feel free to double check it and update the docs if there is a mistake (there's an "edit button in the top right of each page).

It is _not_ correct to say intrinsic Tait-Bryan Euler angles are "known as yaw, pitch, and roll". That is only true in certain use cases -- in spite of what you may have read on Wikipedia.

Please see the section https://en.wikipedia.org/wiki/Euler_angles#Conventions_2. I believe that section is accurate.

Also see https://stackoverflow.com/questions/17517937/three-js-camera-tilt-up-or-down-and-keep-horizon-level/17518092#17518092.

Here we present the results for the two most commonly used conventions: ZXZ for proper Euler angles and ZYX for Tait-Bryan.

"Proper" Euler angles do not apply to us. Also, the ZYX order is used in the aeronautics industry, but unlike our coordinate system with positive y-up, in the aeronautics industry, I believe the coordinate system typically sets positive z-down (so headings are measured clockwise), and with the aircraft aligned with the x-axis. The equivalent order in our y-up coordinate system would be YXZ, although that order implies counterclockwise headings.

If we were to change the default Euler order in three.js, I would select YXZ, because it is the most intuitive and would lead to much less user confusion.

@looeee

Three.js uses one of the two most commonly used conventions.

Three.js defaults to Tait-Bryan XYZ, while Wikipedia says that one of the conventions is Tait-Bryan ZYX. These are not the same, hence Three.js does not use a common convention.

You can find proofs of the intrinsic to extrinsic transform online. Here's one discussion.

Thanks, that's an interesting read!

@WestLangley
Thanks for the explanation about why Three.js doesn't follow Tait-Bryan ZYX by default! Do you know what existing reference/inspiration was used when picking XYZ by default?

Was this page helpful?
0 / 5 - 0 ratings