@@ -1703,239 +1703,6 @@ public static bool TryGetValue(string uniPropertyName, out FbxPropertyChannelPai
1703
1703
}
1704
1704
}
1705
1705
1706
- /// <summary>
1707
- /// Exporting rotations is more complicated. We need to convert
1708
- /// from quaternion to euler. We use this class to help.
1709
- /// </summary>
1710
- class FbxAnimCurveModifyHelper : System . IDisposable
1711
- {
1712
- public List < FbxAnimCurve > Curves { get ; private set ; }
1713
-
1714
- public FbxAnimCurveModifyHelper ( List < FbxAnimCurve > list )
1715
- {
1716
- Curves = list ;
1717
-
1718
- foreach ( var curve in Curves )
1719
- curve . KeyModifyBegin ( ) ;
1720
- }
1721
-
1722
- ~ FbxAnimCurveModifyHelper ( ) {
1723
- Dispose ( ) ;
1724
- }
1725
-
1726
- public void Dispose ( )
1727
- {
1728
- foreach ( var curve in Curves )
1729
- curve . KeyModifyEnd ( ) ;
1730
- }
1731
- }
1732
-
1733
- /// <summary>
1734
- /// Base class for QuaternionCurve and EulerCurve.
1735
- /// Provides implementation for computing keys and generating FbxAnimCurves
1736
- /// for euler rotation.
1737
- /// </summary>
1738
- abstract class RotationCurve {
1739
- public double sampleRate ;
1740
- public AnimationCurve [ ] m_curves ;
1741
-
1742
- public struct Key {
1743
- public FbxTime time ;
1744
- public FbxVector4 euler ;
1745
- }
1746
-
1747
- public RotationCurve ( ) { }
1748
-
1749
- public void SetCurve ( int i , AnimationCurve curve ) {
1750
- if ( i < 0 || i >= m_curves . Length ) {
1751
- throw new System . IndexOutOfRangeException ( ) ;
1752
- }
1753
- m_curves [ i ] = curve ;
1754
- }
1755
-
1756
- protected abstract FbxQuaternion GetConvertedQuaternionRotation ( float seconds , UnityEngine . Quaternion restRotation ) ;
1757
-
1758
- private Key [ ] ComputeKeys ( UnityEngine . Quaternion restRotation , FbxNode node ) {
1759
- // Get the source pivot pre-rotation if any, so we can
1760
- // remove it from the animation we get from Unity.
1761
- var fbxPreRotationEuler = node . GetRotationActive ( )
1762
- ? node . GetPreRotation ( FbxNode . EPivotSet . eSourcePivot )
1763
- : new FbxVector4 ( ) ;
1764
-
1765
- // Get the inverse of the prerotation
1766
- var fbxPreRotationInverse = ModelExporter . EulerToQuaternion ( fbxPreRotationEuler ) ;
1767
- fbxPreRotationInverse . Inverse ( ) ;
1768
-
1769
- // Find when we have keys set.
1770
- var keyTimes =
1771
- ( FbxExporters . Editor . ModelExporter . ExportSettings . BakeAnimation )
1772
- ? ModelExporter . GetSampleTimes ( m_curves , sampleRate )
1773
- : ModelExporter . GetKeyTimes ( m_curves ) ;
1774
-
1775
- // Convert to the Key type.
1776
- var keys = new Key [ keyTimes . Count ] ;
1777
- int i = 0 ;
1778
- foreach ( var seconds in keyTimes ) {
1779
- var fbxFinalAnimation = GetConvertedQuaternionRotation ( seconds , restRotation ) ;
1780
-
1781
- // Cancel out the pre-rotation. Order matters. FBX reads left-to-right.
1782
- // When we run animation we will apply:
1783
- // pre-rotation
1784
- // then pre-rotation inverse
1785
- // then animation.
1786
- var fbxFinalQuat = fbxPreRotationInverse * fbxFinalAnimation ;
1787
-
1788
- // Store the key so we can sort them later.
1789
- Key key ;
1790
- key . time = FbxTime . FromSecondDouble ( seconds ) ;
1791
- key . euler = ModelExporter . QuaternionToEuler ( fbxFinalQuat ) ;
1792
- keys [ i ++ ] = key ;
1793
- }
1794
-
1795
- // Sort the keys by time
1796
- System . Array . Sort ( keys , ( Key a , Key b ) => a . time . CompareTo ( b . time ) ) ;
1797
-
1798
- return keys ;
1799
- }
1800
-
1801
- public void Animate ( Transform unityTransform , FbxNode fbxNode , FbxAnimLayer fbxAnimLayer , bool Verbose ) {
1802
-
1803
- /* Find or create the three curves. */
1804
- var fbxAnimCurveX = fbxNode . LclRotation . GetCurve ( fbxAnimLayer , Globals . FBXSDK_CURVENODE_COMPONENT_X , true ) ;
1805
- var fbxAnimCurveY = fbxNode . LclRotation . GetCurve ( fbxAnimLayer , Globals . FBXSDK_CURVENODE_COMPONENT_Y , true ) ;
1806
- var fbxAnimCurveZ = fbxNode . LclRotation . GetCurve ( fbxAnimLayer , Globals . FBXSDK_CURVENODE_COMPONENT_Z , true ) ;
1807
-
1808
- /* set the keys */
1809
- using ( new FbxAnimCurveModifyHelper ( new List < FbxAnimCurve > { fbxAnimCurveX , fbxAnimCurveY , fbxAnimCurveZ } ) )
1810
- {
1811
- foreach ( var key in ComputeKeys ( unityTransform . localRotation , fbxNode ) ) {
1812
-
1813
- int i = fbxAnimCurveX . KeyAdd ( key . time ) ;
1814
- fbxAnimCurveX . KeySet ( i , key . time , ( float ) key . euler . X ) ;
1815
-
1816
- i = fbxAnimCurveY . KeyAdd ( key . time ) ;
1817
- fbxAnimCurveY . KeySet ( i , key . time , ( float ) key . euler . Y ) ;
1818
-
1819
- i = fbxAnimCurveZ . KeyAdd ( key . time ) ;
1820
- fbxAnimCurveZ . KeySet ( i , key . time , ( float ) key . euler . Z ) ;
1821
- }
1822
- }
1823
-
1824
- // Uni-35616 unroll curves to preserve continuous rotations
1825
- var fbxCurveNode = fbxNode . LclRotation . GetCurveNode ( fbxAnimLayer , false /*should already exist*/ ) ;
1826
-
1827
- FbxAnimCurveFilterUnroll fbxAnimUnrollFilter = new FbxAnimCurveFilterUnroll ( ) ;
1828
- fbxAnimUnrollFilter . Apply ( fbxCurveNode ) ;
1829
-
1830
- if ( Verbose ) {
1831
- Debug . Log ( "Exported rotation animation for " + fbxNode . GetName ( ) ) ;
1832
- }
1833
- }
1834
- }
1835
-
1836
- /// <summary>
1837
- /// Convert from ZXY to XYZ euler, and remove
1838
- /// prerotation from animated rotation.
1839
- /// </summary>
1840
- class EulerCurve : RotationCurve {
1841
- public EulerCurve ( ) { m_curves = new AnimationCurve [ 3 ] ; }
1842
-
1843
- /// <summary>
1844
- /// Gets the index of the euler curve by property name.
1845
- /// x = 0, y = 1, z = 2
1846
- /// </summary>
1847
- /// <returns>The index of the curve, or -1 if property doesn't map to Euler curve.</returns>
1848
- /// <param name="uniPropertyName">Unity property name.</param>
1849
- public static int GetEulerIndex ( string uniPropertyName ) {
1850
- System . StringComparison ct = System . StringComparison . CurrentCulture ;
1851
- bool isEulerComponent = uniPropertyName . StartsWith ( "localEulerAnglesRaw." , ct ) ;
1852
-
1853
- if ( ! isEulerComponent ) { return - 1 ; }
1854
-
1855
- switch ( uniPropertyName [ uniPropertyName . Length - 1 ] ) {
1856
- case 'x' : return 0 ;
1857
- case 'y' : return 1 ;
1858
- case 'z' : return 2 ;
1859
- default : return - 1 ;
1860
- }
1861
- }
1862
-
1863
- protected override FbxQuaternion GetConvertedQuaternionRotation ( float seconds , Quaternion restRotation )
1864
- {
1865
- var eulerRest = restRotation . eulerAngles ;
1866
- AnimationCurve x = m_curves [ 0 ] , y = m_curves [ 1 ] , z = m_curves [ 2 ] ;
1867
-
1868
- // The final animation, including the effect of pre-rotation.
1869
- // If we have no curve, assume the node has the correct rotation right now.
1870
- // We need to evaluate since we might only have keys in one of the axes.
1871
- var unityFinalAnimation = Quaternion . Euler (
1872
- ( x == null ) ? eulerRest [ 0 ] : x . Evaluate ( seconds ) ,
1873
- ( y == null ) ? eulerRest [ 1 ] : y . Evaluate ( seconds ) ,
1874
- ( z == null ) ? eulerRest [ 2 ] : z . Evaluate ( seconds )
1875
- ) ;
1876
-
1877
- // convert the final animation to righthanded coords
1878
- var finalEuler = ModelExporter . ConvertQuaternionToXYZEuler ( unityFinalAnimation ) ;
1879
-
1880
- return ModelExporter . EulerToQuaternion ( new FbxVector4 ( finalEuler ) ) ;
1881
- }
1882
- }
1883
-
1884
- /// <summary>
1885
- /// Exporting rotations is more complicated. We need to convert
1886
- /// from quaternion to euler. We use this class to help.
1887
- /// </summary>
1888
- class QuaternionCurve : RotationCurve {
1889
-
1890
- public QuaternionCurve ( ) { m_curves = new AnimationCurve [ 4 ] ; }
1891
-
1892
- /// <summary>
1893
- /// Gets the index of the curve by property name.
1894
- /// x = 0, y = 1, z = 2, w = 3
1895
- /// </summary>
1896
- /// <returns>The index of the curve, or -1 if property doesn't map to Quaternion curve.</returns>
1897
- /// <param name="uniPropertyName">Unity property name.</param>
1898
- public static int GetQuaternionIndex ( string uniPropertyName ) {
1899
- System . StringComparison ct = System . StringComparison . CurrentCulture ;
1900
- bool isQuaternionComponent = false ;
1901
-
1902
- isQuaternionComponent |= uniPropertyName . StartsWith ( "m_LocalRotation." , ct ) ;
1903
- isQuaternionComponent |= uniPropertyName . EndsWith ( "Q.x" , ct ) ;
1904
- isQuaternionComponent |= uniPropertyName . EndsWith ( "Q.y" , ct ) ;
1905
- isQuaternionComponent |= uniPropertyName . EndsWith ( "Q.z" , ct ) ;
1906
- isQuaternionComponent |= uniPropertyName . EndsWith ( "Q.w" , ct ) ;
1907
-
1908
- if ( ! isQuaternionComponent ) { return - 1 ; }
1909
-
1910
- switch ( uniPropertyName [ uniPropertyName . Length - 1 ] ) {
1911
- case 'x' : return 0 ;
1912
- case 'y' : return 1 ;
1913
- case 'z' : return 2 ;
1914
- case 'w' : return 3 ;
1915
- default : return - 1 ;
1916
- }
1917
- }
1918
-
1919
- protected override FbxQuaternion GetConvertedQuaternionRotation ( float seconds , Quaternion restRotation )
1920
- {
1921
- AnimationCurve x = m_curves [ 0 ] , y = m_curves [ 1 ] , z = m_curves [ 2 ] , w = m_curves [ 3 ] ;
1922
-
1923
- // The final animation, including the effect of pre-rotation.
1924
- // If we have no curve, assume the node has the correct rotation right now.
1925
- // We need to evaluate since we might only have keys in one of the axes.
1926
- var fbxFinalAnimation = new FbxQuaternion (
1927
- ( x == null ) ? restRotation [ 0 ] : x . Evaluate ( seconds ) ,
1928
- ( y == null ) ? restRotation [ 1 ] : y . Evaluate ( seconds ) ,
1929
- ( z == null ) ? restRotation [ 2 ] : z . Evaluate ( seconds ) ,
1930
- ( w == null ) ? restRotation [ 3 ] : w . Evaluate ( seconds ) ) ;
1931
-
1932
- // convert the final animation to righthanded coords
1933
- var finalEuler = ModelExporter . ConvertQuaternionToXYZEuler ( fbxFinalAnimation ) ;
1934
-
1935
- return ModelExporter . EulerToQuaternion ( finalEuler ) ;
1936
- }
1937
- }
1938
-
1939
1706
/// <summary>
1940
1707
/// Export an AnimationClip as a single take
1941
1708
/// </summary>
0 commit comments