@@ -958,9 +958,27 @@ private bool ExportSkeleton (SkinnedMeshRenderer skinnedMesh, FbxScene fbxScene,
958
958
while ( s . Count > 0 ) {
959
959
var t = s . Pop ( ) ;
960
960
961
- boneSet . Add ( t ) ;
961
+ if ( ! boneSet . Add ( t ) ) {
962
+ continue ;
963
+ }
964
+
965
+ if ( t . parent == null ) {
966
+ Debug . LogWarningFormat (
967
+ "FbxExporter: {0} is a bone but not a descendant of {1}'s mesh's root bone." ,
968
+ t . name , skinnedMesh . name
969
+ ) ;
970
+ continue ;
971
+ }
962
972
963
- if ( t != root && t . parent != null && ! boneSet . Contains ( t . parent ) ) {
973
+ // Each skinned mesh in Unity has one root bone, but may have objects
974
+ // between the root bone and leaf bones that are not in the bone list.
975
+ // However all objects between two bones in a hierarchy should be bones
976
+ // as well.
977
+ // e.g. in rootBone -> bone1 -> obj1 -> bone2, obj1 should be a bone
978
+ //
979
+ // Traverse from all leaf bones to the root bone adding everything in between
980
+ // to the boneSet regardless of whether it is in the skinned mesh's bone list.
981
+ if ( t != root && ! boneSet . Contains ( t . parent ) ) {
964
982
s . Push ( t . parent ) ;
965
983
}
966
984
}
@@ -2083,7 +2101,7 @@ protected int ExportTransformHierarchy(
2083
2101
// both Maya and Unity use RSrs inheritance by default.
2084
2102
// Note: MotionBuilder uses RrSs inheritance by default as well, though it is possible
2085
2103
// to select a different inheritance type in the UI.
2086
- // Use RSrs as the scaling inhertiance instead.
2104
+ // Use RSrs as the scaling inheritance instead.
2087
2105
fbxNode . SetTransformationInheritType ( FbxTransform . EInheritType . eInheritRSrs ) ;
2088
2106
2089
2107
ExportTransform ( unityGo . transform , fbxNode , newCenter , exportType ) ;
@@ -2098,11 +2116,23 @@ protected int ExportTransformHierarchy(
2098
2116
return numObjectsExported ;
2099
2117
}
2100
2118
2119
+ /// <summary>
2120
+ /// Export data containing what to export when
2121
+ /// exporting animation only.
2122
+ /// </summary>
2101
2123
public struct AnimationOnlyExportData {
2124
+ // map from animation clip to GameObject that has Animation/Animator
2125
+ // component containing clip
2102
2126
public Dictionary < AnimationClip , GameObject > animationClips ;
2127
+
2128
+ // set of all GameObjects to export
2103
2129
public HashSet < GameObject > goExportSet ;
2130
+
2131
+ // map from GameObject to component type to export
2104
2132
public Dictionary < GameObject , System . Type > exportComponent ;
2105
- public AnimationClip defaultClip ; // first clip to export
2133
+
2134
+ // first clip to export
2135
+ public AnimationClip defaultClip ;
2106
2136
2107
2137
public AnimationOnlyExportData (
2108
2138
Dictionary < AnimationClip , GameObject > animClips ,
@@ -2116,6 +2146,13 @@ public AnimationOnlyExportData(
2116
2146
}
2117
2147
}
2118
2148
2149
+ /// <summary>
2150
+ /// Exports all animation clips in the hierarchy along with
2151
+ /// the minimum required GameObject information.
2152
+ /// i.e. Animated GameObjects, their ancestors, and their transforms are exported,
2153
+ /// but components are only exported if explicitly animated. Meshes are not exported.
2154
+ /// </summary>
2155
+ /// <returns>The number of nodes exported.</returns>
2119
2156
protected int ExportAnimationOnly (
2120
2157
GameObject unityGO ,
2121
2158
FbxScene fbxScene ,
@@ -2180,7 +2217,6 @@ protected int ExportAnimationOnly(
2180
2217
}
2181
2218
2182
2219
// export animation
2183
-
2184
2220
// export default clip first
2185
2221
if ( exportData . defaultClip != null ) {
2186
2222
var defaultClip = exportData . defaultClip ;
@@ -2207,6 +2243,11 @@ public SkinnedMeshBoneInfo(SkinnedMeshRenderer skinnedMesh, Dictionary<Transform
2207
2243
}
2208
2244
}
2209
2245
2246
+ /// <summary>
2247
+ /// Exports the Gameobject and it's ancestors.
2248
+ /// </summary>
2249
+ /// <returns><c>true</c>, if game object and parents were exported,
2250
+ /// <c>false</c> if export cancelled.</returns>
2210
2251
private bool ExportGameObjectAndParents (
2211
2252
GameObject unityGo ,
2212
2253
GameObject rootObject ,
@@ -2286,6 +2327,14 @@ private bool ExportGameObjectAndParents(
2286
2327
return true ;
2287
2328
}
2288
2329
2330
+ /// <summary>
2331
+ /// Exports the bone transform.
2332
+ /// </summary>
2333
+ /// <returns><c>true</c>, if bone transform was exported, <c>false</c> otherwise.</returns>
2334
+ /// <param name="fbxNode">Fbx node.</param>
2335
+ /// <param name="fbxScene">Fbx scene.</param>
2336
+ /// <param name="unityBone">Unity bone.</param>
2337
+ /// <param name="boneInfo">Bone info.</param>
2289
2338
private bool ExportBoneTransform (
2290
2339
FbxNode fbxNode , FbxScene fbxScene , Transform unityBone , SkinnedMeshBoneInfo boneInfo
2291
2340
) {
@@ -2358,6 +2407,37 @@ private bool ExportBoneTransform(
2358
2407
return true ;
2359
2408
}
2360
2409
2410
+ /// <summary>
2411
+ /// Counts how many objects are between this object and the root (exclusive).
2412
+ /// </summary>
2413
+ /// <returns>The object to root count.</returns>
2414
+ /// <param name="startObject">Start object.</param>
2415
+ /// <param name="root">Root object.</param>
2416
+ private int GetObjectToRootCount ( Transform startObject , Transform root ) {
2417
+ if ( startObject == null ) {
2418
+ return 0 ;
2419
+ }
2420
+
2421
+ int count = 0 ;
2422
+ var parent = startObject . parent ;
2423
+ while ( parent != null && parent != root ) {
2424
+ count ++ ;
2425
+ parent = parent . parent ;
2426
+ }
2427
+ return count ;
2428
+ }
2429
+
2430
+
2431
+ /// <summary>
2432
+ /// Gets the count of animated objects to be exported.
2433
+ ///
2434
+ /// In addition, collects the minimum set of what needs to be exported for each GameObject hierarchy.
2435
+ /// This contains all the animated GameObjects, their ancestors, their transforms, as well as any animated
2436
+ /// components and the animation clips. Also, the first animation to export, if any.
2437
+ /// </summary>
2438
+ /// <returns>The animation only hierarchy count.</returns>
2439
+ /// <param name="exportSet">GameObject hierarchies selected for export.</param>
2440
+ /// <param name="hierarchyToExportData">Map from GameObject hierarchy to animation export data.</param>
2361
2441
protected int GetAnimOnlyHierarchyCount (
2362
2442
HashSet < GameObject > exportSet ,
2363
2443
out Dictionary < GameObject , AnimationOnlyExportData > hierarchyToExportData
@@ -2380,12 +2460,7 @@ out Dictionary<GameObject, AnimationOnlyExportData> hierarchyToExportData
2380
2460
int fromRoot = int . MaxValue ;
2381
2461
Animation rootAnimation = null ;
2382
2462
foreach ( var anim in legacyAnim ) {
2383
- int count = 0 ;
2384
- var parent = anim . transform . parent ;
2385
- while ( parent != null && parent != go . transform ) {
2386
- count ++ ;
2387
- parent = parent . parent ;
2388
- }
2463
+ int count = GetObjectToRootCount ( anim . transform , go . transform ) ;
2389
2464
2390
2465
if ( count < fromRoot ) {
2391
2466
fromRoot = count ;
@@ -2399,12 +2474,7 @@ out Dictionary<GameObject, AnimationOnlyExportData> hierarchyToExportData
2399
2474
int aFromRoot = int . MaxValue ;
2400
2475
Animator rootAnimator = null ;
2401
2476
foreach ( var anim in genericAnim ) {
2402
- int count = 0 ;
2403
- var parent = anim . transform . parent ;
2404
- while ( parent != null && parent != go . transform ) {
2405
- count ++ ;
2406
- parent = parent . parent ;
2407
- }
2477
+ int count = GetObjectToRootCount ( anim . transform , go . transform ) ;
2408
2478
2409
2479
if ( count < aFromRoot ) {
2410
2480
aFromRoot = count ;
@@ -2431,7 +2501,6 @@ out Dictionary<GameObject, AnimationOnlyExportData> hierarchyToExportData
2431
2501
var motion = dController . layers [ 0 ] . stateMachine . defaultState . motion ;
2432
2502
var defaultClip = motion as AnimationClip ;
2433
2503
if ( defaultClip ) {
2434
- Debug . LogWarning ( "default clip: " + defaultClip . name ) ;
2435
2504
exportData . defaultClip = defaultClip ;
2436
2505
} else {
2437
2506
Debug . LogWarningFormat ( "Couldn't export motion {0}" , motion . name ) ;
0 commit comments