Browse Source

Merge pull request #10100 from takahirox/MMDExporter

MMDExporter
Mr.doob 8 years ago
parent
commit
5cea1894e4

+ 23 - 1
examples/js/animation/CCDIKSolver.js

@@ -69,7 +69,27 @@ THREE.CCDIKSolver.prototype = {
 
 
 	},
 	},
 
 
-	update: function () {
+	/*
+	 * save the bone matrices before solving IK.
+	 * they're used for generating VMD and VPD.
+	 */
+	_saveOriginalBonesInfo: function () {
+
+		var bones = this.mesh.skeleton.bones;
+
+		for ( var i = 0, il = bones.length; i < il; i ++ ) {
+
+			var bone = bones[ i ];
+
+			if ( bone.userData.ik === undefined ) bone.userData.ik = {};
+
+			bone.userData.ik.originalMatrix = bone.matrix.toArray();
+
+		}
+
+	},
+
+	update: function ( saveOriginalBones ) {
 
 
 		var q = new THREE.Quaternion();
 		var q = new THREE.Quaternion();
 
 
@@ -91,6 +111,8 @@ THREE.CCDIKSolver.prototype = {
 
 
 		this.mesh.updateMatrixWorld( true );
 		this.mesh.updateMatrixWorld( true );
 
 
+		if ( saveOriginalBones === true ) this._saveOriginalBonesInfo();
+
 		for ( var i = 0, il = iks.length; i < il; i++ ) {
 		for ( var i = 0, il = iks.length; i < il; i++ ) {
 
 
 			var ik = iks[ i ];
 			var ik = iks[ i ];

+ 211 - 0
examples/js/exporters/MMDExporter.js

@@ -0,0 +1,211 @@
+/**
+ * @author takahiro / http://github.com/takahirox
+ *
+ * Dependencies
+ *  - mmd-parser https://github.com/takahirox/mmd-parser
+ */
+
+THREE.MMDExporter = function () {
+
+	// Unicode to Shift_JIS table
+	var u2sTable;
+
+	function unicodeToShiftjis( str ) {
+
+		if ( u2sTable === undefined ) {
+
+			var encoder = new MMDParser.CharsetEncoder();
+			var table = encoder.s2uTable;
+			u2sTable = {};
+
+			var keys = Object.keys( table );
+
+			for ( var i = 0, il = keys.length; i < il; i ++ ) {
+
+				var key = keys[ i ];
+
+				var value = table[ key ];
+				key = parseInt( key );
+
+				u2sTable[ value ] = key;
+
+			}
+
+		}
+
+		var array = [];
+
+		for ( var i = 0, il = str.length; i < il; i ++ ) {
+
+			var code = str.charCodeAt( i )
+
+			var value = u2sTable[ code ];
+
+			if ( value === undefined ) {
+
+				throw 'cannot convert charcode 0x' + code.toString( 16 );
+
+			} else if ( value > 0xff ) {
+
+				array.push( ( value >> 8 ) & 0xff );
+				array.push( value & 0xff );
+
+			} else {
+
+				array.push( value & 0xff );
+
+			}
+
+		}
+
+		return new Uint8Array( array );
+
+	}
+
+	function getBindBones( skin ) {
+
+		// any more efficient ways?
+		var poseSkin = skin.clone();
+		poseSkin.pose();
+		return poseSkin.skeleton.bones;
+
+	}
+
+	/* TODO: implement
+	// mesh -> pmd
+	this.parsePmd = function ( object ) {
+
+	};
+	*/
+
+	/* TODO: implement
+	// mesh -> pmx
+	this.parsePmx = function ( object ) {
+
+	};
+	*/
+
+	/*
+	 * skeleton -> vpd
+	 * Returns Shift_JIS encoded Uint8Array. Otherwise return strings.
+	 */
+	this.parseVpd = function ( skin, outputShiftJis, useOriginalBones ) {
+
+		if ( skin.isSkinnedMesh !== true ) {
+
+			console.warn( 'THREE.MMDExporter: parseVpd() requires SkinnedMesh instance.' );
+			return null;
+
+		}
+
+		function toStringsFromNumber( num ) {
+
+			if ( Math.abs( num ) < 1e-6 ) num = 0;
+
+			var a = num.toString();
+
+			if ( a.indexOf( '.' ) === -1 ) {
+
+				a += '.';
+
+			}
+
+			a += '000000';
+
+			var index = a.indexOf( '.' );
+
+			var d = a.slice( 0, index );
+			var p = a.slice( index + 1, index + 7 );
+
+			return d + '.' + p;
+
+		}
+
+		function toStringsFromArray( array ) {
+
+			var a = [];
+
+			for ( var i = 0, il = array.length; i < il; i ++ ) {
+
+				a.push( toStringsFromNumber( array[ i ] ) );
+
+			}
+
+			return a.join( ',' );
+
+		}
+
+		skin.updateMatrixWorld( true );
+
+		var bones = skin.skeleton.bones;
+		var bones2 = getBindBones( skin );
+
+		var position = new THREE.Vector3();
+		var quaternion = new THREE.Quaternion();
+		var quaternion2 = new THREE.Quaternion();
+		var matrix = new THREE.Matrix4();
+
+		var array = [];
+		array.push( 'Vocaloid Pose Data file' );
+		array.push( '' );
+		array.push( ( skin.name !== '' ? skin.name.replace( /\s/g, '_' ) : 'skin' ) + '.osm;' );
+		array.push( bones.length + ';' );
+		array.push( '' );
+
+		for ( var i = 0, il = bones.length; i < il; i ++ ) {
+
+			var bone = bones[ i ];
+			var bone2 = bones2[ i ];
+
+			/*
+			 * use the bone matrix saved before solving IK.
+			 * see CCDIKSolver for the detail.
+			 */
+			if ( useOriginalBones === true &&
+				bone.userData.ik !== undefined &&
+				bone.userData.ik.originalMatrix !== undefined ) {
+
+				matrix.fromArray( bone.userData.ik.originalMatrix );
+
+			} else {
+
+				matrix.copy( bone.matrix );
+
+			}
+
+			position.setFromMatrixPosition( matrix );
+			quaternion.setFromRotationMatrix( matrix );
+
+			var pArray = position.sub( bone2.position ).toArray();
+			var qArray = quaternion2.copy( bone2.quaternion ).conjugate().multiply( quaternion ).toArray();
+
+			// right to left
+			pArray[ 2 ] = -pArray[ 2 ];
+			qArray[ 0 ] = -qArray[ 0 ];
+			qArray[ 1 ] = -qArray[ 1 ];
+
+			array.push( 'Bone' + i + '{' + bone.name );
+			array.push( '  ' + toStringsFromArray( pArray ) + ';' );
+			array.push( '  ' + toStringsFromArray( qArray ) + ';' );
+			array.push( '}' );
+			array.push( '' );
+
+		}
+
+		array.push( '' );
+
+		var lines = array.join( '\n' );
+
+		return ( outputShiftJis === true ) ? unicodeToShiftjis( lines ) : lines;
+
+	};
+
+	/* TODO: implement
+	// animation + skeleton -> vmd
+	this.parseVmd = function ( object ) {
+
+	};
+	*/
+
+};
+

+ 11 - 22
examples/js/loaders/MMDLoader.js

@@ -2784,11 +2784,9 @@ THREE.MMDHelper.prototype = {
 
 
 	poseAsVpd: function ( mesh, vpd, params ) {
 	poseAsVpd: function ( mesh, vpd, params ) {
 
 
-		if ( ! ( params && params.preventResetPose === true ) ) {
-
-			mesh.pose();
+		if ( params === undefined ) params = {};
 
 
-		}
+		if ( params.preventResetPose !== true ) mesh.pose();
 
 
 		var bones = mesh.skeleton.bones;
 		var bones = mesh.skeleton.bones;
 		var bones2 = vpd.bones;
 		var bones2 = vpd.bones;
@@ -2797,8 +2795,7 @@ THREE.MMDHelper.prototype = {
 
 
 		for ( var i = 0; i < bones.length; i++ ) {
 		for ( var i = 0; i < bones.length; i++ ) {
 
 
-			var b = bones[ i ];
-			table[ b.name ] = i;
+			table[ bones[ i ].name ] = i;
 
 
 		}
 		}
 
 
@@ -2810,11 +2807,7 @@ THREE.MMDHelper.prototype = {
 			var b = bones2[ i ];
 			var b = bones2[ i ];
 			var index = table[ b.name ];
 			var index = table[ b.name ];
 
 
-			if ( index === undefined ) {
-
-				continue;
-
-			}
+			if ( index === undefined ) continue;
 
 
 			var b2 = bones[ index ];
 			var b2 = bones[ index ];
 			var t = b.translation;
 			var t = b.translation;
@@ -2826,25 +2819,21 @@ THREE.MMDHelper.prototype = {
 			b2.position.add( thV );
 			b2.position.add( thV );
 			b2.quaternion.multiply( thQ );
 			b2.quaternion.multiply( thQ );
 
 
-			b2.updateMatrixWorld( true );
-
 		}
 		}
 
 
-		if ( params === undefined || params.preventIk !== true ) {
+		mesh.updateMatrixWorld( true );
+
+		if ( params.preventIk !== true ) {
 
 
 			var solver = new THREE.CCDIKSolver( mesh );
 			var solver = new THREE.CCDIKSolver( mesh );
-			solver.update();
+			solver.update( params.saveOriginalBonesBeforeIK );
 
 
 		}
 		}
 
 
-		if ( params === undefined || params.preventGrant !== true ) {
-
-			if ( mesh.geometry.grants !== undefined ) {
+		if ( params.preventGrant !== true && mesh.geometry.grants !== undefined ) {
 
 
-				var solver = new THREE.MMDGrantSolver( mesh );
-				solver.update();
-
-			}
+			var solver = new THREE.MMDGrantSolver( mesh );
+			solver.update();
 
 
 		}
 		}