瀏覽代碼

Merge pull request #4812 from ikerr/refactor_flexible_skinning

Refactor flexible skinning
Mr.doob 11 年之前
父節點
當前提交
f0a2a841e1

+ 1 - 1
examples/js/BlendCharacter.js

@@ -193,7 +193,7 @@ THREE.BlendCharacter = function () {
 
 			if ( this.animations[ a ].isPlaying ) {
 
-				this.animations[ a ].pause();
+				this.animations[ a ].stop();
 
 			}
 

+ 1 - 2
examples/webgldeferred_animation.html

@@ -255,7 +255,6 @@
 					geometry.computeBoundingBox();
 
 					ensureLoop( geometry.animation );
-					THREE.AnimationHandler.add( geometry.animation );
 
 					for ( var i = 0, il = materials.length; i < il; i ++ ) {
 
@@ -292,7 +291,7 @@
 					skins.push( mesh );
 
 
-					animation = new THREE.Animation( mesh, "ActionFemale" );
+					animation = new THREE.Animation( mesh, geometry.animation );
 					animation.play();
 					animation.update( 0 );
 

+ 1 - 2
src/extras/animation/Animation.js

@@ -66,7 +66,7 @@ THREE.Animation.prototype.reset = function () {
 			object.animationCache[this.data.name] = {};
 			object.animationCache[this.data.name].prevKey = { pos: 0, rot: 0, scl: 0 };
 			object.animationCache[this.data.name].nextKey = { pos: 0, rot: 0, scl: 0 };
-			object.animationCache[this.data.name].originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix;
+			object.animationCache[this.data.name].originalMatrix = object.matrix;
 
 		}
 
@@ -238,7 +238,6 @@ THREE.Animation.prototype.update = (function(){
 
 						}
 
-
 					} else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
 								this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
 

+ 3 - 12
src/extras/animation/KeyFrameAnimation.js

@@ -75,7 +75,7 @@ THREE.KeyFrameAnimation.prototype.play = function ( startTime ) {
 				node.animationCache = {};
 				node.animationCache.prevKey = null;
 				node.animationCache.nextKey = null;
-				node.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix;
+				node.animationCache.originalMatrix = object.matrix;
 
 			}
 
@@ -122,17 +122,8 @@ THREE.KeyFrameAnimation.prototype.stop = function() {
 
 			var original = node.animationCache.originalMatrix;
 
-			if( obj instanceof THREE.Bone ) {
-
-				original.copy( obj.skinMatrix );
-				obj.skinMatrix = original;
-
-			} else {
-
-				original.copy( obj.matrix );
-				obj.matrix = original;
-
-			}
+			original.copy( obj.matrix );
+			obj.matrix = original;
 
 			delete node.animationCache;
 

+ 36 - 8
src/extras/helpers/SkeletonHelper.js

@@ -2,17 +2,18 @@
  * @author Sean Griffin / http://twitter.com/sgrif
  * @author Michael Guerrero / http://realitymeltdown.com
  * @author mrdoob / http://mrdoob.com/
+ * @author ikerr / http://verold.com
  */
 
 THREE.SkeletonHelper = function ( object ) {
 
-	var skeleton = object.skeleton;
+	this.bones = this.getBoneList( object );
 
 	var geometry = new THREE.Geometry();
 
-	for ( var i = 0; i < skeleton.bones.length; i ++ ) {
+	for ( var i = 0; i < this.bones.length; i ++ ) {
 
-		var bone = skeleton.bones[ i ];
+		var bone = this.bones[ i ];
 
 		if ( bone.parent instanceof THREE.Bone ) {
 
@@ -29,7 +30,7 @@ THREE.SkeletonHelper = function ( object ) {
 
 	THREE.Line.call( this, geometry, material, THREE.LinePieces );
 
-	this.skeleton = skeleton;
+	this.root = object;
 
 	this.matrixWorld = object.matrixWorld;
 	this.matrixAutoUpdate = false;
@@ -41,20 +42,47 @@ THREE.SkeletonHelper = function ( object ) {
 
 THREE.SkeletonHelper.prototype = Object.create( THREE.Line.prototype );
 
+THREE.SkeletonHelper.prototype.getBoneList = function( object ) {
+
+	var boneList = [];
+
+	if ( object instanceof THREE.Bone ) {
+
+		boneList.push( object );
+
+	}
+
+	for ( var i = 0; i < object.children.length; i ++ ) {
+
+		boneList.push.apply( boneList, this.getBoneList( object.children[ i ] ) );
+
+	}
+
+	return boneList;
+
+};
+
 THREE.SkeletonHelper.prototype.update = function () {
 
 	var geometry = this.geometry;
 
+	var matrixWorldInv = new THREE.Matrix4().getInverse( this.root.matrixWorld );
+
+	var boneMatrix = new THREE.Matrix4();
+
 	var j = 0;
 
-	for ( var i = 0; i < this.skeleton.bones.length; i ++ ) {
+	for ( var i = 0; i < this.bones.length; i ++ ) {
 
-		var bone = this.skeleton.bones[ i ];
+		var bone = this.bones[ i ];
 
 		if ( bone.parent instanceof THREE.Bone ) {
 
-			geometry.vertices[ j ].setFromMatrixPosition( bone.skinMatrix );
-			geometry.vertices[ j + 1 ].setFromMatrixPosition( bone.parent.skinMatrix );
+			boneMatrix.multiplyMatrices( matrixWorldInv, bone.matrixWorld );
+			geometry.vertices[ j ].setFromMatrixPosition( boneMatrix );
+
+			boneMatrix.multiplyMatrices( matrixWorldInv, bone.parent.matrixWorld );
+			geometry.vertices[ j + 1 ].setFromMatrixPosition( boneMatrix );
 
 			j += 2;
 

+ 7 - 40
src/objects/Bone.js

@@ -1,6 +1,7 @@
 /**
  * @author mikael emtinger / http://gomo.se/
  * @author alteredq / http://alteredqualia.com/
+ * @author ikerr / http://verold.com
  */
 
 THREE.Bone = function ( belongsToSkin ) {
@@ -8,7 +9,6 @@ THREE.Bone = function ( belongsToSkin ) {
 	THREE.Object3D.call( this );
 
 	this.skin = belongsToSkin;
-	this.skinMatrix = new THREE.Matrix4();
 
 	this.accumulatedRotWeight = 0;
 	this.accumulatedPosWeight = 0;
@@ -18,48 +18,15 @@ THREE.Bone = function ( belongsToSkin ) {
 
 THREE.Bone.prototype = Object.create( THREE.Object3D.prototype );
 
-THREE.Bone.prototype.update = function ( parentSkinMatrix, forceUpdate ) {
+THREE.Bone.prototype.updateMatrixWorld = function ( force ) {
 
-	// update local
+	THREE.Object3D.prototype.updateMatrixWorld.call( this, force );
 
-	if ( this.matrixAutoUpdate ) {
+	// Reset weights to be re-accumulated in the next frame
 
-		forceUpdate |= this.updateMatrix();
-
-	}
-
-	// update skin matrix
-
-	if ( forceUpdate || this.matrixWorldNeedsUpdate ) {
-
-		if ( parentSkinMatrix ) {
-
-			this.skinMatrix.multiplyMatrices( parentSkinMatrix, this.matrix );
-
-		} else {
-
-			this.skinMatrix.copy( this.matrix );
-
-		}
-
-		this.matrixWorldNeedsUpdate = false;
-		forceUpdate = true;
-
-		// Reset weights to be re-accumulated in the next frame
-
-		this.accumulatedRotWeight = 0;
-		this.accumulatedPosWeight = 0;
-		this.accumulatedSclWeight = 0;
-
-	}
-
-	// update children
-
-	for ( var i = 0, l = this.children.length; i < l; i ++ ) {
-
-		this.children[ i ].update( this.skinMatrix, forceUpdate );
-
-	}
+	this.accumulatedRotWeight = 0;
+	this.accumulatedPosWeight = 0;
+	this.accumulatedSclWeight = 0;
 
 };
 

+ 109 - 66
src/objects/Skeleton.js

@@ -2,134 +2,177 @@
  * @author mikael emtinger / http://gomo.se/
  * @author alteredq / http://alteredqualia.com/
  * @author michael guerrero / http://realitymeltdown.com
+ * @author ikerr / http://verold.com
  */
 
-THREE.Skeleton = function ( boneList, useVertexTexture ) {
+THREE.Skeleton = function ( bones, boneInverses, useVertexTexture ) {
 
 	this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true;
 
-	// init bones
+	this.identityMatrix = new THREE.Matrix4();
 
-	this.bones = [];
-	this.boneMatrices = [];
+	// copy the bone array
 
-	var bone, gbone, p, q, s;
+	bones = bones || [];
 
-	if ( boneList !== undefined ) {
+	this.bones = bones.slice( 0 );
 
-		for ( var b = 0; b < boneList.length; ++b ) {
+	// create a bone texture or an array of floats
 
-			gbone = boneList[ b ];
+	if ( this.useVertexTexture ) {
 
-			p = gbone.pos;
-			q = gbone.rotq;
-			s = gbone.scl;
+		// layout (1 matrix = 4 pixels)
+		//      RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
+		//  with  8x8  pixel texture max   16 bones  (8 * 8  / 4)
+		//       16x16 pixel texture max   64 bones (16 * 16 / 4)
+		//       32x32 pixel texture max  256 bones (32 * 32 / 4)
+		//       64x64 pixel texture max 1024 bones (64 * 64 / 4)
 
-			bone = this.addBone();
+		var size;
 
-			bone.name = gbone.name;
-			bone.position.set( p[ 0 ], p[ 1 ], p[ 2 ] );
-			bone.quaternion.set( q[ 0 ], q[ 1 ], q[ 2 ], q[ 3 ] );
+		if ( this.bones.length > 256 )
+			size = 64;
+		else if ( this.bones.length > 64 )
+			size = 32;
+		else if ( this.bones.length > 16 )
+			size = 16;
+		else
+			size = 8;
 
-			if ( s !== undefined ) {
+		this.boneTextureWidth = size;
+		this.boneTextureHeight = size;
 
-				bone.scale.set( s[ 0 ], s[ 1 ], s[ 2 ] );
+		this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel
+		this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType );
+		this.boneTexture.minFilter = THREE.NearestFilter;
+		this.boneTexture.magFilter = THREE.NearestFilter;
+		this.boneTexture.generateMipmaps = false;
+		this.boneTexture.flipY = false;
 
-			} else {
+	} else {
 
-				bone.scale.set( 1, 1, 1 );
+		this.boneMatrices = new Float32Array( 16 * this.bones.length );
+
+	}
+
+	// use the supplied bone inverses or calculate the inverses
+
+	if ( boneInverses === undefined ) {
+
+		this.calculateInverses();
+
+	} else {
+
+		if ( this.bones.length === boneInverses.length ) {
+
+			this.boneInverses = boneInverses.slice( 0 );
+
+		} else {
+
+			console.warn( 'THREE.Skeleton bonInverses is the wrong length.' );
+
+			this.boneInverses = [];
+
+			for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
+
+				this.boneInverses.push( new THREE.Matrix4() );
 
 			}
 
 		}
 
-		for ( var b = 0; b < boneList.length; ++b ) {
+	}
 
-			gbone = boneList[ b ];
+};
 
-			if ( gbone.parent !== - 1 ) {
+THREE.Skeleton.prototype.calculateInverses = function () {
 
-				this.bones[ gbone.parent ].add( this.bones[ b ] );
+	this.boneInverses = [];
 
-			}
+	for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
+
+		var inverse = new THREE.Matrix4();
+
+		if ( this.bones[ b ] ) {
+
+			inverse.getInverse( this.bones[ b ].matrixWorld );
 
 		}
 
-		//
+		this.boneInverses.push( inverse );
 
-		var nBones = this.bones.length;
+	}
 
-		if ( this.useVertexTexture ) {
+};
 
-			// layout (1 matrix = 4 pixels)
-			//  RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
-			//  with  8x8  pixel texture max   16 bones  (8 * 8  / 4)
-			//     16x16 pixel texture max   64 bones (16 * 16 / 4)
-			//     32x32 pixel texture max  256 bones (32 * 32 / 4)
-			//     64x64 pixel texture max 1024 bones (64 * 64 / 4)
+THREE.Skeleton.prototype.pose = function () {
 
-			var size;
+	var bone;
 
-			if ( nBones > 256 )
-				size = 64;
-			else if ( nBones > 64 )
-				size = 32;
-			else if ( nBones > 16 )
-				size = 16;
-			else
-				size = 8;
+	// recover the bind-time world matrices
 
-			this.boneTextureWidth = size;
-			this.boneTextureHeight = size;
+	for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
 
-			this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel
-			this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType );
-			this.boneTexture.minFilter = THREE.NearestFilter;
-			this.boneTexture.magFilter = THREE.NearestFilter;
-			this.boneTexture.generateMipmaps = false;
-			this.boneTexture.flipY = false;
+		bone = this.bones[ b ];
 
-		} else {
+		if ( bone ) {
 
-			this.boneMatrices = new Float32Array( 16 * nBones );
+			bone.matrixWorld.getInverse( this.boneInverses[ b ] );
 
 		}
 
 	}
 
-};
+	// compute the local matrices, positions, rotations and scales
 
+	for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
 
-THREE.Skeleton.prototype = Object.create( THREE.Mesh.prototype );
+		bone = this.bones[ b ];
 
+		if ( bone ) {
 
-THREE.Skeleton.prototype.addBone = function ( bone ) {
+			if ( bone.parent ) {
 
-	if ( bone === undefined ) {
+				bone.matrix.getInverse( bone.parent.matrixWorld );
+				bone.matrix.multiply( bone.matrixWorld );
 
-		bone = new THREE.Bone( this );
+			}
+			else {
 
-	}
+				bone.matrix.copy( bone.matrixWorld );
+
+			}
+
+			bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
 
-	this.bones.push( bone );
+		}
 
-	return bone;
+	}
 
 };
 
+THREE.Skeleton.prototype.update = function () {
 
-THREE.Skeleton.prototype.calculateInverses = function () {
+	var offsetMatrix = new THREE.Matrix4();
 
-	this.boneInverses = [];
+	// flatten bone matrices to array
 
-	for ( var b = 0, bl = this.bones.length; b < bl; ++b ) {
+	for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
 
-		var inverse = new THREE.Matrix4();
+		// compute the offset between the current and the original transform
 
-		inverse.getInverse( this.bones[ b ].skinMatrix );
+		var matrix = this.bones[ b ] ? this.bones[ b ].matrixWorld : this.identityMatrix;
 
-		this.boneInverses.push( inverse );
+		offsetMatrix.multiplyMatrices( matrix, this.boneInverses[ b ] );
+		offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 );
+
+	}
+
+	if ( this.useVertexTexture ) {
+
+		this.boneTexture.needsUpdate = true;
 
 	}
 
 };
+

+ 66 - 63
src/objects/SkinnedMesh.js

@@ -1,121 +1,103 @@
 /**
  * @author mikael emtinger / http://gomo.se/
  * @author alteredq / http://alteredqualia.com/
+ * @author ikerr / http://verold.com
  */
 
 THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) {
 
 	THREE.Mesh.call( this, geometry, material );
 
-	this.skeleton = new THREE.Skeleton( this.geometry && this.geometry.bones, useVertexTexture );
+	this.bindMode = "attached";
+	this.bindMatrix = new THREE.Matrix4();
+	this.bindMatrixInverse = new THREE.Matrix4();
 
-  // Add root level bones as children of the mesh
+	// init bones
 
-	for ( var b = 0; b < this.skeleton.bones.length; ++b ) {
+	// TODO: remove bone creation as there is no reason (other than
+	// convenience) for THREE.SkinnedMesh to do this.
 
-		var bone = this.skeleton.bones[ b ];
+	var bones = [];
 
-		if ( bone.parent === undefined ) {
+	if ( this.geometry && this.geometry.bones !== undefined ) {
 
-			this.add( bone );
+		var bone, gbone, p, q, s;
 
-		}
-
-	}
-
-	this.identityMatrix = new THREE.Matrix4();
-
-	this.pose();
-
-};
-
-
-THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype );
-
-THREE.SkinnedMesh.prototype.updateMatrixWorld = function () {
+		for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++b ) {
 
-	var offsetMatrix = new THREE.Matrix4();
+			gbone = this.geometry.bones[ b ];
 
-	return function ( force ) {
+			p = gbone.pos;
+			q = gbone.rotq;
+			s = gbone.scl;
 
-		this.matrixAutoUpdate && this.updateMatrix();
+			bone = new THREE.Bone( this );
+			bones.push( bone );
 
-		// update matrixWorld
+			bone.name = gbone.name;
+			bone.position.set( p[ 0 ], p[ 1 ], p[ 2 ] );
+			bone.quaternion.set( q[ 0 ], q[ 1 ], q[ 2 ], q[ 3 ] );
 
-		if ( this.matrixWorldNeedsUpdate || force ) {
+			if ( s !== undefined ) {
 
-			if ( this.parent ) {
-
-				this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
+				bone.scale.set( s[ 0 ], s[ 1 ], s[ 2 ] );
 
 			} else {
 
-				this.matrixWorld.copy( this.matrix );
+				bone.scale.set( 1, 1, 1 );
 
 			}
 
-			this.matrixWorldNeedsUpdate = false;
-
-			force = true;
-
 		}
 
-		// update children
+		for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++b ) {
 
-		for ( var i = 0, l = this.children.length; i < l; i ++ ) {
+			gbone = this.geometry.bones[ b ];
 
-			var child = this.children[ i ];
+			if ( gbone.parent !== - 1 ) {
 
-			if ( child instanceof THREE.Bone ) {
-
-				child.update( this.identityMatrix, false );
+				bones[ gbone.parent ].add( bones[ b ] );
 
 			} else {
 
-				child.updateMatrixWorld( true );
+				this.add( bones[ b ] );
 
 			}
 
 		}
 
-		// make a snapshot of the bones' rest position
+	}
 
-		if ( this.skeleton.boneInverses === undefined ) {
+	this.normalizeSkinWeights();
 
-			this.skeleton.calculateInverses();
+	this.updateMatrixWorld( true );
+	this.bind( new THREE.Skeleton( bones, undefined, useVertexTexture ) );
 
-		}
+};
 
-		// flatten bone matrices to array
 
-		for ( var b = 0, bl = this.skeleton.bones.length; b < bl; b ++ ) {
+THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype );
 
-			// compute the offset between the current and the original transform;
+THREE.SkinnedMesh.prototype.bind = function( skeleton, bindMatrix ) {
 
-			// TODO: we could get rid of this multiplication step if the skinMatrix
-			// was already representing the offset; however, this requires some
-			// major changes to the animation system
+	this.skeleton = skeleton;
 
-			offsetMatrix.multiplyMatrices( this.skeleton.bones[ b ].skinMatrix, this.skeleton.boneInverses[ b ] );
-			offsetMatrix.flattenToArrayOffset( this.skeleton.boneMatrices, b * 16 );
+	if ( bindMatrix === undefined ) {
 
-		}
+		this.updateMatrixWorld( true );
 
-		if ( this.skeleton.useVertexTexture ) {
+		bindMatrix = this.matrixWorld;
 
-			this.skeleton.boneTexture.needsUpdate = true;
-
-		}
+	}
 
-	};
+	this.bindMatrix.copy( bindMatrix );
+	this.bindMatrixInverse.getInverse( bindMatrix );
 
-}();
+};
 
 THREE.SkinnedMesh.prototype.pose = function () {
 
-	this.updateMatrixWorld( true );
-
-	this.normalizeSkinWeights();
+	this.skeleton.pose();
 
 };
 
@@ -149,7 +131,27 @@ THREE.SkinnedMesh.prototype.normalizeSkinWeights = function () {
 
 };
 
-THREE.SkinnedMesh.prototype.clone = function ( object ) {
+THREE.SkinnedMesh.prototype.updateMatrixWorld = function( force ) {
+
+	THREE.Mesh.prototype.updateMatrixWorld.call( this, true );
+
+	if ( this.bindMode === "attached" ) {
+
+		this.bindMatrixInverse.getInverse( this.matrixWorld );
+
+	} else if ( this.bindMode === "detached" ) {
+
+		this.bindMatrixInverse.getInverse( this.bindMatrix );
+
+	} else {
+
+		console.warn( 'THREE.SkinnedMesh unreckognized bindMode: ' + this.bindMode );
+
+	}
+
+};
+
+THREE.SkinnedMesh.prototype.clone = function( object ) {
 
 	if ( object === undefined ) {
 
@@ -162,3 +164,4 @@ THREE.SkinnedMesh.prototype.clone = function ( object ) {
 	return object;
 
 };
+

+ 33 - 2
src/renderers/WebGLRenderer.js

@@ -3266,6 +3266,25 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		if ( camera.parent === undefined ) camera.updateMatrixWorld();
 
+		// update Skeleton objects
+		function updateSkeletons( object ) {
+
+			if ( object instanceof THREE.SkinnedMesh ) {
+
+				object.skeleton.update();
+
+			}
+
+			for ( var i = 0, l = object.children.length; i < l; i ++ ) {
+
+				updateSkeletons( object.children[ i ] );
+
+			}
+
+		}
+
+		updateSkeletons( scene );
+
 		camera.matrixWorldInverse.getInverse( camera.matrixWorld );
 
 		_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
@@ -4367,7 +4386,19 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		if ( material.skinning ) {
 
-			if ( _supportsBoneTextures && object.skeleton.useVertexTexture ) {
+			if ( object.bindMatrix && p_uniforms.bindMatrix !== null ) {
+
+				_gl.uniformMatrix4fv( p_uniforms.bindMatrix, false, object.bindMatrix.elements );
+
+			}
+
+			if ( object.bindMatrixInverse && p_uniforms.bindMatrixInverse !== null ) {
+
+				_gl.uniformMatrix4fv( p_uniforms.bindMatrixInverse, false, object.bindMatrixInverse.elements );
+
+			}
+
+			if ( _supportsBoneTextures && object.skeleton && object.skeleton.useVertexTexture ) {
 
 				if ( p_uniforms.boneTexture !== null ) {
 
@@ -4390,7 +4421,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				}
 
-			} else {
+			} else if ( object.skeleton && object.skeleton.boneMatrices ) {
 
 				if ( p_uniforms.boneGlobalMatrices !== null ) {
 

+ 4 - 1
src/renderers/shaders/ShaderChunk/skinning_pars_vertex.glsl

@@ -1,5 +1,8 @@
 #ifdef USE_SKINNING
 
+	uniform mat4 bindMatrix;
+	uniform mat4 bindMatrixInverse;
+
 	#ifdef BONE_TEXTURE
 
 		uniform sampler2D boneTexture;
@@ -41,4 +44,4 @@
 
 	#endif
 
-#endif
+#endif

+ 4 - 3
src/renderers/shaders/ShaderChunk/skinning_vertex.glsl

@@ -2,11 +2,11 @@
 
 	#ifdef USE_MORPHTARGETS
 
-	vec4 skinVertex = vec4( morphed, 1.0 );
+	vec4 skinVertex = bindMatrix * vec4( morphed, 1.0 );
 
 	#else
 
-	vec4 skinVertex = vec4( position, 1.0 );
+	vec4 skinVertex = bindMatrix * vec4( position, 1.0 );
 
 	#endif
 
@@ -15,5 +15,6 @@
 	skinned += boneMatY * skinVertex * skinWeight.y;
 	skinned += boneMatZ * skinVertex * skinWeight.z;
 	skinned += boneMatW * skinVertex * skinWeight.w;
+	skinned  = bindMatrixInverse * skinned;
 
-#endif
+#endif

+ 2 - 1
src/renderers/shaders/ShaderChunk/skinnormal_vertex.glsl

@@ -5,6 +5,7 @@
 	skinMatrix += skinWeight.y * boneMatY;
 	skinMatrix += skinWeight.z * boneMatZ;
 	skinMatrix += skinWeight.w * boneMatW;
+	skinMatrix  = bindMatrixInverse * skinMatrix * bindMatrix;
 
 	#ifdef USE_MORPHNORMALS
 
@@ -16,4 +17,4 @@
 
 	#endif
 
-#endif
+#endif

+ 4 - 2
src/renderers/shaders/ShaderLib.js

@@ -1129,13 +1129,14 @@ THREE.ShaderLib = {
 
 			"			#ifdef USE_SKINNING",
 
-			"				vec4 skinVertex = vec4( position, 1.0 );",
+			"				vec4 skinVertex = bindMatrix * vec4( position, 1.0 );",
 
 			"				vec4 skinned = vec4( 0.0 );",
 			"				skinned += boneMatX * skinVertex * skinWeight.x;",
 			"				skinned += boneMatY * skinVertex * skinWeight.y;",
 			"				skinned += boneMatZ * skinVertex * skinWeight.z;",
 			"				skinned += boneMatW * skinVertex * skinWeight.w;",
+			"				skinned  = bindMatrixInverse * skinned;",
 
 			"				displacedPosition = skinned.xyz;",
 
@@ -1151,13 +1152,14 @@ THREE.ShaderLib = {
 
 			"		#ifdef USE_SKINNING",
 
-			"			vec4 skinVertex = vec4( position, 1.0 );",
+			"			vec4 skinVertex = bindMatrix * vec4( position, 1.0 );",
 
 			"			vec4 skinned = vec4( 0.0 );",
 			"			skinned += boneMatX * skinVertex * skinWeight.x;",
 			"			skinned += boneMatY * skinVertex * skinWeight.y;",
 			"			skinned += boneMatZ * skinVertex * skinWeight.z;",
 			"			skinned += boneMatW * skinVertex * skinWeight.w;",
+			"			skinned  = bindMatrixInverse * skinned;",
 
 			"			displacedPosition = skinned.xyz;",
 

+ 1 - 2
src/renderers/webgl/WebGLProgram.js

@@ -302,8 +302,7 @@ THREE.WebGLProgram = ( function () {
 
 		var identifiers = [
 
-			'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'modelMatrix', 'cameraPosition',
-			'morphTargetInfluences'
+			'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'modelMatrix', 'cameraPosition', 'morphTargetInfluences', 'bindMatrix', 'bindMatrixInverse'
 
 		];