Skip to content

Commit 864956b

Browse files
committed
reimplement anim only export
export in 3 phases: 1. count objects + store objects, animated lights/cameras, and anim clips 2. export bones and regular gameobjects (with animated components) 3. export anim clips
1 parent 73d70e6 commit 864956b

File tree

1 file changed

+324
-7
lines changed

1 file changed

+324
-7
lines changed

Assets/FbxExporters/Editor/FbxExporter.cs

Lines changed: 324 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2176,7 +2176,303 @@ protected int ExportTransformHierarchy(
21762176
return numObjectsExported;
21772177
}
21782178

2179-
protected bool ExportAnimationOnly(GameObject unityGo, FbxScene fbxScene){
2179+
protected void ExportAnimationOnly(
2180+
GameObject unityGO,
2181+
FbxScene fbxScene,
2182+
int exportProgress,
2183+
int objectCount,
2184+
Vector3 newCenter,
2185+
HashSet<AnimationClip> animationClips,
2186+
HashSet<GameObject> goExportSet,
2187+
Dictionary<GameObject, System.Type> exportComponent,
2188+
TransformExportType exportType = TransformExportType.Local
2189+
){
2190+
// export any bones
2191+
var skinnedMeshRenderers = unityGO.GetComponentsInChildren<SkinnedMeshRenderer> ();
2192+
2193+
foreach (var skinnedMesh in skinnedMeshRenderers) {
2194+
var boneArray = skinnedMesh.bones;
2195+
var bones = new HashSet<GameObject>();
2196+
var boneDict = new Dictionary<Transform, int> ();
2197+
2198+
for (int i = 0; i < boneArray.Length; i++) {
2199+
bones.Add (boneArray [i].gameObject);
2200+
boneDict.Add (boneArray [i], i);
2201+
}
2202+
2203+
var rootBone = skinnedMesh.rootBone;
2204+
2205+
// get the bones that are also in the export set
2206+
bones.IntersectWith (goExportSet);
2207+
2208+
// remove the exported bones from the export set
2209+
goExportSet.ExceptWith (bones);
2210+
2211+
foreach (var bone in bones) {
2212+
FbxNode node;
2213+
ExportGameObjectAndParents (
2214+
bone.gameObject, unityGO, fbxScene, out node, newCenter, exportType, exportProgress, objectCount, skinnedMesh, boneDict, rootBone, true
2215+
);
2216+
}
2217+
}
2218+
2219+
// export everything else
2220+
foreach (var go in goExportSet) {
2221+
FbxNode node;
2222+
ExportGameObjectAndParents (
2223+
go, unityGO, fbxScene, out node, newCenter, exportType, exportProgress, objectCount
2224+
);
2225+
2226+
System.Type compType;
2227+
if (exportComponent.TryGetValue (go, out compType)) {
2228+
if (compType == typeof(Light)) {
2229+
ExportLight (go, fbxScene, node);
2230+
} else if (compType == typeof(Camera)) {
2231+
ExportCamera (go, fbxScene, node);
2232+
}
2233+
}
2234+
}
2235+
2236+
// export animation
2237+
foreach (var animClip in animationClips) {
2238+
//ExportAnimationClip (animClip, animationRootObject, fbxScene);
2239+
}
2240+
}
2241+
2242+
private bool ExportGameObjectAndParents(
2243+
GameObject unityGo,
2244+
GameObject rootObject,
2245+
FbxScene fbxScene,
2246+
out FbxNode fbxNode,
2247+
Vector3 newCenter,
2248+
TransformExportType exportType,
2249+
int exportProgress,
2250+
int objectCount,
2251+
SkinnedMeshRenderer skinnedMesh = null,
2252+
Dictionary<Transform, int> boneDict = null,
2253+
Transform rootBone = null,
2254+
bool isBone = false)
2255+
{
2256+
// node already exists
2257+
if (MapUnityObjectToFbxNode.TryGetValue (unityGo, out fbxNode)) {
2258+
return true;
2259+
}
2260+
2261+
if (ExportSettings.mayaCompatibleNames) {
2262+
unityGo.name = ConvertToMayaCompatibleName (unityGo.name);
2263+
}
2264+
2265+
// create an FbxNode and add it as a child of parent
2266+
fbxNode = FbxNode.Create (fbxScene, GetUniqueName (unityGo.name));
2267+
MapUnityObjectToFbxNode [unityGo] = fbxNode;
2268+
2269+
// Default inheritance type in FBX is RrSs, which causes scaling issues in Maya as
2270+
// both Maya and Unity use RSrs inheritance by default.
2271+
// Note: MotionBuilder uses RrSs inheritance by default as well, though it is possible
2272+
// to select a different inheritance type in the UI.
2273+
// Use RSrs as the scaling inhertiance instead.
2274+
fbxNode.SetTransformationInheritType (FbxTransform.EInheritType.eInheritRSrs);
2275+
2276+
// TODO: check if GO is a bone and export accordingly
2277+
var exportedBoneTransform = isBone?
2278+
ExportBoneTransform (fbxNode, fbxScene, unityGo.transform, rootBone, skinnedMesh, boneDict) : false;
2279+
2280+
// export regular transform if we are not a bone or failed to export as a bone
2281+
if(!exportedBoneTransform){
2282+
ExportTransform (unityGo.transform, fbxNode, newCenter, exportType);
2283+
}
2284+
2285+
if (unityGo.transform.parent != null || unityGo.transform.parent != rootObject.transform.parent) {
2286+
var parentIsBone = false;
2287+
if (isBone && rootBone != null && unityGo.transform != rootBone) {
2288+
parentIsBone = true;
2289+
}
2290+
2291+
FbxNode fbxNodeParent;
2292+
if (!ExportGameObjectAndParents (
2293+
unityGo.transform.parent.gameObject,
2294+
rootObject,
2295+
fbxScene,
2296+
out fbxNodeParent,
2297+
newCenter,
2298+
TransformExportType.Local,
2299+
exportProgress,
2300+
objectCount,
2301+
skinnedMesh,
2302+
boneDict,
2303+
rootBone,
2304+
parentIsBone
2305+
)) {
2306+
Debug.LogWarningFormat ("Failed to export GameObject {0}", unityGo.transform.parent.name);
2307+
return false;
2308+
}
2309+
fbxNodeParent.AddChild (fbxNode);
2310+
}
2311+
2312+
if (unityGo == rootObject) {
2313+
fbxScene.GetRootNode ().AddChild (fbxNode);
2314+
}
2315+
2316+
return true;
2317+
}
2318+
2319+
private bool ExportBoneTransform(
2320+
FbxNode fbxNode, FbxScene fbxScene, Transform unityBone, Transform rootBone,
2321+
SkinnedMeshRenderer skinnedMesh, Dictionary<Transform, int> boneDict
2322+
){
2323+
if (skinnedMesh == null || boneDict == null || unityBone == null) {
2324+
return false;
2325+
}
2326+
if (rootBone == null) {
2327+
rootBone = skinnedMesh.rootBone;
2328+
}
2329+
2330+
var fbxSkeleton = fbxNode.GetSkeleton ();
2331+
if (fbxSkeleton == null) {
2332+
fbxSkeleton = FbxSkeleton.Create (fbxScene, unityBone.name + SkeletonPrefix);
2333+
2334+
fbxSkeleton.Size.Set (1.0f * UnitScaleFactor);
2335+
fbxNode.SetNodeAttribute (fbxSkeleton);
2336+
}
2337+
var fbxSkeletonType = rootBone != unityBone
2338+
? FbxSkeleton.EType.eLimbNode : FbxSkeleton.EType.eRoot;
2339+
fbxSkeleton.SetSkeletonType (fbxSkeletonType);
2340+
2341+
var bindPoses = skinnedMesh.sharedMesh.bindposes;
2342+
2343+
// get bind pose
2344+
Matrix4x4 bindPose;
2345+
int index;
2346+
if (boneDict.TryGetValue (unityBone, out index)) {
2347+
bindPose = bindPoses [index];
2348+
} else {
2349+
bindPose = unityBone.worldToLocalMatrix * skinnedMesh.transform.localToWorldMatrix;
2350+
}
2351+
2352+
Matrix4x4 pose;
2353+
if (unityBone == rootBone) {
2354+
pose = (unityBone.parent.worldToLocalMatrix * skinnedMesh.transform.localToWorldMatrix * bindPose.inverse);
2355+
} else {
2356+
// get parent's bind pose
2357+
int pIndex;
2358+
Matrix4x4 parentBindPose;
2359+
if (boneDict.TryGetValue (unityBone.parent, out pIndex)) {
2360+
parentBindPose = bindPoses [pIndex];
2361+
} else {
2362+
parentBindPose = unityBone.parent.worldToLocalMatrix * skinnedMesh.transform.localToWorldMatrix;
2363+
}
2364+
2365+
pose = parentBindPose * bindPose.inverse;
2366+
}
2367+
2368+
// FBX is transposed relative to Unity: transpose as we convert.
2369+
FbxMatrix matrix = new FbxMatrix ();
2370+
matrix.SetColumn (0, new FbxVector4 (pose.GetRow (0).x, pose.GetRow (0).y, pose.GetRow (0).z, pose.GetRow (0).w));
2371+
matrix.SetColumn (1, new FbxVector4 (pose.GetRow (1).x, pose.GetRow (1).y, pose.GetRow (1).z, pose.GetRow (1).w));
2372+
matrix.SetColumn (2, new FbxVector4 (pose.GetRow (2).x, pose.GetRow (2).y, pose.GetRow (2).z, pose.GetRow (2).w));
2373+
matrix.SetColumn (3, new FbxVector4 (pose.GetRow (3).x, pose.GetRow (3).y, pose.GetRow (3).z, pose.GetRow (3).w));
2374+
2375+
// FBX wants translation, rotation (in euler angles) and scale.
2376+
// We assume there's no real shear, just rounding error.
2377+
FbxVector4 translation, rotation, shear, scale;
2378+
double sign;
2379+
matrix.GetElements (out translation, out rotation, out shear, out scale, out sign);
2380+
2381+
// Export bones with zero rotation, using a pivot instead to set the rotation
2382+
// so that the bones are easier to animate and the rotation shows up as the "joint orientation" in Maya.
2383+
fbxNode.LclTranslation.Set (new FbxDouble3(-translation.X*UnitScaleFactor, translation.Y*UnitScaleFactor, translation.Z*UnitScaleFactor));
2384+
fbxNode.LclRotation.Set (new FbxDouble3(0,0,0));
2385+
fbxNode.LclScaling.Set (new FbxDouble3 (scale.X, scale.Y, scale.Z));
2386+
2387+
// TODO (UNI-34294): add detailed comment about why we export rotation as pre-rotation
2388+
fbxNode.SetRotationActive (true);
2389+
fbxNode.SetPivotState (FbxNode.EPivotSet.eSourcePivot, FbxNode.EPivotState.ePivotReference);
2390+
fbxNode.SetPreRotation (FbxNode.EPivotSet.eSourcePivot, new FbxVector4 (rotation.X, -rotation.Y, -rotation.Z));
2391+
2392+
return true;
2393+
}
2394+
2395+
protected int AnimOnlyHierarchyCount(
2396+
HashSet<GameObject> exportSet,
2397+
out HashSet<AnimationClip> animationClips,
2398+
out Dictionary<GameObject, HashSet<GameObject>> mapGameObjectToExportSet,
2399+
out Dictionary<GameObject, System.Type> exportComponent
2400+
){
2401+
animationClips = new HashSet<AnimationClip> ();
2402+
mapGameObjectToExportSet = new Dictionary<GameObject, HashSet<GameObject>> ();
2403+
exportComponent = new Dictionary<GameObject, System.Type> ();
2404+
2405+
foreach (var go in exportSet) {
2406+
// gather all animation clips
2407+
var legacyAnim = go.GetComponentsInChildren<Animation>();
2408+
var genericAnim = go.GetComponentsInChildren<Animator> ();
2409+
2410+
var goToExport = new HashSet<GameObject> ();
2411+
mapGameObjectToExportSet.Add (go, goToExport);
2412+
2413+
foreach (var anim in legacyAnim) {
2414+
var animClips = AnimationUtility.GetAnimationClips (anim.gameObject);
2415+
GetObjectsInAnimationClips (animClips, anim.gameObject, ref animationClips, ref goToExport, ref exportComponent);
2416+
}
2417+
2418+
foreach (var anim in genericAnim) {
2419+
// Try the animator controller (mecanim)
2420+
var controller = anim.runtimeAnimatorController;
2421+
if (controller)
2422+
{
2423+
GetObjectsInAnimationClips (controller.animationClips, anim.gameObject, ref animationClips, ref goToExport, ref exportComponent);
2424+
}
2425+
}
2426+
}
2427+
2428+
int count = 0;
2429+
foreach (var es in mapGameObjectToExportSet.Values) {
2430+
count += es.Count;
2431+
}
2432+
2433+
return count;
2434+
}
2435+
2436+
protected void GetObjectsInAnimationClips(
2437+
AnimationClip[] animClips,
2438+
GameObject animationRootObject,
2439+
ref HashSet<AnimationClip> clipSet,
2440+
ref HashSet<GameObject> goToExport,
2441+
ref Dictionary<GameObject, System.Type> exportComponent
2442+
){
2443+
var cameraProps = new List<string>{"field of view"};
2444+
var lightProps = new List<string>{"m_Intensity", "m_SpotAngle", "m_Color.r", "m_Color.g", "m_Color.b"};
2445+
2446+
foreach (var animClip in animClips) {
2447+
if (!clipSet.Add (animClip)) {
2448+
// we have already exported gameobjects for this clip
2449+
continue;
2450+
}
2451+
2452+
foreach (EditorCurveBinding uniCurveBinding in AnimationUtility.GetCurveBindings (animClip)) {
2453+
Object uniObj = AnimationUtility.GetAnimatedObject (animationRootObject, uniCurveBinding);
2454+
if (!uniObj) {
2455+
continue;
2456+
}
2457+
//Debug.LogWarning (uniObj.name + ": " + uniCurveBinding.propertyName);
2458+
2459+
GameObject unityGo = GetGameObject (uniObj);
2460+
if (!unityGo) {
2461+
continue;
2462+
}
2463+
2464+
if (lightProps.Contains (uniCurveBinding.propertyName)) {
2465+
exportComponent.Add (unityGo, typeof(Light));
2466+
} else if (cameraProps.Contains (uniCurveBinding.propertyName)) {
2467+
exportComponent.Add (unityGo, typeof(Camera));
2468+
}
2469+
2470+
goToExport.Add (unityGo);
2471+
}
2472+
}
2473+
}
2474+
2475+
/*protected bool ExportAnimationOnly(GameObject unityGo, FbxScene fbxScene){
21802476
// gather all animation clips
21812477
var legacyAnim = unityGo.GetComponentsInChildren<Animation>();
21822478
var genericAnim = unityGo.GetComponentsInChildren<Animator> ();
@@ -2234,10 +2530,14 @@ private bool ExportAnimatedGameObjects(AnimationClip[] animClips, GameObject ani
22342530
}
22352531
FbxNode fbxNode;
22362532
ExportGameObjectAndParents (unityGo, exportRoot, fbxScene, out fbxNode);
2533+
2534+
// TODO: export animated components
2535+
// check if animated property is part of a light or a camera and export accordingly
22372536
}
2238-
}
22392537
2240-
return false;
2538+
ExportAnimationClip (animClip, animationRootObject, fbxScene);
2539+
}
2540+
return true;
22412541
}
22422542
22432543
private bool ExportGameObjectAndParents(GameObject unityGo, GameObject rootObject, FbxScene fbxScene, out FbxNode fbxNode){
@@ -2261,6 +2561,8 @@ private bool ExportGameObjectAndParents(GameObject unityGo, GameObject rootObjec
22612561
// Use RSrs as the scaling inhertiance instead.
22622562
fbxNode.SetTransformationInheritType (FbxTransform.EInheritType.eInheritRSrs);
22632563
2564+
// TODO: check if GO is a bone and export accordingly
2565+
22642566
ExportTransform (unityGo.transform, fbxNode, Vector3.zero, TransformExportType.Local);//newCenter, exportType);
22652567
22662568
if (unityGo.transform.parent != null || unityGo.transform.parent != rootObject.transform.parent) {
@@ -2273,12 +2575,11 @@ private bool ExportGameObjectAndParents(GameObject unityGo, GameObject rootObjec
22732575
}
22742576
22752577
if (unityGo == rootObject) {
2276-
Debug.Log ("over here");
22772578
fbxScene.GetRootNode ().AddChild (fbxNode);
22782579
}
22792580
22802581
return true;
2281-
}
2582+
}*/
22822583

22832584
/// <summary>
22842585
/// Export components on this game object.
@@ -2578,7 +2879,23 @@ public int ExportAll (IEnumerable<UnityEngine.Object> unityExportSet)
25782879
var revisedExportSet = RemoveRedundantObjects(unityExportSet);
25792880
int count = GetHierarchyCount (revisedExportSet);
25802881

2581-
if(revisedExportSet.Count == 1){
2882+
Vector3 center = Vector3.zero;
2883+
var exportType = TransformExportType.Reset;
2884+
if(revisedExportSet.Count != 1){
2885+
center = ExportSettings.centerObjects? FindCenter(revisedExportSet) : Vector3.zero;
2886+
exportType = TransformExportType.Global;
2887+
}
2888+
2889+
foreach (var unityGo in revisedExportSet) {
2890+
exportProgress = this.ExportTransformHierarchy (unityGo, fbxScene, fbxRootNode,
2891+
exportProgress, count, center, exportType);
2892+
if (exportCancelled || exportProgress < 0) {
2893+
Debug.LogWarning ("Export Cancelled");
2894+
return 0;
2895+
}
2896+
}
2897+
2898+
/*if(revisedExportSet.Count == 1){
25822899
foreach(var unityGo in revisedExportSet){
25832900
exportProgress = this.ExportTransformHierarchy (
25842901
unityGo, fbxScene, fbxRootNode, exportProgress,
@@ -2601,7 +2918,7 @@ public int ExportAll (IEnumerable<UnityEngine.Object> unityExportSet)
26012918
return 0;
26022919
}
26032920
}
2604-
}
2921+
}*/
26052922

26062923
if(!ExportComponents(fbxScene)){
26072924
Debug.LogWarning ("Export Cancelled");

0 commit comments

Comments
 (0)