Skip to content

Commit 2679593

Browse files
authored
Merge pull request #575 from BabylonJS/drigax/fixMayaRotationAnimation_rotationOrdering
Fix Maya rotation animation quaternion conversion
2 parents 6dacdfa + 8b0bfa8 commit 2679593

File tree

7 files changed

+125
-33
lines changed

7 files changed

+125
-33
lines changed

Maya/Exporter/BabylonExporter.Animation.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,10 @@ private List<BabylonAnimation> GetAnimation(MFnTransform transform)
225225
Dictionary<string, float> defaultValues = new Dictionary<string, float>();
226226
float[] position = null;
227227
float[] rotationQuaternion = null;
228+
BabylonVector3.EulerRotationOrder rotationOrder = BabylonVector3.EulerRotationOrder.XYZ;
228229
float[] rotation = null;
229230
float[] scaling = null;
230-
GetTransform(transform, ref position, ref rotationQuaternion, ref rotation, ref scaling); // coordinate system already switched
231+
GetTransform(transform, ref position, ref rotationQuaternion, ref rotation, ref rotationOrder, ref scaling); // coordinate system already switched
231232
defaultValues.Add("translateX", position[0]);
232233
defaultValues.Add("translateY", position[1]);
233234
defaultValues.Add("translateZ", position[2]);
@@ -306,7 +307,7 @@ private List<BabylonAnimation> GetAnimation(MFnTransform transform)
306307
{
307308
BabylonVector3 eulerAngles = BabylonVector3.FromArray(babylonAnimationKey.values);
308309
BabylonVector3 eulerAnglesRadians = eulerAngles * (float)(Math.PI / 180);
309-
BabylonQuaternion quaternionAngles = eulerAnglesRadians.toQuaternion();
310+
BabylonQuaternion quaternionAngles = eulerAnglesRadians.toQuaternion(rotationOrder);
310311
babylonAnimationKey.values = quaternionAngles.ToArray();
311312
}
312313
}

Maya/Exporter/BabylonExporter.Camera.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,18 @@ private BabylonNode ExportCamera(MDagPath mDagPath, BabylonScene babylonScene)
9191
float[] rotationQuaternion = null;
9292
float[] rotation = null;
9393
float[] scaling = null;
94-
GetTransform(mFnTransform, ref position, ref rotationQuaternion, ref rotation, ref scaling);
94+
var rotationOrder = BabylonVector3.EulerRotationOrder.XYZ;
95+
GetTransform(mFnTransform, ref position, ref rotationQuaternion, ref rotation, ref rotationOrder, ref scaling);
9596
babylonCamera.position = position;
9697
if (_exportQuaternionsInsteadOfEulers)
9798
{
9899
babylonCamera.rotationQuaternion = rotationQuaternion;
99100
}
100-
babylonCamera.rotation = rotation;
101+
else
102+
{
103+
babylonCamera.rotation = rotation;
104+
}
105+
101106

102107
// Field of view of babylon is the vertical one
103108
babylonCamera.fov = (float)mFnCamera.verticalFieldOfView;

Maya/Exporter/BabylonExporter.GLTFExporter.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,8 @@ private GLTFNode ExportNode(BabylonNode babylonNode, GLTF gltf, BabylonScene bab
512512
Y = babylonNode.rotation[1],
513513
Z = babylonNode.rotation[2]
514514
};
515-
gltfNode.rotation = rotationVector3.toQuaternion().ToArray();
515+
// babylon euler rotation order is YXZ
516+
gltfNode.rotation = rotationVector3.toQuaternion(BabylonVector3.EulerRotationOrder.YXZ).ToArray();
516517
}
517518
}
518519
else // Light

Maya/Exporter/BabylonExporter.Mesh.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -967,7 +967,8 @@ private void ExportTransform(BabylonAbstractMesh babylonAbstractMesh, MFnTransfo
967967
float[] rotationQuaternion = null;
968968
float[] rotation = null;
969969
float[] scaling = null;
970-
GetTransform(mFnTransform, ref position, ref rotationQuaternion, ref rotation, ref scaling);
970+
BabylonVector3.EulerRotationOrder rotationOrder = BabylonVector3.EulerRotationOrder.XYZ;
971+
GetTransform(mFnTransform, ref position, ref rotationQuaternion, ref rotation, ref rotationOrder, ref scaling);
971972

972973
babylonAbstractMesh.position = position;
973974
if (_exportQuaternionsInsteadOfEulers)

Maya/Exporter/BabylonExporter.Node.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using Autodesk.Maya.OpenMaya;
22
using BabylonExport.Entities;
3+
using System;
34
using System.Collections.Generic;
5+
using Utilities;
46

57
namespace Maya2Babylon
68
{
@@ -58,9 +60,12 @@ private void ExportHierarchy(BabylonNode babylonNode, MFnTransform mFnTransform)
5860
}
5961
}
6062

61-
private void GetTransform(MFnTransform mFnTransform, ref float[] position, ref float[] rotationQuaternion, ref float[] rotation, ref float[] scaling)
63+
private void GetTransform(MFnTransform mFnTransform, ref float[] position, ref float[] rotationQuaternion, ref float[] rotation, ref BabylonVector3.EulerRotationOrder rotationOrder, ref float[] scaling)
6264
{
6365
var transformationMatrix = new MTransformationMatrix(mFnTransform.transformationMatrix);
66+
var mayaRotationOrder = 0;
67+
MGlobal.executeCommand($"getAttr {mFnTransform.fullPathName}.rotateOrder", out mayaRotationOrder);
68+
rotationOrder = Tools.ConvertMayaRotationOrder((MEulerRotation.RotationOrder)mayaRotationOrder);
6469

6570
position = transformationMatrix.getTranslation();
6671
rotationQuaternion = transformationMatrix.getRotationQuaternion();
@@ -73,6 +78,7 @@ private void GetTransform(MFnTransform mFnTransform, ref float[] position, ref f
7378
rotationQuaternion[1] *= -1;
7479
rotation[0] *= -1;
7580
rotation[1] *= -1;
81+
rotationOrder = Tools.InvertRotationOrder(rotationOrder);
7682
}
7783

7884
private void GetTransform(MFnTransform mFnTransform, ref float[] position)

Maya/Tools/Tools.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Collections.Generic;
44
using System.Linq;
55
using System.Windows.Forms;
6+
using BabylonExport.Entities;
67

78
namespace Maya2Babylon
89
{
@@ -19,6 +20,47 @@ public static float Lerp(float min, float max, float t)
1920
return min + (max - min) * t;
2021
}
2122

23+
public static BabylonVector3.EulerRotationOrder ConvertMayaRotationOrder(MEulerRotation.RotationOrder mayaRotationOrder)
24+
{
25+
// http://download.autodesk.com/us/maya/2010help/api/class_m_transformation_matrix.html#adbf54177dae3a2015e51cd6bde8941e
26+
switch (mayaRotationOrder)
27+
{
28+
case MEulerRotation.RotationOrder.kXYZ:
29+
default:
30+
return BabylonVector3.EulerRotationOrder.XYZ;
31+
case MEulerRotation.RotationOrder.kYZX:
32+
return BabylonVector3.EulerRotationOrder.YZX;
33+
case MEulerRotation.RotationOrder.kZXY:
34+
return BabylonVector3.EulerRotationOrder.ZXY;
35+
case MEulerRotation.RotationOrder.kXZY:
36+
return BabylonVector3.EulerRotationOrder.XZY;
37+
case MEulerRotation.RotationOrder.kYXZ:
38+
return BabylonVector3.EulerRotationOrder.YXZ;
39+
case MEulerRotation.RotationOrder.kZYX:
40+
return BabylonVector3.EulerRotationOrder.ZYX;
41+
}
42+
}
43+
44+
public static BabylonVector3.EulerRotationOrder InvertRotationOrder(BabylonVector3.EulerRotationOrder rotationOrder)
45+
{
46+
switch (rotationOrder)
47+
{
48+
case BabylonVector3.EulerRotationOrder.XYZ:
49+
default:
50+
return BabylonVector3.EulerRotationOrder.ZYX;
51+
case BabylonVector3.EulerRotationOrder.YZX:
52+
return BabylonVector3.EulerRotationOrder.XZY;
53+
case BabylonVector3.EulerRotationOrder.ZXY:
54+
return BabylonVector3.EulerRotationOrder.YXZ;
55+
case BabylonVector3.EulerRotationOrder.XZY:
56+
return BabylonVector3.EulerRotationOrder.YZX;
57+
case BabylonVector3.EulerRotationOrder.YXZ:
58+
return BabylonVector3.EulerRotationOrder.ZXY;
59+
case BabylonVector3.EulerRotationOrder.ZYX:
60+
return BabylonVector3.EulerRotationOrder.XYZ;
61+
}
62+
}
63+
2264
// -------------------------
2365
// --------- Array ---------
2466
// -------------------------

SharedProjects/BabylonExport.Entities/BabylonVector3.cs

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -52,35 +52,71 @@ public float Length()
5252
return new BabylonVector3 { X = a.X * b, Y = a.Y * b, Z = a.Z * b };
5353
}
5454

55-
public BabylonQuaternion toQuaternion()
56-
{
57-
return RotationYawPitchRollToRefBabylon(Y, X, Z);
55+
public enum EulerRotationOrder
56+
{
57+
XYZ,
58+
YZX,
59+
ZXY,
60+
XZY,
61+
YXZ,
62+
ZYX
5863
}
5964

60-
/**
61-
* (Copy pasted from babylon)
62-
* Sets the passed quaternion "result" from the passed float Euler angles (radians) (y, x, z).
63-
*/
64-
private BabylonQuaternion RotationYawPitchRollToRefBabylon(float yaw, float pitch, float roll)
65+
// https://www.mathworks.com/matlabcentral/fileexchange/20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors?s_tid=mwa_osa_a
66+
// https://github.com/mrdoob/three.js/blob/09cfc67a3f52aeb4dd0009921d82396fd5dc5172/src/math/Quaternion.js#L199-L272
67+
68+
public BabylonQuaternion toQuaternion(EulerRotationOrder rotationOrder = EulerRotationOrder.XYZ)
6569
{
66-
// Produces a quaternion from Euler angles in the z-y-x orientation (Tait-Bryan angles)
67-
var halfRoll = roll * 0.5;
68-
var halfPitch = pitch * 0.5;
69-
var halfYaw = yaw * 0.5;
70-
71-
var sinRoll = Math.Sin(halfRoll);
72-
var cosRoll = Math.Cos(halfRoll);
73-
var sinPitch = Math.Sin(halfPitch);
74-
var cosPitch = Math.Cos(halfPitch);
75-
var sinYaw = Math.Sin(halfYaw);
76-
var cosYaw = Math.Cos(halfYaw);
77-
78-
var result = new BabylonQuaternion();
79-
result.X = (float)((cosYaw * sinPitch * cosRoll) + (sinYaw * cosPitch * sinRoll));
80-
result.Y = (float)((sinYaw * cosPitch * cosRoll) - (cosYaw * sinPitch * sinRoll));
81-
result.Z = (float)((cosYaw * cosPitch * sinRoll) - (sinYaw * sinPitch * cosRoll));
82-
result.W = (float)((cosYaw * cosPitch * cosRoll) + (sinYaw * sinPitch * sinRoll));
83-
return result;
70+
BabylonQuaternion quaternion = new BabylonQuaternion();
71+
72+
var c1 = Math.Cos(0.5 * this.X);
73+
var c2 = Math.Cos(0.5 * this.Y);
74+
var c3 = Math.Cos(0.5 * this.Z);
75+
76+
var s1 = Math.Sin(0.5 * this.X);
77+
var s2 = Math.Sin(0.5 * this.Y);
78+
var s3 = Math.Sin(0.5 * this.Z);
79+
80+
switch (rotationOrder)
81+
{
82+
case EulerRotationOrder.XYZ:
83+
quaternion.X = (float)(s1 * c2 * c3 + c1 * s2 * s3);
84+
quaternion.Y = (float)(c1 * s2 * c3 - s1 * c2 * s3);
85+
quaternion.Z = (float)(c1 * c2 * s3 + s1 * s2 * c3);
86+
quaternion.W = (float)(c1 * c2 * c3 - s1 * s2 * s3);
87+
break;
88+
case EulerRotationOrder.YZX:
89+
quaternion.X = (float)(s1 * c2 * c3 + c1 * s2 * s3);
90+
quaternion.Y = (float)(c1 * s2 * c3 + s1 * c2 * s3);
91+
quaternion.Z = (float)(c1 * c2 * s3 - s1 * s2 * c3);
92+
quaternion.W = (float)(c1 * c2 * c3 - s1 * s2 * s3);
93+
break;
94+
case EulerRotationOrder.ZXY:
95+
quaternion.X = (float)(s1 * c2 * c3 - c1 * s2 * s3);
96+
quaternion.Y = (float)(c1 * s2 * c3 + s1 * c2 * s3);
97+
quaternion.Z = (float)(c1 * c2 * s3 + s1 * s2 * c3);
98+
quaternion.W = (float)(c1 * c2 * c3 - s1 * s2 * s3);
99+
break;
100+
case EulerRotationOrder.XZY:
101+
quaternion.X = (float)(s1 * c2 * c3 - c1 * s2 * s3);
102+
quaternion.Y = (float)(c1 * s2 * c3 - s1 * c2 * s3);
103+
quaternion.Z = (float)(c1 * c2 * s3 + s1 * s2 * c3);
104+
quaternion.W = (float)(c1 * c2 * c3 + s1 * s2 * s3);
105+
break;
106+
case EulerRotationOrder.YXZ:
107+
quaternion.X = (float)(s1 * c2 * c3 + c1 * s2 * s3);
108+
quaternion.Y = (float)(c1 * s2 * c3 - s1 * c2 * s3);
109+
quaternion.Z = (float)(c1 * c2 * s3 - s1 * s2 * c3);
110+
quaternion.W = (float)(c1 * c2 * c3 + s1 * s2 * s3);
111+
break;
112+
case EulerRotationOrder.ZYX:
113+
quaternion.X = (float)(s1 * c2 * c3 - c1 * s2 * s3);
114+
quaternion.Y = (float)(c1 * s2 * c3 + s1 * c2 * s3);
115+
quaternion.Z = (float)(c1 * c2 * s3 - s1 * s2 * c3);
116+
quaternion.W = (float)(c1 * c2 * c3 + s1 * s2 * s3);
117+
break;
118+
}
119+
return quaternion;
84120
}
85121

86122
/**

0 commit comments

Comments
 (0)