@@ -1715,6 +1715,13 @@ internal static HashSet<float> GetSampleTimes(AnimationCurve[] animCurves, doubl
1715
1715
lastTime = System . Math . Max ( lastTime , ac [ ac . length - 1 ] . time ) ;
1716
1716
}
1717
1717
1718
+ // if these values didn't get set there were no valid anim curves,
1719
+ // so don't return any keys
1720
+ if ( firstTime == double . MaxValue || lastTime == double . MinValue )
1721
+ {
1722
+ return keyTimes ;
1723
+ }
1724
+
1718
1725
int firstframe = ( int ) System . Math . Floor ( firstTime * sampleRate ) ;
1719
1726
int lastframe = ( int ) System . Math . Ceiling ( lastTime * sampleRate ) ;
1720
1727
for ( int i = firstframe ; i <= lastframe ; i ++ ) {
@@ -1745,23 +1752,9 @@ internal static HashSet<float> GetKeyTimes(AnimationCurve[] animCurves)
1745
1752
/// NOTE : This is a work in progress (WIP). We only export the key time and value on
1746
1753
/// a Cubic curve using the default tangents.
1747
1754
/// </summary>
1748
- internal void ExportAnimationKeys ( AnimationCurve uniAnimCurve , FbxAnimCurve fbxAnimCurve ,
1755
+ internal static void ExportAnimationKeys ( AnimationCurve uniAnimCurve , FbxAnimCurve fbxAnimCurve ,
1749
1756
UnityToMayaConvertSceneHelper convertSceneHelper )
1750
1757
{
1751
- // TODO: complete the mapping between key tangents modes Unity and FBX
1752
- Dictionary < AnimationUtility . TangentMode , List < FbxAnimCurveDef . ETangentMode > > MapUnityKeyTangentModeToFBX =
1753
- new Dictionary < AnimationUtility . TangentMode , List < FbxAnimCurveDef . ETangentMode > >
1754
- {
1755
- //TangeantAuto|GenericTimeIndependent|GenericClampProgressive
1756
- { AnimationUtility . TangentMode . Free , new List < FbxAnimCurveDef . ETangentMode > { FbxAnimCurveDef . ETangentMode . eTangentAuto , FbxAnimCurveDef . ETangentMode . eTangentGenericClampProgressive } } ,
1757
-
1758
- //TangeantAuto|GenericTimeIndependent
1759
- { AnimationUtility . TangentMode . Auto , new List < FbxAnimCurveDef . ETangentMode > { FbxAnimCurveDef . ETangentMode . eTangentAuto , FbxAnimCurveDef . ETangentMode . eTangentGenericTimeIndependent } } ,
1760
-
1761
- //TangeantAuto|GenericTimeIndependent|GenericClampProgressive
1762
- { AnimationUtility . TangentMode . ClampedAuto , new List < FbxAnimCurveDef . ETangentMode > { FbxAnimCurveDef . ETangentMode . eTangentAuto , FbxAnimCurveDef . ETangentMode . eTangentGenericClampProgressive } } ,
1763
- } ;
1764
-
1765
1758
// Copy Unity AnimCurve to FBX AnimCurve.
1766
1759
// NOTE: only cubic keys are supported by the FbxImporter
1767
1760
using ( new FbxAnimCurveModifyHelper ( new List < FbxAnimCurve > { fbxAnimCurve } ) )
@@ -1773,24 +1766,44 @@ internal void ExportAnimationKeys (AnimationCurve uniAnimCurve, FbxAnimCurve fbx
1773
1766
1774
1767
int fbxKeyIndex = fbxAnimCurve . KeyAdd ( fbxTime ) ;
1775
1768
1776
- fbxAnimCurve . KeySet ( fbxKeyIndex ,
1777
- fbxTime ,
1778
- convertSceneHelper . Convert ( uniKeyFrame . value )
1779
- ) ;
1780
1769
1781
1770
// configure tangents
1782
1771
var lTangent = AnimationUtility . GetKeyLeftTangentMode ( uniAnimCurve , keyIndex ) ;
1783
1772
var rTangent = AnimationUtility . GetKeyRightTangentMode ( uniAnimCurve , keyIndex ) ;
1784
1773
1785
- if ( ! ( MapUnityKeyTangentModeToFBX . ContainsKey ( lTangent ) && MapUnityKeyTangentModeToFBX . ContainsKey ( rTangent ) ) )
1774
+ // Always set tangent mode to eTangentBreak, as other modes are not handled the same in FBX as in
1775
+ // Unity, thus leading to discrepancies in animation curves.
1776
+ FbxAnimCurveDef . ETangentMode tanMode = FbxAnimCurveDef . ETangentMode . eTangentBreak ;
1777
+
1778
+ // Default to cubic interpolation, which is the default for KeySet
1779
+ FbxAnimCurveDef . EInterpolationType interpMode = FbxAnimCurveDef . EInterpolationType . eInterpolationCubic ;
1780
+ switch ( rTangent )
1786
1781
{
1787
- Debug . LogWarning ( string . Format ( "key[{0}] missing tangent mapping ({1},{2})" , keyIndex , lTangent . ToString ( ) , rTangent . ToString ( ) ) ) ;
1788
- continue ;
1782
+ case AnimationUtility . TangentMode . Linear :
1783
+ interpMode = FbxAnimCurveDef . EInterpolationType . eInterpolationLinear ;
1784
+ break ;
1785
+ case AnimationUtility . TangentMode . Constant :
1786
+ interpMode = FbxAnimCurveDef . EInterpolationType . eInterpolationConstant ;
1787
+ break ;
1788
+ default :
1789
+ break ;
1789
1790
}
1790
1791
1791
- // TODO : handle broken tangents
1792
-
1793
- // TODO : set key tangents
1792
+ fbxAnimCurve . KeySet ( fbxKeyIndex ,
1793
+ fbxTime ,
1794
+ convertSceneHelper . Convert ( uniKeyFrame . value ) ,
1795
+ interpMode ,
1796
+ tanMode ,
1797
+ // value of right slope
1798
+ convertSceneHelper . Convert ( uniKeyFrame . outTangent ) ,
1799
+ // value of next left slope
1800
+ keyIndex < uniAnimCurve . length - 1 ? convertSceneHelper . Convert ( uniAnimCurve [ keyIndex + 1 ] . inTangent ) : 0 ,
1801
+ FbxAnimCurveDef . EWeightedMode . eWeightedAll ,
1802
+ // weight for right slope
1803
+ uniKeyFrame . outWeight ,
1804
+ // weight for next left slope
1805
+ keyIndex < uniAnimCurve . length - 1 ? uniAnimCurve [ keyIndex + 1 ] . inWeight : 0
1806
+ ) ;
1794
1807
}
1795
1808
}
1796
1809
}
@@ -1934,9 +1947,7 @@ private void ExportAnimationCurve (FbxNode fbxNode,
1934
1947
// AxisSystem (LeftHanded to RightHanded) and FBX's default units
1935
1948
// (Meters to Centimetres)
1936
1949
var convertSceneHelper = new UnityToMayaConvertSceneHelper ( uniPropertyName ) ;
1937
-
1938
- // TODO: we'll resample the curve so we don't have to
1939
- // configure tangents
1950
+
1940
1951
if ( ModelExporter . ExportSettings . BakeAnimationProperty ) {
1941
1952
ExportAnimationSamples ( uniAnimCurve , fbxAnimCurve , frameRate , convertSceneHelper ) ;
1942
1953
} else {
@@ -2117,8 +2128,15 @@ private void ExportAnimationClip (AnimationClip uniAnimClip, GameObject uniRoot,
2117
2128
continue ;
2118
2129
}
2119
2130
2131
+ // If this is an euler curve with a prerotation, then need to sample animations to remove the prerotation.
2132
+ // Otherwise can export normally with tangents.
2120
2133
index = EulerCurve . GetEulerIndex ( propertyName ) ;
2121
- if ( index >= 0 ) {
2134
+ if ( index >= 0 &&
2135
+ // still need to sample euler curves if baking is specified
2136
+ ( ModelExporter . ExportSettings . BakeAnimationProperty ||
2137
+ // also need to make sure to sample if there is a prerotation, as this is baked into the Unity curves
2138
+ fbxNode . GetPreRotation ( FbxNode . EPivotSet . eSourcePivot ) . Distance ( new FbxVector4 ( ) ) > 0 ) ) {
2139
+
2122
2140
RotationCurve rotCurve = GetRotationCurve < EulerCurve > ( uniGO , uniAnimClip . frameRate , ref rotations ) ;
2123
2141
rotCurve . SetCurve ( index , uniAnimCurve ) ;
2124
2142
continue ;
0 commit comments