Three.js - skinned skeletal mesh instances, animat

2020-05-14 19:00发布

I'm working on a small multiplayer game which has a single skinned player mesh with many players using it. Some Background: I've tried loading via maya and blender collada export. Both seem to reference some form of animation data but I couldn't get it working. I've tried the maya JSON exporter, which spat out tiny 1k files with only a material line. Finally the blender JSON exporter worked. To those also trying to load skinned meshes, I found this very helpful: Model with bones animation (blender export) animating incorrectly in three.js

So now I have a geometry object and a materials array from the JSON loader.

I can set skinning=true on the materials, create a THREE.SkinnedMesh, add it to the scene, add animations via THREE.AnimationHandler.add (I'm quite unclear on what the AnimationHandler actually does), create a THREE.Animation, call play() and update(dt). Finally I have a single mesh and an animation playing in my scene.

Now what I want are these...

  1. Many instances - I want more than one player model running around in my scene.

    • I don't want the same mesh and animation data loaded many times.
    • Animation time should be per-instance (so they don't all animate in sync).

    Should I be creating many THREE.SkinnedMesh and THREE.Animation for the same model? Where does THREE.AnimationHandler come in?

  2. Many animations - I want idle/run cycles able to be played individually.

    AFAIK there's only a single timeline of animation keyframes. How does Three.js partition this up for me, or do I have to do it manually?

  3. Animation Blending - When a character stops running and stands still with the idle animation, I don't want an instant snap from one to the other. I'd like to pause the run animation and blend that state back into the idle animation.

    Is this currently possible with skinned meshes (not morph targets)? Are there examples or docs about this?

Any information would be greatly appreciated, even just a nudge in the right direction. I'm not after a full tutorial, I would like some higher level information about these features.

I could happily implement 2 and 3, but I'd like some information/descriptive docs about the threejs skinning and animation framework to get me started. For example, this isn't much to go on.

[EDIT]
Thanks, @NishchitDhanani, this page is quite good but doesn't mention multiple animations or blending skeletal animations: http://chimera.labs.oreilly.com/books/1234000000802/ch05.html#animating_characters_with_skinning

This page says multiple animations are still a current issue but not much more (discussed a little in the comments): http://devmatrix.wordpress.com/2013/02/27/creating-skeletal-animation-in-blender-and-exporting-it-to-three-js/

The current answers are...

  1. Use many THREE.SkinnedMesh and still not sure about THREE.AnimationHandler.
  2. Don't know. Perhaps there's a way to modify the start/end keyframes manually in the THREE.Animation.
  3. Not implemented AFAIK. I might try creating a custom shader that can take two THREE.Animations and interpolate between them.

3条回答
老娘就宠你
2楼-- · 2020-05-14 19:29

As of release 67 (April 2014), both skeletal animation blending and multiple animations are supported. You will still need to create a SkinnedMesh for each model. The AnimationHandler is responsible for updating (ticking) the animations every frame so you should be calling update on that and not manually on each Animation.

See the newly added example: webgl_animation_skinning_blending.html or check out a couple of my own here:

Basic Character Controller (with time warped speed blend)

Time Warped Speed Blend

查看更多
劫难
3楼-- · 2020-05-14 19:41

@Xealgo: There's a new exporter for Maya that does bones and animations as well. I'd love to have that few months ago, before I was forced to go with Blender workflow. :)

Here's a link: https://github.com/mrdoob/three.js/tree/dev/utils/exporters/maya

查看更多
女痞
4楼-- · 2020-05-14 19:49

I have been able to simultaneously deploy four different animated models created with Blender and exported as JSON files by creating individual skinned meshes for each model using individually tailored functions with the JSON loader. Each of my four models has different mesh, animations, textures and numbers of keyframes.

var loader = new THREE.JSONLoader(); 
loader.load("model_1.js", createSkinnedMeshforModel_1);
loader.load("model_2.js", createSkinnedMeshforModel_2);
loader.load("model_3.js", createSkinnedMeshforModel_3);

...

var animations = [];

function createSkinnedMeshforModel_1( geometry, materials )
{
  var myModel1, animation;
  THREE.AnimationHandler.add( geometry.animation );
  myModel1 = new THREE.SkinnedMesh(geometry, new THREE.MeshFaceMaterial(materials));
  enableSkinning( myModel1 );
  scene.add( myModel1 );
  animation = new THREE.Animation(myModel1, Model1_Animation_title, THREE.AnimationHandler.CATMULLROM);
  animations.push( animation );
  for( var i = 0; i < animations.length; i ++ )
  {
    animations[ i ].play();
  }
}


function createSkinnedMeshforModel_2( geometry, materials )
{
  var myModel2, animation;
  THREE.AnimationHandler.add( geometry.animation );
  myModel2 = new THREE.SkinnedMesh(geometry, new THREE.MeshFaceMaterial(materials));
  enableSkinning( myModel2 );
  scene.add( myModel2 );
  animation = new THREE.Animation(myModel2, Model2_Animation_title, THREE.AnimationHandler.CATMULLROM);
  animations.push( animation );
  for( var i = 0; i < animations.length; i ++ )
  {
    animations[ i ].play();
  }
}

function createSkinnedMeshforModel_3( geometry, materials )
{
  var myModel3, animation;
  THREE.AnimationHandler.add( geometry.animation );
  myModel3 = new THREE.SkinnedMesh(geometry, new THREE.MeshFaceMaterial(materials));
  enableSkinning( myModel3 );
  scene.add( myModel3 );
  animation = new THREE.Animation(myModel3, Model3_Animation_title, THREE.AnimationHandler.CATMULLROM);
  animations.push( animation );
  for( var i = 0; i < animations.length; i ++ )
  {
    animations[ i ].play();
  }
}

The enableSkinning() function is the same as the one provided in DEVMATRIX's really helpful tutorial

The "Modelx_Animation_title" variable is the animation title name defined within Blender and copied into the model's exported JSON file by the Three.js Blender exporter.

When I load multiple copies of a given model they initially animate in Sync. However I have been able to get them to animate out of sync by individually pausing each model for a short random duration before starting playing again. The animations for each individual model resume from the frame that they were paused at.

animations[ i ].pause();
... (random delay) ...
animations[ i ].play();

Perhaps this approach provides a solution of sorts to question 1, and possibly to question 2.

With regard to Question 2, Three.js release r62 updated the Blender exporter to allow "Export multiple actions". Although I haven't tried it perhaps this may allow loading two or more copies of a given model while specifying the animation titles for the different actions. It might then be possible to swap the models in and out of the view when different actions are required.

If that works, then a possible solution to Question 3 might be to create an additional animated action within Blender that blends the model from an active state to it's idle state.

查看更多
登录 后发表回答