| Server IP : 137.184.226.51 / Your IP : 10.8.0.1 Web Server : Apache/2.4.41 (Ubuntu) System : Linux vm8 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 User : ( 1000) PHP Version : 7.4.33 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /var/www/aspa/three/animation/ |
Upload File : |
import { Quaternion } from '../math/Quaternion.js';
import { AdditiveAnimationBlendMode } from '../constants.js';
// converts an array to a specific type
function convertArray( array, type, forceClone ) {
if ( ! array || // let 'undefined' and 'null' pass
! forceClone && array.constructor === type ) return array;
if ( typeof type.BYTES_PER_ELEMENT === 'number' ) {
return new type( array ); // create typed array
}
return Array.prototype.slice.call( array ); // create Array
}
function isTypedArray( object ) {
return ArrayBuffer.isView( object ) &&
! ( object instanceof DataView );
}
// returns an array by which times and values can be sorted
function getKeyframeOrder( times ) {
function compareTime( i, j ) {
return times[ i ] - times[ j ];
}
const n = times.length;
const result = new Array( n );
for ( let i = 0; i !== n; ++ i ) result[ i ] = i;
result.sort( compareTime );
return result;
}
// uses the array previously returned by 'getKeyframeOrder' to sort data
function sortedArray( values, stride, order ) {
const nValues = values.length;
const result = new values.constructor( nValues );
for ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {
const srcOffset = order[ i ] * stride;
for ( let j = 0; j !== stride; ++ j ) {
result[ dstOffset ++ ] = values[ srcOffset + j ];
}
}
return result;
}
// function for parsing AOS keyframe formats
function flattenJSON( jsonKeys, times, values, valuePropertyName ) {
let i = 1, key = jsonKeys[ 0 ];
while ( key !== undefined && key[ valuePropertyName ] === undefined ) {
key = jsonKeys[ i ++ ];
}
if ( key === undefined ) return; // no data
let value = key[ valuePropertyName ];
if ( value === undefined ) return; // no data
if ( Array.isArray( value ) ) {
do {
value = key[ valuePropertyName ];
if ( value !== undefined ) {
times.push( key.time );
values.push.apply( values, value ); // push all elements
}
key = jsonKeys[ i ++ ];
} while ( key !== undefined );
} else if ( value.toArray !== undefined ) {
// ...assume THREE.Math-ish
do {
value = key[ valuePropertyName ];
if ( value !== undefined ) {
times.push( key.time );
value.toArray( values, values.length );
}
key = jsonKeys[ i ++ ];
} while ( key !== undefined );
} else {
// otherwise push as-is
do {
value = key[ valuePropertyName ];
if ( value !== undefined ) {
times.push( key.time );
values.push( value );
}
key = jsonKeys[ i ++ ];
} while ( key !== undefined );
}
}
function subclip( sourceClip, name, startFrame, endFrame, fps = 30 ) {
const clip = sourceClip.clone();
clip.name = name;
const tracks = [];
for ( let i = 0; i < clip.tracks.length; ++ i ) {
const track = clip.tracks[ i ];
const valueSize = track.getValueSize();
const times = [];
const values = [];
for ( let j = 0; j < track.times.length; ++ j ) {
const frame = track.times[ j ] * fps;
if ( frame < startFrame || frame >= endFrame ) continue;
times.push( track.times[ j ] );
for ( let k = 0; k < valueSize; ++ k ) {
values.push( track.values[ j * valueSize + k ] );
}
}
if ( times.length === 0 ) continue;
track.times = convertArray( times, track.times.constructor );
track.values = convertArray( values, track.values.constructor );
tracks.push( track );
}
clip.tracks = tracks;
// find minimum .times value across all tracks in the trimmed clip
let minStartTime = Infinity;
for ( let i = 0; i < clip.tracks.length; ++ i ) {
if ( minStartTime > clip.tracks[ i ].times[ 0 ] ) {
minStartTime = clip.tracks[ i ].times[ 0 ];
}
}
// shift all tracks such that clip begins at t=0
for ( let i = 0; i < clip.tracks.length; ++ i ) {
clip.tracks[ i ].shift( - 1 * minStartTime );
}
clip.resetDuration();
return clip;
}
function makeClipAdditive( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) {
if ( fps <= 0 ) fps = 30;
const numTracks = referenceClip.tracks.length;
const referenceTime = referenceFrame / fps;
// Make each track's values relative to the values at the reference frame
for ( let i = 0; i < numTracks; ++ i ) {
const referenceTrack = referenceClip.tracks[ i ];
const referenceTrackType = referenceTrack.ValueTypeName;
// Skip this track if it's non-numeric
if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue;
// Find the track in the target clip whose name and type matches the reference track
const targetTrack = targetClip.tracks.find( function ( track ) {
return track.name === referenceTrack.name
&& track.ValueTypeName === referenceTrackType;
} );
if ( targetTrack === undefined ) continue;
let referenceOffset = 0;
const referenceValueSize = referenceTrack.getValueSize();
if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
referenceOffset = referenceValueSize / 3;
}
let targetOffset = 0;
const targetValueSize = targetTrack.getValueSize();
if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
targetOffset = targetValueSize / 3;
}
const lastIndex = referenceTrack.times.length - 1;
let referenceValue;
// Find the value to subtract out of the track
if ( referenceTime <= referenceTrack.times[ 0 ] ) {
// Reference frame is earlier than the first keyframe, so just use the first keyframe
const startIndex = referenceOffset;
const endIndex = referenceValueSize - referenceOffset;
referenceValue = referenceTrack.values.slice( startIndex, endIndex );
} else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) {
// Reference frame is after the last keyframe, so just use the last keyframe
const startIndex = lastIndex * referenceValueSize + referenceOffset;
const endIndex = startIndex + referenceValueSize - referenceOffset;
referenceValue = referenceTrack.values.slice( startIndex, endIndex );
} else {
// Interpolate to the reference value
const interpolant = referenceTrack.createInterpolant();
const startIndex = referenceOffset;
const endIndex = referenceValueSize - referenceOffset;
interpolant.evaluate( referenceTime );
referenceValue = interpolant.resultBuffer.slice( startIndex, endIndex );
}
// Conjugate the quaternion
if ( referenceTrackType === 'quaternion' ) {
const referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate();
referenceQuat.toArray( referenceValue );
}
// Subtract the reference value from all of the track values
const numTimes = targetTrack.times.length;
for ( let j = 0; j < numTimes; ++ j ) {
const valueStart = j * targetValueSize + targetOffset;
if ( referenceTrackType === 'quaternion' ) {
// Multiply the conjugate for quaternion track types
Quaternion.multiplyQuaternionsFlat(
targetTrack.values,
valueStart,
referenceValue,
0,
targetTrack.values,
valueStart
);
} else {
const valueEnd = targetValueSize - targetOffset * 2;
// Subtract each value for all other numeric track types
for ( let k = 0; k < valueEnd; ++ k ) {
targetTrack.values[ valueStart + k ] -= referenceValue[ k ];
}
}
}
}
targetClip.blendMode = AdditiveAnimationBlendMode;
return targetClip;
}
const AnimationUtils = {
convertArray: convertArray,
isTypedArray: isTypedArray,
getKeyframeOrder: getKeyframeOrder,
sortedArray: sortedArray,
flattenJSON: flattenJSON,
subclip: subclip,
makeClipAdditive: makeClipAdditive
};
export {
convertArray,
isTypedArray,
getKeyframeOrder,
sortedArray,
flattenJSON,
subclip,
makeClipAdditive,
AnimationUtils
};