From 801124dcebe4e3033bbdc4e331c43037450ea04f Mon Sep 17 00:00:00 2001 From: Ben Houston Date: Thu, 3 Sep 2015 10:14:03 -0400 Subject: [PATCH] simplifying code in the clip-based animation system. --- src/animation/AnimationClip.js | 131 ++++-------------- src/animation/KeyframeTrack.js | 18 +-- src/loaders/JSONLoader.js | 2 +- src/loaders/ObjectLoader.js | 6 +- .../addons/io_three/exporter/api/mesh.py | 2 +- .../addons/io_three/exporter/api/object.py | 8 +- 6 files changed, 46 insertions(+), 121 deletions(-) diff --git a/src/animation/AnimationClip.js b/src/animation/AnimationClip.js index 99afd99f85..981a6eb657 100644 --- a/src/animation/AnimationClip.js +++ b/src/animation/AnimationClip.js @@ -75,70 +75,44 @@ THREE.AnimationClip.prototype = { }; -THREE.AnimationClip.CreateMorphAnimationFromNames = function( morphTargetNames, duration ) { +THREE.AnimationClip.CreateFromMorphTargetSequence = function( name, morphTargetSequence, fps ) { + + var numMorphTargets = morphTargetSequence.length; var tracks = []; - var frameStep = duration / morphTargetNames.length; - for( var i = 0; i < morphTargetNames.length; i ++ ) { + for( var i = 0; i < numMorphTargets; i ++ ) { var keys = []; - if( ( i - 1 ) >= 0 ) { - - keys.push( { time: ( i - 1 ) * frameStep, value: 0 } ); - - } - - keys.push( { time: i * frameStep, value: 1 } ); - - if( ( i + 1 ) <= morphTargetNames.length ) { + keys.push( { time: ( i + numMorphTargets - 1 ) % numMorphTargets, value: 0 } ); + keys.push( { time: i, value: 1 } ); + keys.push( { time: ( i + 1 ) % numMorphTargets, value: 0 } ); - keys.push( { time: ( i + 1 ) * frameStep, value: 0 } ); + keys.sort( THREE.KeyframeTrack.keyComparer ); + // if there is a key at the first frame, duplicate it as the last frame as well for perfect loop. + if( keys[0].time === 0 ) { + keys.push( { + time: numMorphTargets, + value: keys[0].value + }); } - if( ( i - 1 ) < 0 ) { - - keys.push( { time: ( morphTargetNames.length - 1 ) * frameStep, value: 0 } ); - keys.push( { time: morphTargetNames.length * frameStep, value: 1 } ); - - } - - var morphName = morphTargetNames[i]; - var trackName = '.morphTargetInfluences[' + morphName + ']'; - var track = new THREE.NumberKeyframeTrack( trackName, keys ); - - tracks.push( track ); + tracks.push( new THREE.NumberKeyframeTrack( '.morphTargetInfluences[' + morphTargetSequence[i].name + ']', keys ) ); } - var clip = new THREE.AnimationClip( 'morphAnimation', duration, tracks ); + return new THREE.AnimationClip( name, -1, tracks ).scale( 1.0 / fps ); - return clip; }; -THREE.AnimationClip.CreateMorphAnimation = function( morphTargets, duration ) { - - var morphTargetNames = []; - - for( var i = 0; i < morphTargets.length; i ++ ) { - - morphTargetNames.push( morphTargets[i].name ); - - } - - return THREE.AnimationClip.CreateMorphAnimationFromNames( morphTargetNames, duration ); - -}; - - -THREE.AnimationClip.FromImplicitMorphTargetAnimations = function( morphTargets, fps ) { +THREE.AnimationClip.CreateClipsFromMorphTargetSequences = function( morphTargets, fps ) { - var animations = {}; - var animationsArray = []; + var animationToMorphTargets = {}; var pattern = /([a-z]+)_?(\d+)/; + // sort morph target names into animation groups based patterns like Walk_001, Walk_002, Run_001, Run_002 for ( var i = 0, il = morphTargets.length; i < il; i ++ ) { var morphTarget = morphTargets[ i ]; @@ -146,29 +120,24 @@ THREE.AnimationClip.FromImplicitMorphTargetAnimations = function( morphTargets, if ( parts && parts.length > 1 ) { - var animationName = parts[ 1 ]; + var name = parts[ 1 ]; - var animation = animations[ animationName ]; - if ( ! animation ) { - animations[ animationName ] = animation = { name: animationName, morphTargetNames: [] }; - animationsArray.push( animation ); + var animationToMorphTargets = animationToMorphTargets[ name ] || []; + if( ! animationToMorphTargets ) { + animationToMorphTargets = []; } - animation.morphTargetNames.push( morphTarget.name ); + animationToMorphTargets.push( morphTarget ); + } } var clips = []; - for( var i = 0; i < animationsArray.length; i ++ ) { - - var animation = animationsArray[i]; - - var clip = new THREE.AnimationClip.CreateMorphAnimationFromNames( animation.morphTargetNames, animation.morphTargetNames.length * fps ); - clip.name = animation.name; + for( var name in animationToMorphTargets ) { - clips.push( clip ); + clips.push( THREE.AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps ) ); } return clips; @@ -178,57 +147,17 @@ THREE.AnimationClip.FromImplicitMorphTargetAnimations = function( morphTargets, // parse the standard JSON format for clips THREE.AnimationClip.parse = function( json ) { - optionalPrefix = optionalPrefix || ""; - var name = json.name || "default"; - var duration = json.duration || -1; - var fps = json.fps || 30; - var animationTracks = json.tracks || []; - - var tracks = []; - - for( var i = 0; i < animationTracks.length; i ++ ) { + for( var i = 0; i < json.tracks.length; i ++ ) { - var track = THREE.KeyframeTrack.parse( animationTracks[i] ).scale( 1 / fps ); - tracks.push( track ); + tracks.push( THREE.KeyframeTrack.parse( json.tracks[i] ).scale( 1.0 / json.fps ) ); } - if( tracks.length === 0 ) return null; - - return new THREE.AnimationClip( name, duration, tracks ); + return new THREE.AnimationClip( json.name, json.duration, tracks ); }; -// parse the JSON format for THREE.Geometry clips -THREE.AnimationClip.parseGeometryClip = function( json ) { - - var name = json.name || "default"; - var duration = json.duration || -1; - var fps = json.fps || 30; - var animationTracks = json.tracks || []; - - var tracks = []; - - for( var i = 0; i < animationTracks.length; i ++ ) { - - var track = THREE.KeyframeTrack.parse( animationTracks[i] ).scale( 1 / fps ); - if( track.name.indexOf('morphTargets') >= 0 ) { - track.name = track.name.replace('morphTargets', 'morphTargetInfluences' ); - } - if( track.name.indexOf('.') !== 0 ) { - track.name = '.' + track.name; - } - tracks.push( track ); - - } - - if( tracks.length === 0 ) return null; - - return new THREE.AnimationClip( name, duration, tracks ); - -}; - // parse the old animation.hierarchy format THREE.AnimationClip.parseAnimationHierarchy = function( animation, bones, nodeName ) { diff --git a/src/animation/KeyframeTrack.js b/src/animation/KeyframeTrack.js index 04a4ee6766..34c8f823c6 100644 --- a/src/animation/KeyframeTrack.js +++ b/src/animation/KeyframeTrack.js @@ -137,19 +137,11 @@ THREE.KeyframeTrack.prototype = { Tracks with out of order keys should be considered to be invalid. - bhouston sort: function() { - function keyComparator(key0, key1) { - return key0.time - key1.time; - }; - - return function() { - - this.keys.sort( keyComparator ); - - return this; + this.keys.sort( THREE.KeyframeTrack.keyComparer ); - } + return this; - }(),*/ + },*/ // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable // One could eventually ensure that all key.values in a track are all of the same type (otherwise interpolation makes no sense.) @@ -238,6 +230,10 @@ THREE.KeyframeTrack.prototype = { }; +THREE.KeyframeTrack.keyComparer = function keyComparator(key0, key1) { + return key0.time - key1.time; +}; + THREE.KeyframeTrack.parse = function( json ) { if( json.type === undefined ) throw new Error( "track type undefined, can not parse" ); diff --git a/src/loaders/JSONLoader.js b/src/loaders/JSONLoader.js index 8a415b0a0d..5c46cac7b4 100644 --- a/src/loaders/JSONLoader.js +++ b/src/loaders/JSONLoader.js @@ -439,7 +439,7 @@ THREE.JSONLoader.prototype = { for( var i = 0; i < clips.length; i ++ ) { - var clip = THREE.AnimationClip.parseGeometryClip( clips[i] ); + var clip = THREE.AnimationClip.parse( clips[i] ); if( clip ) geometry.clips.push( clip ); } diff --git a/src/loaders/ObjectLoader.js b/src/loaders/ObjectLoader.js index 1b22364216..8f1c7f22d9 100755 --- a/src/loaders/ObjectLoader.js +++ b/src/loaders/ObjectLoader.js @@ -633,9 +633,9 @@ THREE.ObjectLoader.prototype = { // One will end up with a few named clips for the scene composed of merged tracks from individual nodes. for( var i = 0; i < Math.min( 1, data.clips.length ); i ++ ) { - var dataTracks = data.clips[i].tracks; - - var fpsToSeconds = ( data.clips[i].fps !== undefined ) ? ( 1.0 / data.clips[i].fps ) : 1.0; + var dataClips = data.clips[i]; + var dataTracks = dataClips.tracks || []; + var fpsToSeconds = 1.0 / ( dataClips.fps || 30 ); for( var i = 0; i < dataTracks.length; i ++ ) { diff --git a/utils/exporters/blender/addons/io_three/exporter/api/mesh.py b/utils/exporters/blender/addons/io_three/exporter/api/mesh.py index fc003efb36..37bf932760 100644 --- a/utils/exporters/blender/addons/io_three/exporter/api/mesh.py +++ b/utils/exporters/blender/addons/io_three/exporter/api/mesh.py @@ -473,7 +473,7 @@ def animated_blend_shapes(mesh, options): animCurves = animCurves.action.fcurves for key in shp.key_blocks.keys()[1:]: # skip "Basis" - key_name = constants.MORPH_TARGETS+"["+key+"]" + key_name = ".morphTargetInfluences["+key+"]" found_animation = False data_path = 'key_blocks["'+key+'"].value' values = [] diff --git a/utils/exporters/blender/addons/io_three/exporter/api/object.py b/utils/exporters/blender/addons/io_three/exporter/api/object.py index 3ff8ddba45..81b60b6b4c 100644 --- a/utils/exporters/blender/addons/io_three/exporter/api/object.py +++ b/utils/exporters/blender/addons/io_three/exporter/api/object.py @@ -172,10 +172,10 @@ def __parse_tracked_vector(fcurves, start_index, nb_curves): # trackable transform fields ( , , ) TRACKABLE_FIELDS = { - "location": ( "position", 3, "vector3" ), - "scale": ( "scale", 3, "vector3" ), - "rotation_euler": ( "rotation", 3, "vector3" ), - "rotation_quaternion": ( "quaternion", 4, "quaternion" ) + "location": ( ".position", 3, "vector3" ), + "scale": ( ".scale", 3, "vector3" ), + "rotation_euler": ( ".rotation", 3, "vector3" ), + "rotation_quaternion": ( ".quaternion", 4, "quaternion" ) } @_object -- GitLab