MMDExporter.js 4.0 KB
Newer Older
D
Don McCurdy 已提交
1 2 3 4
import {
	Matrix4,
	Quaternion,
	Vector3
5 6
} from '../../../build/three.module.js';
import { MMDParser } from '../libs/mmdparser.module.js';
M
Mr.doob 已提交
7

M
Mugen87 已提交
8 9 10 11
/**
 * Dependencies
 *  - mmd-parser https://github.com/takahirox/mmd-parser
 */
D
Don McCurdy 已提交
12

13
class MMDExporter {
D
Don McCurdy 已提交
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

	/* TODO: implement
	// mesh -> pmd
	this.parsePmd = function ( object ) {

	};
	*/

	/* TODO: implement
	// mesh -> pmx
	this.parsePmx = function ( object ) {

	};
	*/

29 30 31 32 33 34 35
	/* TODO: implement
	// animation + skeleton -> vmd
	this.parseVmd = function ( object ) {

	};
	*/

D
Don McCurdy 已提交
36 37 38 39
	/*
	 * skeleton -> vpd
	 * Returns Shift_JIS encoded Uint8Array. Otherwise return strings.
	 */
40
	parseVpd( skin, outputShiftJis, useOriginalBones ) {
D
Don McCurdy 已提交
41 42 43

		if ( skin.isSkinnedMesh !== true ) {

44
			console.warn( 'THREE.MMDExporter: parseVpd() requires SkinnedMesh instance.' );
D
Don McCurdy 已提交
45 46 47 48 49 50 51 52
			return null;

		}

		function toStringsFromNumber( num ) {

			if ( Math.abs( num ) < 1e-6 ) num = 0;

53
			let a = num.toString();
D
Don McCurdy 已提交
54 55 56 57 58 59 60 61 62

			if ( a.indexOf( '.' ) === - 1 ) {

				a += '.';

			}

			a += '000000';

63
			const index = a.indexOf( '.' );
D
Don McCurdy 已提交
64

65 66
			const d = a.slice( 0, index );
			const p = a.slice( index + 1, index + 7 );
D
Don McCurdy 已提交
67 68 69 70 71 72 73

			return d + '.' + p;

		}

		function toStringsFromArray( array ) {

74
			const a = [];
D
Don McCurdy 已提交
75

76
			for ( let i = 0, il = array.length; i < il; i ++ ) {
D
Don McCurdy 已提交
77 78 79 80 81 82 83 84 85 86 87

				a.push( toStringsFromNumber( array[ i ] ) );

			}

			return a.join( ',' );

		}

		skin.updateMatrixWorld( true );

88 89
		const bones = skin.skeleton.bones;
		const bones2 = getBindBones( skin );
D
Don McCurdy 已提交
90

91 92 93 94
		const position = new Vector3();
		const quaternion = new Quaternion();
		const quaternion2 = new Quaternion();
		const matrix = new Matrix4();
D
Don McCurdy 已提交
95

96
		const array = [];
D
Don McCurdy 已提交
97 98 99 100 101 102
		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( '' );

103
		for ( let i = 0, il = bones.length; i < il; i ++ ) {
D
Don McCurdy 已提交
104

105 106
			const bone = bones[ i ];
			const bone2 = bones2[ i ];
D
Don McCurdy 已提交
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126

			/*
			 * 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 );

127 128
			const pArray = position.sub( bone2.position ).toArray();
			const qArray = quaternion2.copy( bone2.quaternion ).conjugate().multiply( quaternion ).toArray();
D
Don McCurdy 已提交
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144

			// 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( '' );

145
		const lines = array.join( '\n' );
D
Don McCurdy 已提交
146 147 148

		return ( outputShiftJis === true ) ? unicodeToShiftjis( lines ) : lines;

149
	}
D
Don McCurdy 已提交
150

151
}
D
Don McCurdy 已提交
152

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
// Unicode to Shift_JIS table
let u2sTable;

function unicodeToShiftjis( str ) {

	if ( u2sTable === undefined ) {

		const encoder = new MMDParser.CharsetEncoder(); // eslint-disable-line no-undef
		const table = encoder.s2uTable;
		u2sTable = {};

		const keys = Object.keys( table );

		for ( let i = 0, il = keys.length; i < il; i ++ ) {

			let key = keys[ i ];

			const value = table[ key ];
			key = parseInt( key );

			u2sTable[ value ] = key;

		}

	}

	const array = [];

	for ( let i = 0, il = str.length; i < il; i ++ ) {

		const code = str.charCodeAt( i );

		const 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?
	const poseSkin = skin.clone();
	poseSkin.pose();
	return poseSkin.skeleton.bones;
D
Don McCurdy 已提交
214

215
}
D
Don McCurdy 已提交
216 217

export { MMDExporter };