Skip to content

Commit

Permalink
Example: Add shared skeleton setup to webgl_animation_multiple. (mr…
Browse files Browse the repository at this point in the history
  • Loading branch information
Mugen87 authored Oct 17, 2023
1 parent de5932e commit 81d91b9
Showing 1 changed file with 137 additions and 25 deletions.
162 changes: 137 additions & 25 deletions examples/webgl_animation_multiple.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</head>
<body>
<div id="info">
This demo shows how to clone a skinned mesh using <strong>SkeletonUtils.clone()</strong><br/>
This demo shows the usage of <strong>SkeletonUtils.clone()</strong> and how to setup a shared skeleton.<br/>
Soldier model from <a href="https://www.mixamo.com" target="_blank" rel="noopener">https://www.mixamo.com</a>.
</div>

Expand All @@ -27,11 +27,16 @@

import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import * as SkeletonUtils from 'three/addons/utils/SkeletonUtils.js';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

let camera, scene, renderer;
let clock;
let camera, scene, renderer, clock;
let model, animations;

const mixers = [];
const mixers = [], objects = [];

const params = {
sharedSkeleton: false
};

init();
animate();
Expand Down Expand Up @@ -75,32 +80,16 @@
const loader = new GLTFLoader();
loader.load( 'models/gltf/Soldier.glb', function ( gltf ) {

gltf.scene.traverse( function ( object ) {
model = gltf.scene;
animations = gltf.animations;

model.traverse( function ( object ) {

if ( object.isMesh ) object.castShadow = true;

} );

const model1 = SkeletonUtils.clone( gltf.scene );
const model2 = SkeletonUtils.clone( gltf.scene );
const model3 = SkeletonUtils.clone( gltf.scene );

const mixer1 = new THREE.AnimationMixer( model1 );
const mixer2 = new THREE.AnimationMixer( model2 );
const mixer3 = new THREE.AnimationMixer( model3 );

mixer1.clipAction( gltf.animations[ 0 ] ).play(); // idle
mixer2.clipAction( gltf.animations[ 1 ] ).play(); // run
mixer3.clipAction( gltf.animations[ 3 ] ).play(); // walk

model1.position.x = - 2;
model2.position.x = 0;
model3.position.x = 2;

scene.add( model1, model2, model3 );
mixers.push( mixer1, mixer2, mixer3 );

animate();
setupDefaultScene();

} );

Expand All @@ -112,6 +101,129 @@

window.addEventListener( 'resize', onWindowResize );

const gui = new GUI();

gui.add( params, 'sharedSkeleton' ).onChange( function () {

clearScene();

if ( params.sharedSkeleton === true ) {

setupSharedSkeletonScene();

} else {

setupDefaultScene();

}

} );
gui.open();

}

function clearScene() {

for ( const mixer of mixers ) {

mixer.stopAllAction();

}

mixers.length = 0;

//

for ( const object of objects ) {

scene.remove( object );

scene.traverse( function ( child ) {

if ( child.isSkinnedMesh ) child.skeleton.dispose();

} );

}

}

function setupDefaultScene() {

// three cloned models with independent skeletons.
// each model can have its own animation state

const model1 = SkeletonUtils.clone( model );
const model2 = SkeletonUtils.clone( model );
const model3 = SkeletonUtils.clone( model );

model1.position.x = - 2;
model2.position.x = 0;
model3.position.x = 2;

const mixer1 = new THREE.AnimationMixer( model1 );
const mixer2 = new THREE.AnimationMixer( model2 );
const mixer3 = new THREE.AnimationMixer( model3 );

mixer1.clipAction( animations[ 0 ] ).play(); // idle
mixer2.clipAction( animations[ 1 ] ).play(); // run
mixer3.clipAction( animations[ 3 ] ).play(); // walk

scene.add( model1, model2, model3 );

objects.push( model1, model2, model3 );
mixers.push( mixer1, mixer2, mixer3 );

}

function setupSharedSkeletonScene() {

// three cloned models with a single shared skeleton.
// all models share the same animation state

const sharedModel = SkeletonUtils.clone( model );
const shareSkinnedMesh = sharedModel.getObjectByName( 'vanguard_Mesh' );
const sharedSkeleton = shareSkinnedMesh.skeleton;
const sharedParentBone = sharedModel.getObjectByName( 'mixamorigHips' );
scene.add( sharedParentBone ); // the bones need to be in the scene for the animation to work

const model1 = shareSkinnedMesh.clone();
const model2 = shareSkinnedMesh.clone();
const model3 = shareSkinnedMesh.clone();

model1.bindMode = THREE.DetachedBindMode;
model2.bindMode = THREE.DetachedBindMode;
model3.bindMode = THREE.DetachedBindMode;

const identity = new THREE.Matrix4();

model1.bind( sharedSkeleton, identity );
model2.bind( sharedSkeleton, identity );
model3.bind( sharedSkeleton, identity );

model1.position.x = - 2;
model2.position.x = 0;
model3.position.x = 2;

// apply transformation from the glTF asset

model1.scale.setScalar( 0.01 );
model1.rotation.x = - Math.PI * 0.5;
model2.scale.setScalar( 0.01 );
model2.rotation.x = - Math.PI * 0.5;
model3.scale.setScalar( 0.01 );
model3.rotation.x = - Math.PI * 0.5;

//

const mixer = new THREE.AnimationMixer( sharedParentBone );
mixer.clipAction( animations[ 1 ] ).play();

scene.add( sharedParentBone, model1, model2, model3 );

objects.push( sharedParentBone, model1, model2, model3 );
mixers.push( mixer );

}

function onWindowResize() {
Expand Down

0 comments on commit 81d91b9

Please sign in to comment.