According to this PR, https://github.com/mrdoob/three.js/pull/4812#issuecomment-43788375, there is ostensibly a way to support animating multiple SkinnedMeshes using a single Skeleton:
Please see the most recent code. I have re-introduced THREE.Skeleton and decoupled it from THREE.SkinnedMesh. This will allow us to animate multiple meshes with a single skeleton. The mesh-specific bind matrices are stored in THREE.SkinnedMesh and used by the vertex shader to transform to/from "bind space" (world space in the current implementation).
Unfortunately, no docs or examples appear to have been contributed to demonstrate how this might be accomplished, and try as I might, I can't seem to come up with a way to achieve this on my own.
I'd like to suggest either adding an example, updating the docs, or both. Alternatively, in the event that it's not currently possible, does anyone have a suggestion on an approach to make it possible in the future?
[ ] ...
[x] All of them
[ ] Internet Explorer
[x] All of them
I'm right there with you. I am about to start posting some detailed inquiries regarding how to most efficiently animate multiple meshes with the new animation system (some share geometry, some do not).
@titansoftime / @fallenoak I have achieved this (multiple meshes sharing same skeleton) using the current dev branch, but its a bit of a pain to do with SkinnedMesh
and BufferGeometry
currently. First, I had to modify the ObjectLoader
to load SkinnedMesh
s without bones from JSON properly.
Then, I used a Group instance as a stand-in for an armature root, with multiple skinned mesh children. And I stored the shared bones in a custom userData
property in the JSON, so it survives the loading process.
You will have to handle the Bone
and Skeleton
creation manually in your code. These can be attached to the Group
root too. Then binding that Skeleton
to each skinned mesh is straightforward. The bone and skeleton creation code is more or less the same as what the SkinnedMesh
constructor usually does when bones are present on the mesh geometry.
@satori99 Hrm, thanks for the details! I'm already working directly with SkinnedMesh
/ Skeleton
/ Bone
(ie not using ObjectLoader
) because the model formats I'm using come from a third party and are non-standard.
So if I understand things right, you're adding the Bone
s to a Group
, placing that Group
in the scene, and then spawning multiple SkinnedMesh
es, each sharing the same Skeleton
(and thus the same Bone
s across each SkinnedMesh
). Is that right?
Does it matter where in the scene the Group
that holds the Bone
s goes? Is the Group
's placement irrelevant, as long as it's part of the scene graph? Does it have to all of the SkinnedMesh
es that are binding to the Skeleton
?
What happens when the matrixWorld
of the SkinnedMesh
es changes after calling bind()
? It looks to me like bind()
copies the matrixWorld
when it's called, but how does that deal with cases like a translating / rotating / scaling SkinnedMesh
?
Relevant code for bind()
:
bind: function( skeleton, bindMatrix ) {
this.skeleton = skeleton;
if ( bindMatrix === undefined ) {
this.updateMatrixWorld( true );
this.skeleton.calculateInverses();
bindMatrix = this.matrixWorld;
}
this.bindMatrix.copy( bindMatrix );
this.bindMatrixInverse.getInverse( bindMatrix );
}
So if I understand things right, you're adding the Bones to a Group, placing that Group in the scene, and then spawning multiple SkinnedMeshes, each sharing the same Skeleton (and thus the same Bones across each SkinnedMesh). Is that right?
I am loading SkinnedMesh instances directly from JSON, so the loader is creating them. But I am loading the skinned meshes without any bones on them (so the SkinnedMesh constructor code does nothing really). Creating the SkinnedMesh instances yourself shouldnt make any difference though. All the SkinnedMeshs plus the Bones I created manually are all parented to the same Group. You can translate rotate the Group to move the whole character in the scene.
Is the Group's placement irrelevant, as long as it's part of the scene graph?
I believe so.
Does it have to all of the SkinnedMeshes that are binding to the Skeleton?
Not if you don't want to; Any static mesh or a skinned mesh with its own skeleton should do its own thing still, relative to the parent. When I apply animationClip's, I use the Group instance as the mixer root object. I have not encountered any issues doing that so far.
Ill try to post a fiddle demo later today.
This is demonstration of the technique i am using to share a skeleton between multiple SkinnedMesh
instances:
https://jsfiddle.net/satori99/pay0oqcd/
The Body and Clothing are separate SkinnedMesh
s. A skeletal animation is applied to the root Group
instance (just one leg). The whole thing is then animated in the render loop independent of the skeletal animation.
@satori99 So your example isn't quite the same as what I had in mind, unfortunately. Your method works well when handling meshes that are effectively segments of a single mesh, but doesn't cover the case where each SkinnedMesh
sharing the Skeleton
has a different placement (translation, rotation, scale) in the scene.
If you modify your example like so:
body = createSkinnedMesh( root.getObjectByName( 'Body' ), skeleton )
body.position.x = -2;
body.position.y = 2;
body.updateMatrix();
body.updateMatrixWorld();
You'll find that the body is still in the same position. As far as I can tell, there's no way to offset the body and clothes SkinnedMesh
es from one another. Their placement is locked to the position of the root.
Maybe sharing a Skeleton
across submeshes was the only kind of sharing intended by @ikerr in his improvements, but it seems like it ought to be mathematically possible to share a skeleton across multiple scene placements.
It should be possible to animate multiple SkinnedMesh
instances with a single Skeleton
. And yes, I should create an example for this... I'm away for the next week or so, but will try to get something working after that. Please give me a nudge if I don't.
The process would be as follows:
THREE.SkinnedMesh
instances.THREE.Skeleton
instance.THREE.SkinnedMesh
determine the "bind space matrix" that "attaches" the mesh to the skeleton. For example, if your mesh is at the origin, but your skeleton is at +1 along the x-axis, the bind shape matrix would be a (1, 0, 0) translation matrix.THREE.SkinnedMesh.prototype.bind()
, along with the skeleton.We should probably change the name of THREE.Skeleton
to THREE.Skin
since it's equivalent to FBX's FbxSkin
and COLLADA's
@ikerr Thanks for popping in.
I'm still foggy on how the bind space matrix would account for separate instances / placements of THREE.SkinnedMesh
in a scene.
I believe I understand how to recycle a set of bones and skeleton for several THREE.SkinnedMesh
instances that co-exist in the same local space--for example, skinned meshes acting as sections of a single parent geometry. But once the THREE.SkinnedMesh
es are separate objects in a THREE.Scene()
, my understanding goes out the window.
For example:
var scene = new THREE.Scene();
var bones = <an array of bones meant to be shared (not cloned) by multiple skinned mesh instances>;
var geometry = <a buffer geometry meant to be shared (not cloned) by multiple skinned mesh instances>;
var material = <a basic material with skinning set to true>;
var skeleton = new THREE.Skeleton(bones);
var object1 = new THREE.SkinnedMesh(geometry, material);
object1.bind(skeleton);
object1.position.x = 5;
object1.position.y = 5;
scene.add(object1);
var object2 = new THREE.SkinnedMesh(geometry, material);
object2.bind(skeleton);
object2.position.x = 10;
object2.position.y = 10;
scene.add(object2);
THREE.Scene
should the bones be added? Do they need to go into the scene at all if I were to manually call updateMatrix()
on them while they animate?bindMatrix
and bindMatrixInverse
? If my bone positions are in the same coordinate system as the geometry, should I just be using a bindMatrix
set to identity, and a bindMode
set to detached
?object1
and object2
would have regularly updated position
, scale
, and rotation
independent of each other, if I need to use something other than identity, how could I calculate an appropriate bind space matrix for them?To build a bit on my last comment, it appears that it's possible to animate multiple independently positioned THREE.SkinnedMesh
objects by using an identity matrix for the bindMatrix
and using bindMode
set to detached
.
When I do this, I'm able to animate the THREE.Bone
objects just once, and share the results between multiple THREE.SkinnedMesh
placements of the same geometry in the scene graph.
I'm still not clear on why this works, but it'd be lovely to update the skinning documentation with a few more details, and add some examples.
Nudging @ikerr!
We probably should do an example showing this 馃槄
I want such an example, too.
I've been working on SkinnedMesh
serialization #8978.
I wanna consider how to support shared Skeleton
on that.
I need a standard way to share Skeleton
.
Nudge @ikerr and/or @mrdoob
Started working on this, but am getting stuck using the Blender exporter. Maybe you guys can help me out...
I'm trying to export a skinned, animated model and would like to use the "new" animation format (with the "tracks" property), but no matter which combination of settings I use, the "animations" property always ends up looking like this:
"animations":[{
"fps":24,
"name":"default",
"tracks":[]
}],
I'm deselect everything before exporting and use the following export settings:
Any ideas?
/ping @bhouston @tschw
I'd suggest that someone create an example that demonstrates multiple skinned meshes being animated using a skeleton. If you can not get it working, that would be a useful test case, and then once it is working, we can maintain it going forward so that it always works.
Hi @bhouston, I'm working on such an example but am having trouble with the Blender exporter. Please see my previous comment for details. Do you know what settings I need to export the "new" animations?
@ikerr I haven't tried the latest Blender exporter in a couple months. It was exported skinned animations with skeletons earlier this year. But it could also be that your scene is setup differently than the ones I was testing with. I would suggest trying the Blender importer from earlier this year -- like February and see if it works. If it doesn't then it may be that your scene structure is not supported by the plugin.
@ikerr Without the blend file it's hard to say. Currently I'm able to export skinned animations from Blender 2.78 and a recent exporter from 32867de625840be971a47f7f07c25aacd448784c.
Edit: Sorry, I'm also not getting "tracks", just the old style hierachies with type Geometry
.
I think part of the problem is problematic coupling in the constructor of SkinnedMesh
which makes users jump through some hoops to allow sharing of bones / skeleton. One possible solution is to define Skeleton
as a completely separate object in the scene graph which can share its bone data with any direct descendent children which are SkinnedMesh
instances. This is similar to how Blender implements skinning, with Armature
objects as separate from Mesh
.
@mrdoob @ikerr @empaempa As far as I can tell, skin
property of Bone
is no longer needed. I'm not sure the original intention of this property, but I couldn't find a reference to it in the renderer or other source code. Removing this relationship would further help to simplify how Skeleton
and Bone
relate to SkinnedMesh
instances.
@mrdoob @ikerr @empaempa As far as I can tell,
skin
property ofBone
is no longer needed. I'm not sure the original intention of this property, but I couldn't find a reference to it in the renderer or other source code. Removing this relationship would further help to simplify howSkeleton
andBone
relate toSkinnedMesh
instances.
Try doing a PR and see if nothing breaks 馃槉
Hello,
Is there anything new or planned about multiples meshes for one skeleton ? I looking to do that in a futur project but apparently there is no example yet (except for the satori99's proposition)
+1 still not sure how to properly implement person with clothing with same skinning animation.
I'm tackling this issue right now. Will report back if I get an example working, otherwise it would be great to know if anyone else has had success?
I personally am waiting for the Khronos Group GLTF2.0 exporter for Blender to work out their animation bugs before doing any heavy animation stuff.
@titansoftime it's a real pain, I know! Just so you know I wrote a little guide helping with this topic (basically the best option right now is to convert from FBX to glTF).
Currently seeing if I can put together a simple example for shared skeletons. Will submit a PR if it is successful :)
Example added. Open to feedback, even if it's just more helpful comments, etc. :)
Most helpful comment
I'd suggest that someone create an example that demonstrates multiple skinned meshes being animated using a skeleton. If you can not get it working, that would be a useful test case, and then once it is working, we can maintain it going forward so that it always works.