22using System . Collections . Generic ;
33using Autodesk . Max ;
44using BabylonExport . Entities ;
5+ using Utilities ;
6+
57
68namespace Max2Babylon
79{
10+ using BoneSearchResult = Tuple < List < IIGameNode > , RootBoneTransformationType > ;
11+
12+ internal enum RootBoneTransformationType
13+ {
14+ unknown , local , world
15+ }
16+
17+
18+
819 partial class BabylonExporter
920 {
21+ internal static readonly BoneSearchResult EmptyBoneSearchResult = new BoneSearchResult ( new List < IIGameNode > ( ) , RootBoneTransformationType . unknown ) ;
22+
1023 readonly List < IIGameSkin > skins = new List < IIGameSkin > ( ) ;
1124
1225 private bool IsSkinEqualTo ( IIGameSkin skin1 , IIGameSkin skin2 )
@@ -50,13 +63,13 @@ private List<IIGameNode> GetBones(IIGameSkin skin)
5063 /// <returns>
5164 /// All nodes needed for the skeleton hierarchy
5265 /// </returns>
53- private Dictionary < IIGameSkin , Tuple < List < IIGameNode > , float [ ] > > relevantNodesBySkin = new Dictionary < IIGameSkin , Tuple < List < IIGameNode > , float [ ] > > ( ) ;
54- private Tuple < List < IIGameNode > , float [ ] > GetSkinnedBones ( IIGameSkin skin )
66+ private Dictionary < IIGameSkin , BoneSearchResult > relevantNodesBySkin = new Dictionary < IIGameSkin , BoneSearchResult > ( ) ;
67+ private Tuple < List < IIGameNode > , RootBoneTransformationType > GetSkinnedBones ( IIGameSkin skin )
5568 {
5669
5770 if ( skin == null )
5871 {
59- return new Tuple < List < IIGameNode > , float [ ] > ( new List < IIGameNode > ( ) , null ) ;
72+ return EmptyBoneSearchResult ;
6073 }
6174
6275 int logRank = 2 ;
@@ -72,14 +85,14 @@ private Tuple<List<IIGameNode>, float[]> GetSkinnedBones(IIGameSkin skin)
7285 if ( bones . Count == 0 )
7386 {
7487 RaiseWarning ( "Skin has no bones." , logRank ) ;
75- return new Tuple < List < IIGameNode > , float [ ] > ( new List < IIGameNode > ( ) , null ) ;
88+ return EmptyBoneSearchResult ;
7689 }
7790
7891 if ( bones . Contains ( null ) )
7992 {
8093 RaiseError ( "Skin has bones that are outside of the exported hierarchy." , logRank ) ;
8194 RaiseError ( "The skin cannot be exported" , logRank ) ;
82- return new Tuple < List < IIGameNode > , float [ ] > ( new List < IIGameNode > ( ) , null ) ;
95+ return EmptyBoneSearchResult ;
8396 }
8497
8598 List < IIGameNode > allHierarchyNodes = null ;
@@ -90,12 +103,12 @@ private Tuple<List<IIGameNode>, float[]> GetSkinnedBones(IIGameSkin skin)
90103 RaiseError ( $ "More than one root node for the skin. The skeleton bones need to be part of the same hierarchy.", logRank ) ;
91104 RaiseError ( $ "The skin cannot be exported", logRank ) ;
92105
93- return new Tuple < List < IIGameNode > , float [ ] > ( new List < IIGameNode > ( ) , null ) ;
106+ return EmptyBoneSearchResult ;
94107 }
95108
96109 allHierarchyNodes . Add ( lowestCommonAncestor ) ;
97110
98- float [ ] rootTransformation = null ;
111+ RootBoneTransformationType tt = RootBoneTransformationType . world ;
99112
100113 // Babylon format assumes skeleton root is at origin, add any additional node parents from the lowest common ancestor to the scene root to the skeleton hierarchy.
101114 if ( lowestCommonAncestor . NodeParent != null )
@@ -106,16 +119,14 @@ private Tuple<List<IIGameNode>, float[]> GetSkinnedBones(IIGameSkin skin)
106119 // in this case, we stop to stack commonAncestor and we set the root transformation Matrix as Local.
107120 if ( HasSkinAsChild ( lowestCommonAncestor . NodeParent , skin ) )
108121 {
109- rootTransformation = lowestCommonAncestor . GetLocalTM ( 0 ) . ToArray ( ) ;
122+ tt = RootBoneTransformationType . local ;
110123 break ;
111124 }
112125 lowestCommonAncestor = lowestCommonAncestor . NodeParent ;
113126 allHierarchyNodes . Add ( lowestCommonAncestor ) ;
114127 } while ( lowestCommonAncestor . NodeParent != null ) ;
115128 }
116129
117- rootTransformation = rootTransformation ?? lowestCommonAncestor . GetWorldTM ( 0 ) . ToArray ( ) ;
118-
119130 // starting from the root, sort the nodes by depth first (add the children before the siblings)
120131 List < IIGameNode > sorted = new List < IIGameNode > ( ) ;
121132 Stack < IIGameNode > siblings = new Stack < IIGameNode > ( ) ; // keep the siblings in a LIFO list to add them after the children
@@ -146,7 +157,7 @@ private Tuple<List<IIGameNode>, float[]> GetSkinnedBones(IIGameSkin skin)
146157 }
147158 }
148159 }
149- var result = new Tuple < List < IIGameNode > , float [ ] > ( sorted , rootTransformation ) ;
160+ var result = new BoneSearchResult ( sorted , tt ) ;
150161
151162 relevantNodesBySkin . Add ( skin , result ) ; // Stock the result for optimization
152163
@@ -356,7 +367,7 @@ private BabylonBone[] ExportBones(IIGameSkin skin)
356367 {
357368 List < BabylonBone > bones = new List < BabylonBone > ( ) ;
358369 List < int > nodeIndices = GetNodeIndices ( skin ) ;
359- Tuple < List < IIGameNode > , float [ ] > revelantNodes = GetSkinnedBones ( skin ) ;
370+ BoneSearchResult revelantNodes = GetSkinnedBones ( skin ) ;
360371
361372 var rootMatrix = revelantNodes . Item2 ;
362373
@@ -365,15 +376,19 @@ private BabylonBone[] ExportBones(IIGameSkin skin)
365376 int parentIndex = ( node . NodeParent == null ) ? - 1 : nodeIndices . IndexOf ( node . NodeParent . NodeID ) ;
366377
367378 string boneId = node . MaxNode . GetGuid ( ) . ToString ( ) ;
379+
380+ // this function is select the correct matrix depending hierarchy case
381+ Func < int , float [ ] > getMatrix = ( i ) => parentIndex == - 1 ? ( revelantNodes . Item2 == RootBoneTransformationType . world ? node . GetWorldTM ( i ) . ToArray ( ) : node . GetLocalTM ( i ) . ToArray ( ) ) : node . GetLocalTM ( i ) . ToArray ( ) ;
382+
368383 // create the bone
369384 BabylonBone bone = new BabylonBone ( )
370385 {
371- id = ( isGltfExported ) ? boneId : boneId + "-bone" , // the suffix "-bone" is added in babylon export format to assure the uniqueness of IDs
372- parentNodeId = ( parentIndex != - 1 ) ? node . NodeParent . MaxNode . GetGuid ( ) . ToString ( ) : null ,
386+ id = ( isGltfExported ) ? boneId : boneId + "-bone" , // the suffix "-bone" is added in babylon export format to assure the uniqueness of IDs
387+ parentNodeId = ( parentIndex != - 1 ) ? node . NodeParent . MaxNode . GetGuid ( ) . ToString ( ) : null ,
373388 name = node . Name ,
374389 index = nodeIndices . IndexOf ( node . NodeID ) ,
375390 parentBoneIndex = parentIndex ,
376- matrix = ( parentIndex == - 1 ) ? rootMatrix : node . GetLocalTM ( 0 ) . ToArray ( )
391+ matrix = MathUtilities . CleanEpsilon ( getMatrix ( 0 ) )
377392 } ;
378393
379394 // Apply unit conversion factor to meter
@@ -387,9 +402,7 @@ private BabylonBone[] ExportBones(IIGameSkin skin)
387402 // export its animation
388403 var babylonAnimation = ExportMatrixAnimation ( "_matrix" , key =>
389404 {
390- IGMatrix mat = node . GetLocalTM ( key ) ;
391-
392- float [ ] matrix = mat . ToArray ( ) ;
405+ float [ ] matrix = MathUtilities . CleanEpsilon ( getMatrix ( key ) ) ;
393406
394407 // Apply unit conversion factor to meter
395408 // Affect translation only
0 commit comments