@@ -1444,13 +1444,111 @@ protected bool ExportLight (GameObject unityGo, FbxScene fbxScene, FbxNode fbxNo
1444
1444
return true ;
1445
1445
}
1446
1446
1447
+ /// <summary>
1448
+ /// Export animation curve key frames with key tangents
1449
+ /// </summary>
1450
+ protected void ExportAnimationKeyFrames ( AnimationCurve uniAnimCurve , FbxAnimCurve fbxAnimCurve ,
1451
+ UnityToMayaConvertSceneHelper convertSceneHelper )
1452
+ {
1453
+ // TODO: map key tangents mode between Unity and FBX
1454
+ Dictionary < AnimationUtility . TangentMode , List < FbxAnimCurveDef . ETangentMode > > MapUnityKeyTangentModeToFBX =
1455
+ new Dictionary < AnimationUtility . TangentMode , List < FbxAnimCurveDef . ETangentMode > >
1456
+ {
1457
+ //TangeantAuto|GenericTimeIndependent|GenericClampProgressive
1458
+ { AnimationUtility . TangentMode . Free , new List < FbxAnimCurveDef . ETangentMode > { FbxAnimCurveDef . ETangentMode . eTangentAuto , FbxAnimCurveDef . ETangentMode . eTangentGenericClampProgressive } } ,
1459
+
1460
+ //TangeantAuto|GenericTimeIndependent
1461
+ { AnimationUtility . TangentMode . Auto , new List < FbxAnimCurveDef . ETangentMode > { FbxAnimCurveDef . ETangentMode . eTangentAuto , FbxAnimCurveDef . ETangentMode . eTangentGenericTimeIndependent } } ,
1462
+
1463
+ //TangeantAuto|GenericTimeIndependent|GenericClampProgressive
1464
+ { AnimationUtility . TangentMode . ClampedAuto , new List < FbxAnimCurveDef . ETangentMode > { FbxAnimCurveDef . ETangentMode . eTangentAuto , FbxAnimCurveDef . ETangentMode . eTangentGenericClampProgressive } } ,
1465
+ } ;
1466
+
1467
+ // Copy Unity AnimCurve to FBX AnimCurve.
1468
+ // NOTE: only cubic keys are supported by the FbxImporter
1469
+ using ( new FbxAnimCurveModifyHelper ( new List < FbxAnimCurve > { fbxAnimCurve } ) )
1470
+ {
1471
+ for ( int keyIndex = 0 ; keyIndex < uniAnimCurve . length ; ++ keyIndex )
1472
+ {
1473
+ var uniKeyFrame = uniAnimCurve [ keyIndex ] ;
1474
+ var fbxTime = FbxTime . FromSecondDouble ( uniKeyFrame . time ) ;
1475
+
1476
+ int fbxKeyIndex = fbxAnimCurve . KeyAdd ( fbxTime ) ;
1477
+
1478
+ fbxAnimCurve . KeySet ( fbxKeyIndex ,
1479
+ fbxTime ,
1480
+ convertSceneHelper . Convert ( uniKeyFrame . value )
1481
+ ) ;
1482
+
1483
+ // configure tangents
1484
+ var lTangent = AnimationUtility . GetKeyLeftTangentMode ( uniAnimCurve , keyIndex ) ;
1485
+ var rTangent = AnimationUtility . GetKeyRightTangentMode ( uniAnimCurve , keyIndex ) ;
1486
+
1487
+ if ( ! ( MapUnityKeyTangentModeToFBX . ContainsKey ( lTangent ) && MapUnityKeyTangentModeToFBX . ContainsKey ( rTangent ) ) )
1488
+ {
1489
+ Debug . LogWarning ( string . Format ( "key[{0}] missing tangent mapping ({1},{2})" , keyIndex , lTangent . ToString ( ) , rTangent . ToString ( ) ) ) ;
1490
+ continue ;
1491
+ }
1492
+
1493
+ // TODO : handle broken tangents
1494
+
1495
+ // TODO : set key tangents
1496
+ }
1497
+ }
1498
+ }
1499
+
1500
+ /// <summary>
1501
+ /// Export animation curve key samples
1502
+ /// </summary>
1503
+ protected void ExportAnimationSamples ( AnimationCurve uniAnimCurve , FbxAnimCurve fbxAnimCurve ,
1504
+ double sampleRate ,
1505
+ UnityToMayaConvertSceneHelper convertSceneHelper )
1506
+ {
1507
+ using ( new FbxAnimCurveModifyHelper ( new List < FbxAnimCurve > { fbxAnimCurve } ) )
1508
+ {
1509
+ double fs = 1.0 / sampleRate ;
1510
+ int numKeys = uniAnimCurve . length ;
1511
+
1512
+ int numSamples = 0 ;
1513
+ int sampleIndex = 0 ;
1514
+ double currSample = double . MaxValue , firstTime = double . MaxValue , lastTime = double . MaxValue ;
1515
+
1516
+ if ( numKeys > 0 )
1517
+ {
1518
+ firstTime = uniAnimCurve [ 0 ] . time ;
1519
+ lastTime = uniAnimCurve [ uniAnimCurve . length - 1 ] . time ;
1520
+
1521
+ numSamples = ( int ) ( ( float ) ( ( lastTime - firstTime ) * sampleRate ) ) ;
1522
+ Debug . Log ( string . Format ( "Exporting Animation Samples : firstTime={0}, lastTime={1} frameRate={2} numSamples={3}" ,
1523
+ firstTime , lastTime , sampleRate , numSamples ) ) ;
1524
+
1525
+ currSample = firstTime ;
1526
+ }
1527
+
1528
+ for ( sampleIndex = 0 , currSample = firstTime ; currSample < lastTime ; ++ sampleIndex , currSample += fs )
1529
+ {
1530
+ float currSampleValue = uniAnimCurve . Evaluate ( ( float ) currSample ) ;
1531
+
1532
+ var fbxTime = FbxTime . FromSecondDouble ( currSample ) ;
1533
+
1534
+ int fbxKeyIndex = fbxAnimCurve . KeyAdd ( fbxTime ) ;
1535
+
1536
+ fbxAnimCurve . KeySet ( fbxKeyIndex ,
1537
+ fbxTime ,
1538
+ convertSceneHelper . Convert ( currSampleValue )
1539
+ ) ;
1540
+ }
1541
+ }
1542
+ }
1543
+
1447
1544
/// <summary>
1448
1545
/// Export an AnimationCurve.
1449
1546
/// NOTE: This is not used for rotations, because we need to convert from
1450
1547
/// quaternion to euler and various other stuff.
1451
1548
/// </summary>
1452
1549
protected void ExportAnimationCurve ( UnityEngine . Object uniObj ,
1453
1550
AnimationCurve uniAnimCurve ,
1551
+ float frameRate ,
1454
1552
string uniPropertyName ,
1455
1553
FbxScene fbxScene ,
1456
1554
FbxAnimLayer fbxAnimLayer )
@@ -1477,6 +1575,7 @@ protected void ExportAnimationCurve (UnityEngine.Object uniObj,
1477
1575
Debug . LogError ( string . Format ( "no fbx node for {0}" , unityGo . ToString ( ) ) ) ;
1478
1576
return ;
1479
1577
}
1578
+
1480
1579
// map unity property name to fbx property
1481
1580
var fbxProperty = fbxNode . FindProperty ( fbxPropertyChannelPair . Property , false ) ;
1482
1581
if ( ! fbxProperty . IsValid ( ) )
@@ -1496,70 +1595,24 @@ protected void ExportAnimationCurve (UnityEngine.Object uniObj,
1496
1595
// Create the AnimCurve on the channel
1497
1596
FbxAnimCurve fbxAnimCurve = fbxProperty . GetCurve ( fbxAnimLayer , fbxPropertyChannelPair . Channel , true ) ;
1498
1597
1499
- var transformBindings = new UnityToMayaConvertSceneHelper ( uniPropertyName ) ;
1500
-
1501
- // TODO: read the curve interpolation
1502
- FbxAnimCurveDef . EInterpolationType fbxInterpolation =
1503
- FbxAnimCurveDef . EInterpolationType . eInterpolationCubic ;
1598
+ // create a convert scene helper so that we can convert from Unity to Maya
1599
+ // AxisSystem (LeftHanded to RightHanded) and FBX's default units
1600
+ // (Meters to Centimetres)
1601
+ var convertSceneHelper = new UnityToMayaConvertSceneHelper ( uniPropertyName ) ;
1504
1602
1505
- Dictionary < AnimationUtility . TangentMode , List < FbxAnimCurveDef . ETangentMode > > MapUnityKeyTangentModeToFBX =
1506
- new Dictionary < AnimationUtility . TangentMode , List < FbxAnimCurveDef . ETangentMode > >
1603
+ // TODO: we'll resample the curve so we don't have to
1604
+ // configure tangents
1605
+ if ( ModelExporter . ExportSettings . BakeAnimation )
1507
1606
{
1508
- //TangeantAuto|GenericTimeIndependent|GenericClampProgressive
1509
- { AnimationUtility . TangentMode . Free , new List < FbxAnimCurveDef . ETangentMode > { FbxAnimCurveDef . ETangentMode . eTangentAuto , FbxAnimCurveDef . ETangentMode . eTangentGenericClampProgressive } } ,
1510
-
1511
- //TangeantAuto|GenericTimeIndependent
1512
- { AnimationUtility . TangentMode . Auto , new List < FbxAnimCurveDef . ETangentMode > { FbxAnimCurveDef . ETangentMode . eTangentAuto , FbxAnimCurveDef . ETangentMode . eTangentGenericTimeIndependent } } ,
1513
-
1514
- //TangeantAuto|GenericTimeIndependent|GenericClampProgressive
1515
- { AnimationUtility . TangentMode . ClampedAuto , new List < FbxAnimCurveDef . ETangentMode > { FbxAnimCurveDef . ETangentMode . eTangentAuto , FbxAnimCurveDef . ETangentMode . eTangentGenericClampProgressive } } ,
1516
- } ;
1517
-
1518
-
1519
- // copy Unity AnimCurve to FBX AnimCurve.
1520
- fbxAnimCurve . KeyModifyBegin ( ) ;
1521
-
1522
- for ( int keyIndex = 0 , n = uniAnimCurve . length ; keyIndex < n ; ++ keyIndex ) {
1523
- var uniKeyFrame = uniAnimCurve [ keyIndex ] ;
1524
- var fbxTime = FbxTime . FromSecondDouble ( uniKeyFrame . time ) ;
1525
-
1526
- keyIndex = fbxAnimCurve . KeyAdd ( fbxTime ) ;
1527
-
1528
- fbxAnimCurve . KeySet ( keyIndex ,
1529
- fbxTime ,
1530
- transformBindings . Convert ( uniKeyFrame . value ) ,
1531
- fbxInterpolation
1532
- ) ;
1533
-
1534
- if ( fbxInterpolation == FbxAnimCurveDef . EInterpolationType . eInterpolationCubic )
1535
- {
1536
- var lTangent = AnimationUtility . GetKeyLeftTangentMode ( uniAnimCurve , keyIndex ) ;
1537
- var rTangent = AnimationUtility . GetKeyRightTangentMode ( uniAnimCurve , keyIndex ) ;
1538
-
1539
- if ( ! MapUnityKeyTangentModeToFBX . ContainsKey ( lTangent ) )
1540
- {
1541
- Debug . LogWarning ( string . Format ( "key[{0}] missing tangent mapping ({1})" , keyIndex , lTangent . ToString ( ) ) ) ;
1542
- continue ;
1543
- }
1544
-
1545
- // TODO : handle broken tangents
1546
- if ( lTangent != rTangent )
1547
- {
1548
- Debug . LogWarning ( string . Format ( "key[{0}] broken tangents ({1},{2}) not supported" , keyIndex , lTangent . ToString ( ) , rTangent . ToString ( ) ) ) ;
1549
- }
1550
-
1551
- foreach ( FbxAnimCurveDef . ETangentMode fbxKeyTangentMode in MapUnityKeyTangentModeToFBX [ lTangent ] )
1552
- {
1553
- fbxAnimCurve . KeySetTangentMode ( keyIndex , fbxKeyTangentMode ) ;
1554
- }
1555
-
1556
- }
1607
+ ExportAnimationSamples ( uniAnimCurve , fbxAnimCurve , frameRate , convertSceneHelper ) ;
1608
+ }
1609
+ else
1610
+ {
1611
+ ExportAnimationKeyFrames ( uniAnimCurve , fbxAnimCurve , convertSceneHelper ) ;
1557
1612
}
1558
-
1559
- fbxAnimCurve . KeyModifyEnd ( ) ;
1560
1613
}
1561
1614
1562
- class UnityToMayaConvertSceneHelper
1615
+ public class UnityToMayaConvertSceneHelper
1563
1616
{
1564
1617
bool convertDistance = false ;
1565
1618
bool convertLtoR = false ;
@@ -1699,6 +1752,33 @@ public static bool TryGetValue(string uniPropertyName, out FbxPropertyChannelPai
1699
1752
}
1700
1753
}
1701
1754
1755
+ /// <summary>
1756
+ /// Exporting rotations is more complicated. We need to convert
1757
+ /// from quaternion to euler. We use this class to help.
1758
+ /// </summary>
1759
+ class FbxAnimCurveModifyHelper : System . IDisposable
1760
+ {
1761
+ public List < FbxAnimCurve > Curves { get ; private set ; }
1762
+
1763
+ public FbxAnimCurveModifyHelper ( List < FbxAnimCurve > list )
1764
+ {
1765
+ Curves = list ;
1766
+
1767
+ foreach ( var curve in Curves )
1768
+ curve . KeyModifyBegin ( ) ;
1769
+ }
1770
+
1771
+ ~ FbxAnimCurveModifyHelper ( ) {
1772
+ Dispose ( ) ;
1773
+ }
1774
+
1775
+ public void Dispose ( )
1776
+ {
1777
+ foreach ( var curve in Curves )
1778
+ curve . KeyModifyEnd ( ) ;
1779
+ }
1780
+ }
1781
+
1702
1782
/// <summary>
1703
1783
/// Exporting rotations is more complicated. We need to convert
1704
1784
/// from quaternion to euler. We use this class to help.
@@ -1818,27 +1898,21 @@ public void Animate(Transform unityTransform, FbxNode fbxNode, FbxAnimLayer fbxA
1818
1898
var fbxAnimCurveZ = fbxNode . LclRotation . GetCurve ( fbxAnimLayer , Globals . FBXSDK_CURVENODE_COMPONENT_Z , true ) ;
1819
1899
1820
1900
/* set the keys */
1821
- fbxAnimCurveX . KeyModifyBegin ( ) ;
1822
- fbxAnimCurveY . KeyModifyBegin ( ) ;
1823
- fbxAnimCurveZ . KeyModifyBegin ( ) ;
1901
+ using ( new FbxAnimCurveModifyHelper ( new List < FbxAnimCurve > { fbxAnimCurveX , fbxAnimCurveY , fbxAnimCurveZ } ) )
1902
+ {
1903
+ foreach ( var key in ComputeKeys ( unityTransform . localRotation , fbxNode ) ) {
1824
1904
1825
- var keys = ComputeKeys ( unityTransform . localRotation , fbxNode ) ;
1826
- for ( int i = 0 , n = keys . Length ; i < n ; ++ i ) {
1827
- var key = keys [ i ] ;
1828
- fbxAnimCurveX . KeyAdd ( key . time ) ;
1829
- fbxAnimCurveX . KeySet ( i , key . time , ( float ) key . euler . X ) ;
1905
+ int i = fbxAnimCurveX . KeyAdd ( key . time ) ;
1906
+ fbxAnimCurveX . KeySet ( i , key . time , ( float ) key . euler . X ) ;
1830
1907
1831
- fbxAnimCurveY . KeyAdd ( key . time ) ;
1832
- fbxAnimCurveY . KeySet ( i , key . time , ( float ) key . euler . Y ) ;
1908
+ i = fbxAnimCurveY . KeyAdd ( key . time ) ;
1909
+ fbxAnimCurveY . KeySet ( i , key . time , ( float ) key . euler . Y ) ;
1833
1910
1834
- fbxAnimCurveZ . KeyAdd ( key . time ) ;
1835
- fbxAnimCurveZ . KeySet ( i , key . time , ( float ) key . euler . Z ) ;
1911
+ i = fbxAnimCurveZ . KeyAdd ( key . time ) ;
1912
+ fbxAnimCurveZ . KeySet ( i , key . time , ( float ) key . euler . Z ) ;
1913
+ }
1836
1914
}
1837
1915
1838
- fbxAnimCurveZ . KeyModifyEnd ( ) ;
1839
- fbxAnimCurveY . KeyModifyEnd ( ) ;
1840
- fbxAnimCurveX . KeyModifyEnd ( ) ;
1841
-
1842
1916
// Uni-35616 unroll curves to preserve continuous rotations
1843
1917
var fbxCurveNode = fbxNode . LclRotation . GetCurveNode ( fbxAnimLayer , false /*should already exist*/ ) ;
1844
1918
@@ -1911,8 +1985,10 @@ protected void ExportAnimationClip (AnimationClip uniAnimClip, GameObject uniRoo
1911
1985
if ( index == - 1 )
1912
1986
{
1913
1987
/* simple property (e.g. intensity), export right away */
1914
- ExportAnimationCurve ( uniObj , uniAnimCurve , uniCurveBinding . propertyName ,
1915
- fbxScene , fbxAnimLayer ) ;
1988
+ ExportAnimationCurve ( uniObj , uniAnimCurve , uniAnimClip . frameRate ,
1989
+ uniCurveBinding . propertyName ,
1990
+ fbxScene ,
1991
+ fbxAnimLayer ) ;
1916
1992
} else {
1917
1993
/* Rotation property; save it to convert quaternion -> euler later. */
1918
1994
@@ -2951,7 +3027,7 @@ public void Dispose ()
2951
3027
{
2952
3028
}
2953
3029
2954
- public bool Verbose { private set { ; } get { return false ; } }
3030
+ public bool Verbose { private set { ; } get { return true ; } }
2955
3031
2956
3032
/// <summary>
2957
3033
/// manage the selection of a filename
0 commit comments