6

I'm trying to define a model of the human body in THREE.js using the classes THREE.Bone, THREE.Skeleton and THREE.SkinnedMesh.

I defined a custom skeleton structure made of 12 body parts, each of which is a THREE.Bone instance, and used the .add() method to define parent / child relationships among them. Finally, I created a standard THREE.Object3D as the body root that is parent of the full skeleton.

Posting only part of the structure for conciseness:

// create person object
var body_root = new THREE.Object3D()

// create torso
var torso  = new THREE.Bone();
torso.id   = 1;
torso.name = "torso";
x_t = 0;
y_t = 0;
z_t = 0;
torso.position.set(x_t,y_t,z_t);
x_alpha = 0 * Math.PI;
y_alpha = 0 * Math.PI;
z_alpha = 0 * Math.PI;
torso.rotation.set(x_alpha,y_alpha,z_alpha);

// create right arm
var right_arm = new THREE.Bone();
right_arm.id   = 2;
right_arm.name = "right_arm";
x_t = -TORSO_WIDTH / 2;
y_t = TORSO_HEIGHT;
z_t = 0;
right_arm.position.set(x_t,y_t,z_t);
x_alpha = 0 * Math.PI;
y_alpha = 0 * Math.PI;
z_alpha = 0 * Math.PI;
right_arm.rotation.set(x_alpha,y_alpha,z_alpha);

// add right_arm as child of torso
torso.add( right_arm );

This works just fine, and after loading the page I can access the model and traverse it correctly through the console.

However, when I try to render the skeleton in the scene things get tricky.

1. How can I add a THREE.SkinnedMesh for a custom skeleton structure?

In the documentation (check source code) a CylinderGeometry and a SkinnedMesh are created for all the bones jointly

var geometry = new THREE.CylinderGeometry( 5, 5, 5, 5, 15, 5, 30 );
var mesh = THREE.SkinnedMesh( geometry, material );

and then the bone structure is binded:

// See example from THREE.Skeleton for the armSkeleton
var rootBone = armSkeleton.bones[ 0 ];
mesh.add( rootBone );
// Bind the skeleton to the mesh
mesh.bind( armSkeleton );

This works perfectly for the simple example in the documentation (5 bones each one parent of the next one), but how can I adapt this example to a more complex structure in which some bones have multiple children? And how can I implement bones with different geometry? For instance I would like to implement joints like shoulder and elbow with a sphere for which I can only change rotation and body parts like arm and forearm with cylinders having different base radius.

Is it possible to define a SkinnedMesh for each joint independently and for a more complex structure than the one in the example? If so how do you link them all together?

2. Can I add a THREE.SkeletonHelper to the scene without defining a skinned mesh but using only the bones?

Since I don't know the answer to question 1 I decided to simply try to render the skeleton structure. This is done in other examples (such as this one) by creating a THREE.SkeletonHelper instance and adding that to the scene.

I tried passing the body_root variable (instead of the SkinnedMesh) to the constructor and the helper is created, but not rendered.

helper = new THREE.SkeletonHelper( body_root );
helper.material.linewidth = 3;
scene.add( helper );

In order to visualize the helper it needs to be binded to a mesh, even if the mesh is not added directly to the scene, i.e. adding the line mesh.bind(armSkeleton) visualizes the skeleton helper.

Is this possible at all to visualize the skeleton helper without defining a mesh? If so how?

NOTE on question 2:

I believe this should be possible, since the THREE.SkeletonHelper class defines internally its own geometry and material, so it should be possible to render it without needing the mesh of the skeleton:

THREE.SkeletonHelper = function ( object ) {

    this.bones = this.getBoneList( object );

    var geometry = new THREE.Geometry();

    for ( var i = 0; i < this.bones.length; i ++ ) {

        var bone = this.bones[ i ];

        if ( bone.parent instanceof THREE.Bone ) {

            geometry.vertices.push( new THREE.Vector3() );
            geometry.vertices.push( new THREE.Vector3() );
            geometry.colors.push( new THREE.Color( 0, 0, 1 ) );
            geometry.colors.push( new THREE.Color( 0, 1, 0 ) );

        }

    }

    geometry.dynamic = true;

    var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors, depthTest: false, depthWrite: false, transparent: true } );

    THREE.LineSegments.call( this, geometry, material );

    this.root = object;

    this.matrix = object.matrixWorld;
    this.matrixAutoUpdate = false;

    this.update();

};
Matteo
  • 7,924
  • 24
  • 84
  • 129
  • 1
    This isn't exactly answering your question, but I'd strongly recommend creating your skeleton using tools like Blender, Maya, or Mixamo. Then export to FBX or glTF, import into three.js, and animate it there. Constructing the whole thing in three.js is, as you've described here, quite hard. :) – Don McCurdy Jan 07 '18 at 06:30
  • @DonMcCurdy Do you think you would be able to answer my question ? https://stackoverflow.com/questions/60036248/how-to-manipulate-individual-bones-of-a-3d-model-in-react-native I've been stuck for a while, and can't find any example of how to manipulate individual bones of a 3d model (obj) imported into three.js – Rahul Iyer Feb 18 '20 at 09:03

0 Answers0