Three.js skeletal animations not working unless so

2019-07-21 10:29发布

问题:

Using Three.js r68+ I have been needing to very slightly modify the source to get my animations working correctly. Unmodified only one of each type of model are animated (there are multiple spawns of each type of model).

This is the modified source at line 29407 (posted code beginning at 29389):

THREE.AnimationHandler = {

LINEAR: 0,
CATMULLROM: 1,
CATMULLROM_FORWARD: 2,

//

add: function () { console.warn( 'THREE.AnimationHandler.add() has been deprecated.' ); },
get: function () { console.warn( 'THREE.AnimationHandler.get() has been deprecated.' ); },
remove: function () { console.warn( 'THREE.AnimationHandler.remove() has been deprecated.' ); },

//

animations: [],

init: function ( data ) {

    // original -> if ( data.initialized === true ) return;
    if ( data.initialized === true ) return data; //<-- modified

The function now returns the animation data if initialized. I'm assuming it doesn't do so because of caching. My question is what is the best practice for animating multiple models that have the same animation names? I tried naming them uniquely per model name ie: "Death_MaleWarrior" but this had no effect.

Currently my models and animations are handled like so:

var modelArray = [];
var geoCache   = [];
var loader     = new THREE.JSONLoader(true);

var _MODEL = function(data){

  this.data       = data;  
  this.mesh       = null;
  this.animations = {};
  this.canAnimate = false;

  this.parseAnimations = function () {

    var len,i,anim;

    if (this.mesh) {

          if( this.mesh.geometry.animations ){
              this.canAnimate = true;
              len = this.mesh.geometry.animations.length;
              if( len ){
                  for(i=0;i<len;i++){
                      anim = this.mesh.geometry.animations[i];
                      if( anim ){
                        this.animations[anim.name] = new THREE.Animation( this.mesh, anim );
                      }
                  }
              }
          }
      }
  };

  this.playAnimation = function(label){

    if (this.canAnimate) {
      if( this.animations[label] ){
        //if( this.animations[label].data ){
          this.animations[label].play(0,1);
        //}
      }
    }
    return false;

  };

  this.load = function(geo){

    var mat;

    mat = new THREE.MeshPhongMaterial({color:somecolor, skinning:true})

    this.mesh = new THREE.SkinnedMesh(geo,mat);

    this.mesh.position.x = this.data.position[0];
    this.mesh.position.y = this.data.position[1];
    this.mesh.position.z = this.data.position[2];

    this.parseAnimations();

    scene.add(this.mesh);

    this.playAnimation('Idle');

  };

  this.init = function(){

    var geo;

    if( geoCache[this.data.name] ){
      geo = geoCache[this.data.name];
      this.load(geo); 
    }else{
       geo = loader.parse(JSON.parse(this.data.json)).geometry;
       geoCache[this.data.name] = geo;
       this.load(geo);            
    }        

  };

  this.init();

};

var dataArray = [{name:'MaleWarrior',json:'json_data',position:[x,y,z]},{name:'FemaleWarrior',json:'json_data',position:[x,y,z]},{name:'MaleWarrior',json:'json_data',position:[x,y,z]}];

for(var i=0, len=objectArray.length; i<len; i++){
  modelArray.push(new _MODEL(dataArray[i]) );
}

In this example the first MaleWarrior will animate but the second will not. If there was a second female she would not be animated either as the animation (even though it is a new THREE.Animation() ) will be considered initialized and will not return any data. If I do not check for the existence of animations.data in playAnimation I get the error ""Uncaught TypeError: Cannot read property 'name' of undefined " on line 29665".

Is what I'm doing bypassing animation caching and hurting performance? I feel like I'm missing something. How will an animation play without data?

All animation names are the same for every model "Idle", "Run", "Attack" etc.

Any help would be appreciated. If I'm not being clear enough please let me know. I have added additional detail.

回答1:

This turned out to be an official three.js bug.

https://github.com/mrdoob/three.js/issues/5516