Skip to content
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 102 additions & 47 deletions examples/jsm/loaders/FBXLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -2700,30 +2700,18 @@ class AnimationParser {

generateRotationTrack( modelName, curves, initialValue, preRotation, postRotation, eulerOrder ) {

if ( curves.x !== undefined ) {
let times;
let values;

this.interpolateRotations( curves.x );
curves.x.values = curves.x.values.map( MathUtils.degToRad );
if ( curves.x !== undefined && curves.y !== undefined && curves.z !== undefined ) {

}

if ( curves.y !== undefined ) {

this.interpolateRotations( curves.y );
curves.y.values = curves.y.values.map( MathUtils.degToRad );

}

if ( curves.z !== undefined ) {
const result = this.interpolateRotations( curves.x, curves.y, curves.z, eulerOrder );

this.interpolateRotations( curves.z );
curves.z.values = curves.z.values.map( MathUtils.degToRad );
times = result[ 0 ];
values = result[ 1 ];

}

const times = this.getTimesForAllAxes( curves );
const values = this.getKeyframeTrackValues( times, curves, initialValue );

if ( preRotation !== undefined ) {

preRotation = preRotation.map( MathUtils.degToRad );
Expand All @@ -2749,15 +2737,32 @@ class AnimationParser {

const quaternionValues = [];

if ( ! values || ! times ) return new QuaternionKeyframeTrack( modelName + '.quaternion', [], [] );

for ( let i = 0; i < values.length; i += 3 ) {

euler.set( values[ i ], values[ i + 1 ], values[ i + 2 ], eulerOrder );

quaternion.setFromEuler( euler );

if ( preRotation !== undefined ) quaternion.premultiply( preRotation );
if ( postRotation !== undefined ) quaternion.multiply( postRotation );

// Check unroll
if ( i > 2 ) {

const prevQuat = new Quaternion().fromArray(
quaternionValues,
( ( i - 3 ) / 3 ) * 4
);

if ( prevQuat.dot( quaternion ) < 0 ) {

quaternion.set( - quaternion.x, - quaternion.y, - quaternion.z, - quaternion.w );

}

}

quaternion.toArray( quaternionValues, ( i / 3 ) * 4 );

}
Expand Down Expand Up @@ -2888,47 +2893,103 @@ class AnimationParser {
// Rotations are defined as Euler angles which can have values of any size
// These will be converted to quaternions which don't support values greater than
// PI, so we'll interpolate large rotations
interpolateRotations( curve ) {
interpolateRotations( curvex, curvey, curvez, eulerOrder ) {

const times = [];
const values = [];
for ( let i = 1; i < curvex.values.length; i ++ ) {

const initialValue = [
curvex.values[ i - 1 ],
curvey.values[ i - 1 ],
curvez.values[ i - 1 ],
];

for ( let i = 1; i < curve.values.length; i ++ ) {
if ( isNaN( initialValue[ 0 ] ) || isNaN( initialValue[ 1 ] ) || isNaN( initialValue[ 2 ] ) ) {

const initialValue = curve.values[ i - 1 ];
const valuesSpan = curve.values[ i ] - initialValue;
continue;

const absoluteSpan = Math.abs( valuesSpan );
}

const initialValueRad = initialValue.map( MathUtils.degToRad );

const currentValue = [
curvex.values[ i ],
curvey.values[ i ],
curvez.values[ i ],
];

if ( isNaN( currentValue[ 0 ] ) || isNaN( currentValue[ 1 ] ) || isNaN( currentValue[ 2 ] ) ) {

continue;

}

const currentValueRad = currentValue.map( MathUtils.degToRad );

const valuesSpan = [
currentValue[ 0 ] - initialValue[ 0 ],
currentValue[ 1 ] - initialValue[ 1 ],
currentValue[ 2 ] - initialValue[ 2 ],
];

const absoluteSpan = [
Math.abs( valuesSpan[ 0 ] ),
Math.abs( valuesSpan[ 1 ] ),
Math.abs( valuesSpan[ 2 ] ),
];

if ( absoluteSpan[ 0 ] >= 180 || absoluteSpan[ 1 ] >= 180 || absoluteSpan[ 2 ] >= 180 ) {

if ( absoluteSpan >= 180 ) {
const maxAbsSpan = Math.max( ...absoluteSpan );

const numSubIntervals = absoluteSpan / 180;
const numSubIntervals = maxAbsSpan / 180;

const step = valuesSpan / numSubIntervals;
let nextValue = initialValue + step;
const E1 = new Euler( ...initialValueRad, eulerOrder );
const E2 = new Euler( ...currentValueRad, eulerOrder );

const initialTime = curve.times[ i - 1 ];
const timeSpan = curve.times[ i ] - initialTime;
const interval = timeSpan / numSubIntervals;
let nextTime = initialTime + interval;
const Q1 = new Quaternion().setFromEuler( E1 );
const Q2 = new Quaternion().setFromEuler( E2 );

const interpolatedTimes = [];
const interpolatedValues = [];
// Check unroll
if ( Q1.dot( Q2 ) ) {

while ( nextTime < curve.times[ i ] ) {
Q2.set( - Q2.x, - Q2.y, - Q2.z, - Q2.w );

interpolatedTimes.push( nextTime );
nextTime += interval;
}

// Interpolate
const initialTime = curvex.times[ i - 1 ];
const timeSpan = curvex.times[ i ] - initialTime;

const Q = new Quaternion();
const E = new Euler();
for ( let t = 0; t < 1; t += 1 / numSubIntervals ) {

interpolatedValues.push( nextValue );
nextValue += step;
Q.copy( Q1.clone().slerp( Q2.clone(), t ) );

times.push( initialTime + t * timeSpan );
E.setFromQuaternion( Q, eulerOrder );

values.push( E.x );
values.push( E.y );
values.push( E.z );

}

curve.times = inject( curve.times, i, interpolatedTimes );
curve.values = inject( curve.values, i, interpolatedValues );
} else {

times.push( curvex.times[ i ] );
values.push( MathUtils.degToRad( curvex.values[ i ] ) );
values.push( MathUtils.degToRad( curvey.values[ i ] ) );
values.push( MathUtils.degToRad( curvez.values[ i ] ) );

}

}

return [ times, values ];

}

}
Expand Down Expand Up @@ -4134,11 +4195,5 @@ function slice( a, b, from, to ) {

}

// inject array a2 into array a1 at index
function inject( a1, index, a2 ) {

return a1.slice( 0, index ).concat( a2 ).concat( a1.slice( index ) );

}

export { FBXLoader };