瀏覽代碼

Fixed formatting and added comments.

Michael Guerrero 11 年之前
父節點
當前提交
12edee29ff
共有 2 個文件被更改,包括 59 次插入29 次删除
  1. 22 19
      examples/js/BlendCharacter.js
  2. 37 10
      examples/webgl_animation_skinning_blending.html

+ 22 - 19
examples/js/BlendCharacter.js

@@ -2,7 +2,6 @@
  * @author Michael Guerrero / http://realitymeltdown.com
  * @author Michael Guerrero / http://realitymeltdown.com
  */
  */
 
 
-//==============================================================================
 THREE.BlendCharacter = function () {
 THREE.BlendCharacter = function () {
 
 
 	var self = this;
 	var self = this;
@@ -12,33 +11,32 @@ THREE.BlendCharacter = function () {
 	this.weightSchedule = [];
 	this.weightSchedule = [];
 	this.warpSchedule = [];
 	this.warpSchedule = [];
 
 
-	// ---------------------------------------------------------------------------
 	this.load = function(url, loadedCB) {
 	this.load = function(url, loadedCB) {
 
 
 		var loader = new THREE.JSONLoader();
 		var loader = new THREE.JSONLoader();
 		loader.load( url, function( geometry, materials ) {
 		loader.load( url, function( geometry, materials ) {
 
 
 			var originalMaterial = materials[ 0 ];
 			var originalMaterial = materials[ 0 ];
-
 			originalMaterial.skinning = true;
 			originalMaterial.skinning = true;
-			originalMaterial.transparent = true;
-			originalMaterial.alphaTest = 0.75;
 
 
 			THREE.SkinnedMesh.call( self, geometry, originalMaterial );
 			THREE.SkinnedMesh.call( self, geometry, originalMaterial );
 
 
+			// Create the animations
+
 			for ( var i = 0; i < geometry.animations.length; ++i ) {
 			for ( var i = 0; i < geometry.animations.length; ++i ) {
 
 
 				THREE.AnimationHandler.add( geometry.animations[ i ] );
 				THREE.AnimationHandler.add( geometry.animations[ i ] );
 
 
-				// Create the animation object and set a default weight
 				var animName = geometry.animations[ i ].name;
 				var animName = geometry.animations[ i ].name;
 				self.animations[ animName ] = new THREE.Animation( self, animName );
 				self.animations[ animName ] = new THREE.Animation( self, animName );
 
 
 			}
 			}
 
 
+			// Create the debug visualization
+
 			for ( var i = 0; i < self.skeleton.bones.length; ++i ) {
 			for ( var i = 0; i < self.skeleton.bones.length; ++i ) {
 
 
-				var helper = new THREE.BoneAxisHelper( self.skeleton.bones[i], 2, 1 );
+				var helper = new THREE.BoneAxisHelper( self.skeleton.bones[ i ], 2, 1 );
 				helper.update();
 				helper.update();
 				self.add( helper );
 				self.add( helper );
 				self.boneHelpers.push( helper );
 				self.boneHelpers.push( helper );
@@ -54,25 +52,31 @@ THREE.BlendCharacter = function () {
 
 
 	};
 	};
 
 
-	// ---------------------------------------------------------------------------
 	this.updateWeights = function( dt ) {
 	this.updateWeights = function( dt ) {
 
 
+
 		for ( var i = this.weightSchedule.length - 1; i >= 0; --i ) {
 		for ( var i = this.weightSchedule.length - 1; i >= 0; --i ) {
 
 
 			var data = this.weightSchedule[ i ];
 			var data = this.weightSchedule[ i ];
 			data.timeElapsed += dt;
 			data.timeElapsed += dt;
 
 
+			// If the transition is complete, remove it from the schedule
+
 			if ( data.timeElapsed > data.duration ) {
 			if ( data.timeElapsed > data.duration ) {
 
 
 				data.anim.weight = data.endWeight;
 				data.anim.weight = data.endWeight;
 				this.weightSchedule.splice( i, 1 );
 				this.weightSchedule.splice( i, 1 );
 
 
+				// If we've fade out completely, stop the animation
+
 				if ( data.anim.weight == 0 ) {
 				if ( data.anim.weight == 0 ) {
 					data.anim.stop( 0 );
 					data.anim.stop( 0 );
 				}
 				}
 
 
 			} else {
 			} else {
 
 
+				// interpolate the weight for the current time
+
 				data.anim.weight = data.startWeight + (data.endWeight - data.startWeight) * data.timeElapsed / data.duration;
 				data.anim.weight = data.startWeight + (data.endWeight - data.startWeight) * data.timeElapsed / data.duration;
 
 
 			}
 			}
@@ -83,9 +87,12 @@ THREE.BlendCharacter = function () {
 
 
 	};
 	};
 
 
-	// ---------------------------------------------------------------------------
 	this.updateWarps = function( dt ) {
 	this.updateWarps = function( dt ) {
 
 
+		// Warping modifies the time scale over time to make 2 animations of different
+		// length match. This is useful for smoothing out transitions that get out of
+		// phase such as between a walk and run cycle
+
 		for ( var i = this.warpSchedule.length - 1; i >= 0; --i ) {
 		for ( var i = this.warpSchedule.length - 1; i >= 0; --i ) {
 
 
 			var data = this.warpSchedule[ i ];
 			var data = this.warpSchedule[ i ];
@@ -112,6 +119,7 @@ THREE.BlendCharacter = function () {
 				var toFromRatio = toLength / fromLength;
 				var toFromRatio = toLength / fromLength;
 
 
 				// scale from each time proportionally to the other animation
 				// scale from each time proportionally to the other animation
+
 				data.from.timeScale = ( 1 - alpha ) + fromToRatio * alpha;
 				data.from.timeScale = ( 1 - alpha ) + fromToRatio * alpha;
 				data.to.timeScale = alpha + toFromRatio * ( 1 - alpha );
 				data.to.timeScale = alpha + toFromRatio * ( 1 - alpha );
 
 
@@ -124,20 +132,21 @@ THREE.BlendCharacter = function () {
 
 
 	}
 	}
 
 
-	// ---------------------------------------------------------------------------
 	this.updateBoneHelpers = function() {
 	this.updateBoneHelpers = function() {
 
 
 		for ( var i = 0; i < this.boneHelpers.length; ++i ) {
 		for ( var i = 0; i < this.boneHelpers.length; ++i ) {
+
 			this.boneHelpers[ i ].update();
 			this.boneHelpers[ i ].update();
 		}
 		}
+
 	};
 	};
 
 
-	// ---------------------------------------------------------------------------
 	this.play = function(animName, weight) {
 	this.play = function(animName, weight) {
+
 		this.animations[ animName ].play( 0, weight );
 		this.animations[ animName ].play( 0, weight );
+
 	};
 	};
 
 
-	// ---------------------------------------------------------------------------
 	this.crossfade = function( fromAnimName, toAnimName, duration ) {
 	this.crossfade = function( fromAnimName, toAnimName, duration ) {
 
 
 		var fromAnim = this.animations[ fromAnimName ];
 		var fromAnim = this.animations[ fromAnimName ];
@@ -168,7 +177,6 @@ THREE.BlendCharacter = function () {
 
 
 	};
 	};
 
 
-	// ---------------------------------------------------------------------------
 	this.warp = function( fromAnimName, toAnimName, duration ) {
 	this.warp = function( fromAnimName, toAnimName, duration ) {
 
 
 		var fromAnim = this.animations[ fromAnimName ];
 		var fromAnim = this.animations[ fromAnimName ];
@@ -188,14 +196,12 @@ THREE.BlendCharacter = function () {
 
 
 	};
 	};
 
 
-	// ---------------------------------------------------------------------------
 	this.applyWeight = function(animName, weight) {
 	this.applyWeight = function(animName, weight) {
 
 
 		this.animations[animName].weight = weight;
 		this.animations[animName].weight = weight;
 
 
 	};
 	};
 
 
-	// ---------------------------------------------------------------------------
 	this.pauseAll = function() {
 	this.pauseAll = function() {
 
 
 		for ( var a in this.animations ) {
 		for ( var a in this.animations ) {
@@ -210,7 +216,6 @@ THREE.BlendCharacter = function () {
 
 
 	};
 	};
 
 
-	// ---------------------------------------------------------------------------
 	this.unPauseAll = function() {
 	this.unPauseAll = function() {
 
 
 		for ( var a in this.animations ) {
 		for ( var a in this.animations ) {
@@ -226,7 +231,6 @@ THREE.BlendCharacter = function () {
 	};
 	};
 
 
 
 
-	// ---------------------------------------------------------------------------
 	this.stopAll = function() {
 	this.stopAll = function() {
 
 
 		for (a in this.animations) {
 		for (a in this.animations) {
@@ -244,7 +248,6 @@ THREE.BlendCharacter = function () {
 
 
 	}
 	}
 
 
-	// ---------------------------------------------------------------------------
 	this.toggleShowBones = function( shouldShow ) {
 	this.toggleShowBones = function( shouldShow ) {
 
 
 		this.visible = !shouldShow;
 		this.visible = !shouldShow;
@@ -263,7 +266,7 @@ THREE.BlendCharacter = function () {
 
 
 };
 };
 
 
-//==============================================================================
+
 THREE.BlendCharacter.prototype = Object.create( THREE.SkinnedMesh.prototype );
 THREE.BlendCharacter.prototype = Object.create( THREE.SkinnedMesh.prototype );
 
 
 THREE.BlendCharacter.prototype.getForward = function() {
 THREE.BlendCharacter.prototype.getForward = function() {

+ 37 - 10
examples/webgl_animation_skinning_blending.html

@@ -25,9 +25,16 @@
   </head>
   </head>
   <body>
   <body>
     <div id="container"></div>
     <div id="container"></div>
+    <div id="info">
+      <a href="http://threejs.org" target="_blank">three.js</a> - Skeletal Animation Blending
+      <br><br> Adjust blend weights to affect the animations that are currently playing.
+      <br> Cross fades (and warping) blend between 2 animations and end with a single animation.
+    </div>
 
 
     <script src="../build/Three.js"></script>
     <script src="../build/Three.js"></script>
+
     <script src="js/Detector.js"></script>
     <script src="js/Detector.js"></script>
+    <script src="js/libs/stats.min.js"></script>
     <script src="js/Controls/OrbitControls.js"></script>
     <script src="js/Controls/OrbitControls.js"></script>
     <script src="js/BlendCharacter.js"></script>
     <script src="js/BlendCharacter.js"></script>
     <script src="js/BlendCharacterGui.js"></script>
     <script src="js/BlendCharacterGui.js"></script>
@@ -37,12 +44,9 @@
 
 
       if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
       if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
 
 
-      var container;
-
-      var camera, scene, renderer, controls;
+      var container, stats;
 
 
-      var light;
-      var blendMesh = null;
+      var blendMesh, camera, scene, renderer, controls;
 
 
       var clock = new THREE.Clock();
       var clock = new THREE.Clock();
       var gui = null;
       var gui = null;
@@ -59,18 +63,29 @@
         scene = new THREE.Scene();
         scene = new THREE.Scene();
         scene.add ( new THREE.AmbientLight( 0xaaaaaa ) );
         scene.add ( new THREE.AmbientLight( 0xaaaaaa ) );
 
 
-        light = new THREE.DirectionalLight( 0xffffff, 1.5 );
+        var light = new THREE.DirectionalLight( 0xffffff, 1.5 );
         light.position = new THREE.Vector3( 0, 0, 1000.0 );
         light.position = new THREE.Vector3( 0, 0, 1000.0 );
         scene.add( light );
         scene.add( light );
 
 
         renderer = new THREE.WebGLRenderer( { antialias: true, alpha: false } );
         renderer = new THREE.WebGLRenderer( { antialias: true, alpha: false } );
         renderer.setClearColor( '#777777', 1 );
         renderer.setClearColor( '#777777', 1 );
         renderer.setSize( window.innerWidth, window.innerHeight );
         renderer.setSize( window.innerWidth, window.innerHeight );
-        renderer.autoClear = false;
+        renderer.autoClear = true;
 
 
         container.appendChild( renderer.domElement );
         container.appendChild( renderer.domElement );
 
 
+        //
+
+        stats = new Stats();
+        stats.domElement.style.position = 'absolute';
+        stats.domElement.style.top = '0px';
+        container.appendChild( stats.domElement );
+
+        //
+
         window.addEventListener( 'resize', onWindowResize, false );
         window.addEventListener( 'resize', onWindowResize, false );
+
+        // listen for messages from the gui
         window.addEventListener( 'start-animation', onStartAnimation );
         window.addEventListener( 'start-animation', onStartAnimation );
         window.addEventListener( 'stop-animation', onStopAnimation );
         window.addEventListener( 'stop-animation', onStopAnimation );
         window.addEventListener( 'pause-animation', onPauseAnimation );
         window.addEventListener( 'pause-animation', onPauseAnimation );
@@ -103,7 +118,9 @@
 
 
         // the blend mesh will combine 1 or more animations
         // the blend mesh will combine 1 or more animations
         for ( var i = 0; i < data.anims.length; ++i ) {
         for ( var i = 0; i < data.anims.length; ++i ) {
+
           blendMesh.play(data.anims[i], data.weights[i]);
           blendMesh.play(data.anims[i], data.weights[i]);
+
         }
         }
 
 
         isFrameStepping = false;
         isFrameStepping = false;
@@ -196,6 +213,7 @@
         controls.update();
         controls.update();
 
 
         // Set default weights
         // Set default weights
+
         blendMesh.animations[ 'idle' ].weight = 1 / 3;
         blendMesh.animations[ 'idle' ].weight = 1 / 3;
         blendMesh.animations[ 'walk' ].weight = 1 / 3;
         blendMesh.animations[ 'walk' ].weight = 1 / 3;
         blendMesh.animations[ 'run' ].weight = 1 / 3;
         blendMesh.animations[ 'run' ].weight = 1 / 3;
@@ -209,20 +227,29 @@
 
 
         requestAnimationFrame( animate, renderer.domElement );
         requestAnimationFrame( animate, renderer.domElement );
 
 
+        // step forward in time based on whether we're stepping and scale
+
         var scale = gui.getTimeScale();
         var scale = gui.getTimeScale();
         var delta = clock.getDelta();
         var delta = clock.getDelta();
         var stepSize = (!isFrameStepping) ? delta * scale: timeToStep;
         var stepSize = (!isFrameStepping) ? delta * scale: timeToStep;
 
 
+        // modify blend weights
+
         blendMesh.updateWeights( stepSize );
         blendMesh.updateWeights( stepSize );
         gui.update();
         gui.update();
 
 
         THREE.AnimationHandler.update( stepSize );
         THREE.AnimationHandler.update( stepSize );
-        blendMesh.updateBoneHelpers();
 
 
-        timeToStep = 0;
+        // update the transform on the bone visualization
+
+        blendMesh.updateBoneHelpers();
 
 
-        renderer.clear();
         renderer.render( scene, camera );
         renderer.render( scene, camera );
+        stats.update();
+
+        // if we are stepping, consume the amount of time set to have been stepped
+
+        timeToStep = 0;
 
 
       }
       }