Browse Source

Add CCDIKHelper (#9996)

* Add CCDIKHelper

* Clean up MMDPhysics.js

* Fix typo
Takahiro 8 years ago
parent
commit
cb2c0ea1fb

+ 187 - 0
examples/js/animation/CCDIKSolver.js

@@ -205,3 +205,190 @@ THREE.CCDIKSolver.prototype = {
 	}
 
 };
+
+
+THREE.CCDIKHelper = function ( mesh ) {
+
+	if ( mesh.geometry.iks === undefined || mesh.skeleton === undefined ) {
+
+		throw 'THREE.CCDIKHelper requires iks in mesh.geometry and skeleton in mesh.';
+
+	}
+
+	THREE.Object3D.call( this );
+
+	this.root = mesh;
+
+	this.matrix = mesh.matrixWorld;
+	this.matrixAutoUpdate = false;
+
+	this.sphereGeometry = new THREE.SphereBufferGeometry( 0.25, 16, 8 );
+
+	this.targetSphereMaterial = new THREE.MeshBasicMaterial( {
+		color: new THREE.Color( 0xff8888 ),
+		depthTest: false,
+		depthWrite: false,
+		transparent: true
+	} );
+
+	this.effectorSphereMaterial = new THREE.MeshBasicMaterial( {
+		color: new THREE.Color( 0x88ff88 ),
+		depthTest: false,
+		depthWrite: false,
+		transparent: true
+	} );
+
+	this.linkSphereMaterial = new THREE.MeshBasicMaterial( {
+		color: new THREE.Color( 0x8888ff ),
+		depthTest: false,
+		depthWrite: false,
+		transparent: true
+	} );
+
+	this.lineMaterial = new THREE.LineBasicMaterial( {
+		color: new THREE.Color( 0xff0000 ),
+		depthTest: false,
+		depthWrite: false,
+		transparent: true
+	} );
+
+	this._init();
+	this.update();
+
+};
+
+THREE.CCDIKHelper.prototype = Object.create( THREE.Object3D.prototype );
+THREE.CCDIKHelper.prototype.constructor = THREE.CCDIKHelper;
+
+THREE.CCDIKHelper.prototype._init = function () {
+
+	var self = this;
+	var mesh = this.root;
+	var iks = mesh.geometry.iks;
+
+	function createLineGeometry( ik ) {
+
+		var geometry = new THREE.BufferGeometry();
+		var vertices = new Float32Array( ( 2 + ik.links.length ) * 3 );
+		geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
+
+		return geometry;
+
+	}
+
+	function createTargetMesh() {
+
+		return new THREE.Mesh( self.sphereGeometry, self.targetSphereMaterial );
+
+	}
+
+	function createEffectorMesh() {
+
+		return new THREE.Mesh( self.sphereGeometry, self.effectorSphereMaterial );
+
+	}
+
+	function createLinkMesh() {
+
+		return new THREE.Mesh( self.sphereGeometry, self.linkSphereMaterial );
+
+	}
+
+	function createLine( ik ) {
+
+		return new THREE.Line( createLineGeometry( ik ), self.lineMaterial );
+
+	}
+
+	for ( var i = 0, il = iks.length; i < il; i ++ ) {
+
+		var ik = iks[ i ];
+
+		this.add( createTargetMesh() );
+		this.add( createEffectorMesh() );
+
+		for ( var j = 0, jl = ik.links.length; j < jl; j ++ ) {
+
+			this.add( createLinkMesh() );
+
+		}
+
+		this.add( createLine( ik ) );
+
+	}
+
+};
+
+THREE.CCDIKHelper.prototype.update = function () {
+
+	var offset = 0;
+
+	var mesh = this.root;
+	var iks = mesh.geometry.iks;
+	var bones = mesh.skeleton.bones;
+
+	var matrixWorldInv = new THREE.Matrix4().getInverse( mesh.matrixWorld );
+	var vector = new THREE.Vector3();
+
+	function getPosition( bone ) {
+
+		vector.setFromMatrixPosition( bone.matrixWorld );
+		vector.applyMatrix4( matrixWorldInv );
+
+		return vector;
+
+	}
+
+	function setPositionOfBoneToAttributeArray( array, index, bone ) {
+
+		var v = getPosition( bone );
+
+		array[ index * 3 + 0 ] = v.x;
+		array[ index * 3 + 1 ] = v.y;
+		array[ index * 3 + 2 ] = v.z;
+
+	}
+
+	for ( var i = 0, il = iks.length; i < il; i ++ ) {
+
+		var ik = iks[ i ];
+
+		var targetBone = bones[ ik.target ];
+		var effectorBone = bones[ ik.effector ];
+
+		var targetMesh = this.children[ offset ++ ];
+		var effectorMesh = this.children[ offset ++ ];
+
+		targetMesh.position.copy( getPosition( targetBone ) );
+		effectorMesh.position.copy( getPosition( effectorBone ) );
+
+		for ( var j = 0, jl = ik.links.length; j < jl; j ++ ) {
+
+			var link = ik.links[ j ];
+			var linkBone = bones[ link.index ];
+
+			var linkMesh = this.children[ offset ++ ];
+
+			linkMesh.position.copy( getPosition( linkBone ) );
+
+		}
+
+		var line = this.children[ offset ++ ];
+		var array = line.geometry.attributes.position.array;
+
+		setPositionOfBoneToAttributeArray( array, 0, targetBone );
+		setPositionOfBoneToAttributeArray( array, 1, effectorBone );
+
+		for ( var j = 0, jl = ik.links.length; j < jl; j ++ ) {
+
+			var link = ik.links[ j ];
+			var linkBone = bones[ link.index ];
+			setPositionOfBoneToAttributeArray( array, j + 2, linkBone );
+
+		}
+
+		line.geometry.attributes.position.needsUpdate = true;
+
+	}
+
+};

+ 69 - 45
examples/js/animation/MMDPhysics.js

@@ -1031,11 +1031,6 @@ THREE.MMDPhysics.Constraint.prototype = {
 };
 
 
-/*
- * This helper displays rigid bodies of mesh for debug.
- * It should be under Scene because it just sets world position/roration to meshes
- * for simplicity.
- */
 THREE.MMDPhysicsHelper = function ( mesh ) {
 
 	if ( mesh.physics === undefined || mesh.geometry.rigidBodies === undefined ) {
@@ -1046,9 +1041,48 @@ THREE.MMDPhysicsHelper = function ( mesh ) {
 
 	THREE.Object3D.call( this );
 
-	this.mesh = mesh;
+	this.root = mesh;
+
+	this.matrix = mesh.matrixWorld;
+	this.matrixAutoUpdate = false;
+
+	this.materials = [];
+
+	this.materials.push(
+		new THREE.MeshBasicMaterial( {
+			color: new THREE.Color( 0xff8888 ),
+			wireframe: true,
+			depthTest: false,
+			depthWrite: false,
+			opacity: 0.25,
+			transparent: true
+		} )
+	);
+
+	this.materials.push(
+		new THREE.MeshBasicMaterial( {
+			color: new THREE.Color( 0x88ff88 ),
+			wireframe: true,
+			depthTest: false,
+			depthWrite: false,
+			opacity: 0.25,
+			transparent: true
+		} )
+	);
+
+	this.materials.push(
+		new THREE.MeshBasicMaterial( {
+			color: new THREE.Color( 0x8888ff ),
+			wireframe: true,
+			depthTest: false,
+			depthWrite: false,
+			opacity: 0.25,
+			transparent: true
+		} )
+	);
 
 	this._init();
+	this.update();
 
 };
 
@@ -1057,6 +1091,9 @@ THREE.MMDPhysicsHelper.prototype.constructor = THREE.MMDPhysicsHelper;
 
 THREE.MMDPhysicsHelper.prototype._init = function () {
 
+	var mesh = this.root;
+	var rigidBodies = mesh.geometry.rigidBodies;
+
 	function createGeometry( param ) {
 
 		switch ( param.shapeType ) {
@@ -1097,67 +1134,54 @@ THREE.MMDPhysicsHelper.prototype._init = function () {
 
 	}
 
+	for ( var i = 0, il = rigidBodies.length; i < il; i ++ ) {
 
-	function createMaterial( param ) {
+		var param = rigidBodies[ i ];
+		this.add( new THREE.Mesh( createGeometry( param ), this.materials[ param.type ] ) );
 
-		var color;
+	}
 
-		switch ( param.type ) {
+};
 
-			case 0:
-				color = 0xff8888;
-				break;
+THREE.MMDPhysicsHelper.prototype.update = function () {
 
-			case 1:
-				color = 0x88ff88;
-				break;
+	var mesh = this.root;
+	var rigidBodies = mesh.geometry.rigidBodies;
+	var bodies = mesh.physics.bodies;
 
-			case 2:
-				color = 0x8888ff;
-				break;
+	var matrixWorldInv = new THREE.Matrix4().getInverse( mesh.matrixWorld );
+	var vector = new THREE.Vector3();
+	var quaternion = new THREE.Quaternion();
+	var quaternion2 = new THREE.Quaternion();
 
-			default:
-				color = 0x000000;
-				break;
+	function getPosition( origin ) {
 
-		}
+		vector.set( origin.x(), origin.y(), origin.z() );
+		vector.applyMatrix4( matrixWorldInv );
 
-		return new THREE.MeshBasicMaterial( {
-			color: new THREE.Color( color ),
-			wireframe: true,
-			depthTest: false,
-			depthWrite: false,
-			opacity: 0.25,
-			transparent: true
-		} );
+		return vector;
 
 	}
 
-	for ( var i = 0, il = this.mesh.geometry.rigidBodies.length; i < il; i ++ ) {
+	function getQuaternion( rotation ) {
 
-		var param = this.mesh.geometry.rigidBodies[ i ];
+		quaternion.set( rotation.x(), rotation.y(), rotation.z(), rotation.w() );
+		quaternion2.setFromRotationMatrix( matrixWorldInv );
+		quaternion2.multiply( quaternion );
 
-		var mesh = new THREE.Mesh( createGeometry( param ), createMaterial( param ) );
-		this.add( mesh );
+		return quaternion2;
 
 	}
 
-};
-
-THREE.MMDPhysicsHelper.prototype.update = function () {
+	for ( var i = 0, il = rigidBodies.length; i < il; i ++ ) {
 
-	for ( var i = 0, il = this.mesh.geometry.rigidBodies.length; i < il; i ++ ) {
-
-		var body = this.mesh.physics.bodies[ i ].body;
+		var body = bodies[ i ].body;
 		var mesh = this.children[ i ];
 
 		var tr = body.getCenterOfMassTransform();
 
-		var o = tr.getOrigin();
-		var r = tr.getRotation();
-
-		mesh.position.set( o.x(), o.y(), o.z() );
-		mesh.quaternion.set( r.x(), r.y(), r.z(), r.w() );
+		mesh.position.copy( getPosition( tr.getOrigin() ) );
+		mesh.quaternion.copy( getQuaternion( tr.getRotation() ) );
 
 	}
 

+ 6 - 1
examples/webgl_loader_mmd.html

@@ -52,7 +52,7 @@
 			var container, stats;
 
 			var mesh, camera, scene, renderer;
-			var helper, physicsHelper;
+			var helper, ikHelper, physicsHelper;
 
 			var mouseX = 0, mouseY = 0;
 
@@ -119,6 +119,10 @@
 					helper.add( mesh );
 					helper.setAnimation( mesh );
 
+					// create CCDIKHelper after calling helper.setAnimation()
+					ikHelper = new THREE.CCDIKHelper( mesh );
+					scene.add( ikHelper );
+
 					/*
 					 * Note: You're recommended to call helper.setPhysics()
 					 *       after calling helper.setAnimation().
@@ -186,6 +190,7 @@
 
 					helper.animate( clock.getDelta() );
 					if ( physicsHelper !== undefined ) physicsHelper.update();
+					ikHelper.update();
 					helper.render( scene, camera );
 
 				} else {