@@ -2731,13 +2731,11 @@ class AnimationParser {
27312731 const tracks = [ ] ;
27322732
27332733 let initialPosition = new Vector3 ( ) ;
2734- let initialRotation = new Quaternion ( ) ;
27352734 let initialScale = new Vector3 ( ) ;
27362735
2737- if ( rawTracks . transform ) rawTracks . transform . decompose ( initialPosition , initialRotation , initialScale ) ;
2736+ if ( rawTracks . transform ) rawTracks . transform . decompose ( initialPosition , new Quaternion ( ) , initialScale ) ;
27382737
27392738 initialPosition = initialPosition . toArray ( ) ;
2740- initialRotation = new Euler ( ) . setFromQuaternion ( initialRotation , rawTracks . eulerOrder ) . toArray ( ) ;
27412739 initialScale = initialScale . toArray ( ) ;
27422740
27432741 if ( rawTracks . T !== undefined && Object . keys ( rawTracks . T . curves ) . length > 0 ) {
@@ -2749,7 +2747,7 @@ class AnimationParser {
27492747
27502748 if ( rawTracks . R !== undefined && Object . keys ( rawTracks . R . curves ) . length > 0 ) {
27512749
2752- const rotationTrack = this . generateRotationTrack ( rawTracks . modelName , rawTracks . R . curves , initialRotation , rawTracks . preRotation , rawTracks . postRotation , rawTracks . eulerOrder ) ;
2750+ const rotationTrack = this . generateRotationTrack ( rawTracks . modelName , rawTracks . R . curves , rawTracks . preRotation , rawTracks . postRotation , rawTracks . eulerOrder ) ;
27532751 if ( rotationTrack !== undefined ) tracks . push ( rotationTrack ) ;
27542752
27552753 }
@@ -2781,32 +2779,20 @@ class AnimationParser {
27812779
27822780 }
27832781
2784- generateRotationTrack ( modelName , curves , initialValue , preRotation , postRotation , eulerOrder ) {
2782+ generateRotationTrack ( modelName , curves , preRotation , postRotation , eulerOrder ) {
27852783
2786- if ( curves . x !== undefined ) {
2784+ let times ;
2785+ let values ;
27872786
2788- this . interpolateRotations ( curves . x ) ;
2789- curves . x . values = curves . x . values . map ( MathUtils . degToRad ) ;
2787+ if ( curves . x !== undefined && curves . y !== undefined && curves . z !== undefined ) {
27902788
2791- }
2792-
2793- if ( curves . y !== undefined ) {
2794-
2795- this . interpolateRotations ( curves . y ) ;
2796- curves . y . values = curves . y . values . map ( MathUtils . degToRad ) ;
2797-
2798- }
2799-
2800- if ( curves . z !== undefined ) {
2789+ const result = this . interpolateRotations ( curves . x , curves . y , curves . z , eulerOrder ) ;
28012790
2802- this . interpolateRotations ( curves . z ) ;
2803- curves . z . values = curves . z . values . map ( MathUtils . degToRad ) ;
2791+ times = result [ 0 ] ;
2792+ values = result [ 1 ] ;
28042793
28052794 }
28062795
2807- const times = this . getTimesForAllAxes ( curves ) ;
2808- const values = this . getKeyframeTrackValues ( times , curves , initialValue ) ;
2809-
28102796 if ( preRotation !== undefined ) {
28112797
28122798 preRotation = preRotation . map ( MathUtils . degToRad ) ;
@@ -2832,15 +2818,32 @@ class AnimationParser {
28322818
28332819 const quaternionValues = [ ] ;
28342820
2821+ if ( ! values || ! times ) return new QuaternionKeyframeTrack ( modelName + '.quaternion' , [ ] , [ ] ) ;
2822+
28352823 for ( let i = 0 ; i < values . length ; i += 3 ) {
28362824
28372825 euler . set ( values [ i ] , values [ i + 1 ] , values [ i + 2 ] , eulerOrder ) ;
2838-
28392826 quaternion . setFromEuler ( euler ) ;
28402827
28412828 if ( preRotation !== undefined ) quaternion . premultiply ( preRotation ) ;
28422829 if ( postRotation !== undefined ) quaternion . multiply ( postRotation ) ;
28432830
2831+ // Check unroll
2832+ if ( i > 2 ) {
2833+
2834+ const prevQuat = new Quaternion ( ) . fromArray (
2835+ quaternionValues ,
2836+ ( ( i - 3 ) / 3 ) * 4
2837+ ) ;
2838+
2839+ if ( prevQuat . dot ( quaternion ) < 0 ) {
2840+
2841+ quaternion . set ( - quaternion . x , - quaternion . y , - quaternion . z , - quaternion . w ) ;
2842+
2843+ }
2844+
2845+ }
2846+
28442847 quaternion . toArray ( quaternionValues , ( i / 3 ) * 4 ) ;
28452848
28462849 }
@@ -2971,47 +2974,103 @@ class AnimationParser {
29712974 // Rotations are defined as Euler angles which can have values of any size
29722975 // These will be converted to quaternions which don't support values greater than
29732976 // PI, so we'll interpolate large rotations
2974- interpolateRotations ( curve ) {
2977+ interpolateRotations ( curvex , curvey , curvez , eulerOrder ) {
2978+
2979+ const times = [ ] ;
2980+ const values = [ ] ;
2981+ for ( let i = 1 ; i < curvex . values . length ; i ++ ) {
2982+
2983+ const initialValue = [
2984+ curvex . values [ i - 1 ] ,
2985+ curvey . values [ i - 1 ] ,
2986+ curvez . values [ i - 1 ] ,
2987+ ] ;
29752988
2976- for ( let i = 1 ; i < curve . values . length ; i ++ ) {
2989+ if ( isNaN ( initialValue [ 0 ] ) || isNaN ( initialValue [ 1 ] ) || isNaN ( initialValue [ 2 ] ) ) {
29772990
2978- const initialValue = curve . values [ i - 1 ] ;
2979- const valuesSpan = curve . values [ i ] - initialValue ;
2991+ continue ;
29802992
2981- const absoluteSpan = Math . abs ( valuesSpan ) ;
2993+ }
2994+
2995+ const initialValueRad = initialValue . map ( MathUtils . degToRad ) ;
2996+
2997+ const currentValue = [
2998+ curvex . values [ i ] ,
2999+ curvey . values [ i ] ,
3000+ curvez . values [ i ] ,
3001+ ] ;
3002+
3003+ if ( isNaN ( currentValue [ 0 ] ) || isNaN ( currentValue [ 1 ] ) || isNaN ( currentValue [ 2 ] ) ) {
3004+
3005+ continue ;
3006+
3007+ }
3008+
3009+ const currentValueRad = currentValue . map ( MathUtils . degToRad ) ;
3010+
3011+ const valuesSpan = [
3012+ currentValue [ 0 ] - initialValue [ 0 ] ,
3013+ currentValue [ 1 ] - initialValue [ 1 ] ,
3014+ currentValue [ 2 ] - initialValue [ 2 ] ,
3015+ ] ;
3016+
3017+ const absoluteSpan = [
3018+ Math . abs ( valuesSpan [ 0 ] ) ,
3019+ Math . abs ( valuesSpan [ 1 ] ) ,
3020+ Math . abs ( valuesSpan [ 2 ] ) ,
3021+ ] ;
3022+
3023+ if ( absoluteSpan [ 0 ] >= 180 || absoluteSpan [ 1 ] >= 180 || absoluteSpan [ 2 ] >= 180 ) {
29823024
2983- if ( absoluteSpan >= 180 ) {
3025+ const maxAbsSpan = Math . max ( ... absoluteSpan ) ;
29843026
2985- const numSubIntervals = absoluteSpan / 180 ;
3027+ const numSubIntervals = maxAbsSpan / 180 ;
29863028
2987- const step = valuesSpan / numSubIntervals ;
2988- let nextValue = initialValue + step ;
3029+ const E1 = new Euler ( ... initialValueRad , eulerOrder ) ;
3030+ const E2 = new Euler ( ... currentValueRad , eulerOrder ) ;
29893031
2990- const initialTime = curve . times [ i - 1 ] ;
2991- const timeSpan = curve . times [ i ] - initialTime ;
2992- const interval = timeSpan / numSubIntervals ;
2993- let nextTime = initialTime + interval ;
3032+ const Q1 = new Quaternion ( ) . setFromEuler ( E1 ) ;
3033+ const Q2 = new Quaternion ( ) . setFromEuler ( E2 ) ;
29943034
2995- const interpolatedTimes = [ ] ;
2996- const interpolatedValues = [ ] ;
3035+ // Check unroll
3036+ if ( Q1 . dot ( Q2 ) ) {
29973037
2998- while ( nextTime < curve . times [ i ] ) {
3038+ Q2 . set ( - Q2 . x , - Q2 . y , - Q2 . z , - Q2 . w ) ;
29993039
3000- interpolatedTimes . push ( nextTime ) ;
3001- nextTime += interval ;
3040+ }
3041+
3042+ // Interpolate
3043+ const initialTime = curvex . times [ i - 1 ] ;
3044+ const timeSpan = curvex . times [ i ] - initialTime ;
3045+
3046+ const Q = new Quaternion ( ) ;
3047+ const E = new Euler ( ) ;
3048+ for ( let t = 0 ; t < 1 ; t += 1 / numSubIntervals ) {
30023049
3003- interpolatedValues . push ( nextValue ) ;
3004- nextValue += step ;
3050+ Q . copy ( Q1 . clone ( ) . slerp ( Q2 . clone ( ) , t ) ) ;
3051+
3052+ times . push ( initialTime + t * timeSpan ) ;
3053+ E . setFromQuaternion ( Q , eulerOrder ) ;
3054+
3055+ values . push ( E . x ) ;
3056+ values . push ( E . y ) ;
3057+ values . push ( E . z ) ;
30053058
30063059 }
30073060
3008- curve . times = inject ( curve . times , i , interpolatedTimes ) ;
3009- curve . values = inject ( curve . values , i , interpolatedValues ) ;
3061+ } else {
3062+
3063+ times . push ( curvex . times [ i ] ) ;
3064+ values . push ( MathUtils . degToRad ( curvex . values [ i ] ) ) ;
3065+ values . push ( MathUtils . degToRad ( curvey . values [ i ] ) ) ;
3066+ values . push ( MathUtils . degToRad ( curvez . values [ i ] ) ) ;
30103067
30113068 }
30123069
30133070 }
30143071
3072+ return [ times , values ] ;
3073+
30153074 }
30163075
30173076}
@@ -4217,11 +4276,5 @@ function slice( a, b, from, to ) {
42174276
42184277}
42194278
4220- // inject array a2 into array a1 at index
4221- function inject ( a1 , index , a2 ) {
4222-
4223- return a1 . slice ( 0 , index ) . concat ( a2 ) . concat ( a1 . slice ( index ) ) ;
4224-
4225- }
42264279
42274280export { FBXLoader } ;
0 commit comments