Skip to content

Commit 1b2f9e0

Browse files
committed
add anim only export test
1 parent 5029f35 commit 1b2f9e0

10 files changed

+2898
-13
lines changed

Assets/FbxExporters/Editor/FbxExporter.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -941,11 +941,8 @@ private bool ExportSkeleton (SkinnedMeshRenderer skinnedMesh, FbxScene fbxScene,
941941

942942
// Three steps:
943943
// 0. Set up the map from bone to index.
944-
// 1. Create the bones, in arbitrary order.
945-
// 2. Connect up the hierarchy.
946-
// 3. Set the transforms.
947-
// Step 0 supports step 1 (finding which is the root bone) and step 3
948-
// (setting up transforms; the complication is the use of pivots).
944+
// 1. Gather complete list of bones
945+
// 2. Set the transforms.
949946

950947
// Step 0: map transform to index so we can look up index by bone.
951948
Dictionary<Transform, int> index = new Dictionary<Transform, int>();
@@ -971,6 +968,7 @@ private bool ExportSkeleton (SkinnedMeshRenderer skinnedMesh, FbxScene fbxScene,
971968
var boneList = boneSet.ToArray();
972969
skinnedMeshToBonesMap.Add (skinnedMesh, boneList);
973970

971+
// Step 2: Set transforms
974972
var boneInfo = new SkinnedMeshBoneInfo (skinnedMesh, index);
975973
foreach (var bone in boneList) {
976974
var fbxBone = MapUnityObjectToFbxNode [bone.gameObject];
@@ -2103,6 +2101,7 @@ public struct AnimationOnlyExportData {
21032101
public Dictionary<AnimationClip, GameObject> animationClips;
21042102
public HashSet<GameObject> goExportSet;
21052103
public Dictionary<GameObject, System.Type> exportComponent;
2104+
public AnimationClip defaultClip; // first clip to export
21062105

21072106
public AnimationOnlyExportData(
21082107
Dictionary<AnimationClip, GameObject> animClips,
@@ -2112,6 +2111,7 @@ public AnimationOnlyExportData(
21122111
this.animationClips = animClips;
21132112
this.goExportSet = exportSet;
21142113
this.exportComponent = exportComponent;
2114+
this.defaultClip = null;
21152115
}
21162116
}
21172117

@@ -3176,7 +3176,7 @@ public bool HasValidVertexColors(){
31763176
/// <summary>
31773177
/// Get the GameObject
31783178
/// </summary>
3179-
private static GameObject GetGameObject (Object obj)
3179+
public static GameObject GetGameObject (Object obj)
31803180
{
31813181
if (obj is UnityEngine.Transform) {
31823182
var xform = obj as UnityEngine.Transform;
@@ -3484,9 +3484,9 @@ public static string ExportObjects (string filePath, UnityEngine.Object[] object
34843484
return null;
34853485
}
34863486

3487-
public static string ExportObject (string filePath, UnityEngine.Object root)
3487+
public static string ExportObject (string filePath, UnityEngine.Object root, bool animOnly = false)
34883488
{
3489-
return ExportObjects(filePath, new Object[] { root } );
3489+
return ExportObjects(filePath, new Object[] { root }, animOnly);
34903490
}
34913491

34923492
private static void EnsureDirectory (string path)

Assets/FbxExporters/Editor/UnitTests/FbxAnimationTest.cs

Lines changed: 139 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ public static IEnumerable BlendShapeTestCases {
9393
yield return "Models/blendshape_with_skinning.fbx";
9494
}
9595
}
96+
97+
public static IEnumerable AnimOnlyTestCaases {
98+
get {
99+
yield return new TestCaseData ("Models/DefaultMale/DefaultMale.prefab");
100+
}
101+
}
96102
}
97103

98104
[TestFixture]
@@ -477,8 +483,7 @@ public int Main (KeyData keyData, string testName, string path)
477483

478484
public static void ClipPropertyTest (AnimationClip animClipExpected, AnimationClip animClipActual)
479485
{
480-
// TODO: figure out why we get __preview__ on Windows
481-
Assert.That (animClipActual.name, Is.EqualTo (animClipExpected.name).Or.EqualTo("__preview__" + animClipExpected.name));
486+
Assert.That (animClipActual.name, Is.EqualTo (animClipExpected.name).Or.EqualTo(animClipExpected.name));
482487
Assert.That (animClipActual.legacy, Is.EqualTo (animClipExpected.legacy));
483488
Assert.That (animClipActual.isLooping, Is.EqualTo (animClipExpected.isLooping));
484489
Assert.That (animClipActual.wrapMode, Is.EqualTo (animClipExpected.wrapMode));
@@ -568,6 +573,28 @@ public static void CurveTest(AnimationCurve animCurveImported, AnimationCurve an
568573
Assert.That(actualValueKeys, Is.EqualTo(importedValueKeys), string.Format("{0} key value doesn't match", message));
569574
}
570575

576+
577+
public static Dictionary<string, AnimationClip> GetClipsFromFbx(string path, bool setLegacy = false){
578+
//acquire imported object from exported file
579+
Object [] goAssetImported = AssetDatabase.LoadAllAssetsAtPath (path);
580+
Assert.That (goAssetImported, Is.Not.Null);
581+
582+
// TODO : configure object so that it imports w Legacy Animation
583+
584+
var animClips = new Dictionary<string, AnimationClip> ();
585+
foreach (Object o in goAssetImported) {
586+
var animClipImported = o as AnimationClip;
587+
if (animClipImported && !animClipImported.name.StartsWith("__preview__")) {
588+
// TODO : configure import settings so we don't need to force legacy
589+
animClipImported.legacy = setLegacy;
590+
animClips.Add (animClipImported.name, animClipImported);
591+
}
592+
}
593+
Assert.That (animClips, Is.Not.Empty, "expected imported clips");
594+
595+
return animClips;
596+
}
597+
571598
public static AnimationClip GetClipFromFbx(string path){
572599
//acquire imported object from exported file
573600
Object [] goAssetImported = AssetDatabase.LoadAllAssetsAtPath (path);
@@ -578,7 +605,7 @@ public static AnimationClip GetClipFromFbx(string path){
578605
AnimationClip animClipImported = null;
579606
foreach (Object o in goAssetImported) {
580607
animClipImported = o as AnimationClip;
581-
if (animClipImported) break;
608+
if (animClipImported && !animClipImported.name.StartsWith("__preview__")) break;
582609
}
583610
Assert.That (animClipImported, Is.Not.Null, "expected imported clip");
584611

@@ -638,8 +665,6 @@ public void LegacySkinnedMeshAnimTest (string fbxPath)
638665
AnimTester.CurveTest(animCurveImported, animCurveOrig, curveBinding.propertyName);
639666
}
640667
}
641-
642-
643668
}
644669

645670
[Test, TestCaseSource (typeof (AnimationTestDataClass), "TransformIndependantComponentTestCases")]
@@ -764,5 +789,114 @@ public int ComponentAnimTest (System.Type componentType)
764789
var tester = new AnimTester {keyData=keyData, testName=testName, path=GetRandomFbxFilePath ()};
765790
return tester.DoIt() <= propertyNames.Length ? 1 : 0;
766791
}
792+
793+
[Test, TestCaseSource (typeof (AnimationTestDataClass), "AnimOnlyTestCaases")]
794+
public void AnimOnlyExportTest(string prefabPath)
795+
{
796+
prefabPath = FindPathInUnitTests (prefabPath);
797+
Assert.That (prefabPath, Is.Not.Null);
798+
799+
// add prefab to scene
800+
GameObject originalObj = AssetDatabase.LoadMainAssetAtPath ("Assets/" + prefabPath) as GameObject;
801+
Assert.IsNotNull (originalObj);
802+
GameObject originalGO = GameObject.Instantiate (originalObj);
803+
Assert.IsTrue (originalGO);
804+
805+
// get clips
806+
var animator = originalGO.GetComponentInChildren<Animator> ();
807+
Assert.That (animator, Is.Not.Null);
808+
809+
var controller = animator.runtimeAnimatorController;
810+
Assert.That (controller, Is.Not.Null);
811+
812+
var animClips = controller.animationClips;
813+
Assert.That (animClips, Is.Not.Null);
814+
815+
// get the set of GameObject transforms to be exported with the clip
816+
var animatedObjects = GetAnimatedGameObjects (animClips, animator.gameObject);
817+
818+
// export fbx
819+
// get GameObject
820+
string filename = GetRandomFbxFilePath ();
821+
var exportedFilePath = ModelExporter.ExportObject (filename, originalGO, animOnly: true);
822+
Assert.That (exportedFilePath, Is.EqualTo (filename));
823+
824+
GameObject fbxObj = AssetDatabase.LoadMainAssetAtPath (filename) as GameObject;
825+
Assert.IsTrue (fbxObj);
826+
827+
// compare hierarchy matches animated objects
828+
var s = new Stack<Transform> ();
829+
830+
// don't check the root since it probably won't have the same name anyway
831+
foreach (Transform child in fbxObj.transform) {
832+
s.Push (child);
833+
}
834+
while (s.Count > 0) {
835+
var transform = s.Pop ();
836+
837+
Assert.That (animatedObjects.Contains(transform.name));
838+
animatedObjects.Remove (transform.name);
839+
840+
foreach (Transform child in transform) {
841+
s.Push (child);
842+
}
843+
}
844+
845+
// compare clips
846+
var fbxAnimClips = AnimTester.GetClipsFromFbx (filename);
847+
Assert.That (fbxAnimClips.Count, Is.EqualTo (animClips.Count()));
848+
849+
foreach (var clip in animClips) {
850+
Assert.That (fbxAnimClips.ContainsKey (clip.name));
851+
852+
var fbxClip = fbxAnimClips [clip.name];
853+
854+
AnimTester.ClipPropertyTest (clip, fbxClip);
855+
856+
foreach (EditorCurveBinding curveBinding in AnimationUtility.GetCurveBindings (clip)) {
857+
foreach(EditorCurveBinding impCurveBinding in AnimationUtility.GetCurveBindings (fbxClip)) {
858+
859+
// only compare if the path and property names match
860+
if (curveBinding.path != impCurveBinding.path || curveBinding.propertyName != impCurveBinding.propertyName) {
861+
continue;
862+
}
863+
864+
AnimationCurve animCurveOrig = AnimationUtility.GetEditorCurve (clip, curveBinding);
865+
Assert.That (animCurveOrig, Is.Not.Null);
866+
867+
AnimationCurve animCurveImported = AnimationUtility.GetEditorCurve (fbxClip, impCurveBinding);
868+
Assert.That (animCurveImported, Is.Not.Null);
869+
870+
AnimTester.CurveTest(animCurveImported, animCurveOrig, curveBinding.propertyName);
871+
}
872+
}
873+
}
874+
}
875+
876+
private HashSet<string> GetAnimatedGameObjects(AnimationClip[] animClips, GameObject animatorObject){
877+
var animatedObjects = new HashSet<string>();
878+
foreach (var clip in animClips) {
879+
foreach (EditorCurveBinding uniCurveBinding in AnimationUtility.GetCurveBindings (clip)) {
880+
Object uniObj = AnimationUtility.GetAnimatedObject (animatorObject, uniCurveBinding);
881+
if (!uniObj) {
882+
continue;
883+
}
884+
885+
GameObject unityGo = ModelExporter.GetGameObject (uniObj);
886+
if (!unityGo) {
887+
continue;
888+
}
889+
890+
// also it's parents up until but excluding the root (the root will have a different name)
891+
var parent = unityGo.transform;
892+
while (parent != null && parent.parent != null) {
893+
animatedObjects.Add (parent.name);
894+
parent = parent.parent;
895+
}
896+
897+
}
898+
}
899+
return animatedObjects;
900+
}
767901
}
768902
}
Binary file not shown.

0 commit comments

Comments
 (0)