@@ -1889,8 +1889,8 @@ protected void ExportAnimationClip (AnimationClip uniAnimClip, GameObject uniRoo
1889
1889
/// Transfers transform animation from source to dest. Replaces dest's Unity Animation Curves with updated animations.
1890
1890
/// NOTE: Source must be the parent of dest.
1891
1891
/// </summary>
1892
- /// <param name="source">Source.</param>
1893
- /// <param name="dest">Destination.</param>
1892
+ /// <param name="source">Source animated object .</param>
1893
+ /// <param name="dest">Destination, child of the source .</param>
1894
1894
/// <param name="sampleRate">Sample rate.</param>
1895
1895
/// <param name="unityCurves">Unity curves.</param>
1896
1896
private void TransferMotion ( Transform source , Transform dest , float sampleRate , ref Dictionary < GameObject , List < UnityCurve > > unityCurves ) {
@@ -1933,14 +1933,23 @@ private void TransferMotion(Transform source, Transform dest, float sampleRate,
1933
1933
scaleKeyFrames [ k ] = new Keyframe [ sampleTimes . Count ] ;
1934
1934
}
1935
1935
1936
+ // If we have a point in local coords represented as a column-vector x, the equation of x in coordinates relative to source's parent is:
1937
+ // x_grandparent = source * dest * x
1938
+ // Now we're going to change dest to dest' which has the animation from source. And we're going to change
1939
+ // source to source' which has no animation. The equation of x will become:
1940
+ // x_grandparent = source' * dest' * x
1941
+ // We're not changing x_grandparent and x, so we need that:
1942
+ // source * dest = source' * dest'
1943
+ // We know dest and source (both animated) and source' (static). Solve for dest':
1944
+ // dest' = (source')^-1 * source * dest
1936
1945
int keyIndex = 0 ;
1946
+ var sourceStaticMatrixInverse = Matrix4x4 . TRS ( source . localPosition , source . localRotation , source . localScale ) . inverse ;
1937
1947
foreach ( var currSampleTime in sampleTimes )
1938
1948
{
1939
1949
var sourceLocalMatrix = GetTransformMatrix ( currSampleTime , source , sourceUnityCurves ) ;
1940
1950
var destLocalMatrix = GetTransformMatrix ( currSampleTime , dest , destUnityCurves ) ;
1941
1951
1942
- // child * parent
1943
- var newLocalMatrix = sourceLocalMatrix * destLocalMatrix ;
1952
+ var newLocalMatrix = sourceStaticMatrixInverse * sourceLocalMatrix * destLocalMatrix ;
1944
1953
1945
1954
FbxVector4 translation , rotation , scale ;
1946
1955
GetTRSFromMatrix ( newLocalMatrix , out translation , out rotation , out scale ) ;
@@ -2227,9 +2236,6 @@ protected int ExportTransformHierarchy(
2227
2236
// Use RSrs as the scaling inheritance instead.
2228
2237
fbxNode . SetTransformationInheritType ( FbxTransform . EInheritType . eInheritRSrs ) ;
2229
2238
2230
- if ( TransformShouldBeReset ( unityGo . transform ) ) {
2231
- exportType = TransformExportType . Reset ;
2232
- }
2233
2239
ExportTransform ( unityGo . transform , fbxNode , newCenter , exportType ) ;
2234
2240
2235
2241
fbxNodeParent . AddChild ( fbxNode ) ;
@@ -2278,35 +2284,6 @@ protected int ExportTransformHierarchy(
2278
2284
return numObjectsExported ;
2279
2285
}
2280
2286
2281
- /// <summary>
2282
- /// Checks if the transform should be reset.
2283
- /// Transform should be reset if animation is being transferred, and this transform
2284
- /// is either the animation source, destination, or between these nodes.
2285
- /// </summary>
2286
- /// <returns><c>true</c>, if transform should be reset, <c>false</c> otherwise.</returns>
2287
- /// <param name="t">Transform.</param>
2288
- private bool TransformShouldBeReset ( Transform t ) {
2289
- var source = ExportOptions . AnimationSource ;
2290
- var dest = ExportOptions . AnimationDest ;
2291
-
2292
- if ( ! source || ! dest || source == dest ) {
2293
- return false ;
2294
- }
2295
-
2296
- // don't want to reset destination, if it's a bone this could cause issues with the skinning
2297
- var curr = dest . parent ;
2298
- while ( curr != source && curr != null ) {
2299
- if ( t == curr ) {
2300
- return true ;
2301
- }
2302
- curr = curr . parent ;
2303
- }
2304
- if ( t == source ) {
2305
- return true ;
2306
- }
2307
- return false ;
2308
- }
2309
-
2310
2287
/// <summary>
2311
2288
/// Export data containing what to export when
2312
2289
/// exporting animation only.
@@ -2325,10 +2302,6 @@ public struct AnimationOnlyExportData {
2325
2302
// first clip to export
2326
2303
public AnimationClip defaultClip ;
2327
2304
2328
- // TODO: find a better way to keep track of which components + properties we support
2329
- private static List < string > cameraProps = new List < string > { "field of view" } ;
2330
- private static List < string > lightProps = new List < string > { "m_Intensity" , "m_SpotAngle" , "m_Color.r" , "m_Color.g" , "m_Color.b" } ;
2331
-
2332
2305
public AnimationOnlyExportData (
2333
2306
Dictionary < AnimationClip , GameObject > animClips ,
2334
2307
HashSet < GameObject > exportSet ,
@@ -2345,6 +2318,9 @@ public void ComputeObjectsInAnimationClips(
2345
2318
GameObject animationRootObject ,
2346
2319
bool exportSkinnedMeshAnim = true
2347
2320
) {
2321
+ // NOTE: the object (animationRootObject) containing the animation is not necessarily animated
2322
+ // when driven by an animator or animation component.
2323
+
2348
2324
foreach ( var animClip in animClips ) {
2349
2325
if ( this . animationClips . ContainsKey ( animClip ) ) {
2350
2326
// we have already exported gameobjects for this clip
@@ -2368,11 +2344,12 @@ public void ComputeObjectsInAnimationClips(
2368
2344
continue ;
2369
2345
}
2370
2346
2371
- if ( lightProps . Contains ( uniCurveBinding . propertyName ) ) {
2372
- this . exportComponent . Add ( unityGo , typeof ( Light ) ) ;
2373
- } else if ( cameraProps . Contains ( uniCurveBinding . propertyName ) ) {
2374
- this . exportComponent . Add ( unityGo , typeof ( Camera ) ) ;
2375
- }
2347
+ // If we have a clip driving a camera or light then force the export of FbxNodeAttribute
2348
+ // so that they point the right way when imported into Maya.
2349
+ if ( unityGo . GetComponent < Light > ( ) )
2350
+ this . exportComponent [ unityGo ] = typeof ( Light ) ;
2351
+ else if ( unityGo . GetComponent < Camera > ( ) )
2352
+ this . exportComponent [ unityGo ] = typeof ( Camera ) ;
2376
2353
2377
2354
this . goExportSet . Add ( unityGo ) ;
2378
2355
}
@@ -2534,9 +2511,6 @@ private bool ExportGameObjectAndParents(
2534
2511
2535
2512
// export regular transform if we are not a bone or failed to export as a bone
2536
2513
if ( ! exportedBoneTransform ) {
2537
- if ( TransformShouldBeReset ( unityGo . transform ) ) {
2538
- exportType = TransformExportType . Reset ;
2539
- }
2540
2514
ExportTransform ( unityGo . transform , fbxNode , newCenter , exportType ) ;
2541
2515
}
2542
2516
@@ -3339,7 +3313,7 @@ public static void ExportSingleTimelineClip(TimelineClip timelineClipSelected, G
3339
3313
} ;
3340
3314
3341
3315
if ( ! string . IsNullOrEmpty ( filePath ) ) {
3342
- ExportObjects ( filePath , exportArray , timelineAnim : true ) ;
3316
+ ExportObjects ( filePath , exportArray ) ;
3343
3317
return ;
3344
3318
}
3345
3319
@@ -3372,7 +3346,7 @@ public static void ExportAllTimelineClips(GameObject objectWithPlayableDirector,
3372
3346
}
3373
3347
string filePath = string . Format ( AnimFbxFormat , folderPath , atObject . name , timelineClip . displayName ) ;
3374
3348
UnityEngine . Object [ ] myArray = new UnityEngine . Object [ ] { atObject , timelineClip . animationClip } ;
3375
- ExportObjects ( filePath , myArray , exportOptions , timelineAnim : true ) ;
3349
+ ExportObjects ( filePath , myArray , exportOptions ) ;
3376
3350
}
3377
3351
}
3378
3352
}
@@ -3866,8 +3840,7 @@ private static void OnExport ()
3866
3840
public static string ExportObjects (
3867
3841
string filePath ,
3868
3842
UnityEngine . Object [ ] objects = null ,
3869
- IExportOptions exportOptions = null ,
3870
- bool timelineAnim = false )
3843
+ IExportOptions exportOptions = null )
3871
3844
{
3872
3845
LastFilePath = filePath ;
3873
3846
@@ -3881,7 +3854,8 @@ public static string ExportObjects (
3881
3854
}
3882
3855
3883
3856
Dictionary < GameObject , AnimationOnlyExportData > animationExportData = null ;
3884
- if ( timelineAnim ) {
3857
+ // if there are only two objects for export and the second is an animation clip, then we are exporting from the timeline
3858
+ if ( objects . Length == 2 && objects [ 1 ] is AnimationClip ) {
3885
3859
// We expect the first argument in the list to be the GameObject, the second one is the Animation Clip/Track we are exporting from the timeline
3886
3860
GameObject rootObject = ModelExporter . GetGameObject ( objects [ 0 ] ) ;
3887
3861
AnimationClip timelineClip = objects [ 1 ] as AnimationClip ;
@@ -3909,10 +3883,9 @@ public static string ExportObjects (
3909
3883
3910
3884
public static string ExportObject (
3911
3885
string filePath , UnityEngine . Object root ,
3912
- IExportOptions exportOptions = null ,
3913
- bool isTimelineAnim = false )
3886
+ IExportOptions exportOptions = null )
3914
3887
{
3915
- return ExportObjects ( filePath , new Object [ ] { root } , exportOptions , isTimelineAnim ) ;
3888
+ return ExportObjects ( filePath , new Object [ ] { root } , exportOptions ) ;
3916
3889
}
3917
3890
3918
3891
private static void EnsureDirectory ( string path )
0 commit comments