@@ -984,10 +984,9 @@ private bool ExportSkeleton (SkinnedMeshRenderer skinnedMesh, FbxScene fbxScene,
984
984
return false ;
985
985
}
986
986
987
- // Three steps:
987
+ // Two steps:
988
988
// 0. Set up the map from bone to index.
989
- // 1. Gather complete list of bones
990
- // 2. Set the transforms.
989
+ // 1. Set the transforms.
991
990
992
991
// Step 0: map transform to index so we can look up index by bone.
993
992
Dictionary < Transform , int > index = new Dictionary < Transform , int > ( ) ;
@@ -996,44 +995,11 @@ private bool ExportSkeleton (SkinnedMeshRenderer skinnedMesh, FbxScene fbxScene,
996
995
index [ unityBoneTransform ] = boneIndex ;
997
996
}
998
997
999
- // Step 1: gather all the bones
1000
- HashSet < Transform > boneSet = new HashSet < Transform > ( ) ;
1001
- var s = new Stack < Transform > ( bones ) ;
1002
- var root = skinnedMesh . rootBone ;
1003
- while ( s . Count > 0 ) {
1004
- var t = s . Pop ( ) ;
998
+ skinnedMeshToBonesMap . Add ( skinnedMesh , bones ) ;
1005
999
1006
- if ( ! boneSet . Add ( t ) ) {
1007
- continue ;
1008
- }
1009
-
1010
- if ( t . parent == null ) {
1011
- Debug . LogWarningFormat (
1012
- "FbxExporter: {0} is a bone but not a descendant of {1}'s mesh's root bone." ,
1013
- t . name , skinnedMesh . name
1014
- ) ;
1015
- continue ;
1016
- }
1017
-
1018
- // Each skinned mesh in Unity has one root bone, but may have objects
1019
- // between the root bone and leaf bones that are not in the bone list.
1020
- // However all objects between two bones in a hierarchy should be bones
1021
- // as well.
1022
- // e.g. in rootBone -> bone1 -> obj1 -> bone2, obj1 should be a bone
1023
- //
1024
- // Traverse from all leaf bones to the root bone adding everything in between
1025
- // to the boneSet regardless of whether it is in the skinned mesh's bone list.
1026
- if ( t != root && ! boneSet . Contains ( t . parent ) ) {
1027
- s . Push ( t . parent ) ;
1028
- }
1029
- }
1030
-
1031
- var boneList = boneSet . ToArray ( ) ;
1032
- skinnedMeshToBonesMap . Add ( skinnedMesh , boneList ) ;
1033
-
1034
- // Step 2: Set transforms
1000
+ // Step 1: Set transforms
1035
1001
var boneInfo = new SkinnedMeshBoneInfo ( skinnedMesh , index ) ;
1036
- foreach ( var bone in boneList ) {
1002
+ foreach ( var bone in bones ) {
1037
1003
var fbxBone = MapUnityObjectToFbxNode [ bone . gameObject ] ;
1038
1004
ExportBoneTransform ( fbxBone , fbxScene , bone , boneInfo ) ;
1039
1005
}
@@ -2564,6 +2530,39 @@ private string GetUniqueName(string name)
2564
2530
return uniqueName ;
2565
2531
}
2566
2532
2533
+ /// <summary>
2534
+ /// Create a fbxNode from unityGo.
2535
+ /// </summary>
2536
+ /// <param name="unityGo"></param>
2537
+ /// <param name="fbxScene"></param>
2538
+ /// <returns>the created FbxNode</returns>
2539
+ private FbxNode CreateFbxNode ( GameObject unityGo , FbxScene fbxScene )
2540
+ {
2541
+
2542
+ string fbxName = unityGo . name ;
2543
+ if ( ExportOptions . UseMayaCompatibleNames )
2544
+ {
2545
+ fbxName = ConvertToMayaCompatibleName ( unityGo . name ) ;
2546
+ if ( ExportOptions . AllowSceneModification )
2547
+ {
2548
+ unityGo . name = fbxName ;
2549
+ }
2550
+ }
2551
+
2552
+ FbxNode fbxNode = FbxNode . Create ( fbxScene , GetUniqueName ( fbxName ) ) ;
2553
+
2554
+ // Default inheritance type in FBX is RrSs, which causes scaling issues in Maya as
2555
+ // both Maya and Unity use RSrs inheritance by default.
2556
+ // Note: MotionBuilder uses RrSs inheritance by default as well, though it is possible
2557
+ // to select a different inheritance type in the UI.
2558
+ // Use RSrs as the scaling inheritance instead.
2559
+ fbxNode . SetTransformationInheritType ( FbxTransform . EInheritType . eInheritRSrs ) ;
2560
+
2561
+ MapUnityObjectToFbxNode [ unityGo ] = fbxNode ;
2562
+
2563
+ return fbxNode ;
2564
+ }
2565
+
2567
2566
/// <summary>
2568
2567
/// Creates an FbxNode for each GameObject.
2569
2568
/// </summary>
@@ -2577,18 +2576,7 @@ internal int ExportTransformHierarchy(
2577
2576
{
2578
2577
int numObjectsExported = exportProgress ;
2579
2578
2580
- string fbxName = unityGo . name ;
2581
- if ( ExportOptions . UseMayaCompatibleNames ) {
2582
- fbxName = ConvertToMayaCompatibleName ( unityGo . name ) ;
2583
- if ( ExportOptions . AllowSceneModification )
2584
- {
2585
- unityGo . name = fbxName ;
2586
- }
2587
- }
2588
-
2589
- // create an FbxNode and add it as a child of parent
2590
- FbxNode fbxNode = FbxNode . Create ( fbxScene , GetUniqueName ( fbxName ) ) ;
2591
- MapUnityObjectToFbxNode [ unityGo ] = fbxNode ;
2579
+ FbxNode fbxNode = CreateFbxNode ( unityGo , fbxScene ) ;
2592
2580
2593
2581
if ( Verbose )
2594
2582
Debug . Log ( string . Format ( "exporting {0}" , fbxNode . GetName ( ) ) ) ;
@@ -2602,13 +2590,6 @@ internal int ExportTransformHierarchy(
2602
2590
return - 1 ;
2603
2591
}
2604
2592
2605
- // Default inheritance type in FBX is RrSs, which causes scaling issues in Maya as
2606
- // both Maya and Unity use RSrs inheritance by default.
2607
- // Note: MotionBuilder uses RrSs inheritance by default as well, though it is possible
2608
- // to select a different inheritance type in the UI.
2609
- // Use RSrs as the scaling inheritance instead.
2610
- fbxNode . SetTransformationInheritType ( FbxTransform . EInheritType . eInheritRSrs ) ;
2611
-
2612
2593
ExportTransform ( unityGo . transform , fbxNode , newCenter , exportType ) ;
2613
2594
2614
2595
fbxNodeParent . AddChild ( fbxNode ) ;
@@ -2675,48 +2656,24 @@ internal int ExportAnimationOnly(
2675
2656
TransformExportType exportType = TransformExportType . Local
2676
2657
) {
2677
2658
AnimationOnlyExportData exportData = ( AnimationOnlyExportData ) data ;
2678
-
2679
- // export any bones
2680
- var skinnedMeshRenderers = unityGO . GetComponentsInChildren < SkinnedMeshRenderer > ( ) ;
2681
2659
int numObjectsExported = exportProgress ;
2682
2660
2683
- foreach ( var skinnedMesh in skinnedMeshRenderers ) {
2684
- var boneArray = skinnedMesh . bones ;
2685
- var bones = new HashSet < GameObject > ( ) ;
2686
- var boneDict = new Dictionary < Transform , int > ( ) ;
2687
-
2688
- for ( int i = 0 ; i < boneArray . Length ; i ++ ) {
2689
- bones . Add ( boneArray [ i ] . gameObject ) ;
2690
- boneDict . Add ( boneArray [ i ] , i ) ;
2691
- }
2692
-
2693
- // get the bones that are also in the export set
2694
- bones . IntersectWith ( exportData . Objects ) ;
2695
-
2696
- // remove the exported bones from the export set
2697
- exportData . Objects . ExceptWith ( bones ) ;
2698
-
2699
- var boneInfo = new SkinnedMeshBoneInfo ( skinnedMesh , boneDict ) ;
2700
- foreach ( var bone in bones ) {
2701
- FbxNode node ;
2702
- if ( ! ExportGameObjectAndParents (
2703
- bone . gameObject , unityGO , fbxScene , out node , newCenter ,
2704
- exportType , ref numObjectsExported , objectCount ,
2705
- boneInfo
2706
- ) ) {
2707
- // export cancelled
2708
- return - 1 ;
2709
- }
2710
- }
2711
- }
2712
-
2713
2661
// make sure anim destination node is exported as well
2714
2662
var exportSet = exportData . Objects ;
2715
- if ( ExportOptions . AnimationDest && ExportOptions . AnimationSource ) {
2716
- exportSet . Add ( ExportOptions . AnimationDest . gameObject ) ;
2663
+ if ( ExportOptions . AnimationDest && ExportOptions . AnimationSource )
2664
+ {
2665
+ exportSet . Add ( ExportOptions . AnimationDest . gameObject ) ;
2666
+ }
2667
+
2668
+ // first export all the animated bones that are in the export set
2669
+ // as only a subset of bones are exported, but we still need to make sure the bone transforms are correct
2670
+ if ( ! ExportAnimatedBones ( unityGO , fbxScene , ref numObjectsExported , objectCount , exportData ) )
2671
+ {
2672
+ // export cancelled
2673
+ return - 1 ;
2717
2674
}
2718
2675
2719
- // export everything else
2676
+ // export everything else and make sure all nodes are connected
2720
2677
foreach ( var go in exportSet ) {
2721
2678
FbxNode node ;
2722
2679
if ( ! ExportGameObjectAndParents (
@@ -2765,6 +2722,57 @@ public SkinnedMeshBoneInfo(SkinnedMeshRenderer skinnedMesh, Dictionary<Transform
2765
2722
}
2766
2723
}
2767
2724
2725
+ private bool ExportAnimatedBones (
2726
+ GameObject unityGo ,
2727
+ FbxScene fbxScene ,
2728
+ ref int exportProgress ,
2729
+ int objectCount ,
2730
+ AnimationOnlyExportData exportData
2731
+ )
2732
+ {
2733
+ var skinnedMeshRenderers = unityGo . GetComponentsInChildren < SkinnedMeshRenderer > ( ) ;
2734
+ foreach ( var skinnedMesh in skinnedMeshRenderers )
2735
+ {
2736
+ var boneArray = skinnedMesh . bones ;
2737
+ var bones = new HashSet < GameObject > ( ) ;
2738
+ var boneDict = new Dictionary < Transform , int > ( ) ;
2739
+
2740
+ for ( int i = 0 ; i < boneArray . Length ; i ++ )
2741
+ {
2742
+ bones . Add ( boneArray [ i ] . gameObject ) ;
2743
+ boneDict . Add ( boneArray [ i ] , i ) ;
2744
+ }
2745
+
2746
+ // get the bones that are also in the export set
2747
+ bones . IntersectWith ( exportData . Objects ) ;
2748
+
2749
+ var boneInfo = new SkinnedMeshBoneInfo ( skinnedMesh , boneDict ) ;
2750
+ foreach ( var bone in bones )
2751
+ {
2752
+ FbxNode fbxNode ;
2753
+ // bone already exported
2754
+ if ( MapUnityObjectToFbxNode . TryGetValue ( bone , out fbxNode ) )
2755
+ {
2756
+ continue ;
2757
+ }
2758
+ fbxNode = CreateFbxNode ( bone , fbxScene ) ;
2759
+
2760
+ exportProgress ++ ;
2761
+ if ( EditorUtility . DisplayCancelableProgressBar (
2762
+ ProgressBarTitle ,
2763
+ string . Format ( "Creating FbxNode {0}/{1}" , exportProgress , objectCount ) ,
2764
+ ( exportProgress / ( float ) objectCount ) * 0.5f ) )
2765
+ {
2766
+ // cancel silently
2767
+ return false ;
2768
+ }
2769
+
2770
+ ExportBoneTransform ( fbxNode , fbxScene , bone . transform , boneInfo ) ;
2771
+ }
2772
+ }
2773
+ return true ;
2774
+ }
2775
+
2768
2776
/// <summary>
2769
2777
/// Exports the Gameobject and its ancestors.
2770
2778
/// </summary>
@@ -2778,58 +2786,34 @@ private bool ExportGameObjectAndParents(
2778
2786
Vector3 newCenter ,
2779
2787
TransformExportType exportType ,
2780
2788
ref int exportProgress ,
2781
- int objectCount ,
2782
- SkinnedMeshBoneInfo boneInfo = null )
2789
+ int objectCount
2790
+ )
2783
2791
{
2784
- // node already exists
2785
- if ( MapUnityObjectToFbxNode . TryGetValue ( unityGo , out fbxNode ) ) {
2786
- return true ;
2787
- }
2788
-
2789
- string fbxName = unityGo . name ;
2790
- if ( ExportOptions . UseMayaCompatibleNames ) {
2791
- fbxName = ConvertToMayaCompatibleName ( unityGo . name ) ;
2792
- }
2793
-
2794
- // create an FbxNode and add it as a child of parent
2795
- fbxNode = FbxNode . Create ( fbxScene , GetUniqueName ( fbxName ) ) ;
2796
- MapUnityObjectToFbxNode [ unityGo ] = fbxNode ;
2797
-
2798
- exportProgress ++ ;
2799
- if ( EditorUtility . DisplayCancelableProgressBar (
2800
- ProgressBarTitle ,
2801
- string . Format ( "Creating FbxNode {0}/{1}" , exportProgress , objectCount ) ,
2802
- ( exportProgress / ( float ) objectCount ) * 0.5f ) ) {
2803
- // cancel silently
2804
- return false ;
2805
- }
2806
-
2807
- // Default inheritance type in FBX is RrSs, which causes scaling issues in Maya as
2808
- // both Maya and Unity use RSrs inheritance by default.
2809
- // Note: MotionBuilder uses RrSs inheritance by default as well, though it is possible
2810
- // to select a different inheritance type in the UI.
2811
- // Use RSrs as the scaling inhertiance instead.
2812
- fbxNode . SetTransformationInheritType ( FbxTransform . EInheritType . eInheritRSrs ) ;
2792
+ // node doesn't exist so create it
2793
+ if ( ! MapUnityObjectToFbxNode . TryGetValue ( unityGo , out fbxNode ) )
2794
+ {
2795
+ fbxNode = CreateFbxNode ( unityGo , fbxScene ) ;
2813
2796
2814
- // TODO: check if GO is a bone and export accordingly
2815
- var exportedBoneTransform = boneInfo != null ?
2816
- ExportBoneTransform ( fbxNode , fbxScene , unityGo . transform , boneInfo ) : false ;
2797
+ exportProgress ++ ;
2798
+ if ( EditorUtility . DisplayCancelableProgressBar (
2799
+ ProgressBarTitle ,
2800
+ string . Format ( "Creating FbxNode {0}/{1}" , exportProgress , objectCount ) ,
2801
+ ( exportProgress / ( float ) objectCount ) * 0.5f ) )
2802
+ {
2803
+ // cancel silently
2804
+ return false ;
2805
+ }
2817
2806
2818
- // export regular transform if we are not a bone or failed to export as a bone
2819
- if ( ! exportedBoneTransform ) {
2820
- ExportTransform ( unityGo . transform , fbxNode , newCenter , exportType ) ;
2807
+ ExportTransform ( unityGo . transform , fbxNode , newCenter , exportType ) ;
2821
2808
}
2822
2809
2823
- if ( unityGo == rootObject || unityGo . transform . parent == null ) {
2824
- fbxScene . GetRootNode ( ) . AddChild ( fbxNode ) ;
2810
+ if ( unityGo == rootObject || unityGo . transform . parent == null )
2811
+ {
2812
+ fbxScene . GetRootNode ( ) . AddChild ( fbxNode ) ;
2825
2813
return true ;
2826
2814
}
2827
2815
2828
- SkinnedMeshBoneInfo parentBoneInfo = null ;
2829
- if ( boneInfo != null && boneInfo . skinnedMesh . rootBone != null && unityGo . transform != boneInfo . skinnedMesh . rootBone ) {
2830
- parentBoneInfo = boneInfo ;
2831
- }
2832
-
2816
+ // make sure all the nodes are connected and exported
2833
2817
FbxNode fbxNodeParent ;
2834
2818
if ( ! ExportGameObjectAndParents (
2835
2819
unityGo . transform . parent . gameObject ,
@@ -2839,8 +2823,7 @@ private bool ExportGameObjectAndParents(
2839
2823
newCenter ,
2840
2824
TransformExportType . Local ,
2841
2825
ref exportProgress ,
2842
- objectCount ,
2843
- parentBoneInfo
2826
+ objectCount
2844
2827
) ) {
2845
2828
// export cancelled
2846
2829
return false ;
@@ -2891,17 +2874,13 @@ private bool ExportBoneTransform(
2891
2874
}
2892
2875
2893
2876
Matrix4x4 pose ;
2894
- if ( unityBone == rootBone ) {
2895
- pose = ( unityBone . parent . worldToLocalMatrix * skinnedMesh . transform . localToWorldMatrix * bindPose . inverse ) ;
2896
- } else {
2897
- // get parent's bind pose
2898
- Matrix4x4 parentBindPose ;
2899
- if ( ! boneInfo . boneToBindPose . TryGetValue ( unityBone . parent , out parentBindPose ) ) {
2900
- parentBindPose = GetBindPose ( unityBone . parent , bindPoses , boneDict , skinnedMesh ) ;
2901
- boneInfo . boneToBindPose . Add ( unityBone . parent , parentBindPose ) ;
2902
- }
2903
- pose = parentBindPose * bindPose . inverse ;
2877
+ // get parent's bind pose
2878
+ Matrix4x4 parentBindPose ;
2879
+ if ( ! boneInfo . boneToBindPose . TryGetValue ( unityBone . parent , out parentBindPose ) ) {
2880
+ parentBindPose = GetBindPose ( unityBone . parent , bindPoses , boneDict , skinnedMesh ) ;
2881
+ boneInfo . boneToBindPose . Add ( unityBone . parent , parentBindPose ) ;
2904
2882
}
2883
+ pose = parentBindPose * bindPose . inverse ;
2905
2884
2906
2885
FbxVector4 translation , rotation , scale ;
2907
2886
GetTRSFromMatrix ( pose , out translation , out rotation , out scale ) ;
0 commit comments