Преглед на файлове

Example: Add shared skeleton setup to `webgl_animation_multiple`. (#26995)

Michael Herzog преди 1 година
родител
ревизия
81d91b94f3
променени са 1 файла, в които са добавени 137 реда и са изтрити 25 реда
  1. 137 25
      examples/webgl_animation_multiple.html

+ 137 - 25
examples/webgl_animation_multiple.html

@@ -8,7 +8,7 @@
 	</head>
 	</head>
 	<body>
 	<body>
 		<div id="info">
 		<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>.
 			Soldier model from <a href="https://www.mixamo.com" target="_blank" rel="noopener">https://www.mixamo.com</a>.
 		</div>
 		</div>
 
 
@@ -27,11 +27,16 @@
 
 
 			import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
 			import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
 			import * as SkeletonUtils from 'three/addons/utils/SkeletonUtils.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();
 			init();
 			animate();
 			animate();
@@ -75,32 +80,16 @@
 				const loader = new GLTFLoader();
 				const loader = new GLTFLoader();
 				loader.load( 'models/gltf/Soldier.glb', function ( gltf ) {
 				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;
 						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();
 
 
 				} );
 				} );
 
 
@@ -112,6 +101,129 @@
 
 
 				window.addEventListener( 'resize', onWindowResize );
 				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() {
 			function onWindowResize() {