FBXLoader.js 80.3 KB
Newer Older
Y
yamahigashi 已提交
1
/**
K
Kyle Larson 已提交
2
 * @author Kyle-Larson https://github.com/Kyle-Larson
M
Mr.doob 已提交
3
 * @author Takahiro https://github.com/takahirox
L
Lewy Blue 已提交
4
 * @author Lewy Blue https://github.com/looeee
Y
yamahigashi 已提交
5
 *
M
Mr.doob 已提交
6 7
 * Loader loads FBX file and generates Group representing FBX scene.
 * Requires FBX file to be >= 7.0 and in ASCII or to be any version in Binary format.
Y
yamahigashi 已提交
8
 *
M
Mr.doob 已提交
9 10 11
 * Supports:
 * 	Mesh Generation (Positional Data)
 * 	Normal Data (Per Vertex Drawing Instance)
L
Lewy Blue 已提交
12 13 14
 *	UV Data (Per Vertex Drawing Instance)
 *	Skinning
 *	Animation
M
Mr.doob 已提交
15 16
 * 	- Separated Animations based on stacks.
 * 	- Skeletal & Non-Skeletal Animations
L
Lewy Blue 已提交
17
 *	NURBS (Open, Closed and Periodic forms)
Y
yamahigashi 已提交
18
 *
M
Mr.doob 已提交
19
 * Needs Support:
L
Lewy Blue 已提交
20
 *	Euler rotation order
L
Lewy Blue 已提交
21
 *
L
Lewy Blue 已提交
22
 *
L
Lewy Blue 已提交
23 24 25 26 27 28
 * FBX format references:
 * 	https://wiki.blender.org/index.php/User:Mont29/Foundation/FBX_File_Structure
 *
 * 	Binary format specification:
 *		https://code.blender.org/2013/08/fbx-binary-file-format-specification/
 *		https://wiki.rogiken.org/specifications/file-format/fbx/ (more detail but Japanese)
Y
yamahigashi 已提交
29 30
 */

31
( function () {
Y
yamahigashi 已提交
32

M
Mr.doob 已提交
33
	THREE.FBXLoader = function ( manager ) {
Y
yamahigashi 已提交
34

Y
yamahigashi 已提交
35
		this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
Y
yamahigashi 已提交
36

Y
yamahigashi 已提交
37
	};
Y
yamahigashi 已提交
38

39
	Object.assign( THREE.FBXLoader.prototype, {
Y
yamahigashi 已提交
40

41
		load: function ( url, onLoad, onProgress, onError ) {
Y
yamahigashi 已提交
42

M
Mr.doob 已提交
43
			var self = this;
Y
yamahigashi 已提交
44

45
			var resourceDirectory = THREE.LoaderUtils.extractUrlBase( url );
Y
yamahigashi 已提交
46

M
Mr.doob 已提交
47 48 49
			var loader = new THREE.FileLoader( this.manager );
			loader.setResponseType( 'arraybuffer' );
			loader.load( url, function ( buffer ) {
Y
yamahigashi 已提交
50

M
Mr.doob 已提交
51
				try {
Y
yamahigashi 已提交
52

L
Lewy Blue 已提交
53
					var scene = self.parse( buffer, resourceDirectory );
M
Mr.doob 已提交
54
					onLoad( scene );
Y
yamahigashi 已提交
55

M
Mr.doob 已提交
56
				} catch ( error ) {
Y
yamahigashi 已提交
57

M
Mr.doob 已提交
58
					window.setTimeout( function () {
Y
yamahigashi 已提交
59

M
Mr.doob 已提交
60
						if ( onError ) onError( error );
Y
yamahigashi 已提交
61

M
Mr.doob 已提交
62
						self.manager.itemError( url );
Y
yamahigashi 已提交
63

M
Mr.doob 已提交
64
					}, 0 );
Y
yamahigashi 已提交
65

M
Mr.doob 已提交
66
				}
Y
yamahigashi 已提交
67

M
Mr.doob 已提交
68
			}, onProgress, onError );
Y
yamahigashi 已提交
69

70
		},
Y
yamahigashi 已提交
71

M
Mr.doob 已提交
72
		parse: function ( FBXBuffer, resourceDirectory ) {
Y
yamahigashi 已提交
73

M
Mr.doob 已提交
74
			var FBXTree;
Y
yamahigashi 已提交
75

M
Mr.doob 已提交
76
			if ( isFbxFormatBinary( FBXBuffer ) ) {
Y
yamahigashi 已提交
77

M
Mr.doob 已提交
78
				FBXTree = new BinaryParser().parse( FBXBuffer );
Y
yamahigashi 已提交
79

M
Mr.doob 已提交
80
			} else {
Y
yamahigashi 已提交
81

M
Mr.doob 已提交
82
				var FBXText = convertArrayBufferToString( FBXBuffer );
Y
yamahigashi 已提交
83

M
Mr.doob 已提交
84
				if ( ! isFbxFormatASCII( FBXText ) ) {
Y
yamahigashi 已提交
85

M
Mugen87 已提交
86
					throw new Error( 'THREE.FBXLoader: Unknown format.' );
Y
yamahigashi 已提交
87

88
				}
Y
yamahigashi 已提交
89

M
Mr.doob 已提交
90
				if ( getFbxVersion( FBXText ) < 7000 ) {
Y
yamahigashi 已提交
91

M
Mugen87 已提交
92
					throw new Error( 'THREE.FBXLoader: FBX version not supported, FileVersion: ' + getFbxVersion( FBXText ) );
Y
yamahigashi 已提交
93

M
Mr.doob 已提交
94
				}
Y
yamahigashi 已提交
95

M
Mr.doob 已提交
96
				FBXTree = new TextParser().parse( FBXText );
Y
yamahigashi 已提交
97

98
			}
M
Mr.doob 已提交
99

L
Lewy Blue 已提交
100
			// console.log( FBXTree );
M
Mr.doob 已提交
101

M
Mr.doob 已提交
102 103 104 105
			var connections = parseConnections( FBXTree );
			var images = parseImages( FBXTree );
			var textures = parseTextures( FBXTree, new THREE.TextureLoader( this.manager ).setPath( resourceDirectory ), images, connections );
			var materials = parseMaterials( FBXTree, textures, connections );
L
Lewy Blue 已提交
106 107 108
			var skeletons = parseDeformers( FBXTree, connections );
			var geometryMap = parseGeometries( FBXTree, connections, skeletons );
			var sceneGraph = parseScene( FBXTree, connections, skeletons, geometryMap, materials );
Y
yamahigashi 已提交
109

M
Mr.doob 已提交
110
			return sceneGraph;
Y
yamahigashi 已提交
111

M
Mr.doob 已提交
112
		}
M
Mr.doob 已提交
113

M
Mr.doob 已提交
114
	} );
Y
yamahigashi 已提交
115

L
Lewy Blue 已提交
116 117
	// Parses FBXTree.Connections which holds parent-child connections between objects (e.g. material -> texture, model->geometry )
	// and details the connection type
M
Mr.doob 已提交
118
	function parseConnections( FBXTree ) {
Y
yamahigashi 已提交
119

M
Mr.doob 已提交
120
		var connectionMap = new Map();
K
Kyle Larson 已提交
121

M
Mr.doob 已提交
122
		if ( 'Connections' in FBXTree ) {
Y
yamahigashi 已提交
123

L
Lewy Blue 已提交
124
			var rawConnections = FBXTree.Connections.connections;
Y
yamahigashi 已提交
125

126
			rawConnections.forEach( function ( rawConnection ) {
Y
yamahigashi 已提交
127

128 129 130
				var fromID = rawConnection[ 0 ];
				var toID = rawConnection[ 1 ];
				var relationship = rawConnection[ 2 ];
Y
yamahigashi 已提交
131

132 133 134
				if ( ! connectionMap.has( fromID ) ) {

					connectionMap.set( fromID, {
M
Mr.doob 已提交
135 136 137
						parents: [],
						children: []
					} );
Y
yamahigashi 已提交
138

139
				}
Y
yamahigashi 已提交
140

141 142
				var parentRelationship = { ID: toID, relationship: relationship };
				connectionMap.get( fromID ).parents.push( parentRelationship );
Y
yamahigashi 已提交
143

144
				if ( ! connectionMap.has( toID ) ) {
Y
yamahigashi 已提交
145

146
					connectionMap.set( toID, {
M
Mr.doob 已提交
147 148 149
						parents: [],
						children: []
					} );
Y
yamahigashi 已提交
150

M
Mr.doob 已提交
151
				}
Y
yamahigashi 已提交
152

153 154
				var childRelationship = { ID: fromID, relationship: relationship };
				connectionMap.get( toID ).children.push( childRelationship );
Y
yamahigashi 已提交
155

156
			} );
Y
yamahigashi 已提交
157

M
Mr.doob 已提交
158
		}
Y
yamahigashi 已提交
159

M
Mr.doob 已提交
160
		return connectionMap;
K
Kyle Larson 已提交
161

M
Mr.doob 已提交
162
	}
K
Kyle Larson 已提交
163

L
Lewy Blue 已提交
164 165
	// Parse FBXTree.Objects.Video for embedded image data
	// These images are connected to textures in FBXTree.Objects.Textures
L
Lewy Blue 已提交
166
	// via FBXTree.Connections.
M
Mr.doob 已提交
167
	function parseImages( FBXTree ) {
K
Kyle Larson 已提交
168

L
Lewy Blue 已提交
169 170
		var images = {};
		var blobs = {};
171

L
Lewy Blue 已提交
172
		if ( 'Video' in FBXTree.Objects ) {
K
Kyle Larson 已提交
173

L
Lewy Blue 已提交
174
			var videoNodes = FBXTree.Objects.Video;
K
Kyle Larson 已提交
175

M
Mr.doob 已提交
176
			for ( var nodeID in videoNodes ) {
K
Kyle Larson 已提交
177

M
Mr.doob 已提交
178
				var videoNode = videoNodes[ nodeID ];
K
Kyle Larson 已提交
179

180 181
				var id = parseInt( nodeID );

L
Lewy Blue 已提交
182
				images[ id ] = videoNode.Filename;
183

L
Lewy Blue 已提交
184 185
				// raw image data is in videoNode.Content
				if ( 'Content' in videoNode ) {
186

L
Lewy Blue 已提交
187 188
					var arrayBufferContent = ( videoNode.Content instanceof ArrayBuffer ) && ( videoNode.Content.byteLength > 0 );
					var base64Content = ( typeof videoNode.Content === 'string' ) && ( videoNode.Content !== '' );
189

L
Lewy Blue 已提交
190
					if ( arrayBufferContent || base64Content ) {
191

L
Lewy Blue 已提交
192
						var image = parseImage( videoNodes[ nodeID ] );
K
Kyle Larson 已提交
193

L
Lewy Blue 已提交
194
						blobs[ videoNode.Filename ] = image;
195

L
Lewy Blue 已提交
196
					}
K
Kyle Larson 已提交
197

M
Mr.doob 已提交
198
				}
K
Kyle Larson 已提交
199

M
Mr.doob 已提交
200
			}
K
Kyle Larson 已提交
201

M
Mr.doob 已提交
202
		}
K
Kyle Larson 已提交
203

L
Lewy Blue 已提交
204
		for ( var id in images ) {
205

L
Lewy Blue 已提交
206
			var filename = images[ id ];
207

L
Lewy Blue 已提交
208 209
			if ( blobs[ filename ] !== undefined ) images[ id ] = blobs[ filename ];
			else images[ id ] = images[ id ].split( '\\' ).pop();
210

L
Lewy Blue 已提交
211
		}
212

L
Lewy Blue 已提交
213
		return images;
K
Kyle Larson 已提交
214

M
Mr.doob 已提交
215
	}
K
Kyle Larson 已提交
216

L
Lewy Blue 已提交
217
	// Parse embedded image data in FBXTree.Video.Content
M
Mr.doob 已提交
218
	function parseImage( videoNode ) {
K
Kyle Larson 已提交
219

L
Lewy Blue 已提交
220 221
		var content = videoNode.Content;
		var fileName = videoNode.RelativeFilename || videoNode.Filename;
M
Mr.doob 已提交
222
		var extension = fileName.slice( fileName.lastIndexOf( '.' ) + 1 ).toLowerCase();
K
Kyle Larson 已提交
223

M
Mr.doob 已提交
224
		var type;
K
Kyle Larson 已提交
225

M
Mr.doob 已提交
226
		switch ( extension ) {
K
Kyle Larson 已提交
227

M
Mr.doob 已提交
228
			case 'bmp':
K
Kyle Larson 已提交
229

M
Mr.doob 已提交
230 231
				type = 'image/bmp';
				break;
K
Kyle Larson 已提交
232

M
Mr.doob 已提交
233
			case 'jpg':
234
			case 'jpeg':
K
Kyle Larson 已提交
235

M
Mr.doob 已提交
236 237
				type = 'image/jpeg';
				break;
K
Kyle Larson 已提交
238

M
Mr.doob 已提交
239
			case 'png':
K
Kyle Larson 已提交
240

M
Mr.doob 已提交
241 242
				type = 'image/png';
				break;
K
Kyle Larson 已提交
243

M
Mr.doob 已提交
244
			case 'tif':
K
Kyle Larson 已提交
245

M
Mr.doob 已提交
246 247
				type = 'image/tiff';
				break;
K
Kyle Larson 已提交
248

M
Mr.doob 已提交
249
			default:
K
Kyle Larson 已提交
250

251
				console.warn( 'FBXLoader: Image type "' + extension + '" is not supported.' );
M
Mr.doob 已提交
252
				return;
K
Kyle Larson 已提交
253

M
Mr.doob 已提交
254
		}
K
Kyle Larson 已提交
255

256
		if ( typeof content === 'string' ) { // ASCII format
257 258 259

			return 'data:' + type + ';base64,' + content;

260
		} else { // Binary Format
261 262 263 264 265

			var array = new Uint8Array( content );
			return window.URL.createObjectURL( new Blob( [ array ], { type: type } ) );

		}
K
Kyle Larson 已提交
266

M
Mr.doob 已提交
267
	}
K
Kyle Larson 已提交
268

L
Lewy Blue 已提交
269
	// Parse nodes in FBXTree.Objects.Texture
L
Lewy Blue 已提交
270
	// These contain details such as UV scaling, cropping, rotation etc and are connected
L
Lewy Blue 已提交
271
	// to images in FBXTree.Objects.Video
L
Lewy Blue 已提交
272
	function parseTextures( FBXTree, loader, images, connections ) {
K
Kyle Larson 已提交
273

M
Mr.doob 已提交
274
		var textureMap = new Map();
K
Kyle Larson 已提交
275

L
Lewy Blue 已提交
276
		if ( 'Texture' in FBXTree.Objects ) {
K
Kyle Larson 已提交
277

L
Lewy Blue 已提交
278
			var textureNodes = FBXTree.Objects.Texture;
M
Mr.doob 已提交
279
			for ( var nodeID in textureNodes ) {
K
Kyle Larson 已提交
280

L
Lewy Blue 已提交
281
				var texture = parseTexture( textureNodes[ nodeID ], loader, images, connections );
M
Mr.doob 已提交
282
				textureMap.set( parseInt( nodeID ), texture );
K
Kyle Larson 已提交
283

M
Mr.doob 已提交
284
			}
K
Kyle Larson 已提交
285

M
Mr.doob 已提交
286
		}
K
Kyle Larson 已提交
287

M
Mr.doob 已提交
288
		return textureMap;
K
Kyle Larson 已提交
289

M
Mr.doob 已提交
290
	}
K
Kyle Larson 已提交
291

L
Lewy Blue 已提交
292
	// Parse individual node in FBXTree.Objects.Texture
L
Lewy Blue 已提交
293
	function parseTexture( textureNode, loader, images, connections ) {
K
Kyle Larson 已提交
294

L
Lewy Blue 已提交
295
		var texture = loadTexture( textureNode, loader, images, connections );
K
Kyle Larson 已提交
296

L
Lewy Blue 已提交
297
		texture.ID = textureNode.id;
L
Lewy Blue 已提交
298 299 300

		texture.name = textureNode.attrName;

L
Lewy Blue 已提交
301 302
		var wrapModeU = textureNode.WrapModeU;
		var wrapModeV = textureNode.WrapModeV;
L
Lewy Blue 已提交
303 304 305 306 307 308 309 310 311 312

		var valueU = wrapModeU !== undefined ? wrapModeU.value : 0;
		var valueV = wrapModeV !== undefined ? wrapModeV.value : 0;

		// http://download.autodesk.com/us/fbx/SDKdocs/FBX_SDK_Help/files/fbxsdkref/class_k_fbx_texture.html#889640e63e2e681259ea81061b85143a
		// 0: repeat(default), 1: clamp

		texture.wrapS = valueU === 0 ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
		texture.wrapT = valueV === 0 ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;

L
Lewy Blue 已提交
313
		if ( 'Scaling' in textureNode ) {
L
Lewy Blue 已提交
314

L
Lewy Blue 已提交
315
			var values = textureNode.Scaling.value;
L
Lewy Blue 已提交
316 317 318 319 320

			texture.repeat.x = values[ 0 ];
			texture.repeat.y = values[ 1 ];

		}
K
Kyle Larson 已提交
321

L
Lewy Blue 已提交
322 323 324 325 326
		return texture;

	}

	// load a texture specified as a blob or data URI, or via an external URL using THREE.TextureLoader
L
Lewy Blue 已提交
327
	function loadTexture( textureNode, loader, images, connections ) {
K
Kyle Larson 已提交
328

M
Mr.doob 已提交
329
		var fileName;
K
Kyle Larson 已提交
330

L
Lewy Blue 已提交
331
		var children = connections.get( textureNode.id ).children;
K
Kyle Larson 已提交
332

L
Lewy Blue 已提交
333
		if ( children !== undefined && children.length > 0 && images[ children[ 0 ].ID ] !== undefined ) {
K
Kyle Larson 已提交
334

L
Lewy Blue 已提交
335
			fileName = images[ children[ 0 ].ID ];
336

M
Mr.doob 已提交
337
		}
K
Kyle Larson 已提交
338

M
Mr.doob 已提交
339
		var currentPath = loader.path;
K
Kyle Larson 已提交
340

341
		if ( fileName.indexOf( 'blob:' ) === 0 || fileName.indexOf( 'data:' ) === 0 ) {
K
Kyle Larson 已提交
342

M
Mr.doob 已提交
343
			loader.setPath( undefined );
K
Kyle Larson 已提交
344

M
Mr.doob 已提交
345
		}
346

M
Mr.doob 已提交
347
		var texture = loader.load( fileName );
348

M
Mr.doob 已提交
349
		loader.setPath( currentPath );
350

M
Mr.doob 已提交
351
		return texture;
352

M
Mr.doob 已提交
353
	}
354

L
Lewy Blue 已提交
355
	// Parse nodes in FBXTree.Objects.Material
M
Mr.doob 已提交
356
	function parseMaterials( FBXTree, textureMap, connections ) {
357

M
Mr.doob 已提交
358
		var materialMap = new Map();
359

L
Lewy Blue 已提交
360
		if ( 'Material' in FBXTree.Objects ) {
361

L
Lewy Blue 已提交
362
			var materialNodes = FBXTree.Objects.Material;
363

M
Mr.doob 已提交
364
			for ( var nodeID in materialNodes ) {
365

L
Lewy Blue 已提交
366
				var material = parseMaterial( FBXTree, materialNodes[ nodeID ], textureMap, connections );
L
Lewy Blue 已提交
367

L
Lewy Blue 已提交
368
				if ( material !== null ) materialMap.set( parseInt( nodeID ), material );
369

M
Mr.doob 已提交
370
			}
371

M
Mr.doob 已提交
372
		}
373

M
Mr.doob 已提交
374
		return materialMap;
375

M
Mr.doob 已提交
376
	}
377

L
Lewy Blue 已提交
378 379
	// Parse single node in FBXTree.Objects.Material
	// Materials are connected to texture maps in FBXTree.Objects.Textures
L
Lewy Blue 已提交
380
	// FBX format currently only supports Lambert and Phong shading models
L
Lewy Blue 已提交
381
	function parseMaterial( FBXTree, materialNode, textureMap, connections ) {
382

L
Lewy Blue 已提交
383
		var ID = materialNode.id;
M
Mr.doob 已提交
384
		var name = materialNode.attrName;
L
Lewy Blue 已提交
385
		var type = materialNode.ShadingModel;
386

L
Lewy Blue 已提交
387
		//Case where FBX wraps shading model in property object.
M
Mr.doob 已提交
388
		if ( typeof type === 'object' ) {
389

M
Mr.doob 已提交
390
			type = type.value;
391

M
Mr.doob 已提交
392
		}
393

L
Lewy Blue 已提交
394
		// Ignore unused materials which don't have any connections.
L
Lewy Blue 已提交
395
		if ( ! connections.has( ID ) ) return null;
L
Lewy Blue 已提交
396

L
Lewy Blue 已提交
397
		var parameters = parseParameters( FBXTree, materialNode, textureMap, ID, connections );
398

M
Mr.doob 已提交
399
		var material;
400

M
Mugen87 已提交
401
		switch ( type.toLowerCase() ) {
402

M
Mr.doob 已提交
403 404 405 406 407 408 409
			case 'phong':
				material = new THREE.MeshPhongMaterial();
				break;
			case 'lambert':
				material = new THREE.MeshLambertMaterial();
				break;
			default:
410 411
				console.warn( 'THREE.FBXLoader: unknown material type "%s". Defaulting to MeshPhongMaterial.', type );
				material = new THREE.MeshPhongMaterial( { color: 0x3300ff } );
M
Mr.doob 已提交
412
				break;
413

M
Mr.doob 已提交
414
		}
415

M
Mr.doob 已提交
416 417
		material.setValues( parameters );
		material.name = name;
418

M
Mr.doob 已提交
419
		return material;
420

M
Mr.doob 已提交
421
	}
422

L
Lewy Blue 已提交
423 424
	// Parse FBX material and return parameters suitable for a three.js material
	// Also parse the texture map and return any textures associated with the material
L
Lewy Blue 已提交
425
	function parseParameters( FBXTree, properties, textureMap, ID, connections ) {
426

M
Mr.doob 已提交
427
		var parameters = {};
428

L
Lewy Blue 已提交
429 430
		if ( properties.BumpFactor ) {

431
			parameters.bumpScale = properties.BumpFactor.value;
L
Lewy Blue 已提交
432 433

		}
M
Mr.doob 已提交
434
		if ( properties.Diffuse ) {
435

M
Mr.doob 已提交
436
			parameters.color = parseColor( properties.Diffuse );
437

L
Lewy Blue 已提交
438 439 440
		}
		if ( properties.DisplacementFactor ) {

441
			parameters.displacementScale = properties.DisplacementFactor.value;
L
Lewy Blue 已提交
442 443 444 445

		}
		if ( properties.ReflectionFactor ) {

446
			parameters.reflectivity = properties.ReflectionFactor.value;
L
Lewy Blue 已提交
447

M
Mr.doob 已提交
448 449
		}
		if ( properties.Specular ) {
450

M
Mr.doob 已提交
451
			parameters.specular = parseColor( properties.Specular );
452

M
Mr.doob 已提交
453 454
		}
		if ( properties.Shininess ) {
455

456
			parameters.shininess = properties.Shininess.value;
457

M
Mr.doob 已提交
458 459
		}
		if ( properties.Emissive ) {
460

M
Mr.doob 已提交
461
			parameters.emissive = parseColor( properties.Emissive );
462

M
Mr.doob 已提交
463 464
		}
		if ( properties.EmissiveFactor ) {
465

L
Lewy Blue 已提交
466
			parameters.emissiveIntensity = parseFloat( properties.EmissiveFactor.value );
467

M
Mr.doob 已提交
468 469
		}
		if ( properties.Opacity ) {
470

L
Lewy Blue 已提交
471
			parameters.opacity = parseFloat( properties.Opacity.value );
472

M
Mr.doob 已提交
473 474
		}
		if ( parameters.opacity < 1.0 ) {
K
Kyle Larson 已提交
475

M
Mr.doob 已提交
476
			parameters.transparent = true;
K
Kyle Larson 已提交
477

M
Mr.doob 已提交
478
		}
K
Kyle Larson 已提交
479

L
Lewy Blue 已提交
480
		connections.get( ID ).children.forEach( function ( child ) {
K
Kyle Larson 已提交
481

482
			var type = child.relationship;
K
Kyle Larson 已提交
483

M
Mr.doob 已提交
484
			switch ( type ) {
K
Kyle Larson 已提交
485

L
Lewy Blue 已提交
486
				case 'Bump':
487
					parameters.bumpMap = textureMap.get( child.ID );
L
Lewy Blue 已提交
488 489
					break;

M
Mugen87 已提交
490
				case 'DiffuseColor':
491
					parameters.map = getTexture( FBXTree, textureMap, child.ID, connections );
M
Mr.doob 已提交
492
					break;
K
Kyle Larson 已提交
493

L
Lewy Blue 已提交
494
				case 'DisplacementColor':
495
					parameters.displacementMap = getTexture( FBXTree, textureMap, child.ID, connections );
L
Lewy Blue 已提交
496 497 498 499
					break;


				case 'EmissiveColor':
500
					parameters.emissiveMap = getTexture( FBXTree, textureMap, child.ID, connections );
501 502
					break;

M
Mugen87 已提交
503
				case 'NormalMap':
504
					parameters.normalMap = getTexture( FBXTree, textureMap, child.ID, connections );
505 506
					break;

L
Lewy Blue 已提交
507
				case 'ReflectionColor':
508
					parameters.envMap = getTexture( FBXTree, textureMap, child.ID, connections );
L
Lewy Blue 已提交
509 510 511
					parameters.envMap.mapping = THREE.EquirectangularReflectionMapping;
					break;

L
Lewy Blue 已提交
512
				case 'SpecularColor':
513
					parameters.specularMap = getTexture( FBXTree, textureMap, child.ID, connections );
L
Lewy Blue 已提交
514 515 516
					break;

				case 'TransparentColor':
517
					parameters.alphaMap = getTexture( FBXTree, textureMap, child.ID, connections );
L
Lewy Blue 已提交
518 519 520
					parameters.transparent = true;
					break;

M
Mugen87 已提交
521
				case 'AmbientColor':
L
Lewy Blue 已提交
522 523 524
				case 'ShininessExponent': // AKA glossiness map
				case 'SpecularFactor': // AKA specularLevel
				case 'VectorDisplacementColor': // NOTE: Seems to be a copy of DisplacementColor
M
Mr.doob 已提交
525
				default:
L
Lewy Blue 已提交
526
					console.warn( 'THREE.FBXLoader: %s map is not supported in three.js, skipping texture.', type );
M
Mr.doob 已提交
527
					break;
K
Kyle Larson 已提交
528 529 530

			}

531
		} );
K
Kyle Larson 已提交
532

M
Mr.doob 已提交
533
		return parameters;
K
Kyle Larson 已提交
534

M
Mr.doob 已提交
535
	}
K
Kyle Larson 已提交
536

L
Lewy Blue 已提交
537 538 539 540
	// get a texture from the textureMap for use by a material.
	function getTexture( FBXTree, textureMap, id, connections ) {

		// if the texture is a layered texture, just use the first layer and issue a warning
L
Lewy Blue 已提交
541
		if ( 'LayeredTexture' in FBXTree.Objects && id in FBXTree.Objects.LayeredTexture ) {
L
Lewy Blue 已提交
542 543 544 545 546 547 548 549 550 551

			console.warn( 'THREE.FBXLoader: layered textures are not supported in three.js. Discarding all but first layer.' );
			id = connections.get( id ).children[ 0 ].ID;

		}

		return textureMap.get( id );

	}

L
Lewy Blue 已提交
552
	// Parse nodes in FBXTree.Objects.Deformer
L
Lewy Blue 已提交
553 554
	// Deformer node can contain skinning or Vertex Cache animation data, however only skinning is supported here
	// Generates map of Skeleton-like objects for use later when generating and binding skeletons.
M
Mr.doob 已提交
555
	function parseDeformers( FBXTree, connections ) {
K
Kyle Larson 已提交
556

L
Lewy Blue 已提交
557
		var skeletons = {};
K
Kyle Larson 已提交
558

L
Lewy Blue 已提交
559
		if ( 'Deformer' in FBXTree.Objects ) {
K
Kyle Larson 已提交
560

L
Lewy Blue 已提交
561
			var DeformerNodes = FBXTree.Objects.Deformer;
562

M
Mr.doob 已提交
563
			for ( var nodeID in DeformerNodes ) {
564

M
Mr.doob 已提交
565
				var deformerNode = DeformerNodes[ nodeID ];
566

M
Mr.doob 已提交
567
				if ( deformerNode.attrType === 'Skin' ) {
568

L
Lewy Blue 已提交
569
					var relationships = connections.get( parseInt( nodeID ) );
L
Lewy Blue 已提交
570

L
Lewy Blue 已提交
571
					var skeleton = parseSkeleton( relationships, DeformerNodes );
L
Lewy Blue 已提交
572
					skeleton.ID = nodeID;
573

L
Lewy Blue 已提交
574 575
					if ( relationships.parents.length > 1 ) console.warn( 'THREE.FBXLoader: skeleton attached to more than one geometry is not supported.' );
					skeleton.geometryID = relationships.parents[ 0 ].ID;
576

L
Lewy Blue 已提交
577
					skeletons[ nodeID ] = skeleton;
578 579 580

				}

K
Kyle Larson 已提交
581 582
			}

M
Mr.doob 已提交
583
		}
K
Kyle Larson 已提交
584

L
Lewy Blue 已提交
585
		return skeletons;
K
Kyle Larson 已提交
586

M
Mr.doob 已提交
587
	}
K
Kyle Larson 已提交
588

L
Lewy Blue 已提交
589
	// Parse single nodes in FBXTree.Objects.Deformer
L
Lewy Blue 已提交
590 591 592
	// The top level deformer nodes have type 'Skin' and subDeformer nodes have type 'Cluster'
	// Each skin node represents a skeleton and each cluster node represents a bone
	function parseSkeleton( connections, deformerNodes ) {
K
Kyle Larson 已提交
593

L
Lewy Blue 已提交
594
		var rawBones = [];
K
Kyle Larson 已提交
595

L
Lewy Blue 已提交
596
		connections.children.forEach( function ( child ) {
Y
yamahigashi 已提交
597

L
Lewy Blue 已提交
598
			var subDeformerNode = deformerNodes[ child.ID ];
Y
yamahigashi 已提交
599

L
Lewy Blue 已提交
600
			if ( subDeformerNode.attrType !== 'Cluster' ) return;
Y
yamahigashi 已提交
601

L
Lewy Blue 已提交
602
			var rawBone = {
603

L
Lewy Blue 已提交
604
				ID: child.ID,
M
Mr.doob 已提交
605 606
				indices: [],
				weights: [],
L
Lewy Blue 已提交
607 608
				transform: new THREE.Matrix4().fromArray( subDeformerNode.Transform.a ),
				transformLink: new THREE.Matrix4().fromArray( subDeformerNode.TransformLink.a ),
L
Lewy Blue 已提交
609
				linkMode: subDeformerNode.Mode,
610

M
Mr.doob 已提交
611
			};
Y
yamahigashi 已提交
612

L
Lewy Blue 已提交
613
			if ( 'Indexes' in subDeformerNode ) {
Y
yamahigashi 已提交
614

L
Lewy Blue 已提交
615 616
				rawBone.indices = subDeformerNode.Indexes.a;
				rawBone.weights = subDeformerNode.Weights.a;
Y
yamahigashi 已提交
617

M
Mr.doob 已提交
618
			}
Y
yamahigashi 已提交
619

L
Lewy Blue 已提交
620
			rawBones.push( rawBone );
Y
yamahigashi 已提交
621

622
		} );
Y
yamahigashi 已提交
623

M
Mr.doob 已提交
624
		return {
625

L
Lewy Blue 已提交
626
			rawBones: rawBones,
M
Mr.doob 已提交
627
			bones: []
628

M
Mr.doob 已提交
629
		};
Y
yamahigashi 已提交
630

M
Mr.doob 已提交
631
	}
Y
yamahigashi 已提交
632

L
Lewy Blue 已提交
633
	// Parse nodes in FBXTree.Objects.Geometry
L
Lewy Blue 已提交
634
	function parseGeometries( FBXTree, connections, skeletons ) {
Y
yamahigashi 已提交
635

M
Mr.doob 已提交
636
		var geometryMap = new Map();
Y
yamahigashi 已提交
637

L
Lewy Blue 已提交
638
		if ( 'Geometry' in FBXTree.Objects ) {
Y
yamahigashi 已提交
639

L
Lewy Blue 已提交
640
			var geometryNodes = FBXTree.Objects.Geometry;
Y
yamahigashi 已提交
641 642 643



M
Mr.doob 已提交
644
			for ( var nodeID in geometryNodes ) {
Y
yamahigashi 已提交
645

M
Mr.doob 已提交
646
				var relationships = connections.get( parseInt( nodeID ) );
L
Lewy Blue 已提交
647
				var geo = parseGeometry( FBXTree, relationships, geometryNodes[ nodeID ], skeletons );
L
Lewy Blue 已提交
648

M
Mr.doob 已提交
649
				geometryMap.set( parseInt( nodeID ), geo );
Y
yamahigashi 已提交
650

M
Mr.doob 已提交
651
			}
Y
yamahigashi 已提交
652

M
Mr.doob 已提交
653
		}
Y
yamahigashi 已提交
654

M
Mr.doob 已提交
655
		return geometryMap;
Y
yamahigashi 已提交
656

M
Mr.doob 已提交
657
	}
Y
yamahigashi 已提交
658

L
Lewy Blue 已提交
659
	// Parse single node in FBXTree.Objects.Geometry
L
Lewy Blue 已提交
660
	function parseGeometry( FBXTree, relationships, geometryNode, skeletons ) {
Y
yamahigashi 已提交
661

M
Mr.doob 已提交
662
		switch ( geometryNode.attrType ) {
Y
yamahigashi 已提交
663

M
Mr.doob 已提交
664
			case 'Mesh':
L
Lewy Blue 已提交
665
				return parseMeshGeometry( FBXTree, relationships, geometryNode, skeletons );
M
Mr.doob 已提交
666
				break;
Y
yamahigashi 已提交
667

L
Lewy Blue 已提交
668
			case 'NurbsCurve':
M
Mr.doob 已提交
669 670
				return parseNurbsGeometry( geometryNode );
				break;
Y
yamahigashi 已提交
671

M
Mr.doob 已提交
672
		}
Y
yamahigashi 已提交
673

M
Mr.doob 已提交
674
	}
Y
yamahigashi 已提交
675

L
Lewy Blue 已提交
676

L
Lewy Blue 已提交
677
	// Parse single node mesh geometry in FBXTree.Objects.Geometry
L
Lewy Blue 已提交
678
	function parseMeshGeometry( FBXTree, relationships, geometryNode, skeletons ) {
Y
yamahigashi 已提交
679

680 681
		var modelNodes = relationships.parents.map( function ( parent ) {

L
Lewy Blue 已提交
682
			return FBXTree.Objects.Model[ parent.ID ];
683 684 685 686 687 688

		} );

		// don't create geometry if it is not associated with any models
		if ( modelNodes.length === 0 ) return;

L
Lewy Blue 已提交
689 690 691 692 693 694 695 696
		var skeleton = relationships.children.reduce( function ( skeleton, child ) {

			if ( skeletons[ child.ID ] !== undefined ) skeleton = skeletons[ child.ID ];

			return skeleton;

		}, null );

697 698 699 700 701 702 703 704 705
		var preTransform = new THREE.Matrix4();

		// TODO: if there is more than one model associated with the geometry, AND the models have
		// different geometric transforms, then this will cause problems
		// if ( modelNodes.length > 1 ) { }

		// For now just assume one model and get the preRotations from that
		var modelNode = modelNodes[ 0 ];

L
Lewy Blue 已提交
706
		if ( 'GeometricRotation' in modelNode ) {
707

L
Lewy Blue 已提交
708
			var array = modelNode.GeometricRotation.value.map( THREE.Math.degToRad );
709 710 711 712 713 714
			array[ 3 ] = 'ZYX';

			preTransform.makeRotationFromEuler( new THREE.Euler().fromArray( array ) );

		}

L
Lewy Blue 已提交
715
		if ( 'GeometricTranslation' in modelNode ) {
716

L
Lewy Blue 已提交
717
			preTransform.setPosition( new THREE.Vector3().fromArray( modelNode.GeometricTranslation.value ) );
718 719 720

		}

L
Lewy Blue 已提交
721
		return genGeometry( FBXTree, relationships, geometryNode, skeleton, preTransform );
Y
yamahigashi 已提交
722

M
Mr.doob 已提交
723
	}
Y
yamahigashi 已提交
724

L
Lewy Blue 已提交
725
	// Generate a THREE.BufferGeometry from a node in FBXTree.Objects.Geometry
L
Lewy Blue 已提交
726
	function genGeometry( FBXTree, relationships, geometryNode, skeleton, preTransform ) {
Y
yamahigashi 已提交
727

L
Lewy Blue 已提交
728 729
		var vertexPositions = geometryNode.Vertices.a;
		var vertexIndices = geometryNode.PolygonVertexIndex.a;
Y
yamahigashi 已提交
730

L
tidying  
Lewy Blue 已提交
731
		// create arrays to hold the final data used to build the buffergeometry
L
Lewy Blue 已提交
732 733 734 735 736 737 738
		var vertexBuffer = [];
		var normalBuffer = [];
		var colorsBuffer = [];
		var uvsBuffer = [];
		var materialIndexBuffer = [];
		var vertexWeightsBuffer = [];
		var weightsIndicesBuffer = [];
739

L
Lewy Blue 已提交
740
		if ( geometryNode.LayerElementColor ) {
L
tidying  
Lewy Blue 已提交
741

L
Lewy Blue 已提交
742
			var colorInfo = getColors( geometryNode.LayerElementColor[ 0 ] );
L
tidying  
Lewy Blue 已提交
743 744 745

		}

L
Lewy Blue 已提交
746
		if ( geometryNode.LayerElementMaterial ) {
L
tidying  
Lewy Blue 已提交
747

L
Lewy Blue 已提交
748
			var materialInfo = getMaterials( geometryNode.LayerElementMaterial[ 0 ] );
L
tidying  
Lewy Blue 已提交
749 750

		}
Y
yamahigashi 已提交
751

L
Lewy Blue 已提交
752
		if ( geometryNode.LayerElementNormal ) {
M
Mr.doob 已提交
753

L
Lewy Blue 已提交
754
			var normalInfo = getNormals( geometryNode.LayerElementNormal[ 0 ] );
Y
yamahigashi 已提交
755

M
Mr.doob 已提交
756
		}
Y
yamahigashi 已提交
757

L
Lewy Blue 已提交
758
		if ( geometryNode.LayerElementUV ) {
Y
yamahigashi 已提交
759

L
Lewy Blue 已提交
760 761
			var uvInfo = [];
			var i = 0;
L
Lewy Blue 已提交
762
			while ( geometryNode.LayerElementUV[ i ] ) {
L
Lewy Blue 已提交
763

L
Lewy Blue 已提交
764
				uvInfo.push( getUVs( geometryNode.LayerElementUV[ i ] ) );
L
Lewy Blue 已提交
765
				i ++;
L
Lewy Blue 已提交
766 767

			}
Y
yamahigashi 已提交
768

M
Mr.doob 已提交
769
		}
Y
yamahigashi 已提交
770

T
Takahiro 已提交
771 772
		var weightTable = {};

L
Lewy Blue 已提交
773
		if ( skeleton !== null ) {
T
Takahiro 已提交
774

L
Lewy Blue 已提交
775
			skeleton.rawBones.forEach( function ( rawBone, i ) {
T
Takahiro 已提交
776

L
Lewy Blue 已提交
777 778
				// loop over the bone's vertex indices and weights
				rawBone.indices.forEach( function ( index, j ) {
T
Takahiro 已提交
779 780 781 782

					if ( weightTable[ index ] === undefined ) weightTable[ index ] = [];

					weightTable[ index ].push( {
783

L
Lewy Blue 已提交
784 785
						id: i,
						weight: rawBone.weights[ j ],
786

T
Takahiro 已提交
787 788
					} );

789
				} );
T
Takahiro 已提交
790

L
Lewy Blue 已提交
791
			} );
T
Takahiro 已提交
792 793 794

		}

M
Mr.doob 已提交
795
		var polygonIndex = 0;
796
		var faceLength = 0;
T
Takahiro 已提交
797
		var displayedWeightsWarning = false;
Y
yamahigashi 已提交
798

L
tidying  
Lewy Blue 已提交
799
		// these will hold data for a single face
800 801
		var vertexPositionIndexes = [];
		var faceNormals = [];
802 803
		var faceColors = [];
		var faceUVs = [];
L
tidying  
Lewy Blue 已提交
804 805
		var faceWeights = [];
		var faceWeightIndices = [];
806

807
		vertexIndices.forEach( function ( vertexIndex, polygonVertexIndex ) {
Y
yamahigashi 已提交
808

M
Mr.doob 已提交
809
			var endOfFace = false;
Y
yamahigashi 已提交
810

L
Lewy Blue 已提交
811 812 813 814 815 816 817
			// Face index and vertex index arrays are combined in a single array
			// A cube with quad faces looks like this:
			// PolygonVertexIndex: *24 {
			//  a: 0, 1, 3, -3, 2, 3, 5, -5, 4, 5, 7, -7, 6, 7, 1, -1, 1, 7, 5, -4, 6, 0, 2, -5
			//  }
			// Negative numbers mark the end of a face - first face here is 0, 1, 3, -3
			// to find index of last vertex multiply by -1 and subtract 1: -3 * - 1 - 1 = 2
M
Mr.doob 已提交
818
			if ( vertexIndex < 0 ) {
Y
yamahigashi 已提交
819

820
				vertexIndex = vertexIndex ^ - 1; // equivalent to ( x * -1 ) - 1
L
tidying  
Lewy Blue 已提交
821
				vertexIndices[ polygonVertexIndex ] = vertexIndex;
M
Mr.doob 已提交
822
				endOfFace = true;
Y
yamahigashi 已提交
823

M
Mr.doob 已提交
824
			}
Y
yamahigashi 已提交
825

M
Mr.doob 已提交
826 827
			var weightIndices = [];
			var weights = [];
Y
yamahigashi 已提交
828

829
			vertexPositionIndexes.push( vertexIndex * 3, vertexIndex * 3 + 1, vertexIndex * 3 + 2 );
Y
yamahigashi 已提交
830

L
tidying  
Lewy Blue 已提交
831 832 833 834 835 836 837
			if ( colorInfo ) {

				var data = getData( polygonVertexIndex, polygonIndex, vertexIndex, colorInfo );

				faceColors.push( data[ 0 ], data[ 1 ], data[ 2 ] );

			}
Y
yamahigashi 已提交
838

L
Lewy Blue 已提交
839
			if ( skeleton ) {
Y
yamahigashi 已提交
840

T
Takahiro 已提交
841
				if ( weightTable[ vertexIndex ] !== undefined ) {
Y
yamahigashi 已提交
842

843
					weightTable[ vertexIndex ].forEach( function ( wt ) {
Y
yamahigashi 已提交
844

845 846
						weights.push( wt.weight );
						weightIndices.push( wt.id );
Y
yamahigashi 已提交
847

848
					} );
Y
yamahigashi 已提交
849 850


851
				}
Y
yamahigashi 已提交
852

M
Mr.doob 已提交
853
				if ( weights.length > 4 ) {
Y
yamahigashi 已提交
854

T
Takahiro 已提交
855 856
					if ( ! displayedWeightsWarning ) {

M
Mugen87 已提交
857
						console.warn( 'THREE.FBXLoader: Vertex has more than 4 skinning weights assigned to vertex. Deleting additional weights.' );
T
Takahiro 已提交
858 859 860
						displayedWeightsWarning = true;

					}
Y
yamahigashi 已提交
861

L
Lewy Blue 已提交
862
					var wIndex = [ 0, 0, 0, 0 ];
M
Mr.doob 已提交
863
					var Weight = [ 0, 0, 0, 0 ];
Y
yamahigashi 已提交
864

M
Mr.doob 已提交
865
					weights.forEach( function ( weight, weightIndex ) {
Y
yamahigashi 已提交
866

M
Mr.doob 已提交
867 868
						var currentWeight = weight;
						var currentIndex = weightIndices[ weightIndex ];
Y
yamahigashi 已提交
869

M
Mr.doob 已提交
870
						Weight.forEach( function ( comparedWeight, comparedWeightIndex, comparedWeightArray ) {
Y
yamahigashi 已提交
871

M
Mr.doob 已提交
872
							if ( currentWeight > comparedWeight ) {
Y
yamahigashi 已提交
873

M
Mr.doob 已提交
874 875
								comparedWeightArray[ comparedWeightIndex ] = currentWeight;
								currentWeight = comparedWeight;
Y
yamahigashi 已提交
876

L
Lewy Blue 已提交
877 878
								var tmp = wIndex[ comparedWeightIndex ];
								wIndex[ comparedWeightIndex ] = currentIndex;
M
Mr.doob 已提交
879
								currentIndex = tmp;
Y
yamahigashi 已提交
880

M
Mr.doob 已提交
881
							}
Y
yamahigashi 已提交
882

M
Mr.doob 已提交
883
						} );
Y
yamahigashi 已提交
884

M
Mr.doob 已提交
885
					} );
Y
yamahigashi 已提交
886

L
Lewy Blue 已提交
887
					weightIndices = wIndex;
M
Mr.doob 已提交
888
					weights = Weight;
Y
yamahigashi 已提交
889

M
Mr.doob 已提交
890
				}
Y
yamahigashi 已提交
891

L
Lewy Blue 已提交
892
				// if the weight array is shorter than 4 pad with 0s
893
				while ( weights.length < 4 ) {
Y
yamahigashi 已提交
894

895 896
					weights.push( 0 );
					weightIndices.push( 0 );
Y
yamahigashi 已提交
897

M
Mr.doob 已提交
898
				}
Y
yamahigashi 已提交
899

L
Lewy Blue 已提交
900 901
				for ( var i = 0; i < 4; ++ i ) {

L
tidying  
Lewy Blue 已提交
902 903
					faceWeights.push( weights[ i ] );
					faceWeightIndices.push( weightIndices[ i ] );
L
Lewy Blue 已提交
904 905

				}
Y
yamahigashi 已提交
906

M
Mr.doob 已提交
907
			}
Y
yamahigashi 已提交
908

M
Mr.doob 已提交
909
			if ( normalInfo ) {
Y
yamahigashi 已提交
910

911 912 913
				var data = getData( polygonVertexIndex, polygonIndex, vertexIndex, normalInfo );

				faceNormals.push( data[ 0 ], data[ 1 ], data[ 2 ] );
Y
yamahigashi 已提交
914

M
Mr.doob 已提交
915
			}
Y
yamahigashi 已提交
916

L
Lewy Blue 已提交
917 918 919 920 921 922
			if ( materialInfo && materialInfo.mappingType !== 'AllSame' ) {

				var materialIndex = getData( polygonVertexIndex, polygonIndex, vertexIndex, materialInfo )[ 0 ];

			}

M
Mr.doob 已提交
923
			if ( uvInfo ) {
Y
yamahigashi 已提交
924

925
				uvInfo.forEach( function ( uv, i ) {
L
Lewy Blue 已提交
926

927
					var data = getData( polygonVertexIndex, polygonIndex, vertexIndex, uv );
L
Lewy Blue 已提交
928

L
Lewy Blue 已提交
929
					if ( faceUVs[ i ] === undefined ) {
Y
yamahigashi 已提交
930

L
Lewy Blue 已提交
931
						faceUVs[ i ] = [];
Y
yamahigashi 已提交
932

L
Lewy Blue 已提交
933
					}
Y
yamahigashi 已提交
934

935 936
					faceUVs[ i ].push( data[ 0 ] );
					faceUVs[ i ].push( data[ 1 ] );
L
Lewy Blue 已提交
937

938
				} );
Y
yamahigashi 已提交
939

940
			}
Y
yamahigashi 已提交
941

942
			faceLength ++;
Y
yamahigashi 已提交
943

L
tidying  
Lewy Blue 已提交
944
			// we have reached the end of a face - it may have 4 sides though
L
Lewy Blue 已提交
945
			// in which case the data is split to represent two 3 sided faces
M
Mr.doob 已提交
946
			if ( endOfFace ) {
Y
yamahigashi 已提交
947

948
				for ( var i = 2; i < faceLength; i ++ ) {
Y
yamahigashi 已提交
949

L
Lewy Blue 已提交
950 951 952
					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ 0 ] ] );
					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ 1 ] ] );
					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ 2 ] ] );
Y
yamahigashi 已提交
953

L
Lewy Blue 已提交
954 955 956
					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ ( i - 1 ) * 3 ] ] );
					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ ( i - 1 ) * 3 + 1 ] ] );
					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ ( i - 1 ) * 3 + 2 ] ] );
Y
yamahigashi 已提交
957

L
Lewy Blue 已提交
958 959 960
					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ i * 3 ] ] );
					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ i * 3 + 1 ] ] );
					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ i * 3 + 2 ] ] );
961

L
Lewy Blue 已提交
962
					if ( skeleton ) {
963

L
Lewy Blue 已提交
964
						vertexWeightsBuffer.push( faceWeights[ 0 ] );
L
Lewy Blue 已提交
965 966 967
						vertexWeightsBuffer.push( faceWeights[ 1 ] );
						vertexWeightsBuffer.push( faceWeights[ 2 ] );
						vertexWeightsBuffer.push( faceWeights[ 3 ] );
L
Lewy Blue 已提交
968

L
Lewy Blue 已提交
969 970 971 972
						vertexWeightsBuffer.push( faceWeights[ ( i - 1 ) * 4 ] );
						vertexWeightsBuffer.push( faceWeights[ ( i - 1 ) * 4 + 1 ] );
						vertexWeightsBuffer.push( faceWeights[ ( i - 1 ) * 4 + 2 ] );
						vertexWeightsBuffer.push( faceWeights[ ( i - 1 ) * 4 + 3 ] );
L
Lewy Blue 已提交
973

L
Lewy Blue 已提交
974 975 976 977
						vertexWeightsBuffer.push( faceWeights[ i * 4 ] );
						vertexWeightsBuffer.push( faceWeights[ i * 4 + 1 ] );
						vertexWeightsBuffer.push( faceWeights[ i * 4 + 2 ] );
						vertexWeightsBuffer.push( faceWeights[ i * 4 + 3 ] );
L
Lewy Blue 已提交
978

L
Lewy Blue 已提交
979 980 981 982
						weightsIndicesBuffer.push( faceWeightIndices[ 0 ] );
						weightsIndicesBuffer.push( faceWeightIndices[ 1 ] );
						weightsIndicesBuffer.push( faceWeightIndices[ 2 ] );
						weightsIndicesBuffer.push( faceWeightIndices[ 3 ] );
L
Lewy Blue 已提交
983

L
Lewy Blue 已提交
984 985 986 987
						weightsIndicesBuffer.push( faceWeightIndices[ ( i - 1 ) * 4 ] );
						weightsIndicesBuffer.push( faceWeightIndices[ ( i - 1 ) * 4 + 1 ] );
						weightsIndicesBuffer.push( faceWeightIndices[ ( i - 1 ) * 4 + 2 ] );
						weightsIndicesBuffer.push( faceWeightIndices[ ( i - 1 ) * 4 + 3 ] );
L
Lewy Blue 已提交
988

L
Lewy Blue 已提交
989 990 991 992
						weightsIndicesBuffer.push( faceWeightIndices[ i * 4 ] );
						weightsIndicesBuffer.push( faceWeightIndices[ i * 4 + 1 ] );
						weightsIndicesBuffer.push( faceWeightIndices[ i * 4 + 2 ] );
						weightsIndicesBuffer.push( faceWeightIndices[ i * 4 + 3 ] );
993

L
tidying  
Lewy Blue 已提交
994 995
					}

L
Lewy Blue 已提交
996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
					if ( colorInfo ) {

						colorsBuffer.push( faceColors[ 0 ] );
						colorsBuffer.push( faceColors[ 1 ] );
						colorsBuffer.push( faceColors[ 2 ] );

						colorsBuffer.push( faceColors[ ( i - 1 ) * 3 ] );
						colorsBuffer.push( faceColors[ ( i - 1 ) * 3 + 1 ] );
						colorsBuffer.push( faceColors[ ( i - 1 ) * 3 + 2 ] );

						colorsBuffer.push( faceColors[ i * 3 ] );
						colorsBuffer.push( faceColors[ i * 3 + 1 ] );
						colorsBuffer.push( faceColors[ i * 3 + 2 ] );

					}
1011

L
Lewy Blue 已提交
1012
					if ( materialInfo && materialInfo.mappingType !== 'AllSame' ) {
1013

L
Lewy Blue 已提交
1014 1015 1016
						materialIndexBuffer.push( materialIndex );
						materialIndexBuffer.push( materialIndex );
						materialIndexBuffer.push( materialIndex );
1017

L
Lewy Blue 已提交
1018
					}
1019

L
Lewy Blue 已提交
1020
					if ( normalInfo ) {
1021

L
Lewy Blue 已提交
1022 1023 1024
						normalBuffer.push( faceNormals[ 0 ] );
						normalBuffer.push( faceNormals[ 1 ] );
						normalBuffer.push( faceNormals[ 2 ] );
1025

L
Lewy Blue 已提交
1026 1027 1028
						normalBuffer.push( faceNormals[ ( i - 1 ) * 3 ] );
						normalBuffer.push( faceNormals[ ( i - 1 ) * 3 + 1 ] );
						normalBuffer.push( faceNormals[ ( i - 1 ) * 3 + 2 ] );
Y
yamahigashi 已提交
1029

L
Lewy Blue 已提交
1030 1031 1032
						normalBuffer.push( faceNormals[ i * 3 ] );
						normalBuffer.push( faceNormals[ i * 3 + 1 ] );
						normalBuffer.push( faceNormals[ i * 3 + 2 ] );
1033 1034

					}
Y
yamahigashi 已提交
1035

L
Lewy Blue 已提交
1036
					if ( uvInfo ) {
1037

1038
						uvInfo.forEach( function ( uv, j ) {
Y
yamahigashi 已提交
1039

L
Lewy Blue 已提交
1040
							if ( uvsBuffer[ j ] === undefined ) uvsBuffer[ j ] = [];
Y
yamahigashi 已提交
1041

L
Lewy Blue 已提交
1042 1043
							uvsBuffer[ j ].push( faceUVs[ j ][ 0 ] );
							uvsBuffer[ j ].push( faceUVs[ j ][ 1 ] );
Y
yamahigashi 已提交
1044

L
Lewy Blue 已提交
1045
							uvsBuffer[ j ].push( faceUVs[ j ][ ( i - 1 ) * 2 ] );
L
Lewy Blue 已提交
1046
							uvsBuffer[ j ].push( faceUVs[ j ][ ( i - 1 ) * 2 + 1 ] );
Y
yamahigashi 已提交
1047

L
Lewy Blue 已提交
1048 1049
							uvsBuffer[ j ].push( faceUVs[ j ][ i * 2 ] );
							uvsBuffer[ j ].push( faceUVs[ j ][ i * 2 + 1 ] );
Y
yamahigashi 已提交
1050

1051
						} );
Y
yamahigashi 已提交
1052

1053
					}
L
Lewy Blue 已提交
1054

1055
				}
L
Lewy Blue 已提交
1056

M
Mr.doob 已提交
1057
				polygonIndex ++;
L
tidying  
Lewy Blue 已提交
1058 1059 1060
				faceLength = 0;

				// reset arrays for the next face
1061 1062
				vertexPositionIndexes = [];
				faceNormals = [];
1063 1064
				faceColors = [];
				faceUVs = [];
L
Lewy Blue 已提交
1065 1066
				faceWeights = [];
				faceWeightIndices = [];
L
Lewy Blue 已提交
1067 1068

			}
Y
yamahigashi 已提交
1069

1070
		} );
L
Lewy Blue 已提交
1071

M
Mr.doob 已提交
1072 1073
		var geo = new THREE.BufferGeometry();
		geo.name = geometryNode.name;
L
tidying  
Lewy Blue 已提交
1074

1075 1076 1077 1078 1079
		var positionAttribute = new THREE.Float32BufferAttribute( vertexBuffer, 3 );

		preTransform.applyToBufferAttribute( positionAttribute );

		geo.addAttribute( 'position', positionAttribute );
Y
yamahigashi 已提交
1080

L
Lewy Blue 已提交
1081
		if ( colorsBuffer.length > 0 ) {
L
tidying  
Lewy Blue 已提交
1082

L
Lewy Blue 已提交
1083
			geo.addAttribute( 'color', new THREE.Float32BufferAttribute( colorsBuffer, 3 ) );
Y
yamahigashi 已提交
1084

M
Mr.doob 已提交
1085
		}
Y
yamahigashi 已提交
1086

L
Lewy Blue 已提交
1087
		if ( skeleton ) {
Y
yamahigashi 已提交
1088

L
Lewy Blue 已提交
1089
			geo.addAttribute( 'skinIndex', new THREE.Float32BufferAttribute( weightsIndicesBuffer, 4 ) );
Y
yamahigashi 已提交
1090

L
Lewy Blue 已提交
1091
			geo.addAttribute( 'skinWeight', new THREE.Float32BufferAttribute( vertexWeightsBuffer, 4 ) );
Y
yamahigashi 已提交
1092

L
Lewy Blue 已提交
1093
			// used later to bind the skeleton to the model
L
Lewy Blue 已提交
1094
			geo.FBX_Deformer = skeleton;
Y
yamahigashi 已提交
1095

M
Mr.doob 已提交
1096
		}
Y
yamahigashi 已提交
1097

L
Lewy Blue 已提交
1098
		if ( normalBuffer.length > 0 ) {
Y
yamahigashi 已提交
1099

L
Lewy Blue 已提交
1100
			geo.addAttribute( 'normal', new THREE.Float32BufferAttribute( normalBuffer, 3 ) );
Y
yamahigashi 已提交
1101

M
Mr.doob 已提交
1102
		}
L
Lewy Blue 已提交
1103

1104
		uvsBuffer.forEach( function ( uvBuffer, i ) {
L
Lewy Blue 已提交
1105

1106 1107
			// subsequent uv buffers are called 'uv1', 'uv2', ...
			var name = 'uv' + ( i + 1 ).toString();
L
Lewy Blue 已提交
1108

1109 1110
			// the first uv buffer is just called 'uv'
			if ( i === 0 ) {
Y
yamahigashi 已提交
1111

1112
				name = 'uv';
L
Lewy Blue 已提交
1113 1114

			}
Y
yamahigashi 已提交
1115

1116 1117 1118
			geo.addAttribute( name, new THREE.Float32BufferAttribute( uvsBuffer[ i ], 2 ) );

		} );
L
Lewy Blue 已提交
1119

1120
		if ( materialInfo && materialInfo.mappingType !== 'AllSame' ) {
Y
yamahigashi 已提交
1121

1122 1123 1124
			// Convert the material indices of each vertex into rendering groups on the geometry.
			var prevMaterialIndex = materialIndexBuffer[ 0 ];
			var startIndex = 0;
Y
yamahigashi 已提交
1125

1126
			materialIndexBuffer.forEach( function ( currentIndex, i ) {
Y
yamahigashi 已提交
1127

1128
				if ( currentIndex !== prevMaterialIndex ) {
Y
yamahigashi 已提交
1129

1130
					geo.addGroup( startIndex, i - startIndex, prevMaterialIndex );
M
Mr.doob 已提交
1131

1132
					prevMaterialIndex = currentIndex;
1133 1134 1135
					startIndex = i;

				}
Y
yamahigashi 已提交
1136

1137
			} );
Y
yamahigashi 已提交
1138

1139 1140
			// the loop above doesn't add the last group, do that here.
			if ( geo.groups.length > 0 ) {
Y
yamahigashi 已提交
1141

1142 1143
				var lastGroup = geo.groups[ geo.groups.length - 1 ];
				var lastIndex = lastGroup.start + lastGroup.count;
1144

1145
				if ( lastIndex !== materialIndexBuffer.length ) {
1146

1147
					geo.addGroup( lastIndex, materialIndexBuffer.length - lastIndex, prevMaterialIndex );
1148

1149
				}
1150 1151 1152

			}

1153 1154 1155
			// case where there are multiple materials but the whole geometry is only
			// using one of them
			if ( geo.groups.length === 0 ) {
1156

1157
				geo.addGroup( 0, materialIndexBuffer.length, materialIndexBuffer[ 0 ] );
1158

1159
			}
1160 1161 1162

		}

M
Mr.doob 已提交
1163
		return geo;
Y
yamahigashi 已提交
1164

M
Mr.doob 已提交
1165
	}
Y
yamahigashi 已提交
1166

L
Lewy Blue 已提交
1167

L
Lewy Blue 已提交
1168
	// Parse normal from FBXTree.Objects.Geometry.LayerElementNormal if it exists
M
Mr.doob 已提交
1169
	function getNormals( NormalNode ) {
Y
yamahigashi 已提交
1170

L
Lewy Blue 已提交
1171 1172
		var mappingType = NormalNode.MappingInformationType;
		var referenceType = NormalNode.ReferenceInformationType;
L
Lewy Blue 已提交
1173
		var buffer = NormalNode.Normals.a;
M
Mr.doob 已提交
1174 1175
		var indexBuffer = [];
		if ( referenceType === 'IndexToDirect' ) {
Y
yamahigashi 已提交
1176

L
Lewy Blue 已提交
1177
			if ( 'NormalIndex' in NormalNode ) {
Y
yamahigashi 已提交
1178

L
Lewy Blue 已提交
1179
				indexBuffer = NormalNode.NormalIndex.a;
Y
yamahigashi 已提交
1180

L
Lewy Blue 已提交
1181
			} else if ( 'NormalsIndex' in NormalNode ) {
Y
yamahigashi 已提交
1182

L
Lewy Blue 已提交
1183
				indexBuffer = NormalNode.NormalsIndex.a;
Y
yamahigashi 已提交
1184

1185
			}
Y
yamahigashi 已提交
1186

M
Mr.doob 已提交
1187
		}
Y
yamahigashi 已提交
1188

M
Mr.doob 已提交
1189 1190 1191 1192 1193 1194 1195
		return {
			dataSize: 3,
			buffer: buffer,
			indices: indexBuffer,
			mappingType: mappingType,
			referenceType: referenceType
		};
Y
yamahigashi 已提交
1196

M
Mr.doob 已提交
1197
	}
Y
yamahigashi 已提交
1198

L
Lewy Blue 已提交
1199
	// Parse UVs from FBXTree.Objects.Geometry.LayerElementUV if it exists
M
Mr.doob 已提交
1200
	function getUVs( UVNode ) {
Y
yamahigashi 已提交
1201

L
Lewy Blue 已提交
1202 1203
		var mappingType = UVNode.MappingInformationType;
		var referenceType = UVNode.ReferenceInformationType;
L
Lewy Blue 已提交
1204
		var buffer = UVNode.UV.a;
M
Mr.doob 已提交
1205 1206
		var indexBuffer = [];
		if ( referenceType === 'IndexToDirect' ) {
Y
yamahigashi 已提交
1207

L
Lewy Blue 已提交
1208
			indexBuffer = UVNode.UVIndex.a;
Y
yamahigashi 已提交
1209

M
Mr.doob 已提交
1210
		}
Y
yamahigashi 已提交
1211

M
Mr.doob 已提交
1212 1213 1214 1215 1216 1217 1218
		return {
			dataSize: 2,
			buffer: buffer,
			indices: indexBuffer,
			mappingType: mappingType,
			referenceType: referenceType
		};
Y
yamahigashi 已提交
1219

M
Mr.doob 已提交
1220
	}
Y
yamahigashi 已提交
1221

L
Lewy Blue 已提交
1222
	// Parse Vertex Colors from FBXTree.Objects.Geometry.LayerElementColor if it exists
M
Mr.doob 已提交
1223
	function getColors( ColorNode ) {
Y
yamahigashi 已提交
1224

L
Lewy Blue 已提交
1225 1226
		var mappingType = ColorNode.MappingInformationType;
		var referenceType = ColorNode.ReferenceInformationType;
L
Lewy Blue 已提交
1227
		var buffer = ColorNode.Colors.a;
M
Mr.doob 已提交
1228 1229
		var indexBuffer = [];
		if ( referenceType === 'IndexToDirect' ) {
Y
yamahigashi 已提交
1230

L
Lewy Blue 已提交
1231
			indexBuffer = ColorNode.ColorIndex.a;
1232

Y
yamahigashi 已提交
1233
		}
Y
yamahigashi 已提交
1234

M
Mr.doob 已提交
1235 1236 1237 1238 1239 1240 1241
		return {
			dataSize: 4,
			buffer: buffer,
			indices: indexBuffer,
			mappingType: mappingType,
			referenceType: referenceType
		};
Y
yamahigashi 已提交
1242

M
Mr.doob 已提交
1243
	}
Y
yamahigashi 已提交
1244

L
Lewy Blue 已提交
1245
	// Parse mapping and material data in FBXTree.Objects.Geometry.LayerElementMaterial if it exists
M
Mr.doob 已提交
1246
	function getMaterials( MaterialNode ) {
Y
yamahigashi 已提交
1247

L
Lewy Blue 已提交
1248 1249
		var mappingType = MaterialNode.MappingInformationType;
		var referenceType = MaterialNode.ReferenceInformationType;
Y
yamahigashi 已提交
1250

M
Mr.doob 已提交
1251
		if ( mappingType === 'NoMappingInformation' ) {
Y
yamahigashi 已提交
1252

M
Mr.doob 已提交
1253 1254 1255 1256 1257 1258 1259
			return {
				dataSize: 1,
				buffer: [ 0 ],
				indices: [ 0 ],
				mappingType: 'AllSame',
				referenceType: referenceType
			};
Y
yamahigashi 已提交
1260

M
Mr.doob 已提交
1261
		}
Y
yamahigashi 已提交
1262

L
Lewy Blue 已提交
1263
		var materialIndexBuffer = MaterialNode.Materials.a;
Y
yamahigashi 已提交
1264

M
Mr.doob 已提交
1265
		// Since materials are stored as indices, there's a bit of a mismatch between FBX and what
L
Lewy Blue 已提交
1266
		// we expect.So we create an intermediate buffer that points to the index in the buffer,
M
Mr.doob 已提交
1267 1268
		// for conforming with the other functions we've written for other data.
		var materialIndices = [];
Y
yamahigashi 已提交
1269

1270
		for ( var i = 0; i < materialIndexBuffer.length; ++ i ) {
Y
yamahigashi 已提交
1271

1272
			materialIndices.push( i );
Y
yamahigashi 已提交
1273

M
Mr.doob 已提交
1274
		}
Y
yamahigashi 已提交
1275

M
Mr.doob 已提交
1276 1277 1278 1279 1280 1281 1282
		return {
			dataSize: 1,
			buffer: materialIndexBuffer,
			indices: materialIndices,
			mappingType: mappingType,
			referenceType: referenceType
		};
Y
yamahigashi 已提交
1283

M
Mr.doob 已提交
1284 1285
	}

L
Lewy Blue 已提交
1286
	// Functions use the infoObject and given indices to return value array of geometry.
L
Lewy Blue 已提交
1287 1288 1289 1290 1291 1292 1293 1294
	// Parameters:
	// 	- polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
	// 	- polygonIndex - Index of polygon in geometry.
	// 	- vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
	// 	- infoObject: can be materialInfo, normalInfo, UVInfo or colorInfo
	// Index type:
	//	- Direct: index is same as polygonVertexIndex
	//	- IndexToDirect: infoObject has it's own set of indices
M
Mr.doob 已提交
1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318
	var dataArray = [];

	var GetData = {

		ByPolygonVertex: {

			Direct: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {

				var from = ( polygonVertexIndex * infoObject.dataSize );
				var to = ( polygonVertexIndex * infoObject.dataSize ) + infoObject.dataSize;

				return slice( dataArray, infoObject.buffer, from, to );

			},

			IndexToDirect: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {

				var index = infoObject.indices[ polygonVertexIndex ];
				var from = ( index * infoObject.dataSize );
				var to = ( index * infoObject.dataSize ) + infoObject.dataSize;

				return slice( dataArray, infoObject.buffer, from, to );

			}
Y
yamahigashi 已提交
1319

Y
yamahigashi 已提交
1320
		},
Y
yamahigashi 已提交
1321

M
Mr.doob 已提交
1322
		ByPolygon: {
Y
yamahigashi 已提交
1323

M
Mr.doob 已提交
1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341
			Direct: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {

				var from = polygonIndex * infoObject.dataSize;
				var to = polygonIndex * infoObject.dataSize + infoObject.dataSize;

				return slice( dataArray, infoObject.buffer, from, to );

			},

			IndexToDirect: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {

				var index = infoObject.indices[ polygonIndex ];
				var from = index * infoObject.dataSize;
				var to = index * infoObject.dataSize + infoObject.dataSize;

				return slice( dataArray, infoObject.buffer, from, to );

			}
Y
yamahigashi 已提交
1342

Y
yamahigashi 已提交
1343
		},
Y
yamahigashi 已提交
1344

1345
		ByVertice: {
Y
yamahigashi 已提交
1346

M
Mr.doob 已提交
1347 1348 1349 1350 1351 1352 1353 1354
			Direct: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {

				var from = ( vertexIndex * infoObject.dataSize );
				var to = ( vertexIndex * infoObject.dataSize ) + infoObject.dataSize;

				return slice( dataArray, infoObject.buffer, from, to );

			}
Y
yamahigashi 已提交
1355

Y
yamahigashi 已提交
1356
		},
Y
yamahigashi 已提交
1357

M
Mr.doob 已提交
1358
		AllSame: {
Y
yamahigashi 已提交
1359

M
Mr.doob 已提交
1360
			IndexToDirect: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {
Y
yamahigashi 已提交
1361

M
Mr.doob 已提交
1362 1363
				var from = infoObject.indices[ 0 ] * infoObject.dataSize;
				var to = infoObject.indices[ 0 ] * infoObject.dataSize + infoObject.dataSize;
Y
yamahigashi 已提交
1364

M
Mr.doob 已提交
1365
				return slice( dataArray, infoObject.buffer, from, to );
Y
yamahigashi 已提交
1366

M
Mr.doob 已提交
1367
			}
Y
yamahigashi 已提交
1368

M
Mr.doob 已提交
1369
		}
Y
yamahigashi 已提交
1370

M
Mr.doob 已提交
1371
	};
Y
yamahigashi 已提交
1372

M
Mr.doob 已提交
1373
	function getData( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {
Y
yamahigashi 已提交
1374

M
Mr.doob 已提交
1375
		return GetData[ infoObject.mappingType ][ infoObject.referenceType ]( polygonVertexIndex, polygonIndex, vertexIndex, infoObject );
Y
yamahigashi 已提交
1376

M
Mr.doob 已提交
1377
	}
Y
yamahigashi 已提交
1378

L
Lewy Blue 已提交
1379
	// Generate a NurbGeometry from a node in FBXTree.Objects.Geometry
M
Mr.doob 已提交
1380
	function parseNurbsGeometry( geometryNode ) {
Y
yamahigashi 已提交
1381

M
Mr.doob 已提交
1382
		if ( THREE.NURBSCurve === undefined ) {
Y
yamahigashi 已提交
1383

M
Mugen87 已提交
1384
			console.error( 'THREE.FBXLoader: The loader relies on THREE.NURBSCurve for any nurbs present in the model. Nurbs will show up as empty geometry.' );
M
Mr.doob 已提交
1385
			return new THREE.BufferGeometry();
Y
yamahigashi 已提交
1386

M
Mr.doob 已提交
1387
		}
Y
yamahigashi 已提交
1388

L
Lewy Blue 已提交
1389
		var order = parseInt( geometryNode.Order );
Y
yamahigashi 已提交
1390

M
Mr.doob 已提交
1391
		if ( isNaN( order ) ) {
Y
yamahigashi 已提交
1392

L
Lewy Blue 已提交
1393
			console.error( 'THREE.FBXLoader: Invalid Order %s given for geometry ID: %s', geometryNode.Order, geometryNode.id );
M
Mr.doob 已提交
1394
			return new THREE.BufferGeometry();
Y
yamahigashi 已提交
1395

M
Mr.doob 已提交
1396
		}
Y
yamahigashi 已提交
1397

M
Mr.doob 已提交
1398
		var degree = order - 1;
Y
yamahigashi 已提交
1399

L
Lewy Blue 已提交
1400
		var knots = geometryNode.KnotVector.a;
M
Mr.doob 已提交
1401
		var controlPoints = [];
L
Lewy Blue 已提交
1402
		var pointsValues = geometryNode.Points.a;
Y
yamahigashi 已提交
1403

M
Mr.doob 已提交
1404
		for ( var i = 0, l = pointsValues.length; i < l; i += 4 ) {
Y
yamahigashi 已提交
1405

M
Mr.doob 已提交
1406
			controlPoints.push( new THREE.Vector4().fromArray( pointsValues, i ) );
Y
yamahigashi 已提交
1407

M
Mr.doob 已提交
1408
		}
Y
yamahigashi 已提交
1409

M
Mr.doob 已提交
1410 1411
		var startKnot, endKnot;

L
Lewy Blue 已提交
1412
		if ( geometryNode.Form === 'Closed' ) {
M
Mr.doob 已提交
1413 1414 1415

			controlPoints.push( controlPoints[ 0 ] );

L
Lewy Blue 已提交
1416
		} else if ( geometryNode.Form === 'Periodic' ) {
M
Mr.doob 已提交
1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433

			startKnot = degree;
			endKnot = knots.length - 1 - startKnot;

			for ( var i = 0; i < degree; ++ i ) {

				controlPoints.push( controlPoints[ i ] );

			}

		}

		var curve = new THREE.NURBSCurve( degree, knots, controlPoints, startKnot, endKnot );
		var vertices = curve.getPoints( controlPoints.length * 7 );

		var positions = new Float32Array( vertices.length * 3 );

1434
		vertices.forEach( function ( vertex, i ) {
M
Mr.doob 已提交
1435

1436
			vertex.toArray( positions, i * 3 );
M
Mr.doob 已提交
1437

1438
		} );
M
Mr.doob 已提交
1439 1440 1441 1442 1443 1444 1445 1446

		var geometry = new THREE.BufferGeometry();
		geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );

		return geometry;

	}

L
Lewy Blue 已提交
1447
	// create the main THREE.Group() to be returned by the loader
L
Lewy Blue 已提交
1448
	function parseScene( FBXTree, connections, skeletons, geometryMap, materialMap ) {
M
Mr.doob 已提交
1449 1450 1451

		var sceneGraph = new THREE.Group();

L
Lewy Blue 已提交
1452
		var modelMap = parseModels( FBXTree, skeletons, geometryMap, materialMap, connections );
M
Mr.doob 已提交
1453

L
Lewy Blue 已提交
1454
		var modelNodes = FBXTree.Objects.Model;
1455 1456 1457

		modelMap.forEach( function ( model ) {

L
Lewy Blue 已提交
1458 1459
			var modelNode = modelNodes[ model.ID ];
			setLookAtProperties( FBXTree, model, modelNode, connections, sceneGraph );
1460

L
Lewy Blue 已提交
1461
			var parentConnections = connections.get( model.ID ).parents;
1462

L
Lewy Blue 已提交
1463
			parentConnections.forEach( function ( connection ) {
1464

L
Lewy Blue 已提交
1465 1466
				var parent = modelMap.get( connection.ID );
				if ( parent !== undefined ) parent.add( model );
1467

1468 1469
			} );

1470 1471 1472 1473 1474 1475
			if ( model.parent === null ) {

				sceneGraph.add( model );

			}

L
Lewy Blue 已提交
1476

1477 1478
		} );

M
Mr.doob 已提交
1479
		bindSkeleton( FBXTree, skeletons, geometryMap, modelMap, connections );
1480

M
Mr.doob 已提交
1481
		addAnimations( FBXTree, connections, sceneGraph );
1482 1483 1484 1485 1486 1487

		createAmbientLight( FBXTree, sceneGraph );

		return sceneGraph;

	}
M
Mr.doob 已提交
1488

L
Lewy Blue 已提交
1489
	// parse nodes in FBXTree.Objects.Model
L
Lewy Blue 已提交
1490
	function parseModels( FBXTree, skeletons, geometryMap, materialMap, connections ) {
M
Mr.doob 已提交
1491 1492

		var modelMap = new Map();
L
Lewy Blue 已提交
1493
		var modelNodes = FBXTree.Objects.Model;
M
Mr.doob 已提交
1494

1495
		for ( var nodeID in modelNodes ) {
M
Mr.doob 已提交
1496 1497

			var id = parseInt( nodeID );
1498
			var node = modelNodes[ nodeID ];
L
Lewy Blue 已提交
1499
			var relationships = connections.get( id );
Y
yamahigashi 已提交
1500

L
Lewy Blue 已提交
1501
			var model = buildSkeleton( relationships, skeletons, id, node.attrName );
Y
yamahigashi 已提交
1502

M
Mr.doob 已提交
1503
			if ( ! model ) {
Y
yamahigashi 已提交
1504

M
Mr.doob 已提交
1505
				switch ( node.attrType ) {
Y
yamahigashi 已提交
1506

L
Lewy Blue 已提交
1507
					case 'Camera':
L
Lewy Blue 已提交
1508
						model = createCamera( FBXTree, relationships );
1509 1510
						break;
					case 'Light':
L
Lewy Blue 已提交
1511
						model = createLight( FBXTree, relationships );
1512 1513
						break;
					case 'Mesh':
L
Lewy Blue 已提交
1514
						model = createMesh( FBXTree, relationships, geometryMap, materialMap );
1515 1516
						break;
					case 'NurbsCurve':
L
Lewy Blue 已提交
1517
						model = createCurve( relationships, geometryMap );
1518
						break;
L
Tidy  
Lewy Blue 已提交
1519
					case 'LimbNode': // usually associated with a Bone, however if a Bone was not created we'll make a Group instead
L
Lewy Blue 已提交
1520
					case 'Null':
1521 1522 1523
					default:
						model = new THREE.Group();
						break;
L
Lewy Blue 已提交
1524

1525
				}
L
Lewy Blue 已提交
1526

L
Lewy Blue 已提交
1527 1528
				model.name = THREE.PropertyBinding.sanitizeNodeName( node.attrName );
				model.ID = id;
L
Lewy Blue 已提交
1529

L
Lewy Blue 已提交
1530
			}
L
Lewy Blue 已提交
1531

L
Lewy Blue 已提交
1532
			setModelTransforms( FBXTree, model, node );
1533
			modelMap.set( id, model );
L
Lewy Blue 已提交
1534

1535
		}
L
Lewy Blue 已提交
1536

1537
		return modelMap;
L
Lewy Blue 已提交
1538

1539
	}
L
Lewy Blue 已提交
1540

L
Lewy Blue 已提交
1541
	function buildSkeleton( relationships, skeletons, id, name ) {
L
Lewy Blue 已提交
1542

L
Lewy Blue 已提交
1543
		var bone = null;
L
Lewy Blue 已提交
1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554

		relationships.parents.forEach( function ( parent ) {

			for ( var ID in skeletons ) {

				var skeleton = skeletons[ ID ];

				skeleton.rawBones.forEach( function ( rawBone, i ) {

					if ( rawBone.ID === parent.ID ) {

L
Lewy Blue 已提交
1555 1556
						var subBone = bone;
						bone = new THREE.Bone();
L
Lewy Blue 已提交
1557
						bone.matrixWorld.copy( rawBone.transformLink );
L
Lewy Blue 已提交
1558 1559 1560 1561 1562 1563

						// set name and id here - otherwise in cases where "subBone" is created it will not have a name / id
						bone.name = THREE.PropertyBinding.sanitizeNodeName( name );
						bone.ID = id;

						skeleton.bones[ i ] = bone;
L
Lewy Blue 已提交
1564 1565

						// In cases where a bone is shared between multiple meshes
L
Lewy Blue 已提交
1566 1567
						// duplicate the bone here and and it as a child of the first bone
						if ( subBone !== null ) {
L
Lewy Blue 已提交
1568

L
Lewy Blue 已提交
1569
							bone.add( subBone );
L
Lewy Blue 已提交
1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580

						}

					}

				} );

			}

		} );

L
Lewy Blue 已提交
1581
		return bone;
L
Lewy Blue 已提交
1582 1583 1584

	}

L
Lewy Blue 已提交
1585
	// create a THREE.PerspectiveCamera or THREE.OrthographicCamera
L
Lewy Blue 已提交
1586
	function createCamera( FBXTree, relationships ) {
L
Lewy Blue 已提交
1587

1588 1589
		var model;
		var cameraAttribute;
L
Lewy Blue 已提交
1590

L
Lewy Blue 已提交
1591
		relationships.children.forEach( function ( child ) {
L
Lewy Blue 已提交
1592

L
Lewy Blue 已提交
1593
			var attr = FBXTree.Objects.NodeAttribute[ child.ID ];
L
Lewy Blue 已提交
1594

L
Lewy Blue 已提交
1595
			if ( attr !== undefined ) {
L
Lewy Blue 已提交
1596

L
Lewy Blue 已提交
1597
				cameraAttribute = attr;
L
Lewy Blue 已提交
1598

1599
			}
L
Lewy Blue 已提交
1600

1601
		} );
L
Lewy Blue 已提交
1602

1603
		if ( cameraAttribute === undefined ) {
L
Lewy Blue 已提交
1604

1605
			model = new THREE.Object3D();
L
Lewy Blue 已提交
1606

1607
		} else {
L
Lewy Blue 已提交
1608

1609 1610
			var type = 0;
			if ( cameraAttribute.CameraProjectionType !== undefined && cameraAttribute.CameraProjectionType.value === 1 ) {
L
Lewy Blue 已提交
1611

1612
				type = 1;
L
Lewy Blue 已提交
1613

1614
			}
L
Lewy Blue 已提交
1615

1616 1617
			var nearClippingPlane = 1;
			if ( cameraAttribute.NearPlane !== undefined ) {
L
Lewy Blue 已提交
1618

1619
				nearClippingPlane = cameraAttribute.NearPlane.value / 1000;
L
Lewy Blue 已提交
1620

1621
			}
L
Lewy Blue 已提交
1622

1623 1624
			var farClippingPlane = 1000;
			if ( cameraAttribute.FarPlane !== undefined ) {
L
Lewy Blue 已提交
1625

1626
				farClippingPlane = cameraAttribute.FarPlane.value / 1000;
L
Lewy Blue 已提交
1627

1628
			}
L
Lewy Blue 已提交
1629 1630


1631 1632
			var width = window.innerWidth;
			var height = window.innerHeight;
L
Lewy Blue 已提交
1633

1634
			if ( cameraAttribute.AspectWidth !== undefined && cameraAttribute.AspectHeight !== undefined ) {
L
Lewy Blue 已提交
1635

1636 1637
				width = cameraAttribute.AspectWidth.value;
				height = cameraAttribute.AspectHeight.value;
L
Lewy Blue 已提交
1638

1639
			}
L
Lewy Blue 已提交
1640

1641
			var aspect = width / height;
L
Lewy Blue 已提交
1642

1643 1644
			var fov = 45;
			if ( cameraAttribute.FieldOfView !== undefined ) {
L
Lewy Blue 已提交
1645

1646
				fov = cameraAttribute.FieldOfView.value;
L
Lewy Blue 已提交
1647

1648
			}
L
Lewy Blue 已提交
1649

1650
			switch ( type ) {
L
Lewy Blue 已提交
1651

1652 1653 1654
				case 0: // Perspective
					model = new THREE.PerspectiveCamera( fov, aspect, nearClippingPlane, farClippingPlane );
					break;
L
Lewy Blue 已提交
1655

1656 1657 1658
				case 1: // Orthographic
					model = new THREE.OrthographicCamera( - width / 2, width / 2, height / 2, - height / 2, nearClippingPlane, farClippingPlane );
					break;
L
Lewy Blue 已提交
1659

1660 1661 1662 1663
				default:
					console.warn( 'THREE.FBXLoader: Unknown camera type ' + type + '.' );
					model = new THREE.Object3D();
					break;
L
Lewy Blue 已提交
1664

1665
			}
L
Lewy Blue 已提交
1666

1667
		}
L
Lewy Blue 已提交
1668

1669
		return model;
L
Lewy Blue 已提交
1670

1671
	}
L
Lewy Blue 已提交
1672

L
Lewy Blue 已提交
1673
	// Create a THREE.DirectionalLight, THREE.PointLight or THREE.SpotLight
L
Lewy Blue 已提交
1674
	function createLight( FBXTree, relationships ) {
L
Lewy Blue 已提交
1675

1676 1677
		var model;
		var lightAttribute;
L
Lewy Blue 已提交
1678

L
Lewy Blue 已提交
1679
		relationships.children.forEach( function ( child ) {
L
Lewy Blue 已提交
1680

L
Lewy Blue 已提交
1681
			var attr = FBXTree.Objects.NodeAttribute[ child.ID ];
L
Lewy Blue 已提交
1682

L
Lewy Blue 已提交
1683
			if ( attr !== undefined ) {
L
Lewy Blue 已提交
1684

L
Lewy Blue 已提交
1685
				lightAttribute = attr;
L
Lewy Blue 已提交
1686

1687
			}
L
Lewy Blue 已提交
1688

1689
		} );
L
Lewy Blue 已提交
1690

1691
		if ( lightAttribute === undefined ) {
L
Lewy Blue 已提交
1692

1693
			model = new THREE.Object3D();
L
Lewy Blue 已提交
1694

1695
		} else {
L
Lewy Blue 已提交
1696

1697
			var type;
L
Lewy Blue 已提交
1698

L
Lewy Blue 已提交
1699
			// LightType can be undefined for Point lights
1700
			if ( lightAttribute.LightType === undefined ) {
L
Lewy Blue 已提交
1701

1702
				type = 0;
L
Lewy Blue 已提交
1703

1704
			} else {
L
Lewy Blue 已提交
1705

1706
				type = lightAttribute.LightType.value;
L
Lewy Blue 已提交
1707

1708
			}
L
Lewy Blue 已提交
1709

1710
			var color = 0xffffff;
L
Lewy Blue 已提交
1711

1712
			if ( lightAttribute.Color !== undefined ) {
L
Lewy Blue 已提交
1713

1714
				color = parseColor( lightAttribute.Color );
L
Lewy Blue 已提交
1715

1716
			}
L
Lewy Blue 已提交
1717

1718
			var intensity = ( lightAttribute.Intensity === undefined ) ? 1 : lightAttribute.Intensity.value / 100;
L
Lewy Blue 已提交
1719

L
Lewy Blue 已提交
1720
			// light disabled
1721
			if ( lightAttribute.CastLightOnObject !== undefined && lightAttribute.CastLightOnObject.value === 0 ) {
L
Lewy Blue 已提交
1722

1723
				intensity = 0;
L
Lewy Blue 已提交
1724

1725
			}
L
Lewy Blue 已提交
1726

1727 1728
			var distance = 0;
			if ( lightAttribute.FarAttenuationEnd !== undefined ) {
L
Lewy Blue 已提交
1729

1730
				if ( lightAttribute.EnableFarAttenuation !== undefined && lightAttribute.EnableFarAttenuation.value === 0 ) {
L
Lewy Blue 已提交
1731

1732
					distance = 0;
L
Lewy Blue 已提交
1733

1734
				} else {
L
Lewy Blue 已提交
1735

1736
					distance = lightAttribute.FarAttenuationEnd.value / 1000;
L
Lewy Blue 已提交
1737

1738
				}
L
Lewy Blue 已提交
1739

1740
			}
L
Lewy Blue 已提交
1741

L
Lewy Blue 已提交
1742
			// TODO: could this be calculated linearly from FarAttenuationStart to FarAttenuationEnd?
1743
			var decay = 1;
L
Lewy Blue 已提交
1744

1745
			switch ( type ) {
L
Lewy Blue 已提交
1746

1747 1748 1749
				case 0: // Point
					model = new THREE.PointLight( color, intensity, distance, decay );
					break;
L
Lewy Blue 已提交
1750

1751 1752 1753
				case 1: // Directional
					model = new THREE.DirectionalLight( color, intensity );
					break;
L
Lewy Blue 已提交
1754

1755 1756
				case 2: // Spot
					var angle = Math.PI / 3;
L
Lewy Blue 已提交
1757

1758
					if ( lightAttribute.InnerAngle !== undefined ) {
L
Lewy Blue 已提交
1759

1760
						angle = THREE.Math.degToRad( lightAttribute.InnerAngle.value );
L
Lewy Blue 已提交
1761

1762
					}
L
Lewy Blue 已提交
1763

1764 1765
					var penumbra = 0;
					if ( lightAttribute.OuterAngle !== undefined ) {
L
Lewy Blue 已提交
1766

L
Lewy Blue 已提交
1767 1768 1769
						// TODO: this is not correct - FBX calculates outer and inner angle in degrees
						// with OuterAngle > InnerAngle && OuterAngle <= Math.PI
						// while three.js uses a penumbra between (0, 1) to attenuate the inner angle
1770 1771
						penumbra = THREE.Math.degToRad( lightAttribute.OuterAngle.value );
						penumbra = Math.max( penumbra, 1 );
L
Lewy Blue 已提交
1772

1773
					}
Y
yamahigashi 已提交
1774

1775 1776
					model = new THREE.SpotLight( color, intensity, distance, angle, penumbra, decay );
					break;
Y
yamahigashi 已提交
1777

1778 1779 1780 1781
				default:
					console.warn( 'THREE.FBXLoader: Unknown light type ' + lightAttribute.LightType.value + ', defaulting to a THREE.PointLight.' );
					model = new THREE.PointLight( color, intensity );
					break;
Y
yamahigashi 已提交
1782

1783
			}
Y
yamahigashi 已提交
1784

1785
			if ( lightAttribute.CastShadows !== undefined && lightAttribute.CastShadows.value === 1 ) {
Y
yamahigashi 已提交
1786

1787
				model.castShadow = true;
Y
yamahigashi 已提交
1788

1789
			}
Y
yamahigashi 已提交
1790

1791
		}
Y
yamahigashi 已提交
1792

1793
		return model;
Y
yamahigashi 已提交
1794

1795
	}
Y
yamahigashi 已提交
1796

L
Lewy Blue 已提交
1797
	function createMesh( FBXTree, relationships, geometryMap, materialMap ) {
M
Mr.doob 已提交
1798

1799 1800 1801 1802
		var model;
		var geometry = null;
		var material = null;
		var materials = [];
M
Mr.doob 已提交
1803

L
Lewy Blue 已提交
1804
		// get geometry and materials(s) from connections
L
Lewy Blue 已提交
1805
		relationships.children.forEach( function ( child ) {
Y
yamahigashi 已提交
1806

1807
			if ( geometryMap.has( child.ID ) ) {
Y
yamahigashi 已提交
1808

1809
				geometry = geometryMap.get( child.ID );
Y
yamahigashi 已提交
1810

1811
			}
Y
yamahigashi 已提交
1812

1813
			if ( materialMap.has( child.ID ) ) {
Y
yamahigashi 已提交
1814

1815
				materials.push( materialMap.get( child.ID ) );
Y
yamahigashi 已提交
1816

1817
			}
Y
yamahigashi 已提交
1818

1819 1820
		} );

1821
		if ( materials.length > 1 ) {
Y
yamahigashi 已提交
1822

1823
			material = materials;
Y
yamahigashi 已提交
1824

1825
		} else if ( materials.length > 0 ) {
Y
yamahigashi 已提交
1826

1827
			material = materials[ 0 ];
1828

1829
		} else {
1830

1831 1832
			material = new THREE.MeshPhongMaterial( { color: 0xcccccc } );
			materials.push( material );
Y
yamahigashi 已提交
1833

1834
		}
1835

1836
		if ( 'color' in geometry.attributes ) {
M
Mr.doob 已提交
1837

1838
			materials.forEach( function ( material ) {
M
Mr.doob 已提交
1839

1840
				material.vertexColors = THREE.VertexColors;
M
Mr.doob 已提交
1841

1842
			} );
M
Mr.doob 已提交
1843

1844
		}
1845

1846
		if ( geometry.FBX_Deformer ) {
M
Mr.doob 已提交
1847

1848
			materials.forEach( function ( material ) {
M
Mr.doob 已提交
1849

1850
				material.skinning = true;
M
Mr.doob 已提交
1851

1852
			} );
M
Mr.doob 已提交
1853

1854
			model = new THREE.SkinnedMesh( geometry, material );
M
Mr.doob 已提交
1855

1856
		} else {
Y
yamahigashi 已提交
1857

1858
			model = new THREE.Mesh( geometry, material );
Y
yamahigashi 已提交
1859

1860
		}
Y
yamahigashi 已提交
1861

1862
		return model;
Y
yamahigashi 已提交
1863

1864
	}
M
Mr.doob 已提交
1865

L
Lewy Blue 已提交
1866
	function createCurve( relationships, geometryMap ) {
M
Mr.doob 已提交
1867

L
Lewy Blue 已提交
1868
		var geometry = relationships.children.reduce( function ( geo, child ) {
M
Mr.doob 已提交
1869

L
Lewy Blue 已提交
1870
			if ( geometryMap.has( child.ID ) ) geo = geometryMap.get( child.ID );
M
Mr.doob 已提交
1871

L
Lewy Blue 已提交
1872
			return geo;
Y
yamahigashi 已提交
1873

1874
		}, null );
Y
yamahigashi 已提交
1875

L
Lewy Blue 已提交
1876
		// FBX does not list materials for Nurbs lines, so we'll just put our own in here.
1877 1878
		var material = new THREE.LineBasicMaterial( { color: 0x3300ff, linewidth: 1 } );
		return new THREE.Line( geometry, material );
Y
yamahigashi 已提交
1879

1880
	}
Y
yamahigashi 已提交
1881

L
Lewy Blue 已提交
1882
	// Parse ambient color in FBXTree.GlobalSettings - if it's not set to black (default), create an ambient light
1883
	function createAmbientLight( FBXTree, sceneGraph ) {
Y
yamahigashi 已提交
1884

L
Lewy Blue 已提交
1885
		if ( 'GlobalSettings' in FBXTree && 'AmbientColor' in FBXTree.GlobalSettings ) {
Y
yamahigashi 已提交
1886

L
Lewy Blue 已提交
1887
			var ambientColor = FBXTree.GlobalSettings.AmbientColor.value;
1888 1889 1890
			var r = ambientColor[ 0 ];
			var g = ambientColor[ 1 ];
			var b = ambientColor[ 2 ];
Y
yamahigashi 已提交
1891

1892
			if ( r !== 0 || g !== 0 || b !== 0 ) {
Y
yamahigashi 已提交
1893

1894 1895
				var color = new THREE.Color( r, g, b );
				sceneGraph.add( new THREE.AmbientLight( color, 1 ) );
Y
yamahigashi 已提交
1896

M
Mr.doob 已提交
1897
			}
Y
yamahigashi 已提交
1898

1899
		}
Y
yamahigashi 已提交
1900

1901
	}
L
Lewy Blue 已提交
1902

L
Lewy Blue 已提交
1903 1904
	function setLookAtProperties( FBXTree, model, modelNode, connections, sceneGraph ) {

L
Lewy Blue 已提交
1905
		if ( 'LookAtProperty' in modelNode ) {
L
Lewy Blue 已提交
1906 1907 1908 1909 1910 1911 1912

			var children = connections.get( model.ID ).children;

			children.forEach( function ( child ) {

				if ( child.relationship === 'LookAtProperty' ) {

L
Lewy Blue 已提交
1913
					var lookAtTarget = FBXTree.Objects.Model[ child.ID ];
L
Lewy Blue 已提交
1914

L
Lewy Blue 已提交
1915
					if ( 'Lcl_Translation' in lookAtTarget ) {
L
Lewy Blue 已提交
1916

L
Lewy Blue 已提交
1917
						var pos = lookAtTarget.Lcl_Translation.value;
L
Lewy Blue 已提交
1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940

						// DirectionalLight, SpotLight
						if ( model.target !== undefined ) {

							model.target.position.fromArray( pos );
							sceneGraph.add( model.target );

						} else { // Cameras and other Object3Ds

							model.lookAt( new THREE.Vector3().fromArray( pos ) );

						}

					}

				}

			} );

		}

	}

L
Lewy Blue 已提交
1941
	// parse the model node for transform details and apply them to the model
L
Lewy Blue 已提交
1942
	function setModelTransforms( FBXTree, model, modelNode ) {
L
Lewy Blue 已提交
1943

L
Lewy Blue 已提交
1944
		// http://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_euler_html
L
Lewy Blue 已提交
1945
		if ( 'RotationOrder' in modelNode ) {
Y
yamahigashi 已提交
1946

L
Lewy Blue 已提交
1947 1948 1949 1950 1951 1952 1953 1954 1955
			var enums = [
				'XYZ', // default
				'XZY',
				'YZX',
				'ZXY',
				'YXZ',
				'ZYX',
				'SphericXYZ',
			];
Y
yamahigashi 已提交
1956

L
Lewy Blue 已提交
1957
			var value = parseInt( modelNode.RotationOrder.value, 10 );
Y
yamahigashi 已提交
1958

L
Lewy Blue 已提交
1959
			if ( value > 0 && value < 6 ) {
Y
yamahigashi 已提交
1960

L
Lewy Blue 已提交
1961
				// model.rotation.order = enums[ value ];
Y
yamahigashi 已提交
1962

L
Lewy Blue 已提交
1963 1964
				// Note: Euler order other than XYZ is currently not supported, so just display a warning for now
				console.warn( 'THREE.FBXLoader: unsupported Euler Order: %s. Currently only XYZ order is supported. Animations and rotations may be incorrect.', enums[ value ] );
Y
yamahigashi 已提交
1965

L
Lewy Blue 已提交
1966
			} else if ( value === 6 ) {
Y
yamahigashi 已提交
1967

L
Lewy Blue 已提交
1968
				console.warn( 'THREE.FBXLoader: unsupported Euler Order: Spherical XYZ. Animations and rotations may be incorrect.' );
M
Mr.doob 已提交
1969 1970 1971

			}

L
Lewy Blue 已提交
1972
		}
L
Lewy Blue 已提交
1973

L
Lewy Blue 已提交
1974
		if ( 'Lcl_Translation' in modelNode ) {
M
Mr.doob 已提交
1975

L
Lewy Blue 已提交
1976
			model.position.fromArray( modelNode.Lcl_Translation.value );
M
Mr.doob 已提交
1977

1978
		}
L
Lewy Blue 已提交
1979

L
Lewy Blue 已提交
1980
		if ( 'Lcl_Rotation' in modelNode ) {
L
Lewy Blue 已提交
1981

L
Lewy Blue 已提交
1982
			var rotation = modelNode.Lcl_Rotation.value.map( THREE.Math.degToRad );
1983 1984
			rotation.push( 'ZYX' );
			model.rotation.fromArray( rotation );
L
Lewy Blue 已提交
1985

1986
		}
L
Lewy Blue 已提交
1987

L
Lewy Blue 已提交
1988
		if ( 'Lcl_Scaling' in modelNode ) {
L
Lewy Blue 已提交
1989

L
Lewy Blue 已提交
1990
			model.scale.fromArray( modelNode.Lcl_Scaling.value );
L
Lewy Blue 已提交
1991

1992
		}
L
Lewy Blue 已提交
1993

L
Lewy Blue 已提交
1994
		if ( 'PreRotation' in modelNode ) {
L
Lewy Blue 已提交
1995

L
Lewy Blue 已提交
1996
			var array = modelNode.PreRotation.value.map( THREE.Math.degToRad );
1997
			array[ 3 ] = 'ZYX';
L
Lewy Blue 已提交
1998

1999
			var preRotations = new THREE.Euler().fromArray( array );
L
Lewy Blue 已提交
2000

2001 2002 2003 2004
			preRotations = new THREE.Quaternion().setFromEuler( preRotations );
			var currentRotation = new THREE.Quaternion().setFromEuler( model.rotation );
			preRotations.multiply( currentRotation );
			model.rotation.setFromQuaternion( preRotations, 'ZYX' );
L
Lewy Blue 已提交
2005

2006
		}
L
Lewy Blue 已提交
2007

2008 2009
	}

L
Lewy Blue 已提交
2010 2011 2012
	function bindSkeleton( FBXTree, skeletons, geometryMap, modelMap, connections ) {

		var bindMatrices = parsePoseNodes( FBXTree );
M
Mr.doob 已提交
2013

L
Lewy Blue 已提交
2014
		for ( var ID in skeletons ) {
M
Mr.doob 已提交
2015

L
Lewy Blue 已提交
2016
			var skeleton = skeletons[ ID ];
M
Mr.doob 已提交
2017

L
Lewy Blue 已提交
2018
			var parents = connections.get( parseInt( skeleton.ID ) ).parents;
Y
yamahigashi 已提交
2019

L
Lewy Blue 已提交
2020
			parents.forEach( function ( parent ) {
Y
yamahigashi 已提交
2021

M
Mr.doob 已提交
2022
				if ( geometryMap.has( parent.ID ) ) {
Y
yamahigashi 已提交
2023

M
Mr.doob 已提交
2024
					var geoID = parent.ID;
L
Lewy Blue 已提交
2025
					var geoRelationships = connections.get( geoID );
M
Mr.doob 已提交
2026

L
Lewy Blue 已提交
2027
					geoRelationships.parents.forEach( function ( geoConnParent ) {
M
Mr.doob 已提交
2028

2029
						if ( modelMap.has( geoConnParent.ID ) ) {
L
Lewy Blue 已提交
2030

2031
							var model = modelMap.get( geoConnParent.ID );
L
Lewy Blue 已提交
2032

L
Lewy Blue 已提交
2033
							model.bind( new THREE.Skeleton( skeleton.bones ), bindMatrices[ geoConnParent.ID ] );
M
Mr.doob 已提交
2034 2035 2036

						}

2037
					} );
Y
yamahigashi 已提交
2038

Y
yamahigashi 已提交
2039
				}
Y
yamahigashi 已提交
2040

2041
			} );
Y
yamahigashi 已提交
2042

M
Mr.doob 已提交
2043
		}
Y
yamahigashi 已提交
2044

M
Mr.doob 已提交
2045
	}
Y
yamahigashi 已提交
2046

L
Lewy Blue 已提交
2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084
	function parsePoseNodes( FBXTree ) {

		var bindMatrices = {};

		if ( 'Pose' in FBXTree.Objects ) {

			var BindPoseNode = FBXTree.Objects.Pose;

			for ( var nodeID in BindPoseNode ) {

				if ( BindPoseNode[ nodeID ].attrType === 'BindPose' ) {

					var poseNodes = BindPoseNode[ nodeID ].PoseNode;

					if ( Array.isArray( poseNodes ) ) {

						poseNodes.forEach( function ( poseNode ) {

							bindMatrices[ poseNode.Node ] = new THREE.Matrix4().fromArray( poseNode.Matrix.a );

						} );

					} else {

						bindMatrices[ poseNodes.Node ] = new THREE.Matrix4().fromArray( poseNodes.Matrix.a );

					}

				}

			}

		}

		return bindMatrices;

	}

L
Lewy Blue 已提交
2085
	function parseAnimations( FBXTree, connections ) {
M
Mr.doob 已提交
2086

L
Lewy Blue 已提交
2087
		// since the actual transformation data is stored in FBXTree.Objects.AnimationCurve,
L
Lewy Blue 已提交
2088
		// if this is undefined we can safely assume there are no animations
L
Lewy Blue 已提交
2089
		if ( FBXTree.Objects.AnimationCurve === undefined ) return undefined;
L
Lewy Blue 已提交
2090

L
Lewy Blue 已提交
2091
		var curveNodesMap = parseAnimationCurveNodes( FBXTree );
2092

L
Lewy Blue 已提交
2093
		parseAnimationCurves( FBXTree, connections, curveNodesMap );
2094

L
Lewy Blue 已提交
2095 2096 2097 2098 2099 2100 2101
		var layersMap = parseAnimationLayers( FBXTree, connections, curveNodesMap );
		var rawClips = parseAnimStacks( FBXTree, connections, layersMap );

		return rawClips;

	}

L
Lewy Blue 已提交
2102
	// parse nodes in FBXTree.Objects.AnimationCurveNode
L
Lewy Blue 已提交
2103 2104 2105 2106
	// each AnimationCurveNode holds data for an animation transform for a model (e.g. left arm rotation )
	// and is referenced by an AnimationLayer
	function parseAnimationCurveNodes( FBXTree ) {

L
Lewy Blue 已提交
2107
		var rawCurveNodes = FBXTree.Objects.AnimationCurveNode;
M
Mr.doob 已提交
2108

L
Lewy Blue 已提交
2109
		var curveNodesMap = new Map();
M
Mr.doob 已提交
2110

L
Lewy Blue 已提交
2111
		for ( var nodeID in rawCurveNodes ) {
M
Mr.doob 已提交
2112

L
Lewy Blue 已提交
2113 2114 2115 2116 2117
			var rawCurveNode = rawCurveNodes[ nodeID ];

			if ( rawCurveNode.attrName.match( /S|R|T/ ) !== null ) {

				var curveNode = {
Y
yamahigashi 已提交
2118

L
Lewy Blue 已提交
2119 2120 2121
					id: rawCurveNode.id,
					attr: rawCurveNode.attrName,
					curves: {},
Y
yamahigashi 已提交
2122

L
Lewy Blue 已提交
2123
				};
Y
yamahigashi 已提交
2124

L
Lewy Blue 已提交
2125
				curveNodesMap.set( curveNode.id, curveNode );
M
Mr.doob 已提交
2126

L
Lewy Blue 已提交
2127
			}
L
Lewy Blue 已提交
2128

M
Mr.doob 已提交
2129 2130
		}

L
Lewy Blue 已提交
2131 2132 2133 2134
		return curveNodesMap;

	}

L
Lewy Blue 已提交
2135
	// parse nodes in FBXTree.Objects.AnimationCurve and connect them up to
L
Lewy Blue 已提交
2136 2137 2138 2139
	// previously parsed AnimationCurveNodes. Each AnimationCurve holds data for a single animated
	// axis ( e.g. times and values of x rotation)
	function parseAnimationCurves( FBXTree, connections, curveNodesMap ) {

L
Lewy Blue 已提交
2140
		var rawCurves = FBXTree.Objects.AnimationCurve;
L
Lewy Blue 已提交
2141 2142

		for ( var nodeID in rawCurves ) {
M
Mr.doob 已提交
2143

L
Lewy Blue 已提交
2144 2145 2146
			var animationCurve = {

				id: rawCurves[ nodeID ].id,
L
Lewy Blue 已提交
2147 2148
				times: rawCurves[ nodeID ].KeyTime.a.map( convertFBXTimeToSeconds ),
				values: rawCurves[ nodeID ].KeyValueFloat.a,
L
Lewy Blue 已提交
2149 2150

			};
M
Mr.doob 已提交
2151

L
Lewy Blue 已提交
2152
			var relationships = connections.get( animationCurve.id );
M
Mr.doob 已提交
2153

L
Lewy Blue 已提交
2154
			if ( relationships !== undefined ) {
M
Mr.doob 已提交
2155

L
Lewy Blue 已提交
2156 2157
				var animationCurveID = relationships.parents[ 0 ].ID;
				var animationCurveRelationship = relationships.parents[ 0 ].relationship;
2158
				var axis = '';
M
Mr.doob 已提交
2159

L
Lewy Blue 已提交
2160
				if ( animationCurveRelationship.match( /X/ ) ) {
M
Mr.doob 已提交
2161

2162
					axis = 'x';
M
Mr.doob 已提交
2163

L
Lewy Blue 已提交
2164
				} else if ( animationCurveRelationship.match( /Y/ ) ) {
M
Mr.doob 已提交
2165

2166
					axis = 'y';
Y
yamahigashi 已提交
2167

L
Lewy Blue 已提交
2168
				} else if ( animationCurveRelationship.match( /Z/ ) ) {
Y
yamahigashi 已提交
2169

2170
					axis = 'z';
Y
yamahigashi 已提交
2171

2172
				} else {
Y
yamahigashi 已提交
2173

2174
					continue;
L
Lewy Blue 已提交
2175 2176

				}
M
Mr.doob 已提交
2177

L
Lewy Blue 已提交
2178
				curveNodesMap.get( animationCurveID ).curves[ axis ] = animationCurve;
2179

Y
yamahigashi 已提交
2180
			}
Y
yamahigashi 已提交
2181

M
Mr.doob 已提交
2182
		}
Y
yamahigashi 已提交
2183

L
Lewy Blue 已提交
2184
	}
Y
yamahigashi 已提交
2185

L
Lewy Blue 已提交
2186
	// parse nodes in FBXTree.Objects.AnimationLayer. Each layers holds references
L
Lewy Blue 已提交
2187 2188 2189
	// to various AnimationCurveNodes and is referenced by an AnimationStack node
	// note: theoretically a stack can multiple layers, however in practice there always seems to be one per stack
	function parseAnimationLayers( FBXTree, connections, curveNodesMap ) {
Y
yamahigashi 已提交
2190

L
Lewy Blue 已提交
2191
		var rawLayers = FBXTree.Objects.AnimationLayer;
Y
yamahigashi 已提交
2192

L
Lewy Blue 已提交
2193 2194
		var layersMap = new Map();

M
Mr.doob 已提交
2195 2196
		for ( var nodeID in rawLayers ) {

L
Lewy Blue 已提交
2197
			var layerCurveNodes = [];
Y
yamahigashi 已提交
2198

2199
			var connection = connections.get( parseInt( nodeID ) );
Y
yamahigashi 已提交
2200

2201
			if ( connection !== undefined ) {
M
Mr.doob 已提交
2202

L
Lewy Blue 已提交
2203
				// all the animationCurveNodes used in the layer
2204
				var children = connection.children;
M
Mr.doob 已提交
2205

L
Lewy Blue 已提交
2206
				children.forEach( function ( child, i ) {
M
Mr.doob 已提交
2207

L
Lewy Blue 已提交
2208
					if ( curveNodesMap.has( child.ID ) ) {
Y
yamahigashi 已提交
2209

L
Lewy Blue 已提交
2210
						var curveNode = curveNodesMap.get( child.ID );
Y
yamahigashi 已提交
2211

L
Lewy Blue 已提交
2212
						if ( layerCurveNodes[ i ] === undefined ) {
Y
yamahigashi 已提交
2213

L
Lewy Blue 已提交
2214 2215 2216 2217 2218 2219 2220
							var modelID;

							connections.get( child.ID ).parents.forEach( function ( parent ) {

								if ( parent.relationship !== undefined ) modelID = parent.ID;

							} );
Y
yamahigashi 已提交
2221

L
Lewy Blue 已提交
2222
							var rawModel = FBXTree.Objects.Model[ modelID.toString() ];
Y
yamahigashi 已提交
2223

L
Lewy Blue 已提交
2224
							var node = {
Y
yamahigashi 已提交
2225

L
Lewy Blue 已提交
2226 2227 2228 2229
								modelName: THREE.PropertyBinding.sanitizeNodeName( rawModel.attrName ),
								initialPosition: [ 0, 0, 0 ],
								initialRotation: [ 0, 0, 0 ],
								initialScale: [ 1, 1, 1 ],
Y
yamahigashi 已提交
2230

L
Lewy Blue 已提交
2231
							};
Y
yamahigashi 已提交
2232

L
Lewy Blue 已提交
2233
							if ( 'Lcl_Translation' in rawModel ) node.initialPosition = rawModel.Lcl_Translation.value;
Y
yamahigashi 已提交
2234

L
Lewy Blue 已提交
2235
							if ( 'Lcl_Rotation' in rawModel ) node.initialRotation = rawModel.Lcl_Rotation.value;
Y
yamahigashi 已提交
2236

L
Lewy Blue 已提交
2237
							if ( 'Lcl_Scaling' in rawModel ) node.initialScale = rawModel.Lcl_Scaling.value;
Y
yamahigashi 已提交
2238

L
Lewy Blue 已提交
2239 2240
							// if the animated model is pre rotated, we'll have to apply the pre rotations to every
							// animation value as well
L
Lewy Blue 已提交
2241
							if ( 'PreRotation' in rawModel ) node.preRotations = rawModel.PreRotation.value;
Y
yamahigashi 已提交
2242

L
Lewy Blue 已提交
2243
							layerCurveNodes[ i ] = node;
M
Mr.doob 已提交
2244 2245 2246

						}

L
Lewy Blue 已提交
2247
						layerCurveNodes[ i ][ curveNode.attr ] = curveNode;
M
Mr.doob 已提交
2248

L
Lewy Blue 已提交
2249
					}
L
Lewy Blue 已提交
2250

L
Lewy Blue 已提交
2251
				} );
L
Lewy Blue 已提交
2252

L
Lewy Blue 已提交
2253
				layersMap.set( parseInt( nodeID ), layerCurveNodes );
Y
yamahigashi 已提交
2254

M
Mr.doob 已提交
2255
			}
Y
yamahigashi 已提交
2256

M
Mr.doob 已提交
2257
		}
Y
yamahigashi 已提交
2258

L
Lewy Blue 已提交
2259
		return layersMap;
Y
yamahigashi 已提交
2260

Y
yamahigashi 已提交
2261
	}
Y
yamahigashi 已提交
2262

L
Lewy Blue 已提交
2263
	// parse nodes in FBXTree.Objects.AnimationStack. These are the top level node in the animation
L
Lewy Blue 已提交
2264 2265
	// hierarchy. Each Stack node will be used to create a THREE.AnimationClip
	function parseAnimStacks( FBXTree, connections, layersMap ) {
Y
yamahigashi 已提交
2266

L
Lewy Blue 已提交
2267
		var rawStacks = FBXTree.Objects.AnimationStack;
Y
yamahigashi 已提交
2268

L
Lewy Blue 已提交
2269 2270
		// connect the stacks (clips) up to the layers
		var rawClips = {};
Y
yamahigashi 已提交
2271

L
Lewy Blue 已提交
2272
		for ( var nodeID in rawStacks ) {
Y
yamahigashi 已提交
2273

L
Lewy Blue 已提交
2274
			var children = connections.get( parseInt( nodeID ) ).children;
Y
yamahigashi 已提交
2275

L
Lewy Blue 已提交
2276
			if ( children.length > 1 ) {
L
Lewy Blue 已提交
2277

L
Lewy Blue 已提交
2278 2279 2280
				// it seems like stacks will always be associated with a single layer. But just in case there are files
				// where there are multiple layers per stack, we'll display a warning
				console.warn( 'THREE.FBXLoader: Encountered an animation stack with multiple layers, this is currently not supported. Ignoring subsequent layers.' );
L
Lewy Blue 已提交
2281

L
Lewy Blue 已提交
2282
			}
Y
yamahigashi 已提交
2283

L
Lewy Blue 已提交
2284
			var layer = layersMap.get( children[ 0 ].ID );
Y
yamahigashi 已提交
2285

L
Lewy Blue 已提交
2286
			rawClips[ nodeID ] = {
2287

L
Lewy Blue 已提交
2288 2289
				name: rawStacks[ nodeID ].attrName,
				layer: layer,
Y
yamahigashi 已提交
2290

L
Lewy Blue 已提交
2291
			};
Y
yamahigashi 已提交
2292

Y
yamahigashi 已提交
2293
		}
Y
yamahigashi 已提交
2294

L
Lewy Blue 已提交
2295
		return rawClips;
Y
yamahigashi 已提交
2296

M
Mr.doob 已提交
2297
	}
Y
yamahigashi 已提交
2298

L
Lewy Blue 已提交
2299 2300
	// take raw animation data from parseAnimations and connect it up to the loaded models
	function addAnimations( FBXTree, connections, sceneGraph ) {
Y
yamahigashi 已提交
2301

L
Lewy Blue 已提交
2302
		sceneGraph.animations = [];
L
Lewy Blue 已提交
2303

L
Lewy Blue 已提交
2304
		var rawClips = parseAnimations( FBXTree, connections );
M
Mr.doob 已提交
2305

L
Lewy Blue 已提交
2306
		if ( rawClips === undefined ) return;
Y
yamahigashi 已提交
2307

L
Lewy Blue 已提交
2308

L
Lewy Blue 已提交
2309
		for ( var key in rawClips ) {
Y
yamahigashi 已提交
2310

L
Lewy Blue 已提交
2311
			var rawClip = rawClips[ key ];
L
Lewy Blue 已提交
2312

L
Lewy Blue 已提交
2313
			var clip = addClip( rawClip );
L
Lewy Blue 已提交
2314

L
Lewy Blue 已提交
2315
			sceneGraph.animations.push( clip );
L
Lewy Blue 已提交
2316

L
Lewy Blue 已提交
2317
		}
L
Lewy Blue 已提交
2318

L
Lewy Blue 已提交
2319
	}
L
Lewy Blue 已提交
2320

L
Lewy Blue 已提交
2321
	function addClip( rawClip ) {
L
Lewy Blue 已提交
2322

L
Lewy Blue 已提交
2323
		var tracks = [];
L
Lewy Blue 已提交
2324

L
Lewy Blue 已提交
2325
		rawClip.layer.forEach( function ( rawTracks ) {
L
Lewy Blue 已提交
2326

L
Lewy Blue 已提交
2327
			tracks = tracks.concat( generateTracks( rawTracks ) );
L
Lewy Blue 已提交
2328

L
Lewy Blue 已提交
2329
		} );
L
Lewy Blue 已提交
2330

L
Lewy Blue 已提交
2331
		return new THREE.AnimationClip( rawClip.name, - 1, tracks );
L
Lewy Blue 已提交
2332 2333 2334

	}

L
Lewy Blue 已提交
2335
	function generateTracks( rawTracks ) {
M
Mr.doob 已提交
2336

L
Lewy Blue 已提交
2337
		var tracks = [];
M
Mr.doob 已提交
2338

L
Lewy Blue 已提交
2339
		if ( rawTracks.T !== undefined && Object.keys( rawTracks.T.curves ).length > 0 ) {
Y
yamahigashi 已提交
2340

L
Lewy Blue 已提交
2341 2342
			var positionTrack = generateVectorTrack( rawTracks.modelName, rawTracks.T.curves, rawTracks.initialPosition, 'position' );
			if ( positionTrack !== undefined ) tracks.push( positionTrack );
Y
yamahigashi 已提交
2343

M
Mr.doob 已提交
2344
		}
Y
yamahigashi 已提交
2345

L
Lewy Blue 已提交
2346
		if ( rawTracks.R !== undefined && Object.keys( rawTracks.R.curves ).length > 0 ) {
Y
yamahigashi 已提交
2347

L
Lewy Blue 已提交
2348 2349
			var rotationTrack = generateRotationTrack( rawTracks.modelName, rawTracks.R.curves, rawTracks.initialRotation, rawTracks.preRotations );
			if ( rotationTrack !== undefined ) tracks.push( rotationTrack );
Y
yamahigashi 已提交
2350

Y
yamahigashi 已提交
2351
		}
Y
yamahigashi 已提交
2352

L
Lewy Blue 已提交
2353
		if ( rawTracks.S !== undefined && Object.keys( rawTracks.S.curves ).length > 0 ) {
Y
yamahigashi 已提交
2354

L
Lewy Blue 已提交
2355 2356
			var scaleTrack = generateVectorTrack( rawTracks.modelName, rawTracks.S.curves, rawTracks.initialScale, 'scale' );
			if ( scaleTrack !== undefined ) tracks.push( scaleTrack );
2357

M
Mr.doob 已提交
2358
		}
2359

L
Lewy Blue 已提交
2360
		return tracks;
Y
yamahigashi 已提交
2361

M
Mr.doob 已提交
2362
	}
Y
yamahigashi 已提交
2363

L
Lewy Blue 已提交
2364
	function generateVectorTrack( modelName, curves, initialValue, type ) {
2365

L
Lewy Blue 已提交
2366 2367
		var times = getTimesForAllAxes( curves );
		var values = getKeyframeTrackValues( times, curves, initialValue );
M
Mr.doob 已提交
2368

L
Lewy Blue 已提交
2369
		return new THREE.VectorKeyframeTrack( modelName + '.' + type, times, values );
M
Mr.doob 已提交
2370

L
Lewy Blue 已提交
2371
	}
Y
yamahigashi 已提交
2372

L
Lewy Blue 已提交
2373
	function generateRotationTrack( modelName, curves, initialValue, preRotations ) {
M
Mr.doob 已提交
2374

L
Lewy Blue 已提交
2375 2376 2377
		if ( curves.x !== undefined ) curves.x.values = curves.x.values.map( THREE.Math.degToRad );
		if ( curves.y !== undefined ) curves.y.values = curves.y.values.map( THREE.Math.degToRad );
		if ( curves.z !== undefined ) curves.z.values = curves.z.values.map( THREE.Math.degToRad );
M
Mr.doob 已提交
2378

L
Lewy Blue 已提交
2379 2380
		var times = getTimesForAllAxes( curves );
		var values = getKeyframeTrackValues( times, curves, initialValue );
M
Mr.doob 已提交
2381

L
Lewy Blue 已提交
2382
		if ( preRotations !== undefined ) {
Y
yamahigashi 已提交
2383

L
Lewy Blue 已提交
2384 2385
			preRotations = preRotations.map( THREE.Math.degToRad );
			preRotations.push( 'ZYX' );
Y
yamahigashi 已提交
2386

L
Lewy Blue 已提交
2387 2388
			preRotations = new THREE.Euler().fromArray( preRotations );
			preRotations = new THREE.Quaternion().setFromEuler( preRotations );
Y
yamahigashi 已提交
2389

L
Lewy Blue 已提交
2390
		}
Y
yamahigashi 已提交
2391

L
Lewy Blue 已提交
2392 2393
		var quaternion = new THREE.Quaternion();
		var euler = new THREE.Euler();
Y
yamahigashi 已提交
2394

L
Lewy Blue 已提交
2395
		var quaternionValues = [];
Y
yamahigashi 已提交
2396

L
Lewy Blue 已提交
2397
		for ( var i = 0; i < values.length; i += 3 ) {
Y
yamahigashi 已提交
2398

L
Lewy Blue 已提交
2399
			euler.set( values[ i ], values[ i + 1 ], values[ i + 2 ], 'ZYX' );
Y
yamahigashi 已提交
2400

L
Lewy Blue 已提交
2401
			quaternion.setFromEuler( euler );
Y
yamahigashi 已提交
2402

L
Lewy Blue 已提交
2403
			if ( preRotations !== undefined )quaternion.premultiply( preRotations );
Y
yamahigashi 已提交
2404

L
Lewy Blue 已提交
2405
			quaternion.toArray( quaternionValues, ( i / 3 ) * 4 );
Y
yamahigashi 已提交
2406

L
Lewy Blue 已提交
2407
		}
Y
yamahigashi 已提交
2408

L
Lewy Blue 已提交
2409
		return new THREE.QuaternionKeyframeTrack( modelName + '.quaternion', times, quaternionValues );
L
Lewy Blue 已提交
2410

M
Mr.doob 已提交
2411
	}
Y
yamahigashi 已提交
2412

L
Lewy Blue 已提交
2413
	function getKeyframeTrackValues( times, curves, initialValue ) {
2414

L
Lewy Blue 已提交
2415
		var prevValue = initialValue;
L
Lewy Blue 已提交
2416

L
Lewy Blue 已提交
2417
		var values = [];
Y
yamahigashi 已提交
2418

L
Lewy Blue 已提交
2419 2420 2421
		var xIndex = - 1;
		var yIndex = - 1;
		var zIndex = - 1;
2422

L
Lewy Blue 已提交
2423
		times.forEach( function ( time ) {
2424

L
Lewy Blue 已提交
2425 2426 2427
			if ( curves.x ) xIndex = curves.x.times.indexOf( time );
			if ( curves.y ) yIndex = curves.y.times.indexOf( time );
			if ( curves.z ) zIndex = curves.z.times.indexOf( time );
2428

L
Lewy Blue 已提交
2429 2430
			// if there is an x value defined for this frame, use that
			if ( xIndex !== - 1 ) {
2431

L
Lewy Blue 已提交
2432 2433 2434
				var xValue = curves.x.values[ xIndex ];
				values.push( xValue );
				prevValue[ 0 ] = xValue;
2435

L
Lewy Blue 已提交
2436
			} else {
M
Mr.doob 已提交
2437

L
Lewy Blue 已提交
2438 2439
				// otherwise use the x value from the previous frame
				values.push( prevValue[ 0 ] );
Y
yamahigashi 已提交
2440

Y
yamahigashi 已提交
2441
			}
Y
yamahigashi 已提交
2442

L
Lewy Blue 已提交
2443
			if ( yIndex !== - 1 ) {
2444

L
Lewy Blue 已提交
2445 2446 2447
				var yValue = curves.y.values[ yIndex ];
				values.push( yValue );
				prevValue[ 1 ] = yValue;
2448

L
Lewy Blue 已提交
2449
			} else {
2450

L
Lewy Blue 已提交
2451
				values.push( prevValue[ 1 ] );
2452

L
Lewy Blue 已提交
2453
			}
2454

L
Lewy Blue 已提交
2455
			if ( zIndex !== - 1 ) {
2456

L
Lewy Blue 已提交
2457 2458 2459
				var zValue = curves.z.values[ zIndex ];
				values.push( zValue );
				prevValue[ 2 ] = zValue;
Y
yamahigashi 已提交
2460

L
Lewy Blue 已提交
2461
			} else {
Y
yamahigashi 已提交
2462

L
Lewy Blue 已提交
2463
				values.push( prevValue[ 2 ] );
L
Lewy Blue 已提交
2464 2465

			}
Y
yamahigashi 已提交
2466

L
Lewy Blue 已提交
2467
		} );
Y
yamahigashi 已提交
2468

L
Lewy Blue 已提交
2469
		return values;
2470

M
Mr.doob 已提交
2471
	}
2472

L
Lewy Blue 已提交
2473 2474 2475
	// For all animated objects, times are defined separately for each axis
	// Here we'll combine the times into one sorted array without duplicates
	function getTimesForAllAxes( curves ) {
2476

L
Lewy Blue 已提交
2477
		var times = [];
2478

L
Lewy Blue 已提交
2479 2480 2481 2482
		// first join together the times for each axis, if defined
		if ( curves.x !== undefined ) times = times.concat( curves.x.times );
		if ( curves.y !== undefined ) times = times.concat( curves.y.times );
		if ( curves.z !== undefined ) times = times.concat( curves.z.times );
M
Mr.doob 已提交
2483

L
Lewy Blue 已提交
2484 2485
		// then sort them and remove duplicates
		times = times.sort( function ( a, b ) {
Y
yamahigashi 已提交
2486

L
Lewy Blue 已提交
2487
			return a - b;
Y
yamahigashi 已提交
2488

L
Lewy Blue 已提交
2489
		} ).filter( function ( elem, index, array ) {
Y
yamahigashi 已提交
2490

L
Lewy Blue 已提交
2491
			return array.indexOf( elem ) == index;
Y
yamahigashi 已提交
2492

M
Mr.doob 已提交
2493
		} );
Y
yamahigashi 已提交
2494

L
Lewy Blue 已提交
2495
		return times;
Y
yamahigashi 已提交
2496

M
Mr.doob 已提交
2497
	}
Y
yamahigashi 已提交
2498

L
Lewy Blue 已提交
2499
	// parse an FBX file in ASCII format
L
Lewy Blue 已提交
2500
	function TextParser() {}
Y
yamahigashi 已提交
2501

M
Mr.doob 已提交
2502
	Object.assign( TextParser.prototype, {
Y
yamahigashi 已提交
2503

M
Mr.doob 已提交
2504
		getPrevNode: function () {
Y
yamahigashi 已提交
2505

M
Mr.doob 已提交
2506
			return this.nodeStack[ this.currentIndent - 2 ];
Y
yamahigashi 已提交
2507

M
Mr.doob 已提交
2508
		},
Y
yamahigashi 已提交
2509

M
Mr.doob 已提交
2510
		getCurrentNode: function () {
Y
yamahigashi 已提交
2511

M
Mr.doob 已提交
2512
			return this.nodeStack[ this.currentIndent - 1 ];
Y
yamahigashi 已提交
2513

M
Mr.doob 已提交
2514
		},
Y
yamahigashi 已提交
2515

M
Mr.doob 已提交
2516
		getCurrentProp: function () {
Y
yamahigashi 已提交
2517

M
Mr.doob 已提交
2518
			return this.currentProp;
Y
yamahigashi 已提交
2519

M
Mr.doob 已提交
2520
		},
Y
yamahigashi 已提交
2521

M
Mr.doob 已提交
2522
		pushStack: function ( node ) {
Y
yamahigashi 已提交
2523

M
Mr.doob 已提交
2524 2525
			this.nodeStack.push( node );
			this.currentIndent += 1;
Y
yamahigashi 已提交
2526

M
Mr.doob 已提交
2527
		},
Y
yamahigashi 已提交
2528

M
Mr.doob 已提交
2529
		popStack: function () {
Y
yamahigashi 已提交
2530

M
Mr.doob 已提交
2531 2532
			this.nodeStack.pop();
			this.currentIndent -= 1;
Y
yamahigashi 已提交
2533

M
Mr.doob 已提交
2534
		},
Y
yamahigashi 已提交
2535

M
Mr.doob 已提交
2536
		setCurrentProp: function ( val, name ) {
Y
yamahigashi 已提交
2537

M
Mr.doob 已提交
2538 2539
			this.currentProp = val;
			this.currentPropName = name;
Y
yamahigashi 已提交
2540

M
Mr.doob 已提交
2541
		},
Y
yamahigashi 已提交
2542

M
Mr.doob 已提交
2543
		parse: function ( text ) {
Y
yamahigashi 已提交
2544

M
Mr.doob 已提交
2545 2546 2547 2548 2549
			this.currentIndent = 0;
			this.allNodes = new FBXTree();
			this.nodeStack = [];
			this.currentProp = [];
			this.currentPropName = '';
Y
yamahigashi 已提交
2550

2551
			var self = this;
Y
yamahigashi 已提交
2552

2553
			var split = text.split( '\n' );
Y
yamahigashi 已提交
2554

2555
			split.forEach( function ( line, i ) {
L
Lewy Blue 已提交
2556

2557 2558
				var matchComment = line.match( /^[\s\t]*;/ );
				var matchEmpty = line.match( /^[\s\t]*$/ );
L
Lewy Blue 已提交
2559

2560
				if ( matchComment || matchEmpty ) return;
M
Mr.doob 已提交
2561

2562 2563 2564
				var matchBeginning = line.match( '^\\t{' + self.currentIndent + '}(\\w+):(.*){', '' );
				var matchProperty = line.match( '^\\t{' + ( self.currentIndent ) + '}(\\w+):[\\s\\t\\r\\n](.*)' );
				var matchEnd = line.match( '^\\t{' + ( self.currentIndent - 1 ) + '}}' );
M
Mr.doob 已提交
2565

2566
				if ( matchBeginning ) {
Y
yamahigashi 已提交
2567

2568
					self.parseNodeBegin( line, matchBeginning );
2569

2570
				} else if ( matchProperty ) {
Y
yamahigashi 已提交
2571

2572
					self.parseNodeProperty( line, matchProperty, split[ ++ i ] );
Y
yamahigashi 已提交
2573

2574
				} else if ( matchEnd ) {
2575

L
Lewy Blue 已提交
2576
					self.popStack();
2577

2578
				} else if ( line.match( /^[^\s\t}]/ ) ) {
2579

2580 2581 2582
					// large arrays are split over multiple lines terminated with a ',' character
					// if this is encountered the line needs to be joined to the previous line
					self.parseNodePropertyContinued( line );
Y
yamahigashi 已提交
2583

M
Mr.doob 已提交
2584
				}
Y
yamahigashi 已提交
2585

2586
			} );
Y
yamahigashi 已提交
2587

2588
			return this.allNodes;
Y
yamahigashi 已提交
2589

2590
		},
Y
yamahigashi 已提交
2591

2592
		parseNodeBegin: function ( line, property ) {
Y
yamahigashi 已提交
2593

2594
			var nodeName = property[ 1 ].trim().replace( /^"/, '' ).replace( /"$/, '' );
Y
yamahigashi 已提交
2595

2596
			var nodeAttrs = property[ 2 ].split( ',' ).map( function ( attr ) {
Y
yamahigashi 已提交
2597

2598
				return attr.trim().replace( /^"/, '' ).replace( /"$/, '' );
Y
yamahigashi 已提交
2599

2600
			} );
Y
yamahigashi 已提交
2601

L
Lewy Blue 已提交
2602
			var node = { name: nodeName };
M
Mr.doob 已提交
2603
			var attrs = this.parseNodeAttr( nodeAttrs );
L
Lewy Blue 已提交
2604

M
Mr.doob 已提交
2605
			var currentNode = this.getCurrentNode();
Y
yamahigashi 已提交
2606

M
Mr.doob 已提交
2607 2608
			// a top node
			if ( this.currentIndent === 0 ) {
Y
yamahigashi 已提交
2609

M
Mr.doob 已提交
2610
				this.allNodes.add( nodeName, node );
Y
yamahigashi 已提交
2611

2612
			} else { // a subnode
Y
yamahigashi 已提交
2613

2614
				// if the subnode already exists, append it
L
Lewy Blue 已提交
2615
				if ( nodeName in currentNode ) {
Y
yamahigashi 已提交
2616

L
Lewy Blue 已提交
2617 2618 2619 2620 2621 2622
				// special case Pose needs PoseNodes as an array
					if ( nodeName === 'PoseNode' ) {

						currentNode.PoseNode.push( node );

					} else if ( currentNode[ nodeName ].id !== undefined ) {
Y
yamahigashi 已提交
2623

L
Lewy Blue 已提交
2624 2625
						currentNode[ nodeName ] = {};
						currentNode[ nodeName ][ currentNode[ nodeName ].id ] = currentNode[ nodeName ];
Y
yamahigashi 已提交
2626

M
Mr.doob 已提交
2627
					}
Y
yamahigashi 已提交
2628

L
Lewy Blue 已提交
2629
					if ( attrs.id !== '' ) currentNode[ nodeName ][ attrs.id ] = node;
Y
yamahigashi 已提交
2630

L
Lewy Blue 已提交
2631
				} else if ( typeof attrs.id === 'number' ) {
Y
yamahigashi 已提交
2632

L
Lewy Blue 已提交
2633 2634
					currentNode[ nodeName ] = {};
					currentNode[ nodeName ][ attrs.id ] = node;
Y
yamahigashi 已提交
2635

L
Lewy Blue 已提交
2636
				} else if ( nodeName !== 'Properties70' ) {
Y
yamahigashi 已提交
2637

L
Lewy Blue 已提交
2638 2639
					if ( nodeName === 'PoseNode' )	currentNode[ nodeName ] = [ node ];
					else currentNode[ nodeName ] = node;
Y
yamahigashi 已提交
2640

M
Mr.doob 已提交
2641
				}
K
Kyle Larson 已提交
2642

Y
yamahigashi 已提交
2643
			}
Y
yamahigashi 已提交
2644

L
Lewy Blue 已提交
2645 2646 2647 2648
			if ( typeof attrs.id === 'number' ) node.id = attrs.id;
			if ( attrs.name !== '' ) node.attrName = attrs.name;
			if ( attrs.type !== '' ) node.attrType = attrs.type;

M
Mr.doob 已提交
2649
			this.pushStack( node );
K
Kyle Larson 已提交
2650

M
Mr.doob 已提交
2651
		},
K
Kyle Larson 已提交
2652

M
Mr.doob 已提交
2653
		parseNodeAttr: function ( attrs ) {
K
Kyle Larson 已提交
2654

M
Mr.doob 已提交
2655
			var id = attrs[ 0 ];
K
Kyle Larson 已提交
2656

M
Mugen87 已提交
2657
			if ( attrs[ 0 ] !== '' ) {
Y
yamahigashi 已提交
2658

M
Mr.doob 已提交
2659
				id = parseInt( attrs[ 0 ] );
Y
yamahigashi 已提交
2660

M
Mr.doob 已提交
2661
				if ( isNaN( id ) ) {
Y
yamahigashi 已提交
2662

M
Mr.doob 已提交
2663
					id = attrs[ 0 ];
Y
yamahigashi 已提交
2664

M
Mr.doob 已提交
2665
				}
Y
yamahigashi 已提交
2666

M
Mr.doob 已提交
2667
			}
Y
yamahigashi 已提交
2668

M
Mr.doob 已提交
2669
			var name = '', type = '';
Y
yamahigashi 已提交
2670

M
Mr.doob 已提交
2671
			if ( attrs.length > 1 ) {
Y
yamahigashi 已提交
2672

M
Mr.doob 已提交
2673 2674
				name = attrs[ 1 ].replace( /^(\w+)::/, '' );
				type = attrs[ 2 ];
Y
yamahigashi 已提交
2675

M
Mr.doob 已提交
2676
			}
Y
yamahigashi 已提交
2677

M
Mr.doob 已提交
2678
			return { id: id, name: name, type: type };
Y
yamahigashi 已提交
2679

M
Mr.doob 已提交
2680
		},
Y
yamahigashi 已提交
2681

2682 2683 2684 2685 2686 2687 2688
		parseNodeProperty: function ( line, property, contentLine ) {

			var propName = property[ 1 ].replace( /^"/, '' ).replace( /"$/, '' ).trim();
			var propValue = property[ 2 ].replace( /^"/, '' ).replace( /"$/, '' ).trim();

			// for special case: base64 image data follows "Content: ," line
			//	Content: ,
L
Lewy Blue 已提交
2689
			//	 "/9j/4RDaRXhpZgAATU0A..."
2690 2691 2692 2693 2694
			if ( propName === 'Content' && propValue === ',' ) {

				propValue = contentLine.replace( /"/g, '' ).replace( /,$/, '' ).trim();

			}
Y
yamahigashi 已提交
2695

M
Mr.doob 已提交
2696 2697
			var currentNode = this.getCurrentNode();
			var parentName = currentNode.name;
Y
yamahigashi 已提交
2698

L
Lewy Blue 已提交
2699
			if ( parentName === 'Properties70' ) {
Y
yamahigashi 已提交
2700

L
Lewy Blue 已提交
2701 2702
				this.parseNodeSpecialProperty( line, propName, propValue );
				return;
Y
yamahigashi 已提交
2703

M
Mr.doob 已提交
2704
			}
Y
yamahigashi 已提交
2705

2706
			// Connections
M
Mugen87 已提交
2707
			if ( propName === 'C' ) {
Y
yamahigashi 已提交
2708

M
Mr.doob 已提交
2709 2710 2711
				var connProps = propValue.split( ',' ).slice( 1 );
				var from = parseInt( connProps[ 0 ] );
				var to = parseInt( connProps[ 1 ] );
Y
yamahigashi 已提交
2712

M
Mr.doob 已提交
2713
				var rest = propValue.split( ',' ).slice( 3 );
Y
yamahigashi 已提交
2714

2715 2716 2717 2718 2719 2720
				rest = rest.map( function ( elem ) {

					return elem.trim().replace( /^"/, '' );

				} );

M
Mr.doob 已提交
2721 2722 2723
				propName = 'connections';
				propValue = [ from, to ];
				append( propValue, rest );
Y
yamahigashi 已提交
2724

L
Lewy Blue 已提交
2725
				if ( currentNode[ propName ] === undefined ) {
Y
yamahigashi 已提交
2726

L
Lewy Blue 已提交
2727
					currentNode[ propName ] = [];
Y
yamahigashi 已提交
2728

M
Mr.doob 已提交
2729
				}
Y
yamahigashi 已提交
2730

M
Mr.doob 已提交
2731
			}
Y
yamahigashi 已提交
2732

2733
			// Node
L
Lewy Blue 已提交
2734
			if ( propName === 'Node' ) currentNode.id = propValue;
Y
yamahigashi 已提交
2735

L
Lewy Blue 已提交
2736 2737
			// connections
			if ( propName in currentNode && Array.isArray( currentNode[ propName ] ) ) {
Y
yamahigashi 已提交
2738

L
Lewy Blue 已提交
2739
				currentNode[ propName ].push( propValue );
Y
yamahigashi 已提交
2740

M
Mr.doob 已提交
2741
			} else {
Y
yamahigashi 已提交
2742

L
Lewy Blue 已提交
2743
				if ( propName !== 'a' ) currentNode[ propName ] = propValue;
L
Lewy Blue 已提交
2744
				else currentNode.a = propValue;
Y
yamahigashi 已提交
2745

M
Mr.doob 已提交
2746
			}
Y
yamahigashi 已提交
2747

L
Lewy Blue 已提交
2748
			this.setCurrentProp( currentNode, propName );
Y
yamahigashi 已提交
2749

2750 2751 2752
			// convert string to array, unless it ends in ',' in which case more will be added to it
			if ( propName === 'a' && propValue.slice( - 1 ) !== ',' ) {

L
Lewy Blue 已提交
2753
				currentNode.a = parseNumberArray( propValue );
2754 2755 2756

			}

M
Mr.doob 已提交
2757
		},
Y
yamahigashi 已提交
2758

M
Mr.doob 已提交
2759
		parseNodePropertyContinued: function ( line ) {
Y
yamahigashi 已提交
2760

L
Lewy Blue 已提交
2761 2762 2763
			var currentNode = this.getCurrentNode();

			currentNode.a += line;
Y
yamahigashi 已提交
2764

2765 2766 2767 2768
			// if the line doesn't end in ',' we have reached the end of the property value
			// so convert the string to an array
			if ( line.slice( - 1 ) !== ',' ) {

L
Lewy Blue 已提交
2769
				currentNode.a = parseNumberArray( currentNode.a );
2770 2771 2772

			}

M
Mr.doob 已提交
2773
		},
Y
yamahigashi 已提交
2774

L
Lewy Blue 已提交
2775
		// parse "Property70"
M
Mr.doob 已提交
2776
		parseNodeSpecialProperty: function ( line, propName, propValue ) {
Y
yamahigashi 已提交
2777

M
Mr.doob 已提交
2778 2779 2780 2781
			// split this
			// P: "Lcl Scaling", "Lcl Scaling", "", "A",1,1,1
			// into array like below
			// ["Lcl Scaling", "Lcl Scaling", "", "A", "1,1,1" ]
2782
			var props = propValue.split( '",' ).map( function ( prop ) {
Y
yamahigashi 已提交
2783

2784
				return prop.trim().replace( /^\"/, '' ).replace( /\s/, '_' );
L
Lewy Blue 已提交
2785

2786
			} );
Y
yamahigashi 已提交
2787

M
Mr.doob 已提交
2788 2789 2790 2791 2792
			var innerPropName = props[ 0 ];
			var innerPropType1 = props[ 1 ];
			var innerPropType2 = props[ 2 ];
			var innerPropFlag = props[ 3 ];
			var innerPropValue = props[ 4 ];
Y
yamahigashi 已提交
2793

L
Lewy Blue 已提交
2794
			// cast values where needed, otherwise leave as strings
M
Mr.doob 已提交
2795
			switch ( innerPropType1 ) {
Y
yamahigashi 已提交
2796

M
Mugen87 已提交
2797
				case 'int':
2798 2799 2800
				case 'enum':
				case 'bool':
				case 'ULongLong':
M
Mugen87 已提交
2801
				case 'double':
2802 2803
				case 'Number':
				case 'FieldOfView':
M
Mr.doob 已提交
2804 2805
					innerPropValue = parseFloat( innerPropValue );
					break;
Y
yamahigashi 已提交
2806

M
Mugen87 已提交
2807 2808
				case 'ColorRGB':
				case 'Vector3D':
2809 2810 2811
				case 'Lcl_Translation':
				case 'Lcl_Rotation':
				case 'Lcl_Scaling':
2812
					innerPropValue = parseNumberArray( innerPropValue );
M
Mr.doob 已提交
2813
					break;
Y
yamahigashi 已提交
2814

M
Mr.doob 已提交
2815
			}
Y
yamahigashi 已提交
2816

M
Mr.doob 已提交
2817
			// CAUTION: these props must append to parent's parent
L
Lewy Blue 已提交
2818
			this.getPrevNode()[ innerPropName ] = {
Y
yamahigashi 已提交
2819

M
Mr.doob 已提交
2820 2821 2822 2823
				'type': innerPropType1,
				'type2': innerPropType2,
				'flag': innerPropFlag,
				'value': innerPropValue
Y
yamahigashi 已提交
2824

M
Mr.doob 已提交
2825
			};
Y
yamahigashi 已提交
2826

L
Lewy Blue 已提交
2827
			this.setCurrentProp( this.getPrevNode(), innerPropName );
Y
yamahigashi 已提交
2828

M
Mr.doob 已提交
2829
		},
2830

M
Mr.doob 已提交
2831
	} );
Y
yamahigashi 已提交
2832

L
Lewy Blue 已提交
2833
	// Parse an FBX file in Binary format
L
Lewy Blue 已提交
2834
	function BinaryParser() {}
Y
yamahigashi 已提交
2835

M
Mr.doob 已提交
2836
	Object.assign( BinaryParser.prototype, {
Y
yamahigashi 已提交
2837

M
Mr.doob 已提交
2838
		parse: function ( buffer ) {
Y
yamahigashi 已提交
2839

M
Mr.doob 已提交
2840 2841
			var reader = new BinaryReader( buffer );
			reader.skip( 23 ); // skip magic 23 bytes
Y
yamahigashi 已提交
2842

M
Mr.doob 已提交
2843
			var version = reader.getUint32();
Y
yamahigashi 已提交
2844

M
Mugen87 已提交
2845
			console.log( 'THREE.FBXLoader: FBX binary version: ' + version );
Y
yamahigashi 已提交
2846

M
Mr.doob 已提交
2847
			var allNodes = new FBXTree();
Y
yamahigashi 已提交
2848

M
Mr.doob 已提交
2849
			while ( ! this.endOfContent( reader ) ) {
Y
yamahigashi 已提交
2850

M
Mr.doob 已提交
2851 2852
				var node = this.parseNode( reader, version );
				if ( node !== null ) allNodes.add( node.name, node );
Y
yamahigashi 已提交
2853

M
Mr.doob 已提交
2854
			}
2855

M
Mr.doob 已提交
2856
			return allNodes;
Y
yamahigashi 已提交
2857

M
Mr.doob 已提交
2858
		},
Y
yamahigashi 已提交
2859

L
Lewy Blue 已提交
2860
		// Check if reader has reached the end of content.
L
Lewy Blue 已提交
2861
		endOfContent: function ( reader ) {
M
Mr.doob 已提交
2862 2863 2864

			// footer size: 160bytes + 16-byte alignment padding
			// - 16bytes: magic
2865
			// - padding til 16-byte alignment (at least 1byte?)
L
Lewy Blue 已提交
2866
			//	(seems like some exporters embed fixed 15 or 16bytes?)
M
Mr.doob 已提交
2867 2868 2869 2870 2871 2872
			// - 4bytes: magic
			// - 4bytes: version
			// - 120bytes: zero
			// - 16bytes: magic
			if ( reader.size() % 16 === 0 ) {

L
Lewy Blue 已提交
2873
				return ( ( reader.getOffset() + 160 + 16 ) & ~ 0xf ) >= reader.size();
Y
yamahigashi 已提交
2874

M
Mr.doob 已提交
2875
			} else {
Y
yamahigashi 已提交
2876

2877
				return reader.getOffset() + 160 + 16 >= reader.size();
Y
yamahigashi 已提交
2878

M
Mr.doob 已提交
2879
			}
Y
yamahigashi 已提交
2880

M
Mr.doob 已提交
2881
		},
Y
yamahigashi 已提交
2882

L
Lewy Blue 已提交
2883
		// recursively parse nodes until the end of the file is reached
M
Mr.doob 已提交
2884
		parseNode: function ( reader, version ) {
Y
yamahigashi 已提交
2885

L
Lewy Blue 已提交
2886 2887
			var node = {};

M
Mr.doob 已提交
2888 2889 2890
			// The first three data sizes depends on version.
			var endOffset = ( version >= 7500 ) ? reader.getUint64() : reader.getUint32();
			var numProperties = ( version >= 7500 ) ? reader.getUint64() : reader.getUint32();
L
tidying  
Lewy Blue 已提交
2891 2892

			// note: do not remove this even if you get a linter warning as it moves the buffer forward
M
Mr.doob 已提交
2893
			var propertyListLen = ( version >= 7500 ) ? reader.getUint64() : reader.getUint32();
L
tidying  
Lewy Blue 已提交
2894

M
Mr.doob 已提交
2895 2896
			var nameLen = reader.getUint8();
			var name = reader.getString( nameLen );
Y
yamahigashi 已提交
2897

M
Mr.doob 已提交
2898 2899
			// Regards this node as NULL-record if endOffset is zero
			if ( endOffset === 0 ) return null;
Y
yamahigashi 已提交
2900

M
Mr.doob 已提交
2901
			var propertyList = [];
Y
yamahigashi 已提交
2902

M
Mr.doob 已提交
2903
			for ( var i = 0; i < numProperties; i ++ ) {
Y
yamahigashi 已提交
2904

M
Mr.doob 已提交
2905
				propertyList.push( this.parseProperty( reader ) );
Y
yamahigashi 已提交
2906

M
Mr.doob 已提交
2907
			}
Y
yamahigashi 已提交
2908

M
Mr.doob 已提交
2909 2910 2911 2912
			// Regards the first three elements in propertyList as id, attrName, and attrType
			var id = propertyList.length > 0 ? propertyList[ 0 ] : '';
			var attrName = propertyList.length > 1 ? propertyList[ 1 ] : '';
			var attrType = propertyList.length > 2 ? propertyList[ 2 ] : '';
Y
yamahigashi 已提交
2913

L
Lewy Blue 已提交
2914
			// check if this node represents just a single property
M
Mr.doob 已提交
2915
			// like (name, 0) set or (name2, [0, 1, 2]) set of {name: 0, name2: [0, 1, 2]}
L
Lewy Blue 已提交
2916
			node.singleProperty = ( numProperties === 1 && reader.getOffset() === endOffset ) ? true : false;
Y
yamahigashi 已提交
2917

M
Mr.doob 已提交
2918
			while ( endOffset > reader.getOffset() ) {
Y
yamahigashi 已提交
2919

L
Lewy Blue 已提交
2920
				var subNode = this.parseNode( reader, version );
Y
yamahigashi 已提交
2921

L
Lewy Blue 已提交
2922
				if ( subNode !== null ) this.parseSubNode( name, node, subNode );
Y
yamahigashi 已提交
2923

L
Lewy Blue 已提交
2924
			}
Y
yamahigashi 已提交
2925

L
Lewy Blue 已提交
2926
			node.propertyList = propertyList; // raw property list used by parent
Y
yamahigashi 已提交
2927

L
Lewy Blue 已提交
2928 2929 2930 2931
			if ( typeof id === 'number' ) node.id = id;
			if ( attrName !== '' ) node.attrName = attrName;
			if ( attrType !== '' ) node.attrType = attrType;
			if ( name !== '' ) node.name = name;
Y
yamahigashi 已提交
2932

L
Lewy Blue 已提交
2933
			return node;
Y
yamahigashi 已提交
2934

L
Lewy Blue 已提交
2935
		},
Y
yamahigashi 已提交
2936

L
Lewy Blue 已提交
2937
		parseSubNode: function ( name, node, subNode ) {
L
Lewy Blue 已提交
2938

L
Lewy Blue 已提交
2939 2940
			// special case: child node is single property
			if ( subNode.singleProperty === true ) {
Y
yamahigashi 已提交
2941

L
Lewy Blue 已提交
2942
				var value = subNode.propertyList[ 0 ];
Y
yamahigashi 已提交
2943

L
Lewy Blue 已提交
2944
				if ( Array.isArray( value ) ) {
Y
yamahigashi 已提交
2945

L
Lewy Blue 已提交
2946
					node[ subNode.name ] = subNode;
Y
yamahigashi 已提交
2947

L
Lewy Blue 已提交
2948
					subNode.a = value;
Y
yamahigashi 已提交
2949

L
Lewy Blue 已提交
2950
				} else {
Y
yamahigashi 已提交
2951

L
Lewy Blue 已提交
2952
					node[ subNode.name ] = value;
Y
yamahigashi 已提交
2953

L
Lewy Blue 已提交
2954
				}
Y
yamahigashi 已提交
2955

L
Lewy Blue 已提交
2956
			} else if ( name === 'Connections' && subNode.name === 'C' ) {
Y
yamahigashi 已提交
2957

L
Lewy Blue 已提交
2958
				var array = [];
Y
yamahigashi 已提交
2959

L
Lewy Blue 已提交
2960
				subNode.propertyList.forEach( function ( property, i ) {
Y
yamahigashi 已提交
2961

L
Lewy Blue 已提交
2962
					// first Connection is FBX type (OO, OP, etc.). We'll discard these
L
Lewy Blue 已提交
2963
					if ( i !== 0 ) array.push( property );
Y
yamahigashi 已提交
2964

L
Lewy Blue 已提交
2965
				} );
Y
yamahigashi 已提交
2966

L
Lewy Blue 已提交
2967
				if ( node.connections === undefined ) {
Y
yamahigashi 已提交
2968

L
Lewy Blue 已提交
2969
					node.connections = [];
Y
yamahigashi 已提交
2970

M
Mr.doob 已提交
2971
				}
Y
yamahigashi 已提交
2972

L
Lewy Blue 已提交
2973
				node.connections.push( array );
Y
yamahigashi 已提交
2974

L
Lewy Blue 已提交
2975
			} else if ( subNode.name === 'Properties70' ) {
Y
yamahigashi 已提交
2976

L
Lewy Blue 已提交
2977
				var keys = Object.keys( subNode );
Y
yamahigashi 已提交
2978

L
Lewy Blue 已提交
2979
				keys.forEach( function ( key ) {
Y
yamahigashi 已提交
2980

L
Lewy Blue 已提交
2981
					node[ key ] = subNode[ key ];
Y
yamahigashi 已提交
2982

L
Lewy Blue 已提交
2983
				} );
Y
yamahigashi 已提交
2984

L
Lewy Blue 已提交
2985
			} else if ( name === 'Properties70' && subNode.name === 'P' ) {
Y
yamahigashi 已提交
2986

L
Lewy Blue 已提交
2987 2988 2989 2990 2991
				var innerPropName = subNode.propertyList[ 0 ];
				var innerPropType1 = subNode.propertyList[ 1 ];
				var innerPropType2 = subNode.propertyList[ 2 ];
				var innerPropFlag = subNode.propertyList[ 3 ];
				var innerPropValue;
Y
yamahigashi 已提交
2992

L
Lewy Blue 已提交
2993 2994
				if ( innerPropName.indexOf( 'Lcl ' ) === 0 ) innerPropName = innerPropName.replace( 'Lcl ', 'Lcl_' );
				if ( innerPropType1.indexOf( 'Lcl ' ) === 0 ) innerPropType1 = innerPropType1.replace( 'Lcl ', 'Lcl_' );
Y
yamahigashi 已提交
2995

L
Lewy Blue 已提交
2996
				if ( innerPropType1 === 'ColorRGB' || innerPropType1 === 'Vector' || innerPropType1 === 'Vector3D' || innerPropType1.indexOf( 'Lcl_' ) === 0 ) {
Y
yamahigashi 已提交
2997

L
Lewy Blue 已提交
2998 2999 3000 3001 3002
					innerPropValue = [
						subNode.propertyList[ 4 ],
						subNode.propertyList[ 5 ],
						subNode.propertyList[ 6 ]
					];
Y
yamahigashi 已提交
3003

L
Lewy Blue 已提交
3004
				} else {
Y
yamahigashi 已提交
3005

L
Lewy Blue 已提交
3006
					innerPropValue = subNode.propertyList[ 4 ];
Y
yamahigashi 已提交
3007

M
Mr.doob 已提交
3008
				}
Y
yamahigashi 已提交
3009

L
Lewy Blue 已提交
3010 3011
				// this will be copied to parent, see above
				node[ innerPropName ] = {
Y
yamahigashi 已提交
3012

L
Lewy Blue 已提交
3013 3014 3015 3016
					'type': innerPropType1,
					'type2': innerPropType2,
					'flag': innerPropFlag,
					'value': innerPropValue
K
Kyle Larson 已提交
3017

L
Lewy Blue 已提交
3018
				};
Y
yamahigashi 已提交
3019

L
Lewy Blue 已提交
3020
			} else if ( node[ subNode.name ] === undefined ) {
Y
yamahigashi 已提交
3021

L
Lewy Blue 已提交
3022
				if ( typeof subNode.id === 'number' ) {
Y
yamahigashi 已提交
3023

L
Lewy Blue 已提交
3024 3025
					node[ subNode.name ] = {};
					node[ subNode.name ][ subNode.id ] = subNode;
Y
yamahigashi 已提交
3026

M
Mr.doob 已提交
3027
				} else {
Y
yamahigashi 已提交
3028

L
Lewy Blue 已提交
3029
					node[ subNode.name ] = subNode;
Y
yamahigashi 已提交
3030

L
Lewy Blue 已提交
3031
				}
Y
yamahigashi 已提交
3032

L
Lewy Blue 已提交
3033
			} else {
Y
yamahigashi 已提交
3034

L
Lewy Blue 已提交
3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049
				if ( subNode.name === 'PoseNode' ) {

					if ( ! Array.isArray( node[ subNode.name ] ) ) {

						node[ subNode.name ] = [ node[ subNode.name ] ];

					}

					node[ subNode.name ].push( subNode );

				} else if ( node[ subNode.name ][ subNode.id ] === undefined ) {

					node[ subNode.name ][ subNode.id ] = subNode;

				}
L
Lewy Blue 已提交
3050

L
Lewy Blue 已提交
3051
			}
L
Lewy Blue 已提交
3052

M
Mr.doob 已提交
3053
		},
K
Kyle Larson 已提交
3054

M
Mr.doob 已提交
3055
		parseProperty: function ( reader ) {
K
Kyle Larson 已提交
3056

L
Lewy Blue 已提交
3057
			var type = reader.getString( 1 );
K
Kyle Larson 已提交
3058

M
Mr.doob 已提交
3059
			switch ( type ) {
K
Kyle Larson 已提交
3060

3061 3062
				case 'C':
					return reader.getBoolean();
K
Kyle Larson 已提交
3063

M
Mr.doob 已提交
3064 3065
				case 'D':
					return reader.getFloat64();
K
Kyle Larson 已提交
3066

3067 3068
				case 'F':
					return reader.getFloat32();
K
Kyle Larson 已提交
3069

M
Mr.doob 已提交
3070 3071
				case 'I':
					return reader.getInt32();
K
Kyle Larson 已提交
3072

3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083
				case 'L':
					return reader.getInt64();

				case 'R':
					var length = reader.getUint32();
					return reader.getArrayBuffer( length );

				case 'S':
					var length = reader.getUint32();
					return reader.getString( length );

M
Mr.doob 已提交
3084 3085
				case 'Y':
					return reader.getInt16();
K
Kyle Larson 已提交
3086

3087 3088
				case 'b':
				case 'c':
M
Mr.doob 已提交
3089
				case 'd':
3090
				case 'f':
M
Mr.doob 已提交
3091
				case 'i':
3092
				case 'l':
K
Kyle Larson 已提交
3093

M
Mr.doob 已提交
3094 3095 3096
					var arrayLength = reader.getUint32();
					var encoding = reader.getUint32(); // 0: non-compressed, 1: compressed
					var compressedLength = reader.getUint32();
K
Kyle Larson 已提交
3097

M
Mr.doob 已提交
3098
					if ( encoding === 0 ) {
K
Kyle Larson 已提交
3099

M
Mr.doob 已提交
3100
						switch ( type ) {
K
Kyle Larson 已提交
3101

3102 3103 3104
							case 'b':
							case 'c':
								return reader.getBooleanArray( arrayLength );
K
Kyle Larson 已提交
3105

M
Mr.doob 已提交
3106 3107
							case 'd':
								return reader.getFloat64Array( arrayLength );
K
Kyle Larson 已提交
3108

3109 3110
							case 'f':
								return reader.getFloat32Array( arrayLength );
K
Kyle Larson 已提交
3111

M
Mr.doob 已提交
3112 3113
							case 'i':
								return reader.getInt32Array( arrayLength );
Y
yamahigashi 已提交
3114

3115 3116
							case 'l':
								return reader.getInt64Array( arrayLength );
Y
yamahigashi 已提交
3117

M
Mr.doob 已提交
3118
						}
Y
yamahigashi 已提交
3119

M
Mr.doob 已提交
3120
					}
Y
yamahigashi 已提交
3121

M
Mr.doob 已提交
3122
					if ( window.Zlib === undefined ) {
Y
yamahigashi 已提交
3123

3124
						console.error( 'THREE.FBXLoader: External library Inflate.min.js required, obtain or import from https://github.com/imaya/zlib.js' );
Y
yamahigashi 已提交
3125

M
Mr.doob 已提交
3126
					}
Y
yamahigashi 已提交
3127

L
Lewy Blue 已提交
3128
					var inflate = new Zlib.Inflate( new Uint8Array( reader.getArrayBuffer( compressedLength ) ) ); // eslint-disable-line no-undef
M
Mr.doob 已提交
3129
					var reader2 = new BinaryReader( inflate.decompress().buffer );
Y
yamahigashi 已提交
3130

M
Mr.doob 已提交
3131
					switch ( type ) {
Y
yamahigashi 已提交
3132

3133 3134 3135
						case 'b':
						case 'c':
							return reader2.getBooleanArray( arrayLength );
Y
yamahigashi 已提交
3136

M
Mr.doob 已提交
3137 3138
						case 'd':
							return reader2.getFloat64Array( arrayLength );
Y
yamahigashi 已提交
3139

3140 3141
						case 'f':
							return reader2.getFloat32Array( arrayLength );
Y
yamahigashi 已提交
3142

M
Mr.doob 已提交
3143 3144
						case 'i':
							return reader2.getInt32Array( arrayLength );
Y
yamahigashi 已提交
3145

3146 3147
						case 'l':
							return reader2.getInt64Array( arrayLength );
Y
yamahigashi 已提交
3148

M
Mr.doob 已提交
3149
					}
Y
yamahigashi 已提交
3150

M
Mr.doob 已提交
3151
				default:
M
Mugen87 已提交
3152
					throw new Error( 'THREE.FBXLoader: Unknown property type ' + type );
Y
yamahigashi 已提交
3153

M
Mr.doob 已提交
3154
			}
Y
yamahigashi 已提交
3155

M
Mr.doob 已提交
3156
		}
Y
yamahigashi 已提交
3157

M
Mr.doob 已提交
3158
	} );
Y
yamahigashi 已提交
3159 3160


M
Mr.doob 已提交
3161
	function BinaryReader( buffer, littleEndian ) {
Y
yamahigashi 已提交
3162

M
Mr.doob 已提交
3163 3164 3165
		this.dv = new DataView( buffer );
		this.offset = 0;
		this.littleEndian = ( littleEndian !== undefined ) ? littleEndian : true;
Y
yamahigashi 已提交
3166

M
Mr.doob 已提交
3167
	}
Y
yamahigashi 已提交
3168

M
Mr.doob 已提交
3169
	Object.assign( BinaryReader.prototype, {
Y
yamahigashi 已提交
3170

M
Mr.doob 已提交
3171
		getOffset: function () {
Y
yamahigashi 已提交
3172

M
Mr.doob 已提交
3173
			return this.offset;
Y
yamahigashi 已提交
3174

M
Mr.doob 已提交
3175
		},
Y
yamahigashi 已提交
3176

M
Mr.doob 已提交
3177
		size: function () {
Y
yamahigashi 已提交
3178

M
Mr.doob 已提交
3179
			return this.dv.buffer.byteLength;
Y
yamahigashi 已提交
3180

M
Mr.doob 已提交
3181
		},
Y
yamahigashi 已提交
3182

M
Mr.doob 已提交
3183
		skip: function ( length ) {
Y
yamahigashi 已提交
3184

M
Mr.doob 已提交
3185
			this.offset += length;
Y
yamahigashi 已提交
3186

M
Mr.doob 已提交
3187
		},
Y
yamahigashi 已提交
3188

M
Mr.doob 已提交
3189
		// seems like true/false representation depends on exporter.
L
Lewy Blue 已提交
3190
		// true: 1 or 'Y'(=0x59), false: 0 or 'T'(=0x54)
M
Mr.doob 已提交
3191 3192
		// then sees LSB.
		getBoolean: function () {
Y
yamahigashi 已提交
3193

M
Mr.doob 已提交
3194
			return ( this.getUint8() & 1 ) === 1;
Y
yamahigashi 已提交
3195

M
Mr.doob 已提交
3196
		},
Y
yamahigashi 已提交
3197

M
Mr.doob 已提交
3198
		getBooleanArray: function ( size ) {
Y
yamahigashi 已提交
3199

M
Mr.doob 已提交
3200
			var a = [];
Y
yamahigashi 已提交
3201

M
Mr.doob 已提交
3202
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3203

M
Mr.doob 已提交
3204
				a.push( this.getBoolean() );
Y
yamahigashi 已提交
3205 3206 3207

			}

M
Mr.doob 已提交
3208
			return a;
Y
yamahigashi 已提交
3209

M
Mr.doob 已提交
3210
		},
Y
yamahigashi 已提交
3211

M
Mr.doob 已提交
3212
		getUint8: function () {
Y
yamahigashi 已提交
3213

M
Mr.doob 已提交
3214 3215 3216
			var value = this.dv.getUint8( this.offset );
			this.offset += 1;
			return value;
Y
yamahigashi 已提交
3217

M
Mr.doob 已提交
3218
		},
Y
yamahigashi 已提交
3219

M
Mr.doob 已提交
3220
		getInt16: function () {
Y
yamahigashi 已提交
3221

M
Mr.doob 已提交
3222 3223 3224
			var value = this.dv.getInt16( this.offset, this.littleEndian );
			this.offset += 2;
			return value;
Y
yamahigashi 已提交
3225

M
Mr.doob 已提交
3226
		},
Y
yamahigashi 已提交
3227

M
Mr.doob 已提交
3228
		getInt32: function () {
3229

M
Mr.doob 已提交
3230 3231 3232
			var value = this.dv.getInt32( this.offset, this.littleEndian );
			this.offset += 4;
			return value;
3233

M
Mr.doob 已提交
3234
		},
3235

M
Mr.doob 已提交
3236
		getInt32Array: function ( size ) {
3237

M
Mr.doob 已提交
3238
			var a = [];
3239

M
Mr.doob 已提交
3240
			for ( var i = 0; i < size; i ++ ) {
3241

M
Mr.doob 已提交
3242
				a.push( this.getInt32() );
3243 3244 3245

			}

M
Mr.doob 已提交
3246
			return a;
3247

M
Mr.doob 已提交
3248
		},
3249

M
Mr.doob 已提交
3250
		getUint32: function () {
3251

M
Mr.doob 已提交
3252 3253 3254 3255 3256
			var value = this.dv.getUint32( this.offset, this.littleEndian );
			this.offset += 4;
			return value;

		},
3257

L
Lewy Blue 已提交
3258
		// JavaScript doesn't support 64-bit integer so calculate this here
M
Mr.doob 已提交
3259
		// 1 << 32 will return 1 so using multiply operation instead here.
L
Lewy Blue 已提交
3260
		// There's a possibility that this method returns wrong value if the value
M
Mr.doob 已提交
3261 3262 3263
		// is out of the range between Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER.
		// TODO: safely handle 64-bit integer
		getInt64: function () {
3264

M
Mr.doob 已提交
3265
			var low, high;
3266

M
Mr.doob 已提交
3267
			if ( this.littleEndian ) {
3268

M
Mr.doob 已提交
3269 3270
				low = this.getUint32();
				high = this.getUint32();
3271

M
Mr.doob 已提交
3272
			} else {
3273

M
Mr.doob 已提交
3274 3275
				high = this.getUint32();
				low = this.getUint32();
3276

M
Mr.doob 已提交
3277
			}
3278

M
Mr.doob 已提交
3279 3280
			// calculate negative value
			if ( high & 0x80000000 ) {
3281

L
Lewy Blue 已提交
3282 3283
				high = ~ high & 0xFFFFFFFF;
				low = ~ low & 0xFFFFFFFF;
3284

M
Mr.doob 已提交
3285
				if ( low === 0xFFFFFFFF ) high = ( high + 1 ) & 0xFFFFFFFF;
3286

M
Mr.doob 已提交
3287
				low = ( low + 1 ) & 0xFFFFFFFF;
3288

M
Mr.doob 已提交
3289
				return - ( high * 0x100000000 + low );
3290

M
Mr.doob 已提交
3291
			}
3292

M
Mr.doob 已提交
3293
			return high * 0x100000000 + low;
3294

M
Mr.doob 已提交
3295
		},
3296

M
Mr.doob 已提交
3297
		getInt64Array: function ( size ) {
3298

M
Mr.doob 已提交
3299
			var a = [];
3300

M
Mr.doob 已提交
3301
			for ( var i = 0; i < size; i ++ ) {
3302

M
Mr.doob 已提交
3303
				a.push( this.getInt64() );
3304 3305 3306

			}

M
Mr.doob 已提交
3307 3308 3309
			return a;

		},
3310

M
Mr.doob 已提交
3311 3312
		// Note: see getInt64() comment
		getUint64: function () {
3313

M
Mr.doob 已提交
3314
			var low, high;
3315

M
Mr.doob 已提交
3316 3317 3318 3319 3320 3321 3322 3323 3324
			if ( this.littleEndian ) {

				low = this.getUint32();
				high = this.getUint32();

			} else {

				high = this.getUint32();
				low = this.getUint32();
3325 3326

			}
3327

M
Mr.doob 已提交
3328
			return high * 0x100000000 + low;
3329

M
Mr.doob 已提交
3330
		},
Y
yamahigashi 已提交
3331

M
Mr.doob 已提交
3332
		getFloat32: function () {
Y
yamahigashi 已提交
3333

M
Mr.doob 已提交
3334 3335 3336
			var value = this.dv.getFloat32( this.offset, this.littleEndian );
			this.offset += 4;
			return value;
Y
yamahigashi 已提交
3337

M
Mr.doob 已提交
3338
		},
Y
yamahigashi 已提交
3339

M
Mr.doob 已提交
3340
		getFloat32Array: function ( size ) {
Y
yamahigashi 已提交
3341

M
Mr.doob 已提交
3342
			var a = [];
Y
yamahigashi 已提交
3343

M
Mr.doob 已提交
3344
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3345

M
Mr.doob 已提交
3346
				a.push( this.getFloat32() );
Y
yamahigashi 已提交
3347 3348 3349

			}

M
Mr.doob 已提交
3350
			return a;
Y
yamahigashi 已提交
3351

M
Mr.doob 已提交
3352
		},
Y
yamahigashi 已提交
3353

M
Mr.doob 已提交
3354
		getFloat64: function () {
Y
yamahigashi 已提交
3355

M
Mr.doob 已提交
3356 3357 3358
			var value = this.dv.getFloat64( this.offset, this.littleEndian );
			this.offset += 8;
			return value;
Y
yamahigashi 已提交
3359

M
Mr.doob 已提交
3360
		},
Y
yamahigashi 已提交
3361

M
Mr.doob 已提交
3362
		getFloat64Array: function ( size ) {
Y
yamahigashi 已提交
3363

M
Mr.doob 已提交
3364
			var a = [];
Y
yamahigashi 已提交
3365

M
Mr.doob 已提交
3366
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3367

M
Mr.doob 已提交
3368
				a.push( this.getFloat64() );
Y
yamahigashi 已提交
3369

M
Mr.doob 已提交
3370
			}
Y
yamahigashi 已提交
3371

M
Mr.doob 已提交
3372
			return a;
Y
yamahigashi 已提交
3373

M
Mr.doob 已提交
3374
		},
Y
yamahigashi 已提交
3375

M
Mr.doob 已提交
3376
		getArrayBuffer: function ( size ) {
Y
yamahigashi 已提交
3377

M
Mr.doob 已提交
3378 3379 3380
			var value = this.dv.buffer.slice( this.offset, this.offset + size );
			this.offset += size;
			return value;
Y
yamahigashi 已提交
3381

M
Mr.doob 已提交
3382
		},
Y
yamahigashi 已提交
3383

L
Lewy Blue 已提交
3384
		getString: function ( size ) {
Y
yamahigashi 已提交
3385

L
Lewy Blue 已提交
3386
			var a = new Uint8Array( size );
Y
yamahigashi 已提交
3387

L
Lewy Blue 已提交
3388
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3389

L
Lewy Blue 已提交
3390 3391 3392
				a[ i ] = this.getUint8();

			}
Y
yamahigashi 已提交
3393

L
Lewy Blue 已提交
3394 3395
			var nullByte = a.indexOf( 0 );
			if ( nullByte >= 0 ) a = a.slice( 0, nullByte );
Y
yamahigashi 已提交
3396

L
Lewy Blue 已提交
3397
			return THREE.LoaderUtils.decodeText( a );
Y
yamahigashi 已提交
3398

M
Mr.doob 已提交
3399
		}
Y
yamahigashi 已提交
3400

M
Mr.doob 已提交
3401
	} );
Y
yamahigashi 已提交
3402

L
Lewy Blue 已提交
3403 3404
	// FBXTree holds a representation of the FBX data, returned by the TextParser ( FBX ASCII format)
	// and BinaryParser( FBX Binary format)
L
Lewy Blue 已提交
3405
	function FBXTree() {}
Y
yamahigashi 已提交
3406

M
Mr.doob 已提交
3407
	Object.assign( FBXTree.prototype, {
Y
yamahigashi 已提交
3408

M
Mr.doob 已提交
3409
		add: function ( key, val ) {
Y
yamahigashi 已提交
3410

M
Mr.doob 已提交
3411
			this[ key ] = val;
Y
yamahigashi 已提交
3412

M
Mr.doob 已提交
3413
		},
Y
yamahigashi 已提交
3414

M
Mr.doob 已提交
3415
	} );
Y
yamahigashi 已提交
3416

M
Mr.doob 已提交
3417
	function isFbxFormatBinary( buffer ) {
Y
yamahigashi 已提交
3418

M
Mr.doob 已提交
3419
		var CORRECT = 'Kaydara FBX Binary  \0';
Y
yamahigashi 已提交
3420

M
Mr.doob 已提交
3421
		return buffer.byteLength >= CORRECT.length && CORRECT === convertArrayBufferToString( buffer, 0, CORRECT.length );
Y
yamahigashi 已提交
3422

M
Mr.doob 已提交
3423
	}
Y
yamahigashi 已提交
3424

M
Mr.doob 已提交
3425
	function isFbxFormatASCII( text ) {
Y
yamahigashi 已提交
3426

M
Mr.doob 已提交
3427
		var CORRECT = [ 'K', 'a', 'y', 'd', 'a', 'r', 'a', '\\', 'F', 'B', 'X', '\\', 'B', 'i', 'n', 'a', 'r', 'y', '\\', '\\' ];
Y
yamahigashi 已提交
3428

M
Mr.doob 已提交
3429
		var cursor = 0;
Y
yamahigashi 已提交
3430

M
Mr.doob 已提交
3431
		function read( offset ) {
Y
yamahigashi 已提交
3432

M
Mr.doob 已提交
3433 3434 3435 3436
			var result = text[ offset - 1 ];
			text = text.slice( cursor + offset );
			cursor ++;
			return result;
Y
yamahigashi 已提交
3437 3438 3439

		}

M
Mr.doob 已提交
3440
		for ( var i = 0; i < CORRECT.length; ++ i ) {
Y
yamahigashi 已提交
3441

M
Mr.doob 已提交
3442
			var num = read( 1 );
M
Mugen87 已提交
3443
			if ( num === CORRECT[ i ] ) {
Y
yamahigashi 已提交
3444

M
Mr.doob 已提交
3445
				return false;
Y
yamahigashi 已提交
3446 3447 3448

			}

M
Mr.doob 已提交
3449
		}
Y
yamahigashi 已提交
3450

M
Mr.doob 已提交
3451
		return true;
Y
yamahigashi 已提交
3452

M
Mr.doob 已提交
3453
	}
Y
yamahigashi 已提交
3454

M
Mr.doob 已提交
3455
	function getFbxVersion( text ) {
Y
yamahigashi 已提交
3456

M
Mr.doob 已提交
3457 3458 3459 3460 3461 3462
		var versionRegExp = /FBXVersion: (\d+)/;
		var match = text.match( versionRegExp );
		if ( match ) {

			var version = parseInt( match[ 1 ] );
			return version;
Y
yamahigashi 已提交
3463 3464

		}
M
Mugen87 已提交
3465
		throw new Error( 'THREE.FBXLoader: Cannot find the version number for the file given.' );
Y
yamahigashi 已提交
3466

M
Mr.doob 已提交
3467 3468
	}

L
Lewy Blue 已提交
3469
	// Converts FBX ticks into real time seconds.
M
Mr.doob 已提交
3470 3471 3472
	function convertFBXTimeToSeconds( time ) {

		return time / 46186158000;
Y
yamahigashi 已提交
3473

K
Kyle Larson 已提交
3474
	}
Y
yamahigashi 已提交
3475

L
Lewy Blue 已提交
3476 3477 3478

	// Parses comma separated list of numbers and returns them an array.
	// Used internally by the TextParser
3479
	function parseNumberArray( value ) {
Y
yamahigashi 已提交
3480

3481
		var array = value.split( ',' ).map( function ( val ) {
Y
yamahigashi 已提交
3482

3483
			return parseFloat( val );
Y
yamahigashi 已提交
3484

3485
		} );
Y
yamahigashi 已提交
3486

M
Mr.doob 已提交
3487
		return array;
Y
yamahigashi 已提交
3488

M
Mr.doob 已提交
3489
	}
Y
yamahigashi 已提交
3490

M
Mr.doob 已提交
3491
	function parseColor( property ) {
Y
yamahigashi 已提交
3492

L
Lewy Blue 已提交
3493 3494
		var color = new THREE.Color();

3495 3496
		if ( property.type === 'Color' ) {

L
Lewy Blue 已提交
3497
			return color.setScalar( property.value );
3498

L
Lewy Blue 已提交
3499
		}
Y
yamahigashi 已提交
3500

L
Lewy Blue 已提交
3501 3502
		return color.fromArray( property.value );

Y
yamahigashi 已提交
3503 3504
	}

M
Mr.doob 已提交
3505
	function convertArrayBufferToString( buffer, from, to ) {
Y
yamahigashi 已提交
3506

M
Mr.doob 已提交
3507 3508
		if ( from === undefined ) from = 0;
		if ( to === undefined ) to = buffer.byteLength;
Y
yamahigashi 已提交
3509

3510
		return THREE.LoaderUtils.decodeText( new Uint8Array( buffer, from, to ) );
Y
yamahigashi 已提交
3511

M
Mr.doob 已提交
3512
	}
Y
yamahigashi 已提交
3513

M
Mr.doob 已提交
3514
	function append( a, b ) {
Y
yamahigashi 已提交
3515

M
Mr.doob 已提交
3516
		for ( var i = 0, j = a.length, l = b.length; i < l; i ++, j ++ ) {
Y
yamahigashi 已提交
3517

M
Mr.doob 已提交
3518
			a[ j ] = b[ i ];
Y
yamahigashi 已提交
3519

M
Mr.doob 已提交
3520
		}
Y
yamahigashi 已提交
3521

3522
	}
Y
yamahigashi 已提交
3523

M
Mr.doob 已提交
3524 3525 3526 3527 3528 3529 3530
	function slice( a, b, from, to ) {

		for ( var i = from, j = 0; i < to; i ++, j ++ ) {

			a[ j ] = b[ i ];

		}
Y
yamahigashi 已提交
3531

M
Mr.doob 已提交
3532
		return a;
Y
yamahigashi 已提交
3533

3534
	}
Y
yamahigashi 已提交
3535 3536

} )();