FBXLoader.js 98.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
 * Loader loads FBX file and generates Group representing FBX scene.
L
Lewy Blue 已提交
7 8
 * Requires FBX file to be >= 7.0 and in ASCII or >= 6400 in Binary format
 * Versions lower than this may load but will probably have errors
Y
yamahigashi 已提交
9
 *
M
Mr.doob 已提交
10
 * Needs Support:
L
Lewy Blue 已提交
11
 *  Morph normals / blend shape normals
L
Lewy Blue 已提交
12 13 14
 *
 * FBX format references:
 * 	https://wiki.blender.org/index.php/User:Mont29/Foundation/FBX_File_Structure
L
Lewy Blue 已提交
15
 * 	http://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_index_html (C++ SDK reference)
L
Lewy Blue 已提交
16 17 18
 *
 * 	Binary format specification:
 *		https://code.blender.org/2013/08/fbx-binary-file-format-specification/
Y
yamahigashi 已提交
19 20
 */

L
Lewy Blue 已提交
21

22
THREE.FBXLoader = ( function () {
Y
yamahigashi 已提交
23

24
	var fbxTree;
25
	var connections;
26
	var sceneGraph;
L
Lewy Blue 已提交
27

28
	function FBXLoader( manager ) {
Y
yamahigashi 已提交
29

30
		THREE.Loader.call( this, manager );
Y
yamahigashi 已提交
31

32
	}
Y
yamahigashi 已提交
33

34
	FBXLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype ), {
35 36

		constructor: FBXLoader,
Y
yamahigashi 已提交
37

38
		load: function ( url, onLoad, onProgress, onError ) {
39

W
WestLangley 已提交
40
			var scope = this;
Y
yamahigashi 已提交
41

W
WestLangley 已提交
42
			var path = ( scope.path === '' ) ? THREE.LoaderUtils.extractUrlBase( url ) : scope.path;
Y
yamahigashi 已提交
43

M
Mr.doob 已提交
44
			var loader = new THREE.FileLoader( this.manager );
W
WestLangley 已提交
45
			loader.setPath( scope.path );
M
Mr.doob 已提交
46
			loader.setResponseType( 'arraybuffer' );
L
Lewy Blue 已提交
47

M
Mr.doob 已提交
48
			loader.load( url, function ( buffer ) {
Y
yamahigashi 已提交
49

L
Lewy Blue 已提交
50 51
				try {

W
WestLangley 已提交
52
					onLoad( scope.parse( buffer, path ) );
L
Lewy Blue 已提交
53 54 55 56 57 58 59

				} catch ( error ) {

					setTimeout( function () {

						if ( onError ) onError( error );

W
WestLangley 已提交
60
						scope.manager.itemError( url );
L
Lewy Blue 已提交
61 62 63 64

					}, 0 );

				}
Y
yamahigashi 已提交
65

L
Lewy Blue 已提交
66
			}, onProgress, onError );
Y
yamahigashi 已提交
67

L
Lewy Blue 已提交
68
		},
Y
yamahigashi 已提交
69

L
Lewy Blue 已提交
70
		parse: function ( FBXBuffer, path ) {
Y
yamahigashi 已提交
71

M
Mr.doob 已提交
72
			if ( isFbxFormatBinary( FBXBuffer ) ) {
Y
yamahigashi 已提交
73

74
				fbxTree = new BinaryParser().parse( FBXBuffer );
Y
yamahigashi 已提交
75

M
Mr.doob 已提交
76
			} else {
Y
yamahigashi 已提交
77

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

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

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

84
				}
Y
yamahigashi 已提交
85

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

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

M
Mr.doob 已提交
90
				}
Y
yamahigashi 已提交
91

92
				fbxTree = new TextParser().parse( FBXText );
Y
yamahigashi 已提交
93

94
			}
M
Mr.doob 已提交
95

96
			// console.log( fbxTree );
M
Mr.doob 已提交
97

L
Lewy Blue 已提交
98
			var textureLoader = new THREE.TextureLoader( this.manager ).setPath( this.resourcePath || path ).setCrossOrigin( this.crossOrigin );
99

M
Mugen87 已提交
100
			return new FBXTreeParser( textureLoader, this.manager ).parse( fbxTree );
Y
yamahigashi 已提交
101

M
Mr.doob 已提交
102
		}
M
Mr.doob 已提交
103

104
	} );
Y
yamahigashi 已提交
105

L
Lewy Blue 已提交
106
	// Parse the FBXTree object returned by the BinaryParser or TextParser and return a THREE.Group
M
Mugen87 已提交
107
	function FBXTreeParser( textureLoader, manager ) {
K
Kyle Larson 已提交
108

L
Lewy Blue 已提交
109
		this.textureLoader = textureLoader;
M
Mugen87 已提交
110
		this.manager = manager;
Y
yamahigashi 已提交
111

L
Lewy Blue 已提交
112
	}
Y
yamahigashi 已提交
113

L
Lewy Blue 已提交
114
	FBXTreeParser.prototype = {
Y
yamahigashi 已提交
115

L
Lewy Blue 已提交
116
		constructor: FBXTreeParser,
Y
yamahigashi 已提交
117

L
Lewy Blue 已提交
118
		parse: function () {
Y
yamahigashi 已提交
119

120
			connections = this.parseConnections();
L
Lewy Blue 已提交
121

L
Lewy Blue 已提交
122 123 124 125
			var images = this.parseImages();
			var textures = this.parseTextures( images );
			var materials = this.parseMaterials( textures );
			var deformers = this.parseDeformers();
126
			var geometryMap = new GeometryParser().parse( deformers );
Y
yamahigashi 已提交
127

L
Lewy Blue 已提交
128 129 130
			this.parseScene( deformers, geometryMap, materials );

			return sceneGraph;
Y
yamahigashi 已提交
131

L
Lewy Blue 已提交
132
		},
Y
yamahigashi 已提交
133

L
Lewy Blue 已提交
134 135 136
		// Parses FBXTree.Connections which holds parent-child connections between objects (e.g. material -> texture, model->geometry )
		// and details the connection type
		parseConnections: function () {
Y
yamahigashi 已提交
137

L
Lewy Blue 已提交
138
			var connectionMap = new Map();
Y
yamahigashi 已提交
139

140
			if ( 'Connections' in fbxTree ) {
Y
yamahigashi 已提交
141

142
				var rawConnections = fbxTree.Connections.connections;
Y
yamahigashi 已提交
143

L
Lewy Blue 已提交
144
				rawConnections.forEach( function ( rawConnection ) {
Y
yamahigashi 已提交
145

L
Lewy Blue 已提交
146 147 148
					var fromID = rawConnection[ 0 ];
					var toID = rawConnection[ 1 ];
					var relationship = rawConnection[ 2 ];
K
Kyle Larson 已提交
149

L
Lewy Blue 已提交
150
					if ( ! connectionMap.has( fromID ) ) {
K
Kyle Larson 已提交
151

L
Lewy Blue 已提交
152 153 154 155
						connectionMap.set( fromID, {
							parents: [],
							children: []
						} );
K
Kyle Larson 已提交
156

L
Lewy Blue 已提交
157
					}
K
Kyle Larson 已提交
158

L
Lewy Blue 已提交
159 160
					var parentRelationship = { ID: toID, relationship: relationship };
					connectionMap.get( fromID ).parents.push( parentRelationship );
K
Kyle Larson 已提交
161

L
Lewy Blue 已提交
162
					if ( ! connectionMap.has( toID ) ) {
K
Kyle Larson 已提交
163

L
Lewy Blue 已提交
164 165 166 167
						connectionMap.set( toID, {
							parents: [],
							children: []
						} );
K
Kyle Larson 已提交
168

L
Lewy Blue 已提交
169
					}
170

L
Lewy Blue 已提交
171 172
					var childRelationship = { ID: fromID, relationship: relationship };
					connectionMap.get( toID ).children.push( childRelationship );
173

L
Lewy Blue 已提交
174
				} );
175

L
Lewy Blue 已提交
176
			}
K
Kyle Larson 已提交
177

L
Lewy Blue 已提交
178
			return connectionMap;
179

L
Lewy Blue 已提交
180
		},
K
Kyle Larson 已提交
181

L
Lewy Blue 已提交
182 183 184 185
		// Parse FBXTree.Objects.Video for embedded image data
		// These images are connected to textures in FBXTree.Objects.Textures
		// via FBXTree.Connections.
		parseImages: function () {
186

L
Lewy Blue 已提交
187 188
			var images = {};
			var blobs = {};
K
Kyle Larson 已提交
189

190
			if ( 'Video' in fbxTree.Objects ) {
K
Kyle Larson 已提交
191

192
				var videoNodes = fbxTree.Objects.Video;
K
Kyle Larson 已提交
193

L
Lewy Blue 已提交
194
				for ( var nodeID in videoNodes ) {
K
Kyle Larson 已提交
195

L
Lewy Blue 已提交
196
					var videoNode = videoNodes[ nodeID ];
197

L
Lewy Blue 已提交
198
					var id = parseInt( nodeID );
199

L
Lewy Blue 已提交
200
					images[ id ] = videoNode.RelativeFilename || videoNode.Filename;
201

L
Lewy Blue 已提交
202 203
					// raw image data is in videoNode.Content
					if ( 'Content' in videoNode ) {
204

L
Lewy Blue 已提交
205 206
						var arrayBufferContent = ( videoNode.Content instanceof ArrayBuffer ) && ( videoNode.Content.byteLength > 0 );
						var base64Content = ( typeof videoNode.Content === 'string' ) && ( videoNode.Content !== '' );
K
Kyle Larson 已提交
207

L
Lewy Blue 已提交
208
						if ( arrayBufferContent || base64Content ) {
K
Kyle Larson 已提交
209

L
Lewy Blue 已提交
210
							var image = this.parseImage( videoNodes[ nodeID ] );
K
Kyle Larson 已提交
211

L
Lewy Blue 已提交
212
							blobs[ videoNode.RelativeFilename || videoNode.Filename ] = image;
K
Kyle Larson 已提交
213

L
Lewy Blue 已提交
214
						}
K
Kyle Larson 已提交
215

L
Lewy Blue 已提交
216
					}
K
Kyle Larson 已提交
217

M
Mr.doob 已提交
218
				}
K
Kyle Larson 已提交
219

M
Mr.doob 已提交
220
			}
K
Kyle Larson 已提交
221

L
Lewy Blue 已提交
222
			for ( var id in images ) {
K
Kyle Larson 已提交
223

L
Lewy Blue 已提交
224
				var filename = images[ id ];
K
Kyle Larson 已提交
225

L
Lewy Blue 已提交
226 227
				if ( blobs[ filename ] !== undefined ) images[ id ] = blobs[ filename ];
				else images[ id ] = images[ id ].split( '\\' ).pop();
K
Kyle Larson 已提交
228

L
Lewy Blue 已提交
229
			}
K
Kyle Larson 已提交
230

L
Lewy Blue 已提交
231
			return images;
K
Kyle Larson 已提交
232

L
Lewy Blue 已提交
233
		},
L
Lewy Blue 已提交
234

L
Lewy Blue 已提交
235 236
		// Parse embedded image data in FBXTree.Video.Content
		parseImage: function ( videoNode ) {
L
Lewy Blue 已提交
237

L
Lewy Blue 已提交
238 239 240
			var content = videoNode.Content;
			var fileName = videoNode.RelativeFilename || videoNode.Filename;
			var extension = fileName.slice( fileName.lastIndexOf( '.' ) + 1 ).toLowerCase();
L
Lewy Blue 已提交
241

L
Lewy Blue 已提交
242
			var type;
K
Kyle Larson 已提交
243

L
Lewy Blue 已提交
244
			switch ( extension ) {
L
Lewy Blue 已提交
245

L
Lewy Blue 已提交
246
				case 'bmp':
N
NicekDev 已提交
247

L
Lewy Blue 已提交
248 249
					type = 'image/bmp';
					break;
N
NicekDev 已提交
250

L
Lewy Blue 已提交
251 252
				case 'jpg':
				case 'jpeg':
L
Lewy Blue 已提交
253

L
Lewy Blue 已提交
254
					type = 'image/jpeg';
N
NicekDev 已提交
255 256
					break;

L
Lewy Blue 已提交
257
				case 'png':
L
Lewy Blue 已提交
258

L
Lewy Blue 已提交
259 260
					type = 'image/png';
					break;
K
Kyle Larson 已提交
261

L
Lewy Blue 已提交
262
				case 'tif':
K
Kyle Larson 已提交
263

L
Lewy Blue 已提交
264 265
					type = 'image/tiff';
					break;
K
Kyle Larson 已提交
266

L
Lewy Blue 已提交
267
				case 'tga':
268

M
Mugen87 已提交
269
					if ( this.manager.getHandler( '.tga' ) === null ) {
270

L
Lewy Blue 已提交
271
						console.warn( 'FBXLoader: TGA loader not found, skipping ', fileName );
K
Kyle Larson 已提交
272

N
NicekDev 已提交
273
					}
K
Kyle Larson 已提交
274

L
Lewy Blue 已提交
275 276 277
					type = 'image/tga';
					break;

L
Lewy Blue 已提交
278
				default:
K
Kyle Larson 已提交
279

L
Lewy Blue 已提交
280 281
					console.warn( 'FBXLoader: Image type "' + extension + '" is not supported.' );
					return;
K
Kyle Larson 已提交
282

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

L
Lewy Blue 已提交
285
			if ( typeof content === 'string' ) { // ASCII format
K
Kyle Larson 已提交
286

L
Lewy Blue 已提交
287
				return 'data:' + type + ';base64,' + content;
K
Kyle Larson 已提交
288

L
Lewy Blue 已提交
289
			} else { // Binary Format
K
Kyle Larson 已提交
290

L
Lewy Blue 已提交
291 292
				var array = new Uint8Array( content );
				return window.URL.createObjectURL( new Blob( [ array ], { type: type } ) );
K
Kyle Larson 已提交
293

L
Lewy Blue 已提交
294
			}
295

L
Lewy Blue 已提交
296
		},
K
Kyle Larson 已提交
297

L
Lewy Blue 已提交
298 299 300 301
		// Parse nodes in FBXTree.Objects.Texture
		// These contain details such as UV scaling, cropping, rotation etc and are connected
		// to images in FBXTree.Objects.Video
		parseTextures: function ( images ) {
K
Kyle Larson 已提交
302

L
Lewy Blue 已提交
303
			var textureMap = new Map();
K
Kyle Larson 已提交
304

305
			if ( 'Texture' in fbxTree.Objects ) {
K
Kyle Larson 已提交
306

307
				var textureNodes = fbxTree.Objects.Texture;
L
Lewy Blue 已提交
308
				for ( var nodeID in textureNodes ) {
K
Kyle Larson 已提交
309

L
Lewy Blue 已提交
310 311
					var texture = this.parseTexture( textureNodes[ nodeID ], images );
					textureMap.set( parseInt( nodeID ), texture );
K
Kyle Larson 已提交
312

L
Lewy Blue 已提交
313
				}
K
Kyle Larson 已提交
314

M
Mr.doob 已提交
315
			}
K
Kyle Larson 已提交
316

L
Lewy Blue 已提交
317
			return textureMap;
318

L
Lewy Blue 已提交
319
		},
320

L
Lewy Blue 已提交
321 322
		// Parse individual node in FBXTree.Objects.Texture
		parseTexture: function ( textureNode, images ) {
K
Kyle Larson 已提交
323

L
Lewy Blue 已提交
324
			var texture = this.loadTexture( textureNode, images );
K
Kyle Larson 已提交
325

L
Lewy Blue 已提交
326
			texture.ID = textureNode.id;
K
Kyle Larson 已提交
327

L
Lewy Blue 已提交
328
			texture.name = textureNode.attrName;
329

L
Lewy Blue 已提交
330 331
			var wrapModeU = textureNode.WrapModeU;
			var wrapModeV = textureNode.WrapModeV;
332

L
Lewy Blue 已提交
333 334
			var valueU = wrapModeU !== undefined ? wrapModeU.value : 0;
			var valueV = wrapModeV !== undefined ? wrapModeV.value : 0;
335

L
Lewy Blue 已提交
336 337
			// http://download.autodesk.com/us/fbx/SDKdocs/FBX_SDK_Help/files/fbxsdkref/class_k_fbx_texture.html#889640e63e2e681259ea81061b85143a
			// 0: repeat(default), 1: clamp
338

L
Lewy Blue 已提交
339 340
			texture.wrapS = valueU === 0 ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
			texture.wrapT = valueV === 0 ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
341

L
Lewy Blue 已提交
342
			if ( 'Scaling' in textureNode ) {
343

L
Lewy Blue 已提交
344
				var values = textureNode.Scaling.value;
J
Juha-Pekka Arimaa 已提交
345

L
Lewy Blue 已提交
346 347
				texture.repeat.x = values[ 0 ];
				texture.repeat.y = values[ 1 ];
J
Juha-Pekka Arimaa 已提交
348

L
Lewy Blue 已提交
349
			}
J
Juha-Pekka Arimaa 已提交
350

L
Lewy Blue 已提交
351
			return texture;
352

L
Lewy Blue 已提交
353
		},
L
Lewy Blue 已提交
354

L
Lewy Blue 已提交
355 356
		// load a texture specified as a blob or data URI, or via an external URL using THREE.TextureLoader
		loadTexture: function ( textureNode, images ) {
L
Lewy Blue 已提交
357

L
Lewy Blue 已提交
358
			var fileName;
L
Lewy Blue 已提交
359

L
Lewy Blue 已提交
360
			var currentPath = this.textureLoader.path;
L
Lewy Blue 已提交
361

362
			var children = connections.get( textureNode.id ).children;
L
Lewy Blue 已提交
363

L
Lewy Blue 已提交
364
			if ( children !== undefined && children.length > 0 && images[ children[ 0 ].ID ] !== undefined ) {
L
Lewy Blue 已提交
365

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

L
Lewy Blue 已提交
368
				if ( fileName.indexOf( 'blob:' ) === 0 || fileName.indexOf( 'data:' ) === 0 ) {
369

L
Lewy Blue 已提交
370
					this.textureLoader.setPath( undefined );
371

L
Lewy Blue 已提交
372
				}
373

L
Lewy Blue 已提交
374
			}
375

L
Lewy Blue 已提交
376
			var texture;
377

L
Lewy Blue 已提交
378
			var extension = textureNode.FileName.slice( - 3 ).toLowerCase();
379

L
Lewy Blue 已提交
380 381
			if ( extension === 'tga' ) {

M
Mugen87 已提交
382
				var loader = this.manager.getHandler( '.tga' );
M
Mr.doob 已提交
383

L
Lewy Blue 已提交
384 385
				if ( loader === null ) {

L
Lewy Blue 已提交
386
					console.warn( 'FBXLoader: TGA loader not found, creating placeholder texture for', textureNode.RelativeFilename );
L
Lewy Blue 已提交
387 388
					texture = new THREE.Texture();

M
Mr.doob 已提交
389 390 391 392 393
				} else {

					texture = loader.load( fileName );

				}
L
Lewy Blue 已提交
394 395 396

			} else if ( extension === 'psd' ) {

L
Lewy Blue 已提交
397
				console.warn( 'FBXLoader: PSD textures are not supported, creating placeholder texture for', textureNode.RelativeFilename );
L
Lewy Blue 已提交
398
				texture = new THREE.Texture();
399

L
Lewy Blue 已提交
400
			} else {
L
Lewy Blue 已提交
401

L
Lewy Blue 已提交
402
				texture = this.textureLoader.load( fileName );
403

M
Mr.doob 已提交
404
			}
405

L
Lewy Blue 已提交
406
			this.textureLoader.setPath( currentPath );
407

L
Lewy Blue 已提交
408
			return texture;
409

L
Lewy Blue 已提交
410
		},
411

L
Lewy Blue 已提交
412 413
		// Parse nodes in FBXTree.Objects.Material
		parseMaterials: function ( textureMap ) {
414

L
Lewy Blue 已提交
415
			var materialMap = new Map();
416

417
			if ( 'Material' in fbxTree.Objects ) {
418

419
				var materialNodes = fbxTree.Objects.Material;
420

L
Lewy Blue 已提交
421
				for ( var nodeID in materialNodes ) {
422

L
Lewy Blue 已提交
423
					var material = this.parseMaterial( materialNodes[ nodeID ], textureMap );
424

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

L
Lewy Blue 已提交
427
				}
428

M
Mr.doob 已提交
429
			}
430

L
Lewy Blue 已提交
431
			return materialMap;
432

L
Lewy Blue 已提交
433
		},
434

L
Lewy Blue 已提交
435 436 437 438
		// Parse single node in FBXTree.Objects.Material
		// Materials are connected to texture maps in FBXTree.Objects.Textures
		// FBX format currently only supports Lambert and Phong shading models
		parseMaterial: function ( materialNode, textureMap ) {
439

L
Lewy Blue 已提交
440 441 442
			var ID = materialNode.id;
			var name = materialNode.attrName;
			var type = materialNode.ShadingModel;
443

L
Lewy Blue 已提交
444 445
			// Case where FBX wraps shading model in property object.
			if ( typeof type === 'object' ) {
L
Lewy Blue 已提交
446

L
Lewy Blue 已提交
447
				type = type.value;
L
Lewy Blue 已提交
448

L
Lewy Blue 已提交
449
			}
450

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

L
Lewy Blue 已提交
454
			var parameters = this.parseParameters( materialNode, textureMap, ID );
455

L
Lewy Blue 已提交
456
			var material;
457

L
Lewy Blue 已提交
458
			switch ( type.toLowerCase() ) {
L
Lewy Blue 已提交
459

L
Lewy Blue 已提交
460 461 462 463 464 465 466 467
				case 'phong':
					material = new THREE.MeshPhongMaterial();
					break;
				case 'lambert':
					material = new THREE.MeshLambertMaterial();
					break;
				default:
					console.warn( 'THREE.FBXLoader: unknown material type "%s". Defaulting to MeshPhongMaterial.', type );
468
					material = new THREE.MeshPhongMaterial();
L
Lewy Blue 已提交
469
					break;
L
Lewy Blue 已提交
470

L
Lewy Blue 已提交
471
			}
472

L
Lewy Blue 已提交
473 474
			material.setValues( parameters );
			material.name = name;
475

L
Lewy Blue 已提交
476
			return material;
477

L
Lewy Blue 已提交
478
		},
479

L
Lewy Blue 已提交
480 481 482
		// 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
		parseParameters: function ( materialNode, textureMap, ID ) {
483

L
Lewy Blue 已提交
484
			var parameters = {};
485

L
Lewy Blue 已提交
486
			if ( materialNode.BumpFactor ) {
487

L
Lewy Blue 已提交
488
				parameters.bumpScale = materialNode.BumpFactor.value;
489

L
Lewy Blue 已提交
490 491
			}
			if ( materialNode.Diffuse ) {
K
Kyle Larson 已提交
492

L
Lewy Blue 已提交
493
				parameters.color = new THREE.Color().fromArray( materialNode.Diffuse.value );
K
Kyle Larson 已提交
494

L
Lewy Blue 已提交
495
			} else if ( materialNode.DiffuseColor && materialNode.DiffuseColor.type === 'Color' ) {
L
Lewy Blue 已提交
496

L
Lewy Blue 已提交
497 498
				// The blender exporter exports diffuse here instead of in materialNode.Diffuse
				parameters.color = new THREE.Color().fromArray( materialNode.DiffuseColor.value );
L
Lewy Blue 已提交
499

L
Lewy Blue 已提交
500
			}
501

L
Lewy Blue 已提交
502
			if ( materialNode.DisplacementFactor ) {
L
Lewy Blue 已提交
503

L
Lewy Blue 已提交
504
				parameters.displacementScale = materialNode.DisplacementFactor.value;
L
Lewy Blue 已提交
505

L
Lewy Blue 已提交
506
			}
507

L
Lewy Blue 已提交
508
			if ( materialNode.Emissive ) {
L
Lewy Blue 已提交
509

L
Lewy Blue 已提交
510
				parameters.emissive = new THREE.Color().fromArray( materialNode.Emissive.value );
L
Lewy Blue 已提交
511

L
Lewy Blue 已提交
512
			} else if ( materialNode.EmissiveColor && materialNode.EmissiveColor.type === 'Color' ) {
L
Lewy Blue 已提交
513

L
Lewy Blue 已提交
514 515
				// The blender exporter exports emissive color here instead of in materialNode.Emissive
				parameters.emissive = new THREE.Color().fromArray( materialNode.EmissiveColor.value );
L
Lewy Blue 已提交
516

L
Lewy Blue 已提交
517
			}
518

L
Lewy Blue 已提交
519
			if ( materialNode.EmissiveFactor ) {
K
Kyle Larson 已提交
520

L
Lewy Blue 已提交
521
				parameters.emissiveIntensity = parseFloat( materialNode.EmissiveFactor.value );
K
Kyle Larson 已提交
522

L
Lewy Blue 已提交
523
			}
524

L
Lewy Blue 已提交
525
			if ( materialNode.Opacity ) {
K
Kyle Larson 已提交
526

L
Lewy Blue 已提交
527
				parameters.opacity = parseFloat( materialNode.Opacity.value );
K
Kyle Larson 已提交
528

L
Lewy Blue 已提交
529
			}
530

L
Lewy Blue 已提交
531
			if ( parameters.opacity < 1.0 ) {
L
Lewy Blue 已提交
532

L
Lewy Blue 已提交
533
				parameters.transparent = true;
K
Kyle Larson 已提交
534

L
Lewy Blue 已提交
535
			}
536

L
Lewy Blue 已提交
537
			if ( materialNode.ReflectionFactor ) {
L
Lewy Blue 已提交
538

L
Lewy Blue 已提交
539
				parameters.reflectivity = materialNode.ReflectionFactor.value;
L
Lewy Blue 已提交
540

L
Lewy Blue 已提交
541
			}
542

L
Lewy Blue 已提交
543
			if ( materialNode.Shininess ) {
544

L
Lewy Blue 已提交
545
				parameters.shininess = materialNode.Shininess.value;
546

L
Lewy Blue 已提交
547
			}
548

L
Lewy Blue 已提交
549
			if ( materialNode.Specular ) {
L
Lewy Blue 已提交
550

L
Lewy Blue 已提交
551
				parameters.specular = new THREE.Color().fromArray( materialNode.Specular.value );
L
Lewy Blue 已提交
552

L
Lewy Blue 已提交
553
			} else if ( materialNode.SpecularColor && materialNode.SpecularColor.type === 'Color' ) {
L
Lewy Blue 已提交
554

L
Lewy Blue 已提交
555 556
				// The blender exporter exports specular color here instead of in materialNode.Specular
				parameters.specular = new THREE.Color().fromArray( materialNode.SpecularColor.value );
K
Kyle Larson 已提交
557 558 559

			}

W
WestLangley 已提交
560
			var scope = this;
561
			connections.get( ID ).children.forEach( function ( child ) {
K
Kyle Larson 已提交
562

L
Lewy Blue 已提交
563
				var type = child.relationship;
K
Kyle Larson 已提交
564

L
Lewy Blue 已提交
565
				switch ( type ) {
L
Lewy Blue 已提交
566

L
Lewy Blue 已提交
567
					case 'Bump':
W
WestLangley 已提交
568
						parameters.bumpMap = scope.getTexture( textureMap, child.ID );
L
Lewy Blue 已提交
569
						break;
L
Lewy Blue 已提交
570

571
					case 'Maya|TEX_ao_map':
W
WestLangley 已提交
572
						parameters.aoMap = scope.getTexture( textureMap, child.ID );
573 574
						break;

L
Lewy Blue 已提交
575
					case 'DiffuseColor':
576
					case 'Maya|TEX_color_map':
W
WestLangley 已提交
577
						parameters.map = scope.getTexture( textureMap, child.ID );
L
Lewy Blue 已提交
578
						parameters.map.encoding = THREE.sRGBEncoding;
L
Lewy Blue 已提交
579
						break;
L
Lewy Blue 已提交
580

L
Lewy Blue 已提交
581
					case 'DisplacementColor':
W
WestLangley 已提交
582
						parameters.displacementMap = scope.getTexture( textureMap, child.ID );
L
Lewy Blue 已提交
583
						break;
L
Lewy Blue 已提交
584

L
Lewy Blue 已提交
585
					case 'EmissiveColor':
W
WestLangley 已提交
586
						parameters.emissiveMap = scope.getTexture( textureMap, child.ID );
L
Lewy Blue 已提交
587
						parameters.emissiveMap.encoding = THREE.sRGBEncoding;
L
Lewy Blue 已提交
588
						break;
L
Lewy Blue 已提交
589

L
Lewy Blue 已提交
590
					case 'NormalMap':
591
					case 'Maya|TEX_normal_map':
W
WestLangley 已提交
592
						parameters.normalMap = scope.getTexture( textureMap, child.ID );
L
Lewy Blue 已提交
593
						break;
K
Kyle Larson 已提交
594

L
Lewy Blue 已提交
595
					case 'ReflectionColor':
W
WestLangley 已提交
596
						parameters.envMap = scope.getTexture( textureMap, child.ID );
L
Lewy Blue 已提交
597
						parameters.envMap.mapping = THREE.EquirectangularReflectionMapping;
L
Lewy Blue 已提交
598
						parameters.envMap.encoding = THREE.sRGBEncoding;
L
Lewy Blue 已提交
599
						break;
K
Kyle Larson 已提交
600

L
Lewy Blue 已提交
601
					case 'SpecularColor':
W
WestLangley 已提交
602
						parameters.specularMap = scope.getTexture( textureMap, child.ID );
L
Lewy Blue 已提交
603
						parameters.specularMap.encoding = THREE.sRGBEncoding;
L
Lewy Blue 已提交
604
						break;
K
Kyle Larson 已提交
605

L
Lewy Blue 已提交
606
					case 'TransparentColor':
W
WestLangley 已提交
607
						parameters.alphaMap = scope.getTexture( textureMap, child.ID );
L
Lewy Blue 已提交
608 609
						parameters.transparent = true;
						break;
610

L
Lewy Blue 已提交
611 612 613 614 615 616 617
					case 'AmbientColor':
					case 'ShininessExponent': // AKA glossiness map
					case 'SpecularFactor': // AKA specularLevel
					case 'VectorDisplacementColor': // NOTE: Seems to be a copy of DisplacementColor
					default:
						console.warn( 'THREE.FBXLoader: %s map is not supported in three.js, skipping texture.', type );
						break;
618

L
Lewy Blue 已提交
619
				}
620

L
Lewy Blue 已提交
621
			} );
622

L
Lewy Blue 已提交
623
			return parameters;
L
Lewy Blue 已提交
624

L
Lewy Blue 已提交
625
		},
626

L
Lewy Blue 已提交
627 628
		// get a texture from the textureMap for use by a material.
		getTexture: function ( textureMap, id ) {
629

L
Lewy Blue 已提交
630
			// if the texture is a layered texture, just use the first layer and issue a warning
631
			if ( 'LayeredTexture' in fbxTree.Objects && id in fbxTree.Objects.LayeredTexture ) {
632

L
Lewy Blue 已提交
633
				console.warn( 'THREE.FBXLoader: layered textures are not supported in three.js. Discarding all but first layer.' );
634
				id = connections.get( id ).children[ 0 ].ID;
L
Lewy Blue 已提交
635

L
Lewy Blue 已提交
636
			}
L
Lewy Blue 已提交
637

L
Lewy Blue 已提交
638
			return textureMap.get( id );
L
Lewy Blue 已提交
639

L
Lewy Blue 已提交
640
		},
L
Lewy Blue 已提交
641

L
Lewy Blue 已提交
642 643 644 645
		// Parse nodes in FBXTree.Objects.Deformer
		// 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.
		parseDeformers: function () {
L
Lewy Blue 已提交
646

L
Lewy Blue 已提交
647 648
			var skeletons = {};
			var morphTargets = {};
649

650
			if ( 'Deformer' in fbxTree.Objects ) {
K
Kyle Larson 已提交
651

652
				var DeformerNodes = fbxTree.Objects.Deformer;
K
Kyle Larson 已提交
653

L
Lewy Blue 已提交
654
				for ( var nodeID in DeformerNodes ) {
L
Lewy Blue 已提交
655

L
Lewy Blue 已提交
656
					var deformerNode = DeformerNodes[ nodeID ];
L
Lewy Blue 已提交
657

658
					var relationships = connections.get( parseInt( nodeID ) );
K
Kyle Larson 已提交
659

L
Lewy Blue 已提交
660
					if ( deformerNode.attrType === 'Skin' ) {
K
Kyle Larson 已提交
661

L
Lewy Blue 已提交
662 663
						var skeleton = this.parseSkeleton( relationships, DeformerNodes );
						skeleton.ID = nodeID;
K
Kyle Larson 已提交
664

L
Lewy Blue 已提交
665 666
						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;
K
Kyle Larson 已提交
667

L
Lewy Blue 已提交
668
						skeletons[ nodeID ] = skeleton;
K
Kyle Larson 已提交
669

L
Lewy Blue 已提交
670
					} else if ( deformerNode.attrType === 'BlendShape' ) {
Y
yamahigashi 已提交
671

L
Lewy Blue 已提交
672 673 674
						var morphTarget = {
							id: nodeID,
						};
Y
yamahigashi 已提交
675

L
Lewy Blue 已提交
676 677
						morphTarget.rawTargets = this.parseMorphTargets( relationships, DeformerNodes );
						morphTarget.id = nodeID;
Y
yamahigashi 已提交
678

L
Lewy Blue 已提交
679
						if ( relationships.parents.length > 1 ) console.warn( 'THREE.FBXLoader: morph target attached to more than one geometry is not supported.' );
680

L
Lewy Blue 已提交
681
						morphTargets[ nodeID ] = morphTarget;
Y
yamahigashi 已提交
682

L
Lewy Blue 已提交
683
					}
Y
yamahigashi 已提交
684

685
				}
Y
yamahigashi 已提交
686

M
Mr.doob 已提交
687
			}
Y
yamahigashi 已提交
688

L
Lewy Blue 已提交
689
			return {
690

L
Lewy Blue 已提交
691 692
				skeletons: skeletons,
				morphTargets: morphTargets,
693

L
Lewy Blue 已提交
694
			};
Y
yamahigashi 已提交
695

L
Lewy Blue 已提交
696
		},
Y
yamahigashi 已提交
697

L
Lewy Blue 已提交
698 699 700 701
		// Parse single nodes in FBXTree.Objects.Deformer
		// The top level skeleton node has type 'Skin' and sub nodes have type 'Cluster'
		// Each skin node represents a skeleton and each cluster node represents a bone
		parseSkeleton: function ( relationships, deformerNodes ) {
L
Lewy Blue 已提交
702

L
Lewy Blue 已提交
703
			var rawBones = [];
L
Lewy Blue 已提交
704

L
Lewy Blue 已提交
705
			relationships.children.forEach( function ( child ) {
L
Lewy Blue 已提交
706

L
Lewy Blue 已提交
707
				var boneNode = deformerNodes[ child.ID ];
L
Lewy Blue 已提交
708

L
Lewy Blue 已提交
709
				if ( boneNode.attrType !== 'Cluster' ) return;
L
Lewy Blue 已提交
710

L
Lewy Blue 已提交
711
				var rawBone = {
L
Lewy Blue 已提交
712

L
Lewy Blue 已提交
713 714 715 716
					ID: child.ID,
					indices: [],
					weights: [],
					transformLink: new THREE.Matrix4().fromArray( boneNode.TransformLink.a ),
L
Lewy Blue 已提交
717 718
					// transform: new THREE.Matrix4().fromArray( boneNode.Transform.a ),
					// linkMode: boneNode.Mode,
L
Lewy Blue 已提交
719

L
Lewy Blue 已提交
720
				};
L
Lewy Blue 已提交
721

L
Lewy Blue 已提交
722
				if ( 'Indexes' in boneNode ) {
L
Lewy Blue 已提交
723

L
Lewy Blue 已提交
724 725
					rawBone.indices = boneNode.Indexes.a;
					rawBone.weights = boneNode.Weights.a;
L
Lewy Blue 已提交
726

L
Lewy Blue 已提交
727
				}
L
Lewy Blue 已提交
728

L
Lewy Blue 已提交
729
				rawBones.push( rawBone );
L
Lewy Blue 已提交
730

L
Lewy Blue 已提交
731
			} );
L
Lewy Blue 已提交
732

L
Lewy Blue 已提交
733
			return {
L
Lewy Blue 已提交
734

L
Lewy Blue 已提交
735 736
				rawBones: rawBones,
				bones: []
L
Lewy Blue 已提交
737

L
Lewy Blue 已提交
738
			};
L
Lewy Blue 已提交
739

L
Lewy Blue 已提交
740
		},
L
Lewy Blue 已提交
741

L
Lewy Blue 已提交
742 743
		// The top level morph deformer node has type "BlendShape" and sub nodes have type "BlendShapeChannel"
		parseMorphTargets: function ( relationships, deformerNodes ) {
L
Lewy Blue 已提交
744

L
Lewy Blue 已提交
745
			var rawMorphTargets = [];
L
Lewy Blue 已提交
746

L
Lewy Blue 已提交
747
			for ( var i = 0; i < relationships.children.length; i ++ ) {
L
Lewy Blue 已提交
748

L
Lewy Blue 已提交
749
				var child = relationships.children[ i ];
Y
yamahigashi 已提交
750

L
Lewy Blue 已提交
751
				var morphTargetNode = deformerNodes[ child.ID ];
Y
yamahigashi 已提交
752

L
Lewy Blue 已提交
753
				var rawMorphTarget = {
L
Lewy Blue 已提交
754

L
Lewy Blue 已提交
755 756 757 758
					name: morphTargetNode.attrName,
					initialWeight: morphTargetNode.DeformPercent,
					id: morphTargetNode.id,
					fullWeights: morphTargetNode.FullWeights.a
Y
yamahigashi 已提交
759

L
Lewy Blue 已提交
760
				};
Y
yamahigashi 已提交
761

L
Lewy Blue 已提交
762
				if ( morphTargetNode.attrType !== 'BlendShapeChannel' ) return;
Y
yamahigashi 已提交
763

L
Lewy Blue 已提交
764
				rawMorphTarget.geoID = connections.get( parseInt( child.ID ) ).children.filter( function ( child ) {
Y
yamahigashi 已提交
765

L
Lewy Blue 已提交
766
					return child.relationship === undefined;
Y
yamahigashi 已提交
767

L
Lewy Blue 已提交
768
				} )[ 0 ].ID;
Y
yamahigashi 已提交
769

L
Lewy Blue 已提交
770
				rawMorphTargets.push( rawMorphTarget );
Y
yamahigashi 已提交
771

L
Lewy Blue 已提交
772
			}
Y
yamahigashi 已提交
773

L
Lewy Blue 已提交
774
			return rawMorphTargets;
Y
yamahigashi 已提交
775

L
Lewy Blue 已提交
776
		},
Y
yamahigashi 已提交
777

L
Lewy Blue 已提交
778 779
		// create the main THREE.Group() to be returned by the loader
		parseScene: function ( deformers, geometryMap, materialMap ) {
Y
yamahigashi 已提交
780

781 782
			sceneGraph = new THREE.Group();

L
Lewy Blue 已提交
783
			var modelMap = this.parseModels( deformers.skeletons, geometryMap, materialMap );
784

785
			var modelNodes = fbxTree.Objects.Model;
786

W
WestLangley 已提交
787
			var scope = this;
L
Lewy Blue 已提交
788
			modelMap.forEach( function ( model ) {
789

L
Lewy Blue 已提交
790
				var modelNode = modelNodes[ model.ID ];
W
WestLangley 已提交
791
				scope.setLookAtProperties( model, modelNode );
L
Lewy Blue 已提交
792

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

L
Lewy Blue 已提交
795
				parentConnections.forEach( function ( connection ) {
L
Lewy Blue 已提交
796

L
Lewy Blue 已提交
797 798
					var parent = modelMap.get( connection.ID );
					if ( parent !== undefined ) parent.add( model );
L
Lewy Blue 已提交
799

L
Lewy Blue 已提交
800
				} );
L
Lewy Blue 已提交
801

L
Lewy Blue 已提交
802
				if ( model.parent === null ) {
L
Lewy Blue 已提交
803

L
Lewy Blue 已提交
804
					sceneGraph.add( model );
L
Lewy Blue 已提交
805

L
Lewy Blue 已提交
806
				}
L
Lewy Blue 已提交
807

808

L
Lewy Blue 已提交
809
			} );
810

L
Lewy Blue 已提交
811
			this.bindSkeleton( deformers.skeletons, geometryMap, modelMap );
Y
yamahigashi 已提交
812

L
Lewy Blue 已提交
813
			this.createAmbientLight();
Y
yamahigashi 已提交
814

L
Lewy Blue 已提交
815
			this.setupMorphMaterials();
816

817 818 819 820 821 822 823 824
			sceneGraph.traverse( function ( node ) {

				if ( node.userData.transformData ) {

					if ( node.parent ) node.userData.transformData.parentMatrixWorld = node.parent.matrix;

					var transform = generateTransform( node.userData.transformData );

W
WestLangley 已提交
825
					node.applyMatrix4( transform );
826 827 828 829 830

				}

			} );

831 832 833 834 835 836 837 838 839 840 841 842
			var animations = new AnimationParser().parse();

			// if all the models where already combined in a single group, just return that
			if ( sceneGraph.children.length === 1 && sceneGraph.children[ 0 ].isGroup ) {

				sceneGraph.children[ 0 ].animations = animations;
				sceneGraph = sceneGraph.children[ 0 ];

			}

			sceneGraph.animations = animations;

L
Lewy Blue 已提交
843
		},
Y
yamahigashi 已提交
844

L
Lewy Blue 已提交
845 846
		// parse nodes in FBXTree.Objects.Model
		parseModels: function ( skeletons, geometryMap, materialMap ) {
L
Lewy Blue 已提交
847

L
Lewy Blue 已提交
848
			var modelMap = new Map();
849
			var modelNodes = fbxTree.Objects.Model;
L
Lewy Blue 已提交
850

L
Lewy Blue 已提交
851
			for ( var nodeID in modelNodes ) {
L
Lewy Blue 已提交
852

L
Lewy Blue 已提交
853 854
				var id = parseInt( nodeID );
				var node = modelNodes[ nodeID ];
855
				var relationships = connections.get( id );
L
Lewy Blue 已提交
856

L
Lewy Blue 已提交
857
				var model = this.buildSkeleton( relationships, skeletons, id, node.attrName );
L
Lewy Blue 已提交
858

L
Lewy Blue 已提交
859
				if ( ! model ) {
L
Lewy Blue 已提交
860

L
Lewy Blue 已提交
861
					switch ( node.attrType ) {
L
Lewy Blue 已提交
862

L
Lewy Blue 已提交
863 864 865 866 867 868 869 870 871 872 873 874
						case 'Camera':
							model = this.createCamera( relationships );
							break;
						case 'Light':
							model = this.createLight( relationships );
							break;
						case 'Mesh':
							model = this.createMesh( relationships, geometryMap, materialMap );
							break;
						case 'NurbsCurve':
							model = this.createCurve( relationships, geometryMap );
							break;
L
Lewy Blue 已提交
875 876 877 878
						case 'LimbNode':
						case 'Root':
							model = new THREE.Bone();
							break;
L
Lewy Blue 已提交
879 880 881 882
						case 'Null':
						default:
							model = new THREE.Group();
							break;
L
Lewy Blue 已提交
883

L
Lewy Blue 已提交
884
					}
L
Lewy Blue 已提交
885

886 887
					model.name = node.attrName ? THREE.PropertyBinding.sanitizeNodeName( node.attrName ) : '';

L
Lewy Blue 已提交
888
					model.ID = id;
L
Lewy Blue 已提交
889

L
Lewy Blue 已提交
890
				}
L
Lewy Blue 已提交
891

892
				this.getTransformData( model, node );
L
Lewy Blue 已提交
893
				modelMap.set( id, model );
L
Lewy Blue 已提交
894

L
Lewy Blue 已提交
895 896 897
			}

			return modelMap;
L
Lewy Blue 已提交
898

L
Lewy Blue 已提交
899
		},
L
Lewy Blue 已提交
900

L
Lewy Blue 已提交
901
		buildSkeleton: function ( relationships, skeletons, id, name ) {
L
Lewy Blue 已提交
902

L
Lewy Blue 已提交
903
			var bone = null;
L
Lewy Blue 已提交
904

L
Lewy Blue 已提交
905
			relationships.parents.forEach( function ( parent ) {
L
Lewy Blue 已提交
906

L
Lewy Blue 已提交
907
				for ( var ID in skeletons ) {
L
Lewy Blue 已提交
908

L
Lewy Blue 已提交
909
					var skeleton = skeletons[ ID ];
L
Lewy Blue 已提交
910

L
Lewy Blue 已提交
911
					skeleton.rawBones.forEach( function ( rawBone, i ) {
L
Lewy Blue 已提交
912

L
Lewy Blue 已提交
913
						if ( rawBone.ID === parent.ID ) {
L
Lewy Blue 已提交
914

L
Lewy Blue 已提交
915 916
							var subBone = bone;
							bone = new THREE.Bone();
L
Lewy Blue 已提交
917

L
Lewy Blue 已提交
918
							bone.matrixWorld.copy( rawBone.transformLink );
L
Lewy Blue 已提交
919

L
Lewy Blue 已提交
920
							// set name and id here - otherwise in cases where "subBone" is created it will not have a name / id
921 922

							bone.name = name ? THREE.PropertyBinding.sanitizeNodeName( name ) : '';
L
Lewy Blue 已提交
923
							bone.ID = id;
L
Lewy Blue 已提交
924

L
Lewy Blue 已提交
925
							skeleton.bones[ i ] = bone;
L
Lewy Blue 已提交
926

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

L
Lewy Blue 已提交
931
								bone.add( subBone );
L
Lewy Blue 已提交
932

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

L
Lewy Blue 已提交
935
						}
L
Lewy Blue 已提交
936

L
Lewy Blue 已提交
937
					} );
L
Lewy Blue 已提交
938

L
Lewy Blue 已提交
939
				}
L
Lewy Blue 已提交
940

L
Lewy Blue 已提交
941
			} );
L
Lewy Blue 已提交
942

L
Lewy Blue 已提交
943
			return bone;
L
Lewy Blue 已提交
944

L
Lewy Blue 已提交
945
		},
L
Lewy Blue 已提交
946

L
Lewy Blue 已提交
947 948
		// create a THREE.PerspectiveCamera or THREE.OrthographicCamera
		createCamera: function ( relationships ) {
Y
yamahigashi 已提交
949

L
Lewy Blue 已提交
950 951
			var model;
			var cameraAttribute;
L
Lewy Blue 已提交
952

L
Lewy Blue 已提交
953
			relationships.children.forEach( function ( child ) {
L
Lewy Blue 已提交
954

955
				var attr = fbxTree.Objects.NodeAttribute[ child.ID ];
L
Lewy Blue 已提交
956

L
Lewy Blue 已提交
957
				if ( attr !== undefined ) {
L
Lewy Blue 已提交
958

L
Lewy Blue 已提交
959 960 961
					cameraAttribute = attr;

				}
L
Lewy Blue 已提交
962

L
Lewy Blue 已提交
963
			} );
L
Lewy Blue 已提交
964

L
Lewy Blue 已提交
965
			if ( cameraAttribute === undefined ) {
L
Lewy Blue 已提交
966

L
Lewy Blue 已提交
967
				model = new THREE.Object3D();
L
Lewy Blue 已提交
968

L
Lewy Blue 已提交
969
			} else {
L
Lewy Blue 已提交
970

L
Lewy Blue 已提交
971 972
				var type = 0;
				if ( cameraAttribute.CameraProjectionType !== undefined && cameraAttribute.CameraProjectionType.value === 1 ) {
L
Lewy Blue 已提交
973

L
Lewy Blue 已提交
974
					type = 1;
L
Lewy Blue 已提交
975

L
Lewy Blue 已提交
976
				}
L
Lewy Blue 已提交
977

L
Lewy Blue 已提交
978 979
				var nearClippingPlane = 1;
				if ( cameraAttribute.NearPlane !== undefined ) {
980

L
Lewy Blue 已提交
981
					nearClippingPlane = cameraAttribute.NearPlane.value / 1000;
L
tidying  
Lewy Blue 已提交
982

L
Lewy Blue 已提交
983
				}
L
tidying  
Lewy Blue 已提交
984

L
Lewy Blue 已提交
985 986
				var farClippingPlane = 1000;
				if ( cameraAttribute.FarPlane !== undefined ) {
L
tidying  
Lewy Blue 已提交
987

L
Lewy Blue 已提交
988
					farClippingPlane = cameraAttribute.FarPlane.value / 1000;
L
tidying  
Lewy Blue 已提交
989

L
Lewy Blue 已提交
990
				}
L
tidying  
Lewy Blue 已提交
991

Y
yamahigashi 已提交
992

L
Lewy Blue 已提交
993 994
				var width = window.innerWidth;
				var height = window.innerHeight;
M
Mr.doob 已提交
995

L
Lewy Blue 已提交
996
				if ( cameraAttribute.AspectWidth !== undefined && cameraAttribute.AspectHeight !== undefined ) {
Y
yamahigashi 已提交
997

L
Lewy Blue 已提交
998 999
					width = cameraAttribute.AspectWidth.value;
					height = cameraAttribute.AspectHeight.value;
Y
yamahigashi 已提交
1000

L
Lewy Blue 已提交
1001
				}
Y
yamahigashi 已提交
1002

L
Lewy Blue 已提交
1003
				var aspect = width / height;
L
Lewy Blue 已提交
1004

L
Lewy Blue 已提交
1005 1006
				var fov = 45;
				if ( cameraAttribute.FieldOfView !== undefined ) {
L
Lewy Blue 已提交
1007

L
Lewy Blue 已提交
1008
					fov = cameraAttribute.FieldOfView.value;
L
Lewy Blue 已提交
1009

L
Lewy Blue 已提交
1010
				}
Y
yamahigashi 已提交
1011

L
Lewy Blue 已提交
1012
				var focalLength = cameraAttribute.FocalLength ? cameraAttribute.FocalLength.value : null;
Y
yamahigashi 已提交
1013

L
Lewy Blue 已提交
1014
				switch ( type ) {
T
Takahiro 已提交
1015

L
Lewy Blue 已提交
1016 1017 1018 1019
					case 0: // Perspective
						model = new THREE.PerspectiveCamera( fov, aspect, nearClippingPlane, farClippingPlane );
						if ( focalLength !== null ) model.setFocalLength( focalLength );
						break;
T
Takahiro 已提交
1020

L
Lewy Blue 已提交
1021 1022 1023
					case 1: // Orthographic
						model = new THREE.OrthographicCamera( - width / 2, width / 2, height / 2, - height / 2, nearClippingPlane, farClippingPlane );
						break;
L
Lewy Blue 已提交
1024

L
Lewy Blue 已提交
1025 1026 1027 1028
					default:
						console.warn( 'THREE.FBXLoader: Unknown camera type ' + type + '.' );
						model = new THREE.Object3D();
						break;
T
Takahiro 已提交
1029

L
Lewy Blue 已提交
1030
				}
1031

L
Lewy Blue 已提交
1032
			}
1033

L
Lewy Blue 已提交
1034
			return model;
T
Takahiro 已提交
1035

L
Lewy Blue 已提交
1036
		},
T
Takahiro 已提交
1037

L
Lewy Blue 已提交
1038 1039
		// Create a THREE.DirectionalLight, THREE.PointLight or THREE.SpotLight
		createLight: function ( relationships ) {
T
Takahiro 已提交
1040

L
Lewy Blue 已提交
1041 1042
			var model;
			var lightAttribute;
T
Takahiro 已提交
1043

L
Lewy Blue 已提交
1044
			relationships.children.forEach( function ( child ) {
L
Lewy Blue 已提交
1045

1046
				var attr = fbxTree.Objects.NodeAttribute[ child.ID ];
L
Lewy Blue 已提交
1047

L
Lewy Blue 已提交
1048 1049 1050
				if ( attr !== undefined ) {

					lightAttribute = attr;
L
Lewy Blue 已提交
1051

L
Lewy Blue 已提交
1052
				}
L
Lewy Blue 已提交
1053

L
Lewy Blue 已提交
1054
			} );
Y
yamahigashi 已提交
1055

L
Lewy Blue 已提交
1056
			if ( lightAttribute === undefined ) {
1057

L
Lewy Blue 已提交
1058
				model = new THREE.Object3D();
Y
yamahigashi 已提交
1059

L
Lewy Blue 已提交
1060
			} else {
Y
yamahigashi 已提交
1061

L
Lewy Blue 已提交
1062
				var type;
Y
yamahigashi 已提交
1063

L
Lewy Blue 已提交
1064 1065
				// LightType can be undefined for Point lights
				if ( lightAttribute.LightType === undefined ) {
Y
yamahigashi 已提交
1066

L
Lewy Blue 已提交
1067
					type = 0;
Y
yamahigashi 已提交
1068

L
Lewy Blue 已提交
1069
				} else {
Y
yamahigashi 已提交
1070

L
Lewy Blue 已提交
1071
					type = lightAttribute.LightType.value;
Y
yamahigashi 已提交
1072

L
Lewy Blue 已提交
1073
				}
L
tidying  
Lewy Blue 已提交
1074

L
Lewy Blue 已提交
1075
				var color = 0xffffff;
L
tidying  
Lewy Blue 已提交
1076

L
Lewy Blue 已提交
1077
				if ( lightAttribute.Color !== undefined ) {
L
tidying  
Lewy Blue 已提交
1078

L
Lewy Blue 已提交
1079
					color = new THREE.Color().fromArray( lightAttribute.Color.value );
Y
yamahigashi 已提交
1080

L
Lewy Blue 已提交
1081
				}
Y
yamahigashi 已提交
1082

L
Lewy Blue 已提交
1083
				var intensity = ( lightAttribute.Intensity === undefined ) ? 1 : lightAttribute.Intensity.value / 100;
Y
yamahigashi 已提交
1084

L
Lewy Blue 已提交
1085 1086
				// light disabled
				if ( lightAttribute.CastLightOnObject !== undefined && lightAttribute.CastLightOnObject.value === 0 ) {
Y
yamahigashi 已提交
1087

L
Lewy Blue 已提交
1088
					intensity = 0;
Y
yamahigashi 已提交
1089

L
Lewy Blue 已提交
1090
				}
Y
yamahigashi 已提交
1091

L
Lewy Blue 已提交
1092 1093
				var distance = 0;
				if ( lightAttribute.FarAttenuationEnd !== undefined ) {
Y
yamahigashi 已提交
1094

L
Lewy Blue 已提交
1095
					if ( lightAttribute.EnableFarAttenuation !== undefined && lightAttribute.EnableFarAttenuation.value === 0 ) {
Y
yamahigashi 已提交
1096

L
Lewy Blue 已提交
1097
						distance = 0;
Y
yamahigashi 已提交
1098

L
Lewy Blue 已提交
1099
					} else {
T
Takahiro 已提交
1100

L
Lewy Blue 已提交
1101 1102 1103
						distance = lightAttribute.FarAttenuationEnd.value;

					}
T
Takahiro 已提交
1104

L
Lewy Blue 已提交
1105
				}
Y
yamahigashi 已提交
1106

L
Lewy Blue 已提交
1107 1108
				// TODO: could this be calculated linearly from FarAttenuationStart to FarAttenuationEnd?
				var decay = 1;
Y
yamahigashi 已提交
1109

L
Lewy Blue 已提交
1110
				switch ( type ) {
Y
yamahigashi 已提交
1111

L
Lewy Blue 已提交
1112 1113 1114
					case 0: // Point
						model = new THREE.PointLight( color, intensity, distance, decay );
						break;
Y
yamahigashi 已提交
1115

L
Lewy Blue 已提交
1116 1117 1118
					case 1: // Directional
						model = new THREE.DirectionalLight( color, intensity );
						break;
Y
yamahigashi 已提交
1119

L
Lewy Blue 已提交
1120 1121
					case 2: // Spot
						var angle = Math.PI / 3;
Y
yamahigashi 已提交
1122

L
Lewy Blue 已提交
1123
						if ( lightAttribute.InnerAngle !== undefined ) {
Y
yamahigashi 已提交
1124

M
Mugen87 已提交
1125
							angle = THREE.MathUtils.degToRad( lightAttribute.InnerAngle.value );
Y
yamahigashi 已提交
1126

L
Lewy Blue 已提交
1127
						}
Y
yamahigashi 已提交
1128

L
Lewy Blue 已提交
1129 1130
						var penumbra = 0;
						if ( lightAttribute.OuterAngle !== undefined ) {
Y
yamahigashi 已提交
1131

1132 1133 1134
							// 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
M
Mugen87 已提交
1135
							penumbra = THREE.MathUtils.degToRad( lightAttribute.OuterAngle.value );
L
Lewy Blue 已提交
1136
							penumbra = Math.max( penumbra, 1 );
Y
yamahigashi 已提交
1137

L
Lewy Blue 已提交
1138
						}
Y
yamahigashi 已提交
1139

L
Lewy Blue 已提交
1140 1141
						model = new THREE.SpotLight( color, intensity, distance, angle, penumbra, decay );
						break;
Y
yamahigashi 已提交
1142

L
Lewy Blue 已提交
1143 1144 1145 1146
					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 已提交
1147

L
Lewy Blue 已提交
1148
				}
Y
yamahigashi 已提交
1149

L
Lewy Blue 已提交
1150
				if ( lightAttribute.CastShadows !== undefined && lightAttribute.CastShadows.value === 1 ) {
Y
yamahigashi 已提交
1151

L
Lewy Blue 已提交
1152
					model.castShadow = true;
L
Lewy Blue 已提交
1153

L
Lewy Blue 已提交
1154
				}
L
Lewy Blue 已提交
1155

L
Lewy Blue 已提交
1156
			}
Y
yamahigashi 已提交
1157

L
Lewy Blue 已提交
1158
			return model;
Y
yamahigashi 已提交
1159

L
Lewy Blue 已提交
1160
		},
Y
yamahigashi 已提交
1161

L
Lewy Blue 已提交
1162
		createMesh: function ( relationships, geometryMap, materialMap ) {
1163

L
Lewy Blue 已提交
1164 1165 1166 1167
			var model;
			var geometry = null;
			var material = null;
			var materials = [];
Y
yamahigashi 已提交
1168

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

L
Lewy Blue 已提交
1172
				if ( geometryMap.has( child.ID ) ) {
L
Lewy Blue 已提交
1173

L
Lewy Blue 已提交
1174
					geometry = geometryMap.get( child.ID );
L
Lewy Blue 已提交
1175

L
Lewy Blue 已提交
1176
				}
L
Lewy Blue 已提交
1177

L
Lewy Blue 已提交
1178
				if ( materialMap.has( child.ID ) ) {
Y
yamahigashi 已提交
1179

L
Lewy Blue 已提交
1180
					materials.push( materialMap.get( child.ID ) );
L
Lewy Blue 已提交
1181

L
Lewy Blue 已提交
1182
				}
L
Lewy Blue 已提交
1183

L
Lewy Blue 已提交
1184
			} );
Y
yamahigashi 已提交
1185

L
Lewy Blue 已提交
1186
			if ( materials.length > 1 ) {
Y
yamahigashi 已提交
1187

L
Lewy Blue 已提交
1188
				material = materials;
Y
yamahigashi 已提交
1189

L
Lewy Blue 已提交
1190
			} else if ( materials.length > 0 ) {
L
Lewy Blue 已提交
1191

L
Lewy Blue 已提交
1192
				material = materials[ 0 ];
Y
yamahigashi 已提交
1193

L
Lewy Blue 已提交
1194
			} else {
Y
yamahigashi 已提交
1195

L
Lewy Blue 已提交
1196 1197
				material = new THREE.MeshPhongMaterial( { color: 0xcccccc } );
				materials.push( material );
Y
yamahigashi 已提交
1198

L
Lewy Blue 已提交
1199
			}
Y
yamahigashi 已提交
1200

L
Lewy Blue 已提交
1201
			if ( 'color' in geometry.attributes ) {
1202

L
Lewy Blue 已提交
1203
				materials.forEach( function ( material ) {
L
tidying  
Lewy Blue 已提交
1204

1205
					material.vertexColors = true;
L
Lewy Blue 已提交
1206

L
Lewy Blue 已提交
1207
				} );
Y
yamahigashi 已提交
1208

L
Lewy Blue 已提交
1209
			}
L
Lewy Blue 已提交
1210

L
Lewy Blue 已提交
1211
			if ( geometry.FBX_Deformer ) {
1212

L
Lewy Blue 已提交
1213
				materials.forEach( function ( material ) {
1214

L
Lewy Blue 已提交
1215
					material.skinning = true;
Y
yamahigashi 已提交
1216

L
Lewy Blue 已提交
1217
				} );
L
tidying  
Lewy Blue 已提交
1218

L
Lewy Blue 已提交
1219
				model = new THREE.SkinnedMesh( geometry, material );
M
Mugen87 已提交
1220
				model.normalizeSkinWeights();
Y
yamahigashi 已提交
1221

L
Lewy Blue 已提交
1222
			} else {
Y
yamahigashi 已提交
1223

L
Lewy Blue 已提交
1224
				model = new THREE.Mesh( geometry, material );
Y
yamahigashi 已提交
1225

L
Lewy Blue 已提交
1226
			}
Y
yamahigashi 已提交
1227

L
Lewy Blue 已提交
1228
			return model;
Y
yamahigashi 已提交
1229

L
Lewy Blue 已提交
1230
		},
Y
yamahigashi 已提交
1231

L
Lewy Blue 已提交
1232
		createCurve: function ( relationships, geometryMap ) {
Y
yamahigashi 已提交
1233

L
Lewy Blue 已提交
1234
			var geometry = relationships.children.reduce( function ( geo, child ) {
L
Lewy Blue 已提交
1235

L
Lewy Blue 已提交
1236
				if ( geometryMap.has( child.ID ) ) geo = geometryMap.get( child.ID );
L
Lewy Blue 已提交
1237

L
Lewy Blue 已提交
1238
				return geo;
Y
yamahigashi 已提交
1239

L
Lewy Blue 已提交
1240
			}, null );
L
Lewy Blue 已提交
1241

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

L
Lewy Blue 已提交
1246
		},
L
Lewy Blue 已提交
1247

1248 1249
		// parse the model node for transform data
		getTransformData: function ( model, modelNode ) {
M
Mr.doob 已提交
1250

L
Lewy Blue 已提交
1251
			var transformData = {};
1252

1253
			if ( 'InheritType' in modelNode ) transformData.inheritType = parseInt( modelNode.InheritType.value );
1254 1255 1256

			if ( 'RotationOrder' in modelNode ) transformData.eulerOrder = getEulerOrder( modelNode.RotationOrder.value );
			else transformData.eulerOrder = 'ZYX';
1257

L
Lewy Blue 已提交
1258
			if ( 'Lcl_Translation' in modelNode ) transformData.translation = modelNode.Lcl_Translation.value;
1259

L
Lewy Blue 已提交
1260
			if ( 'PreRotation' in modelNode ) transformData.preRotation = modelNode.PreRotation.value;
1261
			if ( 'Lcl_Rotation' in modelNode ) transformData.rotation = modelNode.Lcl_Rotation.value;
L
Lewy Blue 已提交
1262
			if ( 'PostRotation' in modelNode ) transformData.postRotation = modelNode.PostRotation.value;
1263

L
Lewy Blue 已提交
1264
			if ( 'Lcl_Scaling' in modelNode ) transformData.scale = modelNode.Lcl_Scaling.value;
Y
yamahigashi 已提交
1265

1266 1267 1268 1269 1270 1271 1272
			if ( 'ScalingOffset' in modelNode ) transformData.scalingOffset = modelNode.ScalingOffset.value;
			if ( 'ScalingPivot' in modelNode ) transformData.scalingPivot = modelNode.ScalingPivot.value;

			if ( 'RotationOffset' in modelNode ) transformData.rotationOffset = modelNode.RotationOffset.value;
			if ( 'RotationPivot' in modelNode ) transformData.rotationPivot = modelNode.RotationPivot.value;

			model.userData.transformData = transformData;
Y
yamahigashi 已提交
1273

L
Lewy Blue 已提交
1274
		},
1275

L
Lewy Blue 已提交
1276
		setLookAtProperties: function ( model, modelNode ) {
1277

L
Lewy Blue 已提交
1278
			if ( 'LookAtProperty' in modelNode ) {
1279

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

L
Lewy Blue 已提交
1282
				children.forEach( function ( child ) {
1283

L
Lewy Blue 已提交
1284
					if ( child.relationship === 'LookAtProperty' ) {
1285

1286
						var lookAtTarget = fbxTree.Objects.Model[ child.ID ];
1287

L
Lewy Blue 已提交
1288
						if ( 'Lcl_Translation' in lookAtTarget ) {
1289

L
Lewy Blue 已提交
1290
							var pos = lookAtTarget.Lcl_Translation.value;
1291

L
Lewy Blue 已提交
1292 1293
							// DirectionalLight, SpotLight
							if ( model.target !== undefined ) {
Y
yamahigashi 已提交
1294

L
Lewy Blue 已提交
1295 1296
								model.target.position.fromArray( pos );
								sceneGraph.add( model.target );
1297

L
Lewy Blue 已提交
1298
							} else { // Cameras and other Object3Ds
1299

L
Lewy Blue 已提交
1300
								model.lookAt( new THREE.Vector3().fromArray( pos ) );
1301

L
Lewy Blue 已提交
1302
							}
1303

L
Lewy Blue 已提交
1304
						}
1305

L
Lewy Blue 已提交
1306
					}
1307

L
Lewy Blue 已提交
1308
				} );
1309

L
Lewy Blue 已提交
1310
			}
1311

L
Lewy Blue 已提交
1312
		},
1313

L
Lewy Blue 已提交
1314
		bindSkeleton: function ( skeletons, geometryMap, modelMap ) {
1315

L
Lewy Blue 已提交
1316
			var bindMatrices = this.parsePoseNodes();
1317

L
Lewy Blue 已提交
1318
			for ( var ID in skeletons ) {
1319

L
Lewy Blue 已提交
1320
				var skeleton = skeletons[ ID ];
L
Lewy Blue 已提交
1321

1322
				var parents = connections.get( parseInt( skeleton.ID ) ).parents;
1323

L
Lewy Blue 已提交
1324
				parents.forEach( function ( parent ) {
1325

L
Lewy Blue 已提交
1326
					if ( geometryMap.has( parent.ID ) ) {
1327

L
Lewy Blue 已提交
1328
						var geoID = parent.ID;
1329
						var geoRelationships = connections.get( geoID );
L
Lewy Blue 已提交
1330

L
Lewy Blue 已提交
1331
						geoRelationships.parents.forEach( function ( geoConnParent ) {
L
Lewy Blue 已提交
1332

L
Lewy Blue 已提交
1333
							if ( modelMap.has( geoConnParent.ID ) ) {
1334

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

L
Lewy Blue 已提交
1337
								model.bind( new THREE.Skeleton( skeleton.bones ), bindMatrices[ geoConnParent.ID ] );
1338

L
Lewy Blue 已提交
1339
							}
1340

L
Lewy Blue 已提交
1341
						} );
L
Lewy Blue 已提交
1342

L
Lewy Blue 已提交
1343
					}
1344

L
Lewy Blue 已提交
1345
				} );
1346

L
Lewy Blue 已提交
1347
			}
Y
yamahigashi 已提交
1348

L
Lewy Blue 已提交
1349
		},
Y
yamahigashi 已提交
1350

L
Lewy Blue 已提交
1351
		parsePoseNodes: function () {
Y
yamahigashi 已提交
1352

L
Lewy Blue 已提交
1353
			var bindMatrices = {};
Y
yamahigashi 已提交
1354

1355
			if ( 'Pose' in fbxTree.Objects ) {
Y
yamahigashi 已提交
1356

1357
				var BindPoseNode = fbxTree.Objects.Pose;
Y
yamahigashi 已提交
1358

L
Lewy Blue 已提交
1359
				for ( var nodeID in BindPoseNode ) {
Y
yamahigashi 已提交
1360

L
Lewy Blue 已提交
1361
					if ( BindPoseNode[ nodeID ].attrType === 'BindPose' ) {
Y
yamahigashi 已提交
1362

L
Lewy Blue 已提交
1363
						var poseNodes = BindPoseNode[ nodeID ].PoseNode;
Y
yamahigashi 已提交
1364

L
Lewy Blue 已提交
1365
						if ( Array.isArray( poseNodes ) ) {
Y
yamahigashi 已提交
1366

L
Lewy Blue 已提交
1367
							poseNodes.forEach( function ( poseNode ) {
Y
yamahigashi 已提交
1368

L
Lewy Blue 已提交
1369
								bindMatrices[ poseNode.Node ] = new THREE.Matrix4().fromArray( poseNode.Matrix.a );
Y
yamahigashi 已提交
1370

L
Lewy Blue 已提交
1371
							} );
Y
yamahigashi 已提交
1372

L
Lewy Blue 已提交
1373
						} else {
Y
yamahigashi 已提交
1374

L
Lewy Blue 已提交
1375
							bindMatrices[ poseNodes.Node ] = new THREE.Matrix4().fromArray( poseNodes.Matrix.a );
Y
yamahigashi 已提交
1376

L
Lewy Blue 已提交
1377
						}
Y
yamahigashi 已提交
1378

L
Lewy Blue 已提交
1379
					}
Y
yamahigashi 已提交
1380

L
Lewy Blue 已提交
1381
				}
1382

L
Lewy Blue 已提交
1383
			}
Y
yamahigashi 已提交
1384

L
Lewy Blue 已提交
1385
			return bindMatrices;
Y
yamahigashi 已提交
1386

L
Lewy Blue 已提交
1387
		},
Y
yamahigashi 已提交
1388

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

1392
			if ( 'GlobalSettings' in fbxTree && 'AmbientColor' in fbxTree.GlobalSettings ) {
Y
yamahigashi 已提交
1393

1394
				var ambientColor = fbxTree.GlobalSettings.AmbientColor.value;
1395 1396 1397
				var r = ambientColor[ 0 ];
				var g = ambientColor[ 1 ];
				var b = ambientColor[ 2 ];
Y
yamahigashi 已提交
1398

1399
				if ( r !== 0 || g !== 0 || b !== 0 ) {
M
Mr.doob 已提交
1400

1401 1402
					var color = new THREE.Color( r, g, b );
					sceneGraph.add( new THREE.AmbientLight( color, 1 ) );
M
Mr.doob 已提交
1403

1404
				}
Y
yamahigashi 已提交
1405

L
Lewy Blue 已提交
1406
			}
Y
yamahigashi 已提交
1407

L
Lewy Blue 已提交
1408
		},
Y
yamahigashi 已提交
1409

L
Lewy Blue 已提交
1410
		setupMorphMaterials: function () {
Y
yamahigashi 已提交
1411

W
WestLangley 已提交
1412
			var scope = this;
1413
			sceneGraph.traverse( function ( child ) {
Y
yamahigashi 已提交
1414

1415
				if ( child.isMesh ) {
Y
yamahigashi 已提交
1416

L
Lewy Blue 已提交
1417
					if ( child.geometry.morphAttributes.position && child.geometry.morphAttributes.position.length ) {
Y
yamahigashi 已提交
1418

L
Lewy Blue 已提交
1419
						if ( Array.isArray( child.material ) ) {
Y
yamahigashi 已提交
1420

L
Lewy Blue 已提交
1421
							child.material.forEach( function ( material, i ) {
Y
yamahigashi 已提交
1422

W
WestLangley 已提交
1423
								scope.setupMorphMaterial( child, material, i );
Y
yamahigashi 已提交
1424

L
Lewy Blue 已提交
1425
							} );
Y
yamahigashi 已提交
1426

L
Lewy Blue 已提交
1427
						} else {
Y
yamahigashi 已提交
1428

W
WestLangley 已提交
1429
							scope.setupMorphMaterial( child, child.material );
Y
yamahigashi 已提交
1430

L
Lewy Blue 已提交
1431
						}
Y
yamahigashi 已提交
1432

1433
					}
L
Lewy Blue 已提交
1434

1435
				}
L
Lewy Blue 已提交
1436

1437
			} );
Y
yamahigashi 已提交
1438

1439
		},
Y
yamahigashi 已提交
1440

L
Lewy Blue 已提交
1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478
		setupMorphMaterial: function ( child, material, index ) {

			var uuid = child.uuid;
			var matUuid = material.uuid;

			// if a geometry has morph targets, it cannot share the material with other geometries
			var sharedMat = false;

			sceneGraph.traverse( function ( node ) {

				if ( node.isMesh ) {

					if ( Array.isArray( node.material ) ) {

						node.material.forEach( function ( mat ) {

							if ( mat.uuid === matUuid && node.uuid !== uuid ) sharedMat = true;

						} );

					} else if ( node.material.uuid === matUuid && node.uuid !== uuid ) sharedMat = true;

				}

			} );

			if ( sharedMat === true ) {

				var clonedMat = material.clone();
				clonedMat.morphTargets = true;

				if ( index === undefined ) child.material = clonedMat;
				else child.material[ index ] = clonedMat;

			} else material.morphTargets = true;

		}

1479
	};
Y
yamahigashi 已提交
1480

1481 1482
	// parse Geometry data from FBXTree and return map of BufferGeometries
	function GeometryParser() {}
Y
yamahigashi 已提交
1483

1484
	GeometryParser.prototype = {
M
Mr.doob 已提交
1485

1486
		constructor: GeometryParser,
M
Mr.doob 已提交
1487

1488 1489
		// Parse nodes in FBXTree.Objects.Geometry
		parse: function ( deformers ) {
M
Mr.doob 已提交
1490

1491
			var geometryMap = new Map();
M
Mr.doob 已提交
1492

1493
			if ( 'Geometry' in fbxTree.Objects ) {
M
Mr.doob 已提交
1494

1495
				var geoNodes = fbxTree.Objects.Geometry;
M
Mr.doob 已提交
1496

1497
				for ( var nodeID in geoNodes ) {
M
Mr.doob 已提交
1498

1499 1500
					var relationships = connections.get( parseInt( nodeID ) );
					var geo = this.parseGeometry( relationships, geoNodes[ nodeID ], deformers );
M
Mr.doob 已提交
1501

1502
					geometryMap.set( parseInt( nodeID ), geo );
M
Mr.doob 已提交
1503

1504
				}
M
Mr.doob 已提交
1505

1506
			}
M
Mr.doob 已提交
1507

1508
			return geometryMap;
L
Lewy Blue 已提交
1509

1510
		},
M
Mr.doob 已提交
1511

1512 1513
		// Parse single node in FBXTree.Objects.Geometry
		parseGeometry: function ( relationships, geoNode, deformers ) {
M
Mr.doob 已提交
1514

1515
			switch ( geoNode.attrType ) {
M
Mr.doob 已提交
1516

1517 1518 1519
				case 'Mesh':
					return this.parseMeshGeometry( relationships, geoNode, deformers );
					break;
M
Mr.doob 已提交
1520

1521 1522 1523
				case 'NurbsCurve':
					return this.parseNurbsGeometry( geoNode );
					break;
M
Mr.doob 已提交
1524

L
Lewy Blue 已提交
1525
			}
M
Mr.doob 已提交
1526

1527
		},
M
Mr.doob 已提交
1528

L
Lewy Blue 已提交
1529

1530 1531
		// Parse single node mesh geometry in FBXTree.Objects.Geometry
		parseMeshGeometry: function ( relationships, geoNode, deformers ) {
M
Mr.doob 已提交
1532

1533
			var skeletons = deformers.skeletons;
1534
			var morphTargets = [];
M
Mr.doob 已提交
1535

1536
			var modelNodes = relationships.parents.map( function ( parent ) {
M
Mr.doob 已提交
1537

1538
				return fbxTree.Objects.Model[ parent.ID ];
M
Mr.doob 已提交
1539

1540
			} );
M
Mr.doob 已提交
1541

1542 1543
			// don't create geometry if it is not associated with any models
			if ( modelNodes.length === 0 ) return;
M
Mr.doob 已提交
1544

1545
			var skeleton = relationships.children.reduce( function ( skeleton, child ) {
M
Mr.doob 已提交
1546

1547
				if ( skeletons[ child.ID ] !== undefined ) skeleton = skeletons[ child.ID ];
M
Mr.doob 已提交
1548

1549
				return skeleton;
M
Mr.doob 已提交
1550

1551
			}, null );
M
Mr.doob 已提交
1552

1553
			relationships.children.forEach( function ( child ) {
1554

1555
				if ( deformers.morphTargets[ child.ID ] !== undefined ) {
1556

1557
					morphTargets.push( deformers.morphTargets[ child.ID ] );
L
Lewy Blue 已提交
1558

1559 1560 1561
				}

			} );
1562

1563
			// Assume one model and get the preRotation from that
1564
			// if there is more than one model associated with the geometry this may cause problems
1565
			var modelNode = modelNodes[ 0 ];
L
Lewy Blue 已提交
1566

1567
			var transformData = {};
L
Lewy Blue 已提交
1568

1569
			if ( 'RotationOrder' in modelNode ) transformData.eulerOrder = getEulerOrder( modelNode.RotationOrder.value );
1570 1571
			if ( 'InheritType' in modelNode ) transformData.inheritType = parseInt( modelNode.InheritType.value );

1572 1573 1574
			if ( 'GeometricTranslation' in modelNode ) transformData.translation = modelNode.GeometricTranslation.value;
			if ( 'GeometricRotation' in modelNode ) transformData.rotation = modelNode.GeometricRotation.value;
			if ( 'GeometricScaling' in modelNode ) transformData.scale = modelNode.GeometricScaling.value;
1575

1576
			var transform = generateTransform( transformData );
1577

1578
			return this.genGeometry( geoNode, skeleton, morphTargets, transform );
1579

1580
		},
1581

1582
		// Generate a THREE.BufferGeometry from a node in FBXTree.Objects.Geometry
1583
		genGeometry: function ( geoNode, skeleton, morphTargets, preTransform ) {
1584

1585 1586
			var geo = new THREE.BufferGeometry();
			if ( geoNode.attrName ) geo.name = geoNode.attrName;
1587

1588 1589
			var geoInfo = this.parseGeoNode( geoNode, skeleton );
			var buffers = this.genBuffers( geoInfo );
1590

1591
			var positionAttribute = new THREE.Float32BufferAttribute( buffers.vertex, 3 );
1592

1593
			positionAttribute.applyMatrix4( preTransform );
1594

1595
			geo.setAttribute( 'position', positionAttribute );
1596

1597
			if ( buffers.colors.length > 0 ) {
1598

1599
				geo.setAttribute( 'color', new THREE.Float32BufferAttribute( buffers.colors, 3 ) );
1600

1601
			}
1602

1603
			if ( skeleton ) {
1604

1605
				geo.setAttribute( 'skinIndex', new THREE.Uint16BufferAttribute( buffers.weightsIndices, 4 ) );
1606

1607
				geo.setAttribute( 'skinWeight', new THREE.Float32BufferAttribute( buffers.vertexWeights, 4 ) );
L
Lewy Blue 已提交
1608

1609 1610
				// used later to bind the skeleton to the model
				geo.FBX_Deformer = skeleton;
L
Lewy Blue 已提交
1611

1612
			}
L
Lewy Blue 已提交
1613

1614
			if ( buffers.normal.length > 0 ) {
L
Lewy Blue 已提交
1615

1616
				var normalMatrix = new THREE.Matrix3().getNormalMatrix( preTransform );
1617

M
Mr.doob 已提交
1618
				var normalAttribute = new THREE.Float32BufferAttribute( buffers.normal, 3 );
1619
				normalAttribute.applyNormalMatrix( normalMatrix );
L
Lewy Blue 已提交
1620

1621
				geo.setAttribute( 'normal', normalAttribute );
L
Lewy Blue 已提交
1622

1623
			}
L
Lewy Blue 已提交
1624

1625
			buffers.uvs.forEach( function ( uvBuffer, i ) {
L
Lewy Blue 已提交
1626

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

1630 1631
				// the first uv buffer is just called 'uv'
				if ( i === 0 ) {
L
Lewy Blue 已提交
1632

1633
					name = 'uv';
L
Lewy Blue 已提交
1634

L
Lewy Blue 已提交
1635
				}
L
Lewy Blue 已提交
1636

1637
				geo.setAttribute( name, new THREE.Float32BufferAttribute( buffers.uvs[ i ], 2 ) );
L
Lewy Blue 已提交
1638

1639
			} );
L
Lewy Blue 已提交
1640

1641
			if ( geoInfo.material && geoInfo.material.mappingType !== 'AllSame' ) {
L
Lewy Blue 已提交
1642

1643 1644 1645
				// Convert the material indices of each vertex into rendering groups on the geometry.
				var prevMaterialIndex = buffers.materialIndex[ 0 ];
				var startIndex = 0;
L
Lewy Blue 已提交
1646

1647
				buffers.materialIndex.forEach( function ( currentIndex, i ) {
L
Lewy Blue 已提交
1648

1649
					if ( currentIndex !== prevMaterialIndex ) {
L
Lewy Blue 已提交
1650

1651
						geo.addGroup( startIndex, i - startIndex, prevMaterialIndex );
L
Lewy Blue 已提交
1652

1653 1654
						prevMaterialIndex = currentIndex;
						startIndex = i;
L
Lewy Blue 已提交
1655

1656
					}
L
Lewy Blue 已提交
1657

1658
				} );
L
Lewy Blue 已提交
1659

1660 1661
				// the loop above doesn't add the last group, do that here.
				if ( geo.groups.length > 0 ) {
L
Lewy Blue 已提交
1662

1663 1664
					var lastGroup = geo.groups[ geo.groups.length - 1 ];
					var lastIndex = lastGroup.start + lastGroup.count;
L
Lewy Blue 已提交
1665

1666
					if ( lastIndex !== buffers.materialIndex.length ) {
L
Lewy Blue 已提交
1667

1668
						geo.addGroup( lastIndex, buffers.materialIndex.length - lastIndex, prevMaterialIndex );
L
Lewy Blue 已提交
1669

1670
					}
L
Lewy Blue 已提交
1671

1672
				}
L
Lewy Blue 已提交
1673

1674 1675 1676
				// case where there are multiple materials but the whole geometry is only
				// using one of them
				if ( geo.groups.length === 0 ) {
1677

1678
					geo.addGroup( 0, buffers.materialIndex.length, buffers.materialIndex[ 0 ] );
L
Lewy Blue 已提交
1679

1680
				}
L
Lewy Blue 已提交
1681

1682
			}
L
Lewy Blue 已提交
1683

1684
			this.addMorphTargets( geo, geoNode, morphTargets, preTransform );
L
Lewy Blue 已提交
1685

1686
			return geo;
L
Lewy Blue 已提交
1687

1688
		},
L
Lewy Blue 已提交
1689

1690
		parseGeoNode: function ( geoNode, skeleton ) {
L
Lewy Blue 已提交
1691

1692
			var geoInfo = {};
L
Lewy Blue 已提交
1693

1694 1695
			geoInfo.vertexPositions = ( geoNode.Vertices !== undefined ) ? geoNode.Vertices.a : [];
			geoInfo.vertexIndices = ( geoNode.PolygonVertexIndex !== undefined ) ? geoNode.PolygonVertexIndex.a : [];
L
Lewy Blue 已提交
1696

1697
			if ( geoNode.LayerElementColor ) {
L
Lewy Blue 已提交
1698

1699
				geoInfo.color = this.parseVertexColors( geoNode.LayerElementColor[ 0 ] );
L
Lewy Blue 已提交
1700

L
Lewy Blue 已提交
1701
			}
L
Lewy Blue 已提交
1702

1703
			if ( geoNode.LayerElementMaterial ) {
L
Lewy Blue 已提交
1704

1705
				geoInfo.material = this.parseMaterialIndices( geoNode.LayerElementMaterial[ 0 ] );
L
Lewy Blue 已提交
1706

1707
			}
L
Lewy Blue 已提交
1708

1709
			if ( geoNode.LayerElementNormal ) {
L
Lewy Blue 已提交
1710

1711
				geoInfo.normal = this.parseNormals( geoNode.LayerElementNormal[ 0 ] );
L
Lewy Blue 已提交
1712

1713
			}
L
Lewy Blue 已提交
1714

1715
			if ( geoNode.LayerElementUV ) {
L
Lewy Blue 已提交
1716

1717
				geoInfo.uv = [];
L
Lewy Blue 已提交
1718

1719 1720
				var i = 0;
				while ( geoNode.LayerElementUV[ i ] ) {
L
Lewy Blue 已提交
1721

1722 1723
					geoInfo.uv.push( this.parseUVs( geoNode.LayerElementUV[ i ] ) );
					i ++;
L
Lewy Blue 已提交
1724

1725
				}
L
Lewy Blue 已提交
1726

1727
			}
L
Lewy Blue 已提交
1728

1729
			geoInfo.weightTable = {};
L
Lewy Blue 已提交
1730

1731
			if ( skeleton !== null ) {
L
Lewy Blue 已提交
1732

1733
				geoInfo.skeleton = skeleton;
L
Lewy Blue 已提交
1734

1735
				skeleton.rawBones.forEach( function ( rawBone, i ) {
L
Lewy Blue 已提交
1736

1737 1738
					// loop over the bone's vertex indices and weights
					rawBone.indices.forEach( function ( index, j ) {
L
Lewy Blue 已提交
1739

1740
						if ( geoInfo.weightTable[ index ] === undefined ) geoInfo.weightTable[ index ] = [];
L
Lewy Blue 已提交
1741

1742
						geoInfo.weightTable[ index ].push( {
L
Lewy Blue 已提交
1743

1744 1745
							id: i,
							weight: rawBone.weights[ j ],
L
Lewy Blue 已提交
1746

1747
						} );
L
Lewy Blue 已提交
1748

1749
					} );
L
Lewy Blue 已提交
1750

1751
				} );
L
Lewy Blue 已提交
1752

1753
			}
L
Lewy Blue 已提交
1754

1755
			return geoInfo;
L
Lewy Blue 已提交
1756

L
Lewy Blue 已提交
1757
		},
L
Lewy Blue 已提交
1758

1759
		genBuffers: function ( geoInfo ) {
L
Lewy Blue 已提交
1760

1761 1762 1763 1764 1765 1766 1767 1768 1769
			var buffers = {
				vertex: [],
				normal: [],
				colors: [],
				uvs: [],
				materialIndex: [],
				vertexWeights: [],
				weightsIndices: [],
			};
L
Lewy Blue 已提交
1770

1771 1772 1773
			var polygonIndex = 0;
			var faceLength = 0;
			var displayedWeightsWarning = false;
L
Lewy Blue 已提交
1774

1775 1776 1777 1778 1779 1780 1781
			// these will hold data for a single face
			var facePositionIndexes = [];
			var faceNormals = [];
			var faceColors = [];
			var faceUVs = [];
			var faceWeights = [];
			var faceWeightIndices = [];
L
Lewy Blue 已提交
1782

W
WestLangley 已提交
1783
			var scope = this;
1784
			geoInfo.vertexIndices.forEach( function ( vertexIndex, polygonVertexIndex ) {
L
Lewy Blue 已提交
1785

1786
				var endOfFace = false;
L
Lewy Blue 已提交
1787

1788 1789 1790 1791 1792 1793 1794 1795
				// 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 bit shift the index: ^ - 1
				if ( vertexIndex < 0 ) {
L
Lewy Blue 已提交
1796

1797 1798
					vertexIndex = vertexIndex ^ - 1; // equivalent to ( x * -1 ) - 1
					endOfFace = true;
L
Lewy Blue 已提交
1799

1800
				}
L
Lewy Blue 已提交
1801

1802 1803
				var weightIndices = [];
				var weights = [];
L
Lewy Blue 已提交
1804

1805
				facePositionIndexes.push( vertexIndex * 3, vertexIndex * 3 + 1, vertexIndex * 3 + 2 );
L
Lewy Blue 已提交
1806

1807
				if ( geoInfo.color ) {
L
Lewy Blue 已提交
1808

1809
					var data = getData( polygonVertexIndex, polygonIndex, vertexIndex, geoInfo.color );
L
Lewy Blue 已提交
1810

1811
					faceColors.push( data[ 0 ], data[ 1 ], data[ 2 ] );
L
Lewy Blue 已提交
1812

1813
				}
L
Lewy Blue 已提交
1814

1815
				if ( geoInfo.skeleton ) {
L
Lewy Blue 已提交
1816

1817
					if ( geoInfo.weightTable[ vertexIndex ] !== undefined ) {
L
Lewy Blue 已提交
1818

1819
						geoInfo.weightTable[ vertexIndex ].forEach( function ( wt ) {
Y
yamahigashi 已提交
1820

1821 1822
							weights.push( wt.weight );
							weightIndices.push( wt.id );
Y
yamahigashi 已提交
1823

1824
						} );
Y
yamahigashi 已提交
1825 1826


1827
					}
Y
yamahigashi 已提交
1828

1829
					if ( weights.length > 4 ) {
Y
yamahigashi 已提交
1830

1831
						if ( ! displayedWeightsWarning ) {
Y
yamahigashi 已提交
1832

1833 1834
							console.warn( 'THREE.FBXLoader: Vertex has more than 4 skinning weights assigned to vertex. Deleting additional weights.' );
							displayedWeightsWarning = true;
Y
yamahigashi 已提交
1835

1836
						}
Y
yamahigashi 已提交
1837

1838 1839
						var wIndex = [ 0, 0, 0, 0 ];
						var Weight = [ 0, 0, 0, 0 ];
Y
yamahigashi 已提交
1840

1841
						weights.forEach( function ( weight, weightIndex ) {
M
Mr.doob 已提交
1842

1843 1844
							var currentWeight = weight;
							var currentIndex = weightIndices[ weightIndex ];
M
Mr.doob 已提交
1845

1846
							Weight.forEach( function ( comparedWeight, comparedWeightIndex, comparedWeightArray ) {
M
Mr.doob 已提交
1847

1848
								if ( currentWeight > comparedWeight ) {
Y
yamahigashi 已提交
1849

1850 1851
									comparedWeightArray[ comparedWeightIndex ] = currentWeight;
									currentWeight = comparedWeight;
Y
yamahigashi 已提交
1852

1853 1854 1855
									var tmp = wIndex[ comparedWeightIndex ];
									wIndex[ comparedWeightIndex ] = currentIndex;
									currentIndex = tmp;
Y
yamahigashi 已提交
1856

1857
								}
Y
yamahigashi 已提交
1858

1859
							} );
Y
yamahigashi 已提交
1860

1861
						} );
Y
yamahigashi 已提交
1862

1863 1864
						weightIndices = wIndex;
						weights = Weight;
Y
yamahigashi 已提交
1865

1866
					}
Y
yamahigashi 已提交
1867

1868 1869
					// if the weight array is shorter than 4 pad with 0s
					while ( weights.length < 4 ) {
Y
yamahigashi 已提交
1870

1871 1872
						weights.push( 0 );
						weightIndices.push( 0 );
1873

1874
					}
1875

1876
					for ( var i = 0; i < 4; ++ i ) {
Y
yamahigashi 已提交
1877

1878 1879
						faceWeights.push( weights[ i ] );
						faceWeightIndices.push( weightIndices[ i ] );
M
Mr.doob 已提交
1880

1881
					}
M
Mr.doob 已提交
1882

1883
				}
M
Mr.doob 已提交
1884

1885
				if ( geoInfo.normal ) {
M
Mr.doob 已提交
1886

1887
					var data = getData( polygonVertexIndex, polygonIndex, vertexIndex, geoInfo.normal );
M
Mr.doob 已提交
1888

1889
					faceNormals.push( data[ 0 ], data[ 1 ], data[ 2 ] );
M
Mr.doob 已提交
1890

1891
				}
M
Mr.doob 已提交
1892

1893
				if ( geoInfo.material && geoInfo.material.mappingType !== 'AllSame' ) {
M
Mr.doob 已提交
1894

1895
					var materialIndex = getData( polygonVertexIndex, polygonIndex, vertexIndex, geoInfo.material )[ 0 ];
L
Lewy Blue 已提交
1896

1897
				}
Y
yamahigashi 已提交
1898

1899
				if ( geoInfo.uv ) {
Y
yamahigashi 已提交
1900

1901
					geoInfo.uv.forEach( function ( uv, i ) {
Y
yamahigashi 已提交
1902

1903
						var data = getData( polygonVertexIndex, polygonIndex, vertexIndex, uv );
M
Mr.doob 已提交
1904

1905
						if ( faceUVs[ i ] === undefined ) {
M
Mr.doob 已提交
1906

1907
							faceUVs[ i ] = [];
M
Mr.doob 已提交
1908

1909
						}
M
Mr.doob 已提交
1910

1911 1912
						faceUVs[ i ].push( data[ 0 ] );
						faceUVs[ i ].push( data[ 1 ] );
Y
yamahigashi 已提交
1913

1914
					} );
Y
yamahigashi 已提交
1915

1916
				}
Y
yamahigashi 已提交
1917

1918
				faceLength ++;
Y
yamahigashi 已提交
1919

1920
				if ( endOfFace ) {
Y
yamahigashi 已提交
1921

W
WestLangley 已提交
1922
					scope.genFace( buffers, geoInfo, facePositionIndexes, materialIndex, faceNormals, faceColors, faceUVs, faceWeights, faceWeightIndices, faceLength );
Y
yamahigashi 已提交
1923

1924 1925
					polygonIndex ++;
					faceLength = 0;
Y
yamahigashi 已提交
1926

1927 1928 1929 1930 1931 1932 1933
					// reset arrays for the next face
					facePositionIndexes = [];
					faceNormals = [];
					faceColors = [];
					faceUVs = [];
					faceWeights = [];
					faceWeightIndices = [];
M
Mr.doob 已提交
1934

1935
				}
L
Lewy Blue 已提交
1936

L
Lewy Blue 已提交
1937
			} );
L
Lewy Blue 已提交
1938

1939
			return buffers;
L
Lewy Blue 已提交
1940

1941
		},
L
Lewy Blue 已提交
1942

1943 1944
		// Generate data for a single face in a geometry. If the face is a quad then split it into 2 tris
		genFace: function ( buffers, geoInfo, facePositionIndexes, materialIndex, faceNormals, faceColors, faceUVs, faceWeights, faceWeightIndices, faceLength ) {
L
Lewy Blue 已提交
1945

1946
			for ( var i = 2; i < faceLength; i ++ ) {
L
Lewy Blue 已提交
1947

1948 1949 1950
				buffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ 0 ] ] );
				buffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ 1 ] ] );
				buffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ 2 ] ] );
L
Lewy Blue 已提交
1951

1952 1953 1954
				buffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ ( i - 1 ) * 3 ] ] );
				buffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ ( i - 1 ) * 3 + 1 ] ] );
				buffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ ( i - 1 ) * 3 + 2 ] ] );
L
Lewy Blue 已提交
1955

1956 1957 1958
				buffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ i * 3 ] ] );
				buffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ i * 3 + 1 ] ] );
				buffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ i * 3 + 2 ] ] );
L
Lewy Blue 已提交
1959

1960
				if ( geoInfo.skeleton ) {
L
Lewy Blue 已提交
1961

1962 1963 1964 1965
					buffers.vertexWeights.push( faceWeights[ 0 ] );
					buffers.vertexWeights.push( faceWeights[ 1 ] );
					buffers.vertexWeights.push( faceWeights[ 2 ] );
					buffers.vertexWeights.push( faceWeights[ 3 ] );
L
Lewy Blue 已提交
1966

1967 1968 1969 1970
					buffers.vertexWeights.push( faceWeights[ ( i - 1 ) * 4 ] );
					buffers.vertexWeights.push( faceWeights[ ( i - 1 ) * 4 + 1 ] );
					buffers.vertexWeights.push( faceWeights[ ( i - 1 ) * 4 + 2 ] );
					buffers.vertexWeights.push( faceWeights[ ( i - 1 ) * 4 + 3 ] );
L
Lewy Blue 已提交
1971

1972 1973 1974 1975
					buffers.vertexWeights.push( faceWeights[ i * 4 ] );
					buffers.vertexWeights.push( faceWeights[ i * 4 + 1 ] );
					buffers.vertexWeights.push( faceWeights[ i * 4 + 2 ] );
					buffers.vertexWeights.push( faceWeights[ i * 4 + 3 ] );
L
Lewy Blue 已提交
1976

1977 1978 1979 1980
					buffers.weightsIndices.push( faceWeightIndices[ 0 ] );
					buffers.weightsIndices.push( faceWeightIndices[ 1 ] );
					buffers.weightsIndices.push( faceWeightIndices[ 2 ] );
					buffers.weightsIndices.push( faceWeightIndices[ 3 ] );
L
Lewy Blue 已提交
1981

1982 1983 1984 1985
					buffers.weightsIndices.push( faceWeightIndices[ ( i - 1 ) * 4 ] );
					buffers.weightsIndices.push( faceWeightIndices[ ( i - 1 ) * 4 + 1 ] );
					buffers.weightsIndices.push( faceWeightIndices[ ( i - 1 ) * 4 + 2 ] );
					buffers.weightsIndices.push( faceWeightIndices[ ( i - 1 ) * 4 + 3 ] );
L
Lewy Blue 已提交
1986

1987 1988 1989 1990
					buffers.weightsIndices.push( faceWeightIndices[ i * 4 ] );
					buffers.weightsIndices.push( faceWeightIndices[ i * 4 + 1 ] );
					buffers.weightsIndices.push( faceWeightIndices[ i * 4 + 2 ] );
					buffers.weightsIndices.push( faceWeightIndices[ i * 4 + 3 ] );
L
Lewy Blue 已提交
1991 1992

				}
L
Lewy Blue 已提交
1993

1994
				if ( geoInfo.color ) {
L
Lewy Blue 已提交
1995

1996 1997 1998
					buffers.colors.push( faceColors[ 0 ] );
					buffers.colors.push( faceColors[ 1 ] );
					buffers.colors.push( faceColors[ 2 ] );
L
Lewy Blue 已提交
1999

2000 2001 2002
					buffers.colors.push( faceColors[ ( i - 1 ) * 3 ] );
					buffers.colors.push( faceColors[ ( i - 1 ) * 3 + 1 ] );
					buffers.colors.push( faceColors[ ( i - 1 ) * 3 + 2 ] );
L
Lewy Blue 已提交
2003

2004 2005 2006
					buffers.colors.push( faceColors[ i * 3 ] );
					buffers.colors.push( faceColors[ i * 3 + 1 ] );
					buffers.colors.push( faceColors[ i * 3 + 2 ] );
L
Lewy Blue 已提交
2007

2008
				}
L
Lewy Blue 已提交
2009

2010
				if ( geoInfo.material && geoInfo.material.mappingType !== 'AllSame' ) {
L
Lewy Blue 已提交
2011

2012 2013 2014
					buffers.materialIndex.push( materialIndex );
					buffers.materialIndex.push( materialIndex );
					buffers.materialIndex.push( materialIndex );
L
Lewy Blue 已提交
2015

2016
				}
M
Mr.doob 已提交
2017

2018
				if ( geoInfo.normal ) {
M
Mr.doob 已提交
2019

2020 2021 2022
					buffers.normal.push( faceNormals[ 0 ] );
					buffers.normal.push( faceNormals[ 1 ] );
					buffers.normal.push( faceNormals[ 2 ] );
M
Mr.doob 已提交
2023

2024 2025 2026
					buffers.normal.push( faceNormals[ ( i - 1 ) * 3 ] );
					buffers.normal.push( faceNormals[ ( i - 1 ) * 3 + 1 ] );
					buffers.normal.push( faceNormals[ ( i - 1 ) * 3 + 2 ] );
M
Mr.doob 已提交
2027

2028 2029 2030
					buffers.normal.push( faceNormals[ i * 3 ] );
					buffers.normal.push( faceNormals[ i * 3 + 1 ] );
					buffers.normal.push( faceNormals[ i * 3 + 2 ] );
Y
yamahigashi 已提交
2031

2032
				}
Y
yamahigashi 已提交
2033

2034
				if ( geoInfo.uv ) {
Y
yamahigashi 已提交
2035

2036
					geoInfo.uv.forEach( function ( uv, j ) {
Y
yamahigashi 已提交
2037

2038
						if ( buffers.uvs[ j ] === undefined ) buffers.uvs[ j ] = [];
M
Mr.doob 已提交
2039

2040 2041
						buffers.uvs[ j ].push( faceUVs[ j ][ 0 ] );
						buffers.uvs[ j ].push( faceUVs[ j ][ 1 ] );
M
Mr.doob 已提交
2042

2043 2044
						buffers.uvs[ j ].push( faceUVs[ j ][ ( i - 1 ) * 2 ] );
						buffers.uvs[ j ].push( faceUVs[ j ][ ( i - 1 ) * 2 + 1 ] );
M
Mr.doob 已提交
2045

2046 2047
						buffers.uvs[ j ].push( faceUVs[ j ][ i * 2 ] );
						buffers.uvs[ j ].push( faceUVs[ j ][ i * 2 + 1 ] );
Y
yamahigashi 已提交
2048

2049
					} );
2050

L
Lewy Blue 已提交
2051
				}
Y
yamahigashi 已提交
2052

L
Lewy Blue 已提交
2053
			}
Y
yamahigashi 已提交
2054

2055
		},
Y
yamahigashi 已提交
2056

2057
		addMorphTargets: function ( parentGeo, parentGeoNode, morphTargets, preTransform ) {
Y
yamahigashi 已提交
2058

2059
			if ( morphTargets.length === 0 ) return;
Y
yamahigashi 已提交
2060

L
Lewy Blue 已提交
2061 2062
			parentGeo.morphTargetsRelative = true;

2063
			parentGeo.morphAttributes.position = [];
L
Lewy Blue 已提交
2064 2065
			// parentGeo.morphAttributes.normal = []; // not implemented

W
WestLangley 已提交
2066
			var scope = this;
2067
			morphTargets.forEach( function ( morphTarget ) {
M
Mr.doob 已提交
2068

2069
				morphTarget.rawTargets.forEach( function ( rawTarget ) {
M
Mr.doob 已提交
2070

2071
					var morphGeoNode = fbxTree.Objects.Geometry[ rawTarget.geoID ];
L
Lewy Blue 已提交
2072

2073
					if ( morphGeoNode !== undefined ) {
L
Lewy Blue 已提交
2074

W
WestLangley 已提交
2075
						scope.genMorphGeometry( parentGeo, parentGeoNode, morphGeoNode, preTransform, rawTarget.name );
2076 2077 2078 2079

					}

				} );
M
Mr.doob 已提交
2080

2081
			} );
Y
yamahigashi 已提交
2082

2083
		},
Y
yamahigashi 已提交
2084

2085 2086 2087 2088
		// a morph geometry node is similar to a standard  node, and the node is also contained
		// in FBXTree.Objects.Geometry, however it can only have attributes for position, normal
		// and a special attribute Index defining which vertices of the original geometry are affected
		// Normal and position attributes only have data for the vertices that are affected by the morph
L
Lewy Blue 已提交
2089
		genMorphGeometry: function ( parentGeo, parentGeoNode, morphGeoNode, preTransform, name ) {
Y
yamahigashi 已提交
2090

2091
			var vertexIndices = ( parentGeoNode.PolygonVertexIndex !== undefined ) ? parentGeoNode.PolygonVertexIndex.a : [];
Y
yamahigashi 已提交
2092

L
Lewy Blue 已提交
2093
			var morphPositionsSparse = ( morphGeoNode.Vertices !== undefined ) ? morphGeoNode.Vertices.a : [];
2094
			var indices = ( morphGeoNode.Indexes !== undefined ) ? morphGeoNode.Indexes.a : [];
M
Mr.doob 已提交
2095

L
Lewy Blue 已提交
2096 2097 2098
			var length = parentGeo.attributes.position.count * 3;
			var morphPositions = new Float32Array( length );

2099
			for ( var i = 0; i < indices.length; i ++ ) {
Y
yamahigashi 已提交
2100

2101
				var morphIndex = indices[ i ] * 3;
Y
yamahigashi 已提交
2102

L
Lewy Blue 已提交
2103 2104 2105
				morphPositions[ morphIndex ] = morphPositionsSparse[ i * 3 ];
				morphPositions[ morphIndex + 1 ] = morphPositionsSparse[ i * 3 + 1 ];
				morphPositions[ morphIndex + 2 ] = morphPositionsSparse[ i * 3 + 2 ];
L
Lewy Blue 已提交
2106

2107
			}
L
Lewy Blue 已提交
2108

2109 2110 2111
			// TODO: add morph normal support
			var morphGeoInfo = {
				vertexIndices: vertexIndices,
L
Lewy Blue 已提交
2112 2113
				vertexPositions: morphPositions,

2114
			};
L
Lewy Blue 已提交
2115

2116
			var morphBuffers = this.genBuffers( morphGeoInfo );
L
Lewy Blue 已提交
2117

2118
			var positionAttribute = new THREE.Float32BufferAttribute( morphBuffers.vertex, 3 );
L
Lewy Blue 已提交
2119
			positionAttribute.name = name || morphGeoNode.attrName;
Y
yamahigashi 已提交
2120

2121
			positionAttribute.applyMatrix4( preTransform );
L
Lewy Blue 已提交
2122

2123
			parentGeo.morphAttributes.position.push( positionAttribute );
L
Lewy Blue 已提交
2124

2125
		},
2126

2127 2128
		// Parse normal from FBXTree.Objects.Geometry.LayerElementNormal if it exists
		parseNormals: function ( NormalNode ) {
L
Lewy Blue 已提交
2129

2130 2131 2132 2133 2134
			var mappingType = NormalNode.MappingInformationType;
			var referenceType = NormalNode.ReferenceInformationType;
			var buffer = NormalNode.Normals.a;
			var indexBuffer = [];
			if ( referenceType === 'IndexToDirect' ) {
L
Lewy Blue 已提交
2135

2136
				if ( 'NormalIndex' in NormalNode ) {
L
Lewy Blue 已提交
2137

2138
					indexBuffer = NormalNode.NormalIndex.a;
L
Lewy Blue 已提交
2139

2140
				} else if ( 'NormalsIndex' in NormalNode ) {
L
Lewy Blue 已提交
2141

2142
					indexBuffer = NormalNode.NormalsIndex.a;
L
Lewy Blue 已提交
2143

2144
				}
Y
yamahigashi 已提交
2145

2146
			}
2147

2148 2149 2150 2151 2152 2153 2154
			return {
				dataSize: 3,
				buffer: buffer,
				indices: indexBuffer,
				mappingType: mappingType,
				referenceType: referenceType
			};
2155

2156
		},
2157

2158 2159
		// Parse UVs from FBXTree.Objects.Geometry.LayerElementUV if it exists
		parseUVs: function ( UVNode ) {
2160

2161 2162 2163 2164 2165
			var mappingType = UVNode.MappingInformationType;
			var referenceType = UVNode.ReferenceInformationType;
			var buffer = UVNode.UV.a;
			var indexBuffer = [];
			if ( referenceType === 'IndexToDirect' ) {
2166

2167
				indexBuffer = UVNode.UVIndex.a;
M
Mr.doob 已提交
2168

2169
			}
M
Mr.doob 已提交
2170

2171 2172 2173 2174 2175 2176 2177
			return {
				dataSize: 2,
				buffer: buffer,
				indices: indexBuffer,
				mappingType: mappingType,
				referenceType: referenceType
			};
M
Mr.doob 已提交
2178

2179
		},
M
Mr.doob 已提交
2180

2181 2182
		// Parse Vertex Colors from FBXTree.Objects.Geometry.LayerElementColor if it exists
		parseVertexColors: function ( ColorNode ) {
Y
yamahigashi 已提交
2183

2184 2185 2186 2187 2188
			var mappingType = ColorNode.MappingInformationType;
			var referenceType = ColorNode.ReferenceInformationType;
			var buffer = ColorNode.Colors.a;
			var indexBuffer = [];
			if ( referenceType === 'IndexToDirect' ) {
M
Mr.doob 已提交
2189

2190
				indexBuffer = ColorNode.ColorIndex.a;
Y
yamahigashi 已提交
2191

2192
			}
Y
yamahigashi 已提交
2193

2194 2195 2196 2197 2198 2199 2200
			return {
				dataSize: 4,
				buffer: buffer,
				indices: indexBuffer,
				mappingType: mappingType,
				referenceType: referenceType
			};
Y
yamahigashi 已提交
2201

2202
		},
M
Mr.doob 已提交
2203

2204 2205
		// Parse mapping and material data in FBXTree.Objects.Geometry.LayerElementMaterial if it exists
		parseMaterialIndices: function ( MaterialNode ) {
M
Mr.doob 已提交
2206

2207 2208
			var mappingType = MaterialNode.MappingInformationType;
			var referenceType = MaterialNode.ReferenceInformationType;
M
Mr.doob 已提交
2209

2210
			if ( mappingType === 'NoMappingInformation' ) {
M
Mr.doob 已提交
2211

2212 2213 2214 2215 2216 2217 2218
				return {
					dataSize: 1,
					buffer: [ 0 ],
					indices: [ 0 ],
					mappingType: 'AllSame',
					referenceType: referenceType
				};
M
Mr.doob 已提交
2219

2220
			}
M
Mr.doob 已提交
2221

2222
			var materialIndexBuffer = MaterialNode.Materials.a;
M
Mr.doob 已提交
2223

2224 2225 2226 2227
			// Since materials are stored as indices, there's a bit of a mismatch between FBX and what
			// we expect.So we create an intermediate buffer that points to the index in the buffer,
			// for conforming with the other functions we've written for other data.
			var materialIndices = [];
M
Mr.doob 已提交
2228

2229
			for ( var i = 0; i < materialIndexBuffer.length; ++ i ) {
M
Mr.doob 已提交
2230

2231
				materialIndices.push( i );
M
Mr.doob 已提交
2232

2233
			}
Y
yamahigashi 已提交
2234

2235 2236 2237 2238 2239 2240 2241
			return {
				dataSize: 1,
				buffer: materialIndexBuffer,
				indices: materialIndices,
				mappingType: mappingType,
				referenceType: referenceType
			};
Y
yamahigashi 已提交
2242

2243
		},
Y
yamahigashi 已提交
2244

2245 2246
		// Generate a NurbGeometry from a node in FBXTree.Objects.Geometry
		parseNurbsGeometry: function ( geoNode ) {
Y
yamahigashi 已提交
2247

2248
			if ( THREE.NURBSCurve === undefined ) {
M
Mr.doob 已提交
2249

2250 2251
				console.error( 'THREE.FBXLoader: The loader relies on THREE.NURBSCurve for any nurbs present in the model. Nurbs will show up as empty geometry.' );
				return new THREE.BufferGeometry();
Y
yamahigashi 已提交
2252

2253
			}
2254

2255
			var order = parseInt( geoNode.Order );
Y
yamahigashi 已提交
2256

2257
			if ( isNaN( order ) ) {
2258

2259 2260
				console.error( 'THREE.FBXLoader: Invalid Order %s given for geometry ID: %s', geoNode.Order, geoNode.id );
				return new THREE.BufferGeometry();
2261

2262
			}
2263

2264
			var degree = order - 1;
L
Lewy Blue 已提交
2265

2266 2267 2268
			var knots = geoNode.KnotVector.a;
			var controlPoints = [];
			var pointsValues = geoNode.Points.a;
2269

2270
			for ( var i = 0, l = pointsValues.length; i < l; i += 4 ) {
2271

2272
				controlPoints.push( new THREE.Vector4().fromArray( pointsValues, i ) );
2273

2274
			}
2275

2276
			var startKnot, endKnot;
2277

2278
			if ( geoNode.Form === 'Closed' ) {
2279

2280
				controlPoints.push( controlPoints[ 0 ] );
2281

2282
			} else if ( geoNode.Form === 'Periodic' ) {
Y
yamahigashi 已提交
2283

2284 2285
				startKnot = degree;
				endKnot = knots.length - 1 - startKnot;
Y
yamahigashi 已提交
2286

2287
				for ( var i = 0; i < degree; ++ i ) {
Y
yamahigashi 已提交
2288

2289
					controlPoints.push( controlPoints[ i ] );
Y
yamahigashi 已提交
2290

L
Lewy Blue 已提交
2291
				}
M
Mr.doob 已提交
2292

2293
			}
L
Lewy Blue 已提交
2294

2295 2296
			var curve = new THREE.NURBSCurve( degree, knots, controlPoints, startKnot, endKnot );
			var vertices = curve.getPoints( controlPoints.length * 7 );
L
Lewy Blue 已提交
2297

2298
			var positions = new Float32Array( vertices.length * 3 );
L
Lewy Blue 已提交
2299

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

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

2304
			} );
M
Mr.doob 已提交
2305

2306
			var geometry = new THREE.BufferGeometry();
2307
			geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
M
Mr.doob 已提交
2308

2309
			return geometry;
Y
yamahigashi 已提交
2310

2311
		},
2312

2313
	};
Y
yamahigashi 已提交
2314

2315 2316
	// parse animation data from FBXTree
	function AnimationParser() {}
Y
yamahigashi 已提交
2317

2318
	AnimationParser.prototype = {
Y
yamahigashi 已提交
2319

2320
		constructor: AnimationParser,
Y
yamahigashi 已提交
2321

2322
		// take raw animation clips and turn them into three.js animation clips
L
Lewy Blue 已提交
2323
		parse: function () {
Y
yamahigashi 已提交
2324

2325
			var animationClips = [];
Y
yamahigashi 已提交
2326

2327
			var rawClips = this.parseClips();
Y
yamahigashi 已提交
2328

2329
			if ( rawClips !== undefined ) {
Y
yamahigashi 已提交
2330

2331
				for ( var key in rawClips ) {
Y
yamahigashi 已提交
2332

2333
					var rawClip = rawClips[ key ];
Y
yamahigashi 已提交
2334

2335
					var clip = this.addClip( rawClip );
Y
yamahigashi 已提交
2336

2337 2338 2339
					animationClips.push( clip );

				}
M
Mr.doob 已提交
2340

2341
			}
L
Lewy Blue 已提交
2342

2343
			return animationClips;
L
Lewy Blue 已提交
2344

2345
		},
Y
yamahigashi 已提交
2346

2347
		parseClips: function () {
Y
yamahigashi 已提交
2348

2349 2350
			// since the actual transformation data is stored in FBXTree.Objects.AnimationCurve,
			// if this is undefined we can safely assume there are no animations
2351
			if ( fbxTree.Objects.AnimationCurve === undefined ) return undefined;
Y
yamahigashi 已提交
2352

2353
			var curveNodesMap = this.parseAnimationCurveNodes();
M
Mr.doob 已提交
2354

2355
			this.parseAnimationCurves( curveNodesMap );
M
Mr.doob 已提交
2356

2357 2358
			var layersMap = this.parseAnimationLayers( curveNodesMap );
			var rawClips = this.parseAnimStacks( layersMap );
M
Mr.doob 已提交
2359

2360
			return rawClips;
M
Mr.doob 已提交
2361

2362
		},
M
Mr.doob 已提交
2363

2364 2365 2366 2367
		// parse nodes in FBXTree.Objects.AnimationCurveNode
		// each AnimationCurveNode holds data for an animation transform for a model (e.g. left arm rotation )
		// and is referenced by an AnimationLayer
		parseAnimationCurveNodes: function () {
M
Mr.doob 已提交
2368

2369
			var rawCurveNodes = fbxTree.Objects.AnimationCurveNode;
M
Mr.doob 已提交
2370

2371
			var curveNodesMap = new Map();
Y
yamahigashi 已提交
2372

2373
			for ( var nodeID in rawCurveNodes ) {
Y
yamahigashi 已提交
2374

2375
				var rawCurveNode = rawCurveNodes[ nodeID ];
Y
yamahigashi 已提交
2376

2377
				if ( rawCurveNode.attrName.match( /S|R|T|DeformPercent/ ) !== null ) {
Y
yamahigashi 已提交
2378

2379
					var curveNode = {
Y
yamahigashi 已提交
2380

2381 2382 2383
						id: rawCurveNode.id,
						attr: rawCurveNode.attrName,
						curves: {},
Y
yamahigashi 已提交
2384

2385
					};
Y
yamahigashi 已提交
2386

2387
					curveNodesMap.set( curveNode.id, curveNode );
Y
yamahigashi 已提交
2388

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

2391
			}
Y
yamahigashi 已提交
2392

2393
			return curveNodesMap;
Y
yamahigashi 已提交
2394

2395
		},
Y
yamahigashi 已提交
2396

2397 2398 2399 2400
		// parse nodes in FBXTree.Objects.AnimationCurve and connect them up to
		// previously parsed AnimationCurveNodes. Each AnimationCurve holds data for a single animated
		// axis ( e.g. times and values of x rotation)
		parseAnimationCurves: function ( curveNodesMap ) {
Y
yamahigashi 已提交
2401

2402
			var rawCurves = fbxTree.Objects.AnimationCurve;
Y
yamahigashi 已提交
2403

2404 2405 2406 2407 2408 2409
			// TODO: Many values are identical up to roundoff error, but won't be optimised
			// e.g. position times: [0, 0.4, 0. 8]
			// position values: [7.23538335023477e-7, 93.67518615722656, -0.9982695579528809, 7.23538335023477e-7, 93.67518615722656, -0.9982695579528809, 7.235384487103147e-7, 93.67520904541016, -0.9982695579528809]
			// clearly, this should be optimised to
			// times: [0], positions [7.23538335023477e-7, 93.67518615722656, -0.9982695579528809]
			// this shows up in nearly every FBX file, and generally time array is length > 100
Y
yamahigashi 已提交
2410

2411
			for ( var nodeID in rawCurves ) {
L
Lewy Blue 已提交
2412

2413
				var animationCurve = {
L
Lewy Blue 已提交
2414

2415 2416 2417
					id: rawCurves[ nodeID ].id,
					times: rawCurves[ nodeID ].KeyTime.a.map( convertFBXTimeToSeconds ),
					values: rawCurves[ nodeID ].KeyValueFloat.a,
L
Lewy Blue 已提交
2418

2419
				};
L
Lewy Blue 已提交
2420

2421
				var relationships = connections.get( animationCurve.id );
L
Lewy Blue 已提交
2422

2423
				if ( relationships !== undefined ) {
L
Lewy Blue 已提交
2424

2425 2426
					var animationCurveID = relationships.parents[ 0 ].ID;
					var animationCurveRelationship = relationships.parents[ 0 ].relationship;
L
Lewy Blue 已提交
2427

2428
					if ( animationCurveRelationship.match( /X/ ) ) {
Y
yamahigashi 已提交
2429

2430
						curveNodesMap.get( animationCurveID ).curves[ 'x' ] = animationCurve;
Y
yamahigashi 已提交
2431

2432
					} else if ( animationCurveRelationship.match( /Y/ ) ) {
L
Lewy Blue 已提交
2433

2434
						curveNodesMap.get( animationCurveID ).curves[ 'y' ] = animationCurve;
L
Lewy Blue 已提交
2435

2436
					} else if ( animationCurveRelationship.match( /Z/ ) ) {
L
Lewy Blue 已提交
2437

2438
						curveNodesMap.get( animationCurveID ).curves[ 'z' ] = animationCurve;
L
Lewy Blue 已提交
2439

2440
					} else if ( animationCurveRelationship.match( /d|DeformPercent/ ) && curveNodesMap.has( animationCurveID ) ) {
L
Lewy Blue 已提交
2441

2442
						curveNodesMap.get( animationCurveID ).curves[ 'morph' ] = animationCurve;
L
Lewy Blue 已提交
2443

2444
					}
L
Lewy Blue 已提交
2445

L
Lewy Blue 已提交
2446
				}
Y
yamahigashi 已提交
2447

L
Lewy Blue 已提交
2448
			}
M
Mr.doob 已提交
2449

L
Lewy Blue 已提交
2450
		},
L
Lewy Blue 已提交
2451

2452 2453 2454 2455
		// parse nodes in FBXTree.Objects.AnimationLayer. Each layers holds references
		// to various AnimationCurveNodes and is referenced by an AnimationStack node
		// note: theoretically a stack can have multiple layers, however in practice there always seems to be one per stack
		parseAnimationLayers: function ( curveNodesMap ) {
Y
yamahigashi 已提交
2456

2457
			var rawLayers = fbxTree.Objects.AnimationLayer;
Y
yamahigashi 已提交
2458

2459
			var layersMap = new Map();
L
Lewy Blue 已提交
2460

2461
			for ( var nodeID in rawLayers ) {
Y
yamahigashi 已提交
2462

2463
				var layerCurveNodes = [];
Y
yamahigashi 已提交
2464

2465
				var connection = connections.get( parseInt( nodeID ) );
2466

2467
				if ( connection !== undefined ) {
2468

2469 2470
					// all the animationCurveNodes used in the layer
					var children = connection.children;
2471

2472
					children.forEach( function ( child, i ) {
2473

2474
						if ( curveNodesMap.has( child.ID ) ) {
2475

2476
							var curveNode = curveNodesMap.get( child.ID );
2477

2478 2479
							// check that the curves are defined for at least one axis, otherwise ignore the curveNode
							if ( curveNode.curves.x !== undefined || curveNode.curves.y !== undefined || curveNode.curves.z !== undefined ) {
2480

2481
								if ( layerCurveNodes[ i ] === undefined ) {
2482

L
Lewy Blue 已提交
2483
									var modelID = connections.get( child.ID ).parents.filter( function ( parent ) {
2484

L
Lewy Blue 已提交
2485
										return parent.relationship !== undefined;
Y
yamahigashi 已提交
2486

L
Lewy Blue 已提交
2487
									} )[ 0 ].ID;
Y
yamahigashi 已提交
2488

L
Lewy Blue 已提交
2489
									if ( modelID !== undefined ) {
Y
yamahigashi 已提交
2490

L
Lewy Blue 已提交
2491
										var rawModel = fbxTree.Objects.Model[ modelID.toString() ];
2492

L
Lewy Blue 已提交
2493
										var node = {
2494

2495
											modelName: rawModel.attrName ? THREE.PropertyBinding.sanitizeNodeName( rawModel.attrName ) : '',
L
Lewy Blue 已提交
2496 2497 2498 2499
											ID: rawModel.id,
											initialPosition: [ 0, 0, 0 ],
											initialRotation: [ 0, 0, 0 ],
											initialScale: [ 1, 1, 1 ],
2500

L
Lewy Blue 已提交
2501
										};
Y
yamahigashi 已提交
2502

L
Lewy Blue 已提交
2503
										sceneGraph.traverse( function ( child ) {
2504

2505
											if ( child.ID === rawModel.id ) {
2506

L
Lewy Blue 已提交
2507
												node.transform = child.matrix;
L
Lewy Blue 已提交
2508

L
Lewy Blue 已提交
2509
												if ( child.userData.transformData ) node.eulerOrder = child.userData.transformData.eulerOrder;
2510

L
Lewy Blue 已提交
2511
											}
2512

L
Lewy Blue 已提交
2513
										} );
2514

L
Lewy Blue 已提交
2515
										if ( ! node.transform ) node.transform = new THREE.Matrix4();
L
Lewy Blue 已提交
2516

L
Lewy Blue 已提交
2517 2518 2519 2520
										// if the animated model is pre rotated, we'll have to apply the pre rotations to every
										// animation value as well
										if ( 'PreRotation' in rawModel ) node.preRotation = rawModel.PreRotation.value;
										if ( 'PostRotation' in rawModel ) node.postRotation = rawModel.PostRotation.value;
L
Lewy Blue 已提交
2521

L
Lewy Blue 已提交
2522 2523 2524
										layerCurveNodes[ i ] = node;

									}
Y
yamahigashi 已提交
2525

2526
								}
Y
yamahigashi 已提交
2527

L
Lewy Blue 已提交
2528
								if ( layerCurveNodes[ i ] ) layerCurveNodes[ i ][ curveNode.attr ] = curveNode;
M
Mr.doob 已提交
2529

2530
							} else if ( curveNode.curves.morph !== undefined ) {
M
Mr.doob 已提交
2531

2532
								if ( layerCurveNodes[ i ] === undefined ) {
Y
yamahigashi 已提交
2533

L
Lewy Blue 已提交
2534
									var deformerID = connections.get( child.ID ).parents.filter( function ( parent ) {
Y
yamahigashi 已提交
2535

L
Lewy Blue 已提交
2536
										return parent.relationship !== undefined;
L
Lewy Blue 已提交
2537

L
Lewy Blue 已提交
2538
									} )[ 0 ].ID;
M
Mr.doob 已提交
2539

2540 2541
									var morpherID = connections.get( deformerID ).parents[ 0 ].ID;
									var geoID = connections.get( morpherID ).parents[ 0 ].ID;
M
Mr.doob 已提交
2542

2543 2544
									// assuming geometry is not used in more than one model
									var modelID = connections.get( geoID ).parents[ 0 ].ID;
Y
yamahigashi 已提交
2545

2546
									var rawModel = fbxTree.Objects.Model[ modelID ];
Y
yamahigashi 已提交
2547

2548
									var node = {
Y
yamahigashi 已提交
2549

2550
										modelName: rawModel.attrName ? THREE.PropertyBinding.sanitizeNodeName( rawModel.attrName ) : '',
2551
										morphName: fbxTree.Objects.Deformer[ deformerID ].attrName,
Y
yamahigashi 已提交
2552

2553
									};
Y
yamahigashi 已提交
2554

2555
									layerCurveNodes[ i ] = node;
Y
yamahigashi 已提交
2556

2557
								}
Y
yamahigashi 已提交
2558

2559
								layerCurveNodes[ i ][ curveNode.attr ] = curveNode;
Y
yamahigashi 已提交
2560

2561
							}
Y
yamahigashi 已提交
2562

2563
						}
Y
yamahigashi 已提交
2564

2565 2566 2567
					} );

					layersMap.set( parseInt( nodeID ), layerCurveNodes );
Y
yamahigashi 已提交
2568

L
Lewy Blue 已提交
2569
				}
Y
yamahigashi 已提交
2570

L
Lewy Blue 已提交
2571
			}
Y
yamahigashi 已提交
2572

2573
			return layersMap;
Y
yamahigashi 已提交
2574

2575
		},
L
Lewy Blue 已提交
2576

2577 2578 2579
		// parse nodes in FBXTree.Objects.AnimationStack. These are the top level node in the animation
		// hierarchy. Each Stack node will be used to create a THREE.AnimationClip
		parseAnimStacks: function ( layersMap ) {
Y
yamahigashi 已提交
2580

2581
			var rawStacks = fbxTree.Objects.AnimationStack;
2582

2583 2584
			// connect the stacks (clips) up to the layers
			var rawClips = {};
2585

2586
			for ( var nodeID in rawStacks ) {
L
Lewy Blue 已提交
2587

2588
				var children = connections.get( parseInt( nodeID ) ).children;
Y
yamahigashi 已提交
2589

2590
				if ( children.length > 1 ) {
Y
yamahigashi 已提交
2591

2592 2593 2594
					// 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.' );
Y
yamahigashi 已提交
2595

2596
				}
Y
yamahigashi 已提交
2597

2598 2599 2600 2601 2602 2603 2604 2605 2606 2607
				var layer = layersMap.get( children[ 0 ].ID );

				rawClips[ nodeID ] = {

					name: rawStacks[ nodeID ].attrName,
					layer: layer,

				};

			}
Y
yamahigashi 已提交
2608

L
Lewy Blue 已提交
2609
			return rawClips;
M
Mr.doob 已提交
2610

L
Lewy Blue 已提交
2611
		},
Y
yamahigashi 已提交
2612

L
Lewy Blue 已提交
2613
		addClip: function ( rawClip ) {
L
Lewy Blue 已提交
2614

2615
			var tracks = [];
L
Lewy Blue 已提交
2616

W
WestLangley 已提交
2617
			var scope = this;
2618
			rawClip.layer.forEach( function ( rawTracks ) {
L
Lewy Blue 已提交
2619

W
WestLangley 已提交
2620
				tracks = tracks.concat( scope.generateTracks( rawTracks ) );
Y
yamahigashi 已提交
2621

2622
			} );
Y
yamahigashi 已提交
2623

2624
			return new THREE.AnimationClip( rawClip.name, - 1, tracks );
2625

2626
		},
2627

L
Lewy Blue 已提交
2628
		generateTracks: function ( rawTracks ) {
2629

2630
			var tracks = [];
2631

2632 2633 2634
			var initialPosition = new THREE.Vector3();
			var initialRotation = new THREE.Quaternion();
			var initialScale = new THREE.Vector3();
2635

L
Lewy Blue 已提交
2636
			if ( rawTracks.transform ) rawTracks.transform.decompose( initialPosition, initialRotation, initialScale );
2637 2638

			initialPosition = initialPosition.toArray();
2639
			initialRotation = new THREE.Euler().setFromQuaternion( initialRotation, rawTracks.eulerOrder ).toArray();
2640 2641 2642 2643 2644 2645
			initialScale = initialScale.toArray();

			if ( rawTracks.T !== undefined && Object.keys( rawTracks.T.curves ).length > 0 ) {

				var positionTrack = this.generateVectorTrack( rawTracks.modelName, rawTracks.T.curves, initialPosition, 'position' );
				if ( positionTrack !== undefined ) tracks.push( positionTrack );
2646

L
Lewy Blue 已提交
2647
			}
2648

2649
			if ( rawTracks.R !== undefined && Object.keys( rawTracks.R.curves ).length > 0 ) {
2650

2651
				var rotationTrack = this.generateRotationTrack( rawTracks.modelName, rawTracks.R.curves, initialRotation, rawTracks.preRotation, rawTracks.postRotation, rawTracks.eulerOrder );
2652
				if ( rotationTrack !== undefined ) tracks.push( rotationTrack );
2653

2654
			}
2655

2656
			if ( rawTracks.S !== undefined && Object.keys( rawTracks.S.curves ).length > 0 ) {
2657

2658 2659
				var scaleTrack = this.generateVectorTrack( rawTracks.modelName, rawTracks.S.curves, initialScale, 'scale' );
				if ( scaleTrack !== undefined ) tracks.push( scaleTrack );
2660

2661
			}
Y
yamahigashi 已提交
2662

2663
			if ( rawTracks.DeformPercent !== undefined ) {
Y
yamahigashi 已提交
2664

L
Lewy Blue 已提交
2665
				var morphTrack = this.generateMorphTrack( rawTracks );
2666
				if ( morphTrack !== undefined ) tracks.push( morphTrack );
Y
yamahigashi 已提交
2667

2668
			}
2669

2670
			return tracks;
2671

2672
		},
2673

2674
		generateVectorTrack: function ( modelName, curves, initialValue, type ) {
2675

2676 2677
			var times = this.getTimesForAllAxes( curves );
			var values = this.getKeyframeTrackValues( times, curves, initialValue );
2678

2679
			return new THREE.VectorKeyframeTrack( modelName + '.' + type, times, values );
2680

2681
		},
2682

2683
		generateRotationTrack: function ( modelName, curves, initialValue, preRotation, postRotation, eulerOrder ) {
2684

2685
			if ( curves.x !== undefined ) {
2686

2687
				this.interpolateRotations( curves.x );
M
Mugen87 已提交
2688
				curves.x.values = curves.x.values.map( THREE.MathUtils.degToRad );
2689

2690 2691
			}
			if ( curves.y !== undefined ) {
2692

2693
				this.interpolateRotations( curves.y );
M
Mugen87 已提交
2694
				curves.y.values = curves.y.values.map( THREE.MathUtils.degToRad );
M
Mr.doob 已提交
2695

2696 2697
			}
			if ( curves.z !== undefined ) {
Y
yamahigashi 已提交
2698

2699
				this.interpolateRotations( curves.z );
M
Mugen87 已提交
2700
				curves.z.values = curves.z.values.map( THREE.MathUtils.degToRad );
Y
yamahigashi 已提交
2701

L
Lewy Blue 已提交
2702
			}
L
Lewy Blue 已提交
2703

2704 2705
			var times = this.getTimesForAllAxes( curves );
			var values = this.getKeyframeTrackValues( times, curves, initialValue );
L
Lewy Blue 已提交
2706

2707
			if ( preRotation !== undefined ) {
L
Lewy Blue 已提交
2708

M
Mugen87 已提交
2709
				preRotation = preRotation.map( THREE.MathUtils.degToRad );
2710
				preRotation.push( eulerOrder );
L
Lewy Blue 已提交
2711

2712 2713
				preRotation = new THREE.Euler().fromArray( preRotation );
				preRotation = new THREE.Quaternion().setFromEuler( preRotation );
2714

2715
			}
L
Lewy Blue 已提交
2716

2717
			if ( postRotation !== undefined ) {
L
Lewy Blue 已提交
2718

M
Mugen87 已提交
2719
				postRotation = postRotation.map( THREE.MathUtils.degToRad );
2720
				postRotation.push( eulerOrder );
Y
yamahigashi 已提交
2721

2722 2723
				postRotation = new THREE.Euler().fromArray( postRotation );
				postRotation = new THREE.Quaternion().setFromEuler( postRotation ).inverse();
2724

2725
			}
2726

2727 2728
			var quaternion = new THREE.Quaternion();
			var euler = new THREE.Euler();
2729

2730
			var quaternionValues = [];
2731

2732
			for ( var i = 0; i < values.length; i += 3 ) {
2733

2734
				euler.set( values[ i ], values[ i + 1 ], values[ i + 2 ], eulerOrder );
2735

2736
				quaternion.setFromEuler( euler );
2737

2738 2739
				if ( preRotation !== undefined ) quaternion.premultiply( preRotation );
				if ( postRotation !== undefined ) quaternion.multiply( postRotation );
2740

2741
				quaternion.toArray( quaternionValues, ( i / 3 ) * 4 );
Y
yamahigashi 已提交
2742

2743
			}
Y
yamahigashi 已提交
2744

2745
			return new THREE.QuaternionKeyframeTrack( modelName + '.quaternion', times, quaternionValues );
Y
yamahigashi 已提交
2746

2747
		},
Y
yamahigashi 已提交
2748

L
Lewy Blue 已提交
2749
		generateMorphTrack: function ( rawTracks ) {
Y
yamahigashi 已提交
2750

2751 2752
			var curves = rawTracks.DeformPercent.curves.morph;
			var values = curves.values.map( function ( val ) {
2753

2754
				return val / 100;
2755

2756
			} );
2757

2758
			var morphNum = sceneGraph.getObjectByName( rawTracks.modelName ).morphTargetDictionary[ rawTracks.morphName ];
2759

2760
			return new THREE.NumberKeyframeTrack( rawTracks.modelName + '.morphTargetInfluences[' + morphNum + ']', curves.times, values );
M
Mr.doob 已提交
2761

2762
		},
Y
yamahigashi 已提交
2763

2764 2765 2766
		// For all animated objects, times are defined separately for each axis
		// Here we'll combine the times into one sorted array without duplicates
		getTimesForAllAxes: function ( curves ) {
Y
yamahigashi 已提交
2767

2768
			var times = [];
Y
yamahigashi 已提交
2769

2770 2771 2772 2773
			// 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 );
Y
yamahigashi 已提交
2774

2775 2776
			// then sort them and remove duplicates
			times = times.sort( function ( a, b ) {
Y
yamahigashi 已提交
2777

2778
				return a - b;
Y
yamahigashi 已提交
2779

2780
			} ).filter( function ( elem, index, array ) {
Y
yamahigashi 已提交
2781

2782
				return array.indexOf( elem ) == index;
Y
yamahigashi 已提交
2783

2784
			} );
Y
yamahigashi 已提交
2785

2786
			return times;
Y
yamahigashi 已提交
2787

2788
		},
Y
yamahigashi 已提交
2789

2790
		getKeyframeTrackValues: function ( times, curves, initialValue ) {
Y
yamahigashi 已提交
2791

2792
			var prevValue = initialValue;
Y
yamahigashi 已提交
2793

2794
			var values = [];
Y
yamahigashi 已提交
2795

2796 2797 2798
			var xIndex = - 1;
			var yIndex = - 1;
			var zIndex = - 1;
Y
yamahigashi 已提交
2799

2800
			times.forEach( function ( time ) {
2801

2802 2803 2804
				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 );
2805

2806 2807
				// if there is an x value defined for this frame, use that
				if ( xIndex !== - 1 ) {
2808

2809 2810 2811
					var xValue = curves.x.values[ xIndex ];
					values.push( xValue );
					prevValue[ 0 ] = xValue;
L
Lewy Blue 已提交
2812

2813 2814 2815 2816
				} else {

					// otherwise use the x value from the previous frame
					values.push( prevValue[ 0 ] );
2817

L
Lewy Blue 已提交
2818
				}
L
Lewy Blue 已提交
2819

2820
				if ( yIndex !== - 1 ) {
2821

2822 2823 2824
					var yValue = curves.y.values[ yIndex ];
					values.push( yValue );
					prevValue[ 1 ] = yValue;
2825

2826
				} else {
2827

2828
					values.push( prevValue[ 1 ] );
2829

2830
				}
2831

2832
				if ( zIndex !== - 1 ) {
2833

2834 2835 2836
					var zValue = curves.z.values[ zIndex ];
					values.push( zValue );
					prevValue[ 2 ] = zValue;
2837

2838
				} else {
2839

2840
					values.push( prevValue[ 2 ] );
2841

2842
				}
2843

2844 2845 2846
			} );

			return values;
Y
yamahigashi 已提交
2847

L
Lewy Blue 已提交
2848
		},
Y
yamahigashi 已提交
2849

2850 2851 2852 2853
		// Rotations are defined as Euler angles which can have values  of any size
		// These will be converted to quaternions which don't support values greater than
		// PI, so we'll interpolate large rotations
		interpolateRotations: function ( curve ) {
2854

2855
			for ( var i = 1; i < curve.values.length; i ++ ) {
2856

2857 2858
				var initialValue = curve.values[ i - 1 ];
				var valuesSpan = curve.values[ i ] - initialValue;
2859

2860
				var absoluteSpan = Math.abs( valuesSpan );
2861

2862
				if ( absoluteSpan >= 180 ) {
L
Lewy Blue 已提交
2863

2864
					var numSubIntervals = absoluteSpan / 180;
2865

2866 2867
					var step = valuesSpan / numSubIntervals;
					var nextValue = initialValue + step;
2868

2869 2870 2871 2872
					var initialTime = curve.times[ i - 1 ];
					var timeSpan = curve.times[ i ] - initialTime;
					var interval = timeSpan / numSubIntervals;
					var nextTime = initialTime + interval;
2873

2874 2875
					var interpolatedTimes = [];
					var interpolatedValues = [];
2876

2877
					while ( nextTime < curve.times[ i ] ) {
2878

2879 2880
						interpolatedTimes.push( nextTime );
						nextTime += interval;
2881

2882 2883
						interpolatedValues.push( nextValue );
						nextValue += step;
2884

2885
					}
2886

2887 2888 2889 2890 2891 2892
					curve.times = inject( curve.times, i, interpolatedTimes );
					curve.values = inject( curve.values, i, interpolatedValues );

				}

			}
2893

L
Lewy Blue 已提交
2894
		},
2895

L
Lewy Blue 已提交
2896
	};
2897

L
Lewy Blue 已提交
2898
	// parse an FBX file in ASCII format
L
Lewy Blue 已提交
2899
	function TextParser() {}
Y
yamahigashi 已提交
2900

2901 2902 2903
	TextParser.prototype = {

		constructor: TextParser,
Y
yamahigashi 已提交
2904

M
Mr.doob 已提交
2905
		getPrevNode: function () {
Y
yamahigashi 已提交
2906

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

M
Mr.doob 已提交
2909
		},
Y
yamahigashi 已提交
2910

M
Mr.doob 已提交
2911
		getCurrentNode: function () {
Y
yamahigashi 已提交
2912

M
Mr.doob 已提交
2913
			return this.nodeStack[ this.currentIndent - 1 ];
Y
yamahigashi 已提交
2914

M
Mr.doob 已提交
2915
		},
Y
yamahigashi 已提交
2916

M
Mr.doob 已提交
2917
		getCurrentProp: function () {
Y
yamahigashi 已提交
2918

M
Mr.doob 已提交
2919
			return this.currentProp;
Y
yamahigashi 已提交
2920

M
Mr.doob 已提交
2921
		},
Y
yamahigashi 已提交
2922

M
Mr.doob 已提交
2923
		pushStack: function ( node ) {
Y
yamahigashi 已提交
2924

M
Mr.doob 已提交
2925 2926
			this.nodeStack.push( node );
			this.currentIndent += 1;
Y
yamahigashi 已提交
2927

M
Mr.doob 已提交
2928
		},
Y
yamahigashi 已提交
2929

M
Mr.doob 已提交
2930
		popStack: function () {
Y
yamahigashi 已提交
2931

M
Mr.doob 已提交
2932 2933
			this.nodeStack.pop();
			this.currentIndent -= 1;
Y
yamahigashi 已提交
2934

M
Mr.doob 已提交
2935
		},
Y
yamahigashi 已提交
2936

M
Mr.doob 已提交
2937
		setCurrentProp: function ( val, name ) {
Y
yamahigashi 已提交
2938

L
Lewy Blue 已提交
2939 2940
			this.currentProp = val;
			this.currentPropName = name;
L
Lewy Blue 已提交
2941

L
Lewy Blue 已提交
2942
		},
M
Mr.doob 已提交
2943

L
Lewy Blue 已提交
2944
		parse: function ( text ) {
M
Mr.doob 已提交
2945

L
Lewy Blue 已提交
2946
			this.currentIndent = 0;
L
Lewy Blue 已提交
2947

L
Lewy Blue 已提交
2948 2949 2950 2951
			this.allNodes = new FBXTree();
			this.nodeStack = [];
			this.currentProp = [];
			this.currentPropName = '';
Y
yamahigashi 已提交
2952

W
WestLangley 已提交
2953
			var scope = this;
2954

2955
			var split = text.split( /[\r\n]+/ );
Y
yamahigashi 已提交
2956

L
Lewy Blue 已提交
2957
			split.forEach( function ( line, i ) {
Y
yamahigashi 已提交
2958

L
Lewy Blue 已提交
2959 2960
				var matchComment = line.match( /^[\s\t]*;/ );
				var matchEmpty = line.match( /^[\s\t]*$/ );
2961

L
Lewy Blue 已提交
2962
				if ( matchComment || matchEmpty ) return;
2963

W
WestLangley 已提交
2964 2965 2966
				var matchBeginning = line.match( '^\\t{' + scope.currentIndent + '}(\\w+):(.*){', '' );
				var matchProperty = line.match( '^\\t{' + ( scope.currentIndent ) + '}(\\w+):[\\s\\t\\r\\n](.*)' );
				var matchEnd = line.match( '^\\t{' + ( scope.currentIndent - 1 ) + '}}' );
2967

L
Lewy Blue 已提交
2968
				if ( matchBeginning ) {
Y
yamahigashi 已提交
2969

W
WestLangley 已提交
2970
					scope.parseNodeBegin( line, matchBeginning );
Y
yamahigashi 已提交
2971

L
Lewy Blue 已提交
2972
				} else if ( matchProperty ) {
2973

W
WestLangley 已提交
2974
					scope.parseNodeProperty( line, matchProperty, split[ ++ i ] );
Y
yamahigashi 已提交
2975

L
Lewy Blue 已提交
2976
				} else if ( matchEnd ) {
Y
yamahigashi 已提交
2977

W
WestLangley 已提交
2978
					scope.popStack();
Y
yamahigashi 已提交
2979

L
Lewy Blue 已提交
2980
				} else if ( line.match( /^[^\s\t}]/ ) ) {
Y
yamahigashi 已提交
2981

L
Lewy Blue 已提交
2982 2983
					// 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
W
WestLangley 已提交
2984
					scope.parseNodePropertyContinued( line );
Y
yamahigashi 已提交
2985

M
Mr.doob 已提交
2986
				}
Y
yamahigashi 已提交
2987

L
Lewy Blue 已提交
2988
			} );
Y
yamahigashi 已提交
2989

M
Mr.doob 已提交
2990
			return this.allNodes;
Y
yamahigashi 已提交
2991

M
Mr.doob 已提交
2992
		},
Y
yamahigashi 已提交
2993

L
Lewy Blue 已提交
2994
		parseNodeBegin: function ( line, property ) {
Y
yamahigashi 已提交
2995

L
Lewy Blue 已提交
2996
			var nodeName = property[ 1 ].trim().replace( /^"/, '' ).replace( /"$/, '' );
L
Lewy Blue 已提交
2997

L
Lewy Blue 已提交
2998
			var nodeAttrs = property[ 2 ].split( ',' ).map( function ( attr ) {
Y
yamahigashi 已提交
2999

L
Lewy Blue 已提交
3000
				return attr.trim().replace( /^"/, '' ).replace( /"$/, '' );
Y
yamahigashi 已提交
3001

L
Lewy Blue 已提交
3002
			} );
Y
yamahigashi 已提交
3003

L
Lewy Blue 已提交
3004
			var node = { name: nodeName };
M
Mr.doob 已提交
3005
			var attrs = this.parseNodeAttr( nodeAttrs );
Y
yamahigashi 已提交
3006

M
Mr.doob 已提交
3007
			var currentNode = this.getCurrentNode();
Y
yamahigashi 已提交
3008

M
Mr.doob 已提交
3009 3010
			// a top node
			if ( this.currentIndent === 0 ) {
Y
yamahigashi 已提交
3011

M
Mr.doob 已提交
3012
				this.allNodes.add( nodeName, node );
Y
yamahigashi 已提交
3013

3014
			} else { // a subnode
Y
yamahigashi 已提交
3015

3016
				// if the subnode already exists, append it
L
Lewy Blue 已提交
3017
				if ( nodeName in currentNode ) {
Y
yamahigashi 已提交
3018

3019
					// special case Pose needs PoseNodes as an array
L
Lewy Blue 已提交
3020
					if ( nodeName === 'PoseNode' ) {
Y
yamahigashi 已提交
3021

L
Lewy Blue 已提交
3022
						currentNode.PoseNode.push( node );
Y
yamahigashi 已提交
3023

L
Lewy Blue 已提交
3024
					} else if ( currentNode[ nodeName ].id !== undefined ) {
Y
yamahigashi 已提交
3025

L
Lewy Blue 已提交
3026 3027
						currentNode[ nodeName ] = {};
						currentNode[ nodeName ][ currentNode[ nodeName ].id ] = currentNode[ nodeName ];
Y
yamahigashi 已提交
3028

M
Mr.doob 已提交
3029
					}
Y
yamahigashi 已提交
3030

L
Lewy Blue 已提交
3031
					if ( attrs.id !== '' ) currentNode[ nodeName ][ attrs.id ] = node;
3032

L
Lewy Blue 已提交
3033
				} else if ( typeof attrs.id === 'number' ) {
Y
yamahigashi 已提交
3034

L
Lewy Blue 已提交
3035 3036
					currentNode[ nodeName ] = {};
					currentNode[ nodeName ][ attrs.id ] = node;
Y
yamahigashi 已提交
3037

L
Lewy Blue 已提交
3038
				} else if ( nodeName !== 'Properties70' ) {
Y
yamahigashi 已提交
3039

L
Lewy Blue 已提交
3040 3041
					if ( nodeName === 'PoseNode' )	currentNode[ nodeName ] = [ node ];
					else currentNode[ nodeName ] = node;
Y
yamahigashi 已提交
3042

M
Mr.doob 已提交
3043
				}
K
Kyle Larson 已提交
3044

Y
yamahigashi 已提交
3045
			}
Y
yamahigashi 已提交
3046

L
Lewy Blue 已提交
3047 3048 3049
			if ( typeof attrs.id === 'number' ) node.id = attrs.id;
			if ( attrs.name !== '' ) node.attrName = attrs.name;
			if ( attrs.type !== '' ) node.attrType = attrs.type;
K
Kyle Larson 已提交
3050

M
Mr.doob 已提交
3051
			this.pushStack( node );
K
Kyle Larson 已提交
3052

M
Mr.doob 已提交
3053
		},
K
Kyle Larson 已提交
3054

M
Mr.doob 已提交
3055
		parseNodeAttr: function ( attrs ) {
K
Kyle Larson 已提交
3056

M
Mr.doob 已提交
3057
			var id = attrs[ 0 ];
K
Kyle Larson 已提交
3058

M
Mugen87 已提交
3059
			if ( attrs[ 0 ] !== '' ) {
Y
yamahigashi 已提交
3060

M
Mr.doob 已提交
3061
				id = parseInt( attrs[ 0 ] );
Y
yamahigashi 已提交
3062

M
Mr.doob 已提交
3063
				if ( isNaN( id ) ) {
Y
yamahigashi 已提交
3064

M
Mr.doob 已提交
3065
					id = attrs[ 0 ];
Y
yamahigashi 已提交
3066

M
Mr.doob 已提交
3067
				}
Y
yamahigashi 已提交
3068

M
Mr.doob 已提交
3069
			}
Y
yamahigashi 已提交
3070

M
Mr.doob 已提交
3071
			var name = '', type = '';
Y
yamahigashi 已提交
3072

M
Mr.doob 已提交
3073
			if ( attrs.length > 1 ) {
Y
yamahigashi 已提交
3074

M
Mr.doob 已提交
3075 3076
				name = attrs[ 1 ].replace( /^(\w+)::/, '' );
				type = attrs[ 2 ];
Y
yamahigashi 已提交
3077

M
Mr.doob 已提交
3078
			}
Y
yamahigashi 已提交
3079

M
Mr.doob 已提交
3080
			return { id: id, name: name, type: type };
Y
yamahigashi 已提交
3081

M
Mr.doob 已提交
3082
		},
Y
yamahigashi 已提交
3083

L
Lewy Blue 已提交
3084
		parseNodeProperty: function ( line, property, contentLine ) {
Y
yamahigashi 已提交
3085

L
Lewy Blue 已提交
3086 3087
			var propName = property[ 1 ].replace( /^"/, '' ).replace( /"$/, '' ).trim();
			var propValue = property[ 2 ].replace( /^"/, '' ).replace( /"$/, '' ).trim();
Y
yamahigashi 已提交
3088

L
Lewy Blue 已提交
3089 3090 3091 3092
			// for special case: base64 image data follows "Content: ," line
			//	Content: ,
			//	 "/9j/4RDaRXhpZgAATU0A..."
			if ( propName === 'Content' && propValue === ',' ) {
Y
yamahigashi 已提交
3093

L
Lewy Blue 已提交
3094
				propValue = contentLine.replace( /"/g, '' ).replace( /,$/, '' ).trim();
Y
yamahigashi 已提交
3095

L
Lewy Blue 已提交
3096
			}
Y
yamahigashi 已提交
3097

L
Lewy Blue 已提交
3098 3099
			var currentNode = this.getCurrentNode();
			var parentName = currentNode.name;
Y
yamahigashi 已提交
3100

L
Lewy Blue 已提交
3101
			if ( parentName === 'Properties70' ) {
Y
yamahigashi 已提交
3102

L
Lewy Blue 已提交
3103 3104
				this.parseNodeSpecialProperty( line, propName, propValue );
				return;
Y
yamahigashi 已提交
3105

M
Mr.doob 已提交
3106
			}
Y
yamahigashi 已提交
3107

3108
			// Connections
M
Mugen87 已提交
3109
			if ( propName === 'C' ) {
Y
yamahigashi 已提交
3110

M
Mr.doob 已提交
3111 3112 3113
				var connProps = propValue.split( ',' ).slice( 1 );
				var from = parseInt( connProps[ 0 ] );
				var to = parseInt( connProps[ 1 ] );
Y
yamahigashi 已提交
3114

M
Mr.doob 已提交
3115
				var rest = propValue.split( ',' ).slice( 3 );
Y
yamahigashi 已提交
3116

3117 3118 3119 3120 3121 3122
				rest = rest.map( function ( elem ) {

					return elem.trim().replace( /^"/, '' );

				} );

M
Mr.doob 已提交
3123 3124 3125
				propName = 'connections';
				propValue = [ from, to ];
				append( propValue, rest );
Y
yamahigashi 已提交
3126

L
Lewy Blue 已提交
3127
				if ( currentNode[ propName ] === undefined ) {
Y
yamahigashi 已提交
3128

L
Lewy Blue 已提交
3129
					currentNode[ propName ] = [];
Y
yamahigashi 已提交
3130

M
Mr.doob 已提交
3131
				}
Y
yamahigashi 已提交
3132

M
Mr.doob 已提交
3133
			}
Y
yamahigashi 已提交
3134

3135
			// Node
L
Lewy Blue 已提交
3136
			if ( propName === 'Node' ) currentNode.id = propValue;
Y
yamahigashi 已提交
3137

L
Lewy Blue 已提交
3138 3139
			// connections
			if ( propName in currentNode && Array.isArray( currentNode[ propName ] ) ) {
Y
yamahigashi 已提交
3140

L
Lewy Blue 已提交
3141
				currentNode[ propName ].push( propValue );
Y
yamahigashi 已提交
3142

M
Mr.doob 已提交
3143
			} else {
Y
yamahigashi 已提交
3144

L
Lewy Blue 已提交
3145 3146
				if ( propName !== 'a' ) currentNode[ propName ] = propValue;
				else currentNode.a = propValue;
Y
yamahigashi 已提交
3147

M
Mr.doob 已提交
3148
			}
Y
yamahigashi 已提交
3149

L
Lewy Blue 已提交
3150
			this.setCurrentProp( currentNode, propName );
Y
yamahigashi 已提交
3151

3152 3153 3154
			// 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 已提交
3155
				currentNode.a = parseNumberArray( propValue );
3156 3157 3158

			}

M
Mr.doob 已提交
3159
		},
Y
yamahigashi 已提交
3160

M
Mr.doob 已提交
3161
		parseNodePropertyContinued: function ( line ) {
Y
yamahigashi 已提交
3162

L
Lewy Blue 已提交
3163
			var currentNode = this.getCurrentNode();
3164

L
Lewy Blue 已提交
3165
			currentNode.a += line;
Y
yamahigashi 已提交
3166

3167 3168 3169 3170
			// 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 已提交
3171
				currentNode.a = parseNumberArray( currentNode.a );
3172 3173 3174

			}

M
Mr.doob 已提交
3175
		},
Y
yamahigashi 已提交
3176

L
Lewy Blue 已提交
3177
		// parse "Property70"
M
Mr.doob 已提交
3178
		parseNodeSpecialProperty: function ( line, propName, propValue ) {
Y
yamahigashi 已提交
3179

M
Mr.doob 已提交
3180 3181 3182 3183
			// split this
			// P: "Lcl Scaling", "Lcl Scaling", "", "A",1,1,1
			// into array like below
			// ["Lcl Scaling", "Lcl Scaling", "", "A", "1,1,1" ]
L
Lewy Blue 已提交
3184
			var props = propValue.split( '",' ).map( function ( prop ) {
Y
yamahigashi 已提交
3185

L
Lewy Blue 已提交
3186
				return prop.trim().replace( /^\"/, '' ).replace( /\s/, '_' );
L
Lewy Blue 已提交
3187

L
Lewy Blue 已提交
3188
			} );
Y
yamahigashi 已提交
3189

M
Mr.doob 已提交
3190 3191 3192 3193 3194
			var innerPropName = props[ 0 ];
			var innerPropType1 = props[ 1 ];
			var innerPropType2 = props[ 2 ];
			var innerPropFlag = props[ 3 ];
			var innerPropValue = props[ 4 ];
Y
yamahigashi 已提交
3195

L
Lewy Blue 已提交
3196
			// cast values where needed, otherwise leave as strings
M
Mr.doob 已提交
3197
			switch ( innerPropType1 ) {
Y
yamahigashi 已提交
3198

M
Mugen87 已提交
3199
				case 'int':
3200 3201 3202
				case 'enum':
				case 'bool':
				case 'ULongLong':
M
Mugen87 已提交
3203
				case 'double':
3204 3205
				case 'Number':
				case 'FieldOfView':
M
Mr.doob 已提交
3206 3207
					innerPropValue = parseFloat( innerPropValue );
					break;
Y
yamahigashi 已提交
3208

L
Lewy Blue 已提交
3209
				case 'Color':
M
Mugen87 已提交
3210 3211
				case 'ColorRGB':
				case 'Vector3D':
3212 3213 3214
				case 'Lcl_Translation':
				case 'Lcl_Rotation':
				case 'Lcl_Scaling':
3215
					innerPropValue = parseNumberArray( innerPropValue );
M
Mr.doob 已提交
3216
					break;
Y
yamahigashi 已提交
3217

M
Mr.doob 已提交
3218
			}
Y
yamahigashi 已提交
3219

M
Mr.doob 已提交
3220
			// CAUTION: these props must append to parent's parent
L
Lewy Blue 已提交
3221
			this.getPrevNode()[ innerPropName ] = {
Y
yamahigashi 已提交
3222

M
Mr.doob 已提交
3223 3224 3225 3226
				'type': innerPropType1,
				'type2': innerPropType2,
				'flag': innerPropFlag,
				'value': innerPropValue
Y
yamahigashi 已提交
3227

M
Mr.doob 已提交
3228
			};
Y
yamahigashi 已提交
3229

L
Lewy Blue 已提交
3230
			this.setCurrentProp( this.getPrevNode(), innerPropName );
3231

M
Mr.doob 已提交
3232
		},
Y
yamahigashi 已提交
3233

3234
	};
Y
yamahigashi 已提交
3235

L
Lewy Blue 已提交
3236
	// Parse an FBX file in Binary format
L
Lewy Blue 已提交
3237
	function BinaryParser() {}
Y
yamahigashi 已提交
3238

3239 3240 3241
	BinaryParser.prototype = {

		constructor: BinaryParser,
Y
yamahigashi 已提交
3242

M
Mr.doob 已提交
3243
		parse: function ( buffer ) {
Y
yamahigashi 已提交
3244

M
Mr.doob 已提交
3245 3246
			var reader = new BinaryReader( buffer );
			reader.skip( 23 ); // skip magic 23 bytes
Y
yamahigashi 已提交
3247

M
Mr.doob 已提交
3248
			var version = reader.getUint32();
Y
yamahigashi 已提交
3249

M
Mugen87 已提交
3250
			console.log( 'THREE.FBXLoader: FBX binary version: ' + version );
Y
yamahigashi 已提交
3251

M
Mr.doob 已提交
3252
			var allNodes = new FBXTree();
Y
yamahigashi 已提交
3253

M
Mr.doob 已提交
3254
			while ( ! this.endOfContent( reader ) ) {
Y
yamahigashi 已提交
3255

M
Mr.doob 已提交
3256 3257
				var node = this.parseNode( reader, version );
				if ( node !== null ) allNodes.add( node.name, node );
Y
yamahigashi 已提交
3258

M
Mr.doob 已提交
3259
			}
3260

M
Mr.doob 已提交
3261
			return allNodes;
Y
yamahigashi 已提交
3262

M
Mr.doob 已提交
3263
		},
Y
yamahigashi 已提交
3264

L
Lewy Blue 已提交
3265
		// Check if reader has reached the end of content.
L
Lewy Blue 已提交
3266
		endOfContent: function ( reader ) {
M
Mr.doob 已提交
3267 3268 3269

			// footer size: 160bytes + 16-byte alignment padding
			// - 16bytes: magic
3270
			// - padding til 16-byte alignment (at least 1byte?)
L
Lewy Blue 已提交
3271
			//	(seems like some exporters embed fixed 15 or 16bytes?)
M
Mr.doob 已提交
3272 3273 3274 3275 3276 3277
			// - 4bytes: magic
			// - 4bytes: version
			// - 120bytes: zero
			// - 16bytes: magic
			if ( reader.size() % 16 === 0 ) {

L
Lewy Blue 已提交
3278
				return ( ( reader.getOffset() + 160 + 16 ) & ~ 0xf ) >= reader.size();
Y
yamahigashi 已提交
3279

M
Mr.doob 已提交
3280
			} else {
Y
yamahigashi 已提交
3281

3282
				return reader.getOffset() + 160 + 16 >= reader.size();
Y
yamahigashi 已提交
3283

M
Mr.doob 已提交
3284
			}
Y
yamahigashi 已提交
3285

M
Mr.doob 已提交
3286
		},
Y
yamahigashi 已提交
3287

L
Lewy Blue 已提交
3288
		// recursively parse nodes until the end of the file is reached
M
Mr.doob 已提交
3289
		parseNode: function ( reader, version ) {
Y
yamahigashi 已提交
3290

L
Lewy Blue 已提交
3291
			var node = {};
Y
yamahigashi 已提交
3292

M
Mr.doob 已提交
3293 3294 3295
			// 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 已提交
3296

M
Mugen87 已提交
3297
			( version >= 7500 ) ? reader.getUint64() : reader.getUint32(); // the returned propertyListLen is not used
L
tidying  
Lewy Blue 已提交
3298

M
Mr.doob 已提交
3299 3300
			var nameLen = reader.getUint8();
			var name = reader.getString( nameLen );
Y
yamahigashi 已提交
3301

M
Mr.doob 已提交
3302 3303
			// Regards this node as NULL-record if endOffset is zero
			if ( endOffset === 0 ) return null;
Y
yamahigashi 已提交
3304

M
Mr.doob 已提交
3305
			var propertyList = [];
Y
yamahigashi 已提交
3306

M
Mr.doob 已提交
3307
			for ( var i = 0; i < numProperties; i ++ ) {
Y
yamahigashi 已提交
3308

M
Mr.doob 已提交
3309
				propertyList.push( this.parseProperty( reader ) );
Y
yamahigashi 已提交
3310

M
Mr.doob 已提交
3311
			}
Y
yamahigashi 已提交
3312

M
Mr.doob 已提交
3313 3314 3315 3316
			// 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 已提交
3317

L
Lewy Blue 已提交
3318
			// check if this node represents just a single property
M
Mr.doob 已提交
3319
			// like (name, 0) set or (name2, [0, 1, 2]) set of {name: 0, name2: [0, 1, 2]}
L
Lewy Blue 已提交
3320
			node.singleProperty = ( numProperties === 1 && reader.getOffset() === endOffset ) ? true : false;
Y
yamahigashi 已提交
3321

M
Mr.doob 已提交
3322
			while ( endOffset > reader.getOffset() ) {
Y
yamahigashi 已提交
3323

L
Lewy Blue 已提交
3324
				var subNode = this.parseNode( reader, version );
Y
yamahigashi 已提交
3325

L
Lewy Blue 已提交
3326
				if ( subNode !== null ) this.parseSubNode( name, node, subNode );
Y
yamahigashi 已提交
3327

L
Lewy Blue 已提交
3328
			}
Y
yamahigashi 已提交
3329

L
Lewy Blue 已提交
3330
			node.propertyList = propertyList; // raw property list used by parent
Y
yamahigashi 已提交
3331

L
Lewy Blue 已提交
3332 3333 3334 3335
			if ( typeof id === 'number' ) node.id = id;
			if ( attrName !== '' ) node.attrName = attrName;
			if ( attrType !== '' ) node.attrType = attrType;
			if ( name !== '' ) node.name = name;
Y
yamahigashi 已提交
3336

L
Lewy Blue 已提交
3337
			return node;
Y
yamahigashi 已提交
3338

L
Lewy Blue 已提交
3339
		},
Y
yamahigashi 已提交
3340

L
Lewy Blue 已提交
3341
		parseSubNode: function ( name, node, subNode ) {
Y
yamahigashi 已提交
3342

L
Lewy Blue 已提交
3343 3344
			// special case: child node is single property
			if ( subNode.singleProperty === true ) {
Y
yamahigashi 已提交
3345

L
Lewy Blue 已提交
3346
				var value = subNode.propertyList[ 0 ];
Y
yamahigashi 已提交
3347

L
Lewy Blue 已提交
3348
				if ( Array.isArray( value ) ) {
Y
yamahigashi 已提交
3349

L
Lewy Blue 已提交
3350
					node[ subNode.name ] = subNode;
Y
yamahigashi 已提交
3351

L
Lewy Blue 已提交
3352
					subNode.a = value;
Y
yamahigashi 已提交
3353

L
Lewy Blue 已提交
3354
				} else {
Y
yamahigashi 已提交
3355

L
Lewy Blue 已提交
3356
					node[ subNode.name ] = value;
Y
yamahigashi 已提交
3357

M
Mr.doob 已提交
3358
				}
Y
yamahigashi 已提交
3359

L
Lewy Blue 已提交
3360
			} else if ( name === 'Connections' && subNode.name === 'C' ) {
Y
yamahigashi 已提交
3361

L
Lewy Blue 已提交
3362
				var array = [];
Y
yamahigashi 已提交
3363

L
Lewy Blue 已提交
3364
				subNode.propertyList.forEach( function ( property, i ) {
Y
yamahigashi 已提交
3365

L
Lewy Blue 已提交
3366 3367
					// first Connection is FBX type (OO, OP, etc.). We'll discard these
					if ( i !== 0 ) array.push( property );
Y
yamahigashi 已提交
3368

L
Lewy Blue 已提交
3369
				} );
Y
yamahigashi 已提交
3370

L
Lewy Blue 已提交
3371
				if ( node.connections === undefined ) {
Y
yamahigashi 已提交
3372

L
Lewy Blue 已提交
3373
					node.connections = [];
Y
yamahigashi 已提交
3374

M
Mr.doob 已提交
3375
				}
Y
yamahigashi 已提交
3376

L
Lewy Blue 已提交
3377
				node.connections.push( array );
Y
yamahigashi 已提交
3378

L
Lewy Blue 已提交
3379
			} else if ( subNode.name === 'Properties70' ) {
Y
yamahigashi 已提交
3380

L
Lewy Blue 已提交
3381
				var keys = Object.keys( subNode );
Y
yamahigashi 已提交
3382

L
Lewy Blue 已提交
3383
				keys.forEach( function ( key ) {
Y
yamahigashi 已提交
3384

L
Lewy Blue 已提交
3385
					node[ key ] = subNode[ key ];
Y
yamahigashi 已提交
3386

L
Lewy Blue 已提交
3387
				} );
Y
yamahigashi 已提交
3388

L
Lewy Blue 已提交
3389
			} else if ( name === 'Properties70' && subNode.name === 'P' ) {
Y
yamahigashi 已提交
3390

L
Lewy Blue 已提交
3391 3392 3393 3394 3395
				var innerPropName = subNode.propertyList[ 0 ];
				var innerPropType1 = subNode.propertyList[ 1 ];
				var innerPropType2 = subNode.propertyList[ 2 ];
				var innerPropFlag = subNode.propertyList[ 3 ];
				var innerPropValue;
Y
yamahigashi 已提交
3396

L
Lewy Blue 已提交
3397 3398
				if ( innerPropName.indexOf( 'Lcl ' ) === 0 ) innerPropName = innerPropName.replace( 'Lcl ', 'Lcl_' );
				if ( innerPropType1.indexOf( 'Lcl ' ) === 0 ) innerPropType1 = innerPropType1.replace( 'Lcl ', 'Lcl_' );
Y
yamahigashi 已提交
3399

L
Lewy Blue 已提交
3400
				if ( innerPropType1 === 'Color' || innerPropType1 === 'ColorRGB' || innerPropType1 === 'Vector' || innerPropType1 === 'Vector3D' || innerPropType1.indexOf( 'Lcl_' ) === 0 ) {
Y
yamahigashi 已提交
3401

L
Lewy Blue 已提交
3402 3403 3404 3405 3406
					innerPropValue = [
						subNode.propertyList[ 4 ],
						subNode.propertyList[ 5 ],
						subNode.propertyList[ 6 ]
					];
Y
yamahigashi 已提交
3407

L
Lewy Blue 已提交
3408
				} else {
K
Kyle Larson 已提交
3409

L
Lewy Blue 已提交
3410
					innerPropValue = subNode.propertyList[ 4 ];
Y
yamahigashi 已提交
3411

M
Mr.doob 已提交
3412
				}
Y
yamahigashi 已提交
3413

L
Lewy Blue 已提交
3414 3415
				// this will be copied to parent, see above
				node[ innerPropName ] = {
Y
yamahigashi 已提交
3416

L
Lewy Blue 已提交
3417 3418 3419 3420
					'type': innerPropType1,
					'type2': innerPropType2,
					'flag': innerPropFlag,
					'value': innerPropValue
K
Kyle Larson 已提交
3421

L
Lewy Blue 已提交
3422
				};
Y
yamahigashi 已提交
3423

L
Lewy Blue 已提交
3424
			} else if ( node[ subNode.name ] === undefined ) {
Y
yamahigashi 已提交
3425

L
Lewy Blue 已提交
3426
				if ( typeof subNode.id === 'number' ) {
Y
yamahigashi 已提交
3427

L
Lewy Blue 已提交
3428 3429
					node[ subNode.name ] = {};
					node[ subNode.name ][ subNode.id ] = subNode;
Y
yamahigashi 已提交
3430

M
Mr.doob 已提交
3431
				} else {
Y
yamahigashi 已提交
3432

L
Lewy Blue 已提交
3433
					node[ subNode.name ] = subNode;
Y
yamahigashi 已提交
3434

L
Lewy Blue 已提交
3435
				}
Y
yamahigashi 已提交
3436

L
Lewy Blue 已提交
3437
			} else {
Y
yamahigashi 已提交
3438

L
Lewy Blue 已提交
3439
				if ( subNode.name === 'PoseNode' ) {
Y
yamahigashi 已提交
3440

L
Lewy Blue 已提交
3441
					if ( ! Array.isArray( node[ subNode.name ] ) ) {
Y
yamahigashi 已提交
3442

L
Lewy Blue 已提交
3443
						node[ subNode.name ] = [ node[ subNode.name ] ];
Y
yamahigashi 已提交
3444

L
Lewy Blue 已提交
3445
					}
Y
yamahigashi 已提交
3446

L
Lewy Blue 已提交
3447
					node[ subNode.name ].push( subNode );
K
Kyle Larson 已提交
3448

L
Lewy Blue 已提交
3449
				} else if ( node[ subNode.name ][ subNode.id ] === undefined ) {
K
Kyle Larson 已提交
3450

L
Lewy Blue 已提交
3451
					node[ subNode.name ][ subNode.id ] = subNode;
K
Kyle Larson 已提交
3452

M
Mr.doob 已提交
3453
				}
K
Kyle Larson 已提交
3454

M
Mr.doob 已提交
3455
			}
K
Kyle Larson 已提交
3456

M
Mr.doob 已提交
3457
		},
K
Kyle Larson 已提交
3458

M
Mr.doob 已提交
3459
		parseProperty: function ( reader ) {
K
Kyle Larson 已提交
3460

L
Lewy Blue 已提交
3461
			var type = reader.getString( 1 );
K
Kyle Larson 已提交
3462

M
Mr.doob 已提交
3463
			switch ( type ) {
K
Kyle Larson 已提交
3464

3465 3466
				case 'C':
					return reader.getBoolean();
K
Kyle Larson 已提交
3467

M
Mr.doob 已提交
3468 3469
				case 'D':
					return reader.getFloat64();
K
Kyle Larson 已提交
3470

3471 3472
				case 'F':
					return reader.getFloat32();
K
Kyle Larson 已提交
3473

M
Mr.doob 已提交
3474 3475
				case 'I':
					return reader.getInt32();
K
Kyle Larson 已提交
3476

3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487
				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 已提交
3488 3489
				case 'Y':
					return reader.getInt16();
K
Kyle Larson 已提交
3490

3491 3492
				case 'b':
				case 'c':
M
Mr.doob 已提交
3493
				case 'd':
3494
				case 'f':
M
Mr.doob 已提交
3495
				case 'i':
3496
				case 'l':
K
Kyle Larson 已提交
3497

M
Mr.doob 已提交
3498 3499 3500
					var arrayLength = reader.getUint32();
					var encoding = reader.getUint32(); // 0: non-compressed, 1: compressed
					var compressedLength = reader.getUint32();
K
Kyle Larson 已提交
3501

M
Mr.doob 已提交
3502
					if ( encoding === 0 ) {
K
Kyle Larson 已提交
3503

M
Mr.doob 已提交
3504
						switch ( type ) {
K
Kyle Larson 已提交
3505

3506 3507 3508
							case 'b':
							case 'c':
								return reader.getBooleanArray( arrayLength );
K
Kyle Larson 已提交
3509

M
Mr.doob 已提交
3510 3511
							case 'd':
								return reader.getFloat64Array( arrayLength );
K
Kyle Larson 已提交
3512

3513 3514
							case 'f':
								return reader.getFloat32Array( arrayLength );
K
Kyle Larson 已提交
3515

M
Mr.doob 已提交
3516 3517
							case 'i':
								return reader.getInt32Array( arrayLength );
Y
yamahigashi 已提交
3518

3519 3520
							case 'l':
								return reader.getInt64Array( arrayLength );
Y
yamahigashi 已提交
3521

M
Mr.doob 已提交
3522
						}
Y
yamahigashi 已提交
3523

M
Mr.doob 已提交
3524
					}
Y
yamahigashi 已提交
3525

3526
					if ( typeof Zlib === 'undefined' ) {
Y
yamahigashi 已提交
3527

L
Lewy Blue 已提交
3528
						console.error( 'THREE.FBXLoader: External library Inflate.min.js required, obtain or import from https://github.com/imaya/zlib.js' );
Y
yamahigashi 已提交
3529

M
Mr.doob 已提交
3530
					}
Y
yamahigashi 已提交
3531

L
Lewy Blue 已提交
3532
					var inflate = new Zlib.Inflate( new Uint8Array( reader.getArrayBuffer( compressedLength ) ) ); // eslint-disable-line no-undef
M
Mr.doob 已提交
3533
					var reader2 = new BinaryReader( inflate.decompress().buffer );
Y
yamahigashi 已提交
3534

M
Mr.doob 已提交
3535
					switch ( type ) {
Y
yamahigashi 已提交
3536

3537 3538 3539
						case 'b':
						case 'c':
							return reader2.getBooleanArray( arrayLength );
Y
yamahigashi 已提交
3540

M
Mr.doob 已提交
3541 3542
						case 'd':
							return reader2.getFloat64Array( arrayLength );
Y
yamahigashi 已提交
3543

3544 3545
						case 'f':
							return reader2.getFloat32Array( arrayLength );
Y
yamahigashi 已提交
3546

M
Mr.doob 已提交
3547 3548
						case 'i':
							return reader2.getInt32Array( arrayLength );
Y
yamahigashi 已提交
3549

3550 3551
						case 'l':
							return reader2.getInt64Array( arrayLength );
Y
yamahigashi 已提交
3552

M
Mr.doob 已提交
3553
					}
Y
yamahigashi 已提交
3554

M
Mr.doob 已提交
3555
				default:
M
Mugen87 已提交
3556
					throw new Error( 'THREE.FBXLoader: Unknown property type ' + type );
Y
yamahigashi 已提交
3557

M
Mr.doob 已提交
3558
			}
Y
yamahigashi 已提交
3559

M
Mr.doob 已提交
3560
		}
Y
yamahigashi 已提交
3561

3562
	};
Y
yamahigashi 已提交
3563

M
Mr.doob 已提交
3564
	function BinaryReader( buffer, littleEndian ) {
Y
yamahigashi 已提交
3565

M
Mr.doob 已提交
3566 3567 3568
		this.dv = new DataView( buffer );
		this.offset = 0;
		this.littleEndian = ( littleEndian !== undefined ) ? littleEndian : true;
Y
yamahigashi 已提交
3569

M
Mr.doob 已提交
3570
	}
Y
yamahigashi 已提交
3571

3572 3573 3574
	BinaryReader.prototype = {

		constructor: BinaryReader,
Y
yamahigashi 已提交
3575

M
Mr.doob 已提交
3576
		getOffset: function () {
Y
yamahigashi 已提交
3577

M
Mr.doob 已提交
3578
			return this.offset;
Y
yamahigashi 已提交
3579

M
Mr.doob 已提交
3580
		},
Y
yamahigashi 已提交
3581

M
Mr.doob 已提交
3582
		size: function () {
Y
yamahigashi 已提交
3583

M
Mr.doob 已提交
3584
			return this.dv.buffer.byteLength;
Y
yamahigashi 已提交
3585

M
Mr.doob 已提交
3586
		},
Y
yamahigashi 已提交
3587

M
Mr.doob 已提交
3588
		skip: function ( length ) {
Y
yamahigashi 已提交
3589

M
Mr.doob 已提交
3590
			this.offset += length;
Y
yamahigashi 已提交
3591

M
Mr.doob 已提交
3592
		},
Y
yamahigashi 已提交
3593

M
Mr.doob 已提交
3594
		// seems like true/false representation depends on exporter.
L
Lewy Blue 已提交
3595
		// true: 1 or 'Y'(=0x59), false: 0 or 'T'(=0x54)
M
Mr.doob 已提交
3596 3597
		// then sees LSB.
		getBoolean: function () {
Y
yamahigashi 已提交
3598

M
Mr.doob 已提交
3599
			return ( this.getUint8() & 1 ) === 1;
Y
yamahigashi 已提交
3600

M
Mr.doob 已提交
3601
		},
Y
yamahigashi 已提交
3602

M
Mr.doob 已提交
3603
		getBooleanArray: function ( size ) {
Y
yamahigashi 已提交
3604

M
Mr.doob 已提交
3605
			var a = [];
Y
yamahigashi 已提交
3606

M
Mr.doob 已提交
3607
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3608

M
Mr.doob 已提交
3609
				a.push( this.getBoolean() );
Y
yamahigashi 已提交
3610 3611 3612

			}

M
Mr.doob 已提交
3613
			return a;
Y
yamahigashi 已提交
3614

M
Mr.doob 已提交
3615
		},
Y
yamahigashi 已提交
3616

M
Mr.doob 已提交
3617
		getUint8: function () {
Y
yamahigashi 已提交
3618

M
Mr.doob 已提交
3619 3620 3621
			var value = this.dv.getUint8( this.offset );
			this.offset += 1;
			return value;
Y
yamahigashi 已提交
3622

M
Mr.doob 已提交
3623
		},
Y
yamahigashi 已提交
3624

M
Mr.doob 已提交
3625
		getInt16: function () {
Y
yamahigashi 已提交
3626

M
Mr.doob 已提交
3627 3628 3629
			var value = this.dv.getInt16( this.offset, this.littleEndian );
			this.offset += 2;
			return value;
Y
yamahigashi 已提交
3630

M
Mr.doob 已提交
3631
		},
Y
yamahigashi 已提交
3632

M
Mr.doob 已提交
3633
		getInt32: function () {
3634

M
Mr.doob 已提交
3635 3636 3637
			var value = this.dv.getInt32( this.offset, this.littleEndian );
			this.offset += 4;
			return value;
3638

M
Mr.doob 已提交
3639
		},
3640

M
Mr.doob 已提交
3641
		getInt32Array: function ( size ) {
3642

M
Mr.doob 已提交
3643
			var a = [];
3644

M
Mr.doob 已提交
3645
			for ( var i = 0; i < size; i ++ ) {
3646

M
Mr.doob 已提交
3647
				a.push( this.getInt32() );
3648 3649 3650

			}

M
Mr.doob 已提交
3651
			return a;
3652

M
Mr.doob 已提交
3653
		},
3654

M
Mr.doob 已提交
3655
		getUint32: function () {
3656

M
Mr.doob 已提交
3657 3658 3659 3660 3661
			var value = this.dv.getUint32( this.offset, this.littleEndian );
			this.offset += 4;
			return value;

		},
3662

L
Lewy Blue 已提交
3663
		// JavaScript doesn't support 64-bit integer so calculate this here
M
Mr.doob 已提交
3664
		// 1 << 32 will return 1 so using multiply operation instead here.
L
Lewy Blue 已提交
3665
		// There's a possibility that this method returns wrong value if the value
M
Mr.doob 已提交
3666 3667 3668
		// is out of the range between Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER.
		// TODO: safely handle 64-bit integer
		getInt64: function () {
3669

M
Mr.doob 已提交
3670
			var low, high;
3671

M
Mr.doob 已提交
3672
			if ( this.littleEndian ) {
3673

M
Mr.doob 已提交
3674 3675
				low = this.getUint32();
				high = this.getUint32();
3676

M
Mr.doob 已提交
3677
			} else {
3678

M
Mr.doob 已提交
3679 3680
				high = this.getUint32();
				low = this.getUint32();
3681

M
Mr.doob 已提交
3682
			}
3683

M
Mr.doob 已提交
3684 3685
			// calculate negative value
			if ( high & 0x80000000 ) {
3686

L
Lewy Blue 已提交
3687 3688
				high = ~ high & 0xFFFFFFFF;
				low = ~ low & 0xFFFFFFFF;
3689

M
Mr.doob 已提交
3690
				if ( low === 0xFFFFFFFF ) high = ( high + 1 ) & 0xFFFFFFFF;
3691

M
Mr.doob 已提交
3692
				low = ( low + 1 ) & 0xFFFFFFFF;
3693

M
Mr.doob 已提交
3694
				return - ( high * 0x100000000 + low );
3695

M
Mr.doob 已提交
3696
			}
3697

M
Mr.doob 已提交
3698
			return high * 0x100000000 + low;
3699

M
Mr.doob 已提交
3700
		},
3701

M
Mr.doob 已提交
3702
		getInt64Array: function ( size ) {
3703

M
Mr.doob 已提交
3704
			var a = [];
3705

M
Mr.doob 已提交
3706
			for ( var i = 0; i < size; i ++ ) {
3707

M
Mr.doob 已提交
3708
				a.push( this.getInt64() );
3709 3710 3711

			}

M
Mr.doob 已提交
3712 3713 3714
			return a;

		},
3715

M
Mr.doob 已提交
3716 3717
		// Note: see getInt64() comment
		getUint64: function () {
3718

M
Mr.doob 已提交
3719
			var low, high;
3720

M
Mr.doob 已提交
3721 3722 3723 3724 3725 3726 3727 3728 3729
			if ( this.littleEndian ) {

				low = this.getUint32();
				high = this.getUint32();

			} else {

				high = this.getUint32();
				low = this.getUint32();
3730 3731

			}
3732

M
Mr.doob 已提交
3733
			return high * 0x100000000 + low;
3734

M
Mr.doob 已提交
3735
		},
Y
yamahigashi 已提交
3736

M
Mr.doob 已提交
3737
		getFloat32: function () {
Y
yamahigashi 已提交
3738

M
Mr.doob 已提交
3739 3740 3741
			var value = this.dv.getFloat32( this.offset, this.littleEndian );
			this.offset += 4;
			return value;
Y
yamahigashi 已提交
3742

M
Mr.doob 已提交
3743
		},
Y
yamahigashi 已提交
3744

M
Mr.doob 已提交
3745
		getFloat32Array: function ( size ) {
Y
yamahigashi 已提交
3746

M
Mr.doob 已提交
3747
			var a = [];
Y
yamahigashi 已提交
3748

M
Mr.doob 已提交
3749
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3750

M
Mr.doob 已提交
3751
				a.push( this.getFloat32() );
Y
yamahigashi 已提交
3752 3753 3754

			}

M
Mr.doob 已提交
3755
			return a;
Y
yamahigashi 已提交
3756

M
Mr.doob 已提交
3757
		},
Y
yamahigashi 已提交
3758

M
Mr.doob 已提交
3759
		getFloat64: function () {
Y
yamahigashi 已提交
3760

M
Mr.doob 已提交
3761 3762 3763
			var value = this.dv.getFloat64( this.offset, this.littleEndian );
			this.offset += 8;
			return value;
Y
yamahigashi 已提交
3764

M
Mr.doob 已提交
3765
		},
Y
yamahigashi 已提交
3766

M
Mr.doob 已提交
3767
		getFloat64Array: function ( size ) {
Y
yamahigashi 已提交
3768

M
Mr.doob 已提交
3769
			var a = [];
Y
yamahigashi 已提交
3770

M
Mr.doob 已提交
3771
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3772

M
Mr.doob 已提交
3773
				a.push( this.getFloat64() );
Y
yamahigashi 已提交
3774

M
Mr.doob 已提交
3775
			}
Y
yamahigashi 已提交
3776

M
Mr.doob 已提交
3777
			return a;
Y
yamahigashi 已提交
3778

M
Mr.doob 已提交
3779
		},
Y
yamahigashi 已提交
3780

M
Mr.doob 已提交
3781
		getArrayBuffer: function ( size ) {
Y
yamahigashi 已提交
3782

M
Mr.doob 已提交
3783 3784 3785
			var value = this.dv.buffer.slice( this.offset, this.offset + size );
			this.offset += size;
			return value;
Y
yamahigashi 已提交
3786

M
Mr.doob 已提交
3787
		},
Y
yamahigashi 已提交
3788

M
Mr.doob 已提交
3789
		getString: function ( size ) {
Y
yamahigashi 已提交
3790

L
Lewy Blue 已提交
3791 3792
			// note: safari 9 doesn't support Uint8Array.indexOf; create intermediate array instead
			var a = [];
Y
yamahigashi 已提交
3793

L
Lewy Blue 已提交
3794
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3795

L
Lewy Blue 已提交
3796
				a[ i ] = this.getUint8();
Y
yamahigashi 已提交
3797

M
Mr.doob 已提交
3798
			}
Y
yamahigashi 已提交
3799

L
Lewy Blue 已提交
3800 3801
			var nullByte = a.indexOf( 0 );
			if ( nullByte >= 0 ) a = a.slice( 0, nullByte );
Y
yamahigashi 已提交
3802

L
Lewy Blue 已提交
3803
			return THREE.LoaderUtils.decodeText( new Uint8Array( a ) );
Y
yamahigashi 已提交
3804

M
Mr.doob 已提交
3805
		}
Y
yamahigashi 已提交
3806

3807
	};
Y
yamahigashi 已提交
3808

L
Lewy Blue 已提交
3809 3810
	// FBXTree holds a representation of the FBX data, returned by the TextParser ( FBX ASCII format)
	// and BinaryParser( FBX Binary format)
L
Lewy Blue 已提交
3811
	function FBXTree() {}
Y
yamahigashi 已提交
3812

3813 3814 3815
	FBXTree.prototype = {

		constructor: FBXTree,
Y
yamahigashi 已提交
3816

M
Mr.doob 已提交
3817
		add: function ( key, val ) {
Y
yamahigashi 已提交
3818

M
Mr.doob 已提交
3819
			this[ key ] = val;
Y
yamahigashi 已提交
3820

M
Mr.doob 已提交
3821
		},
Y
yamahigashi 已提交
3822

3823
	};
Y
yamahigashi 已提交
3824

L
Lewy Blue 已提交
3825
	// ************** UTILITY FUNCTIONS **************
Y
yamahigashi 已提交
3826

M
Mr.doob 已提交
3827
	function isFbxFormatBinary( buffer ) {
Y
yamahigashi 已提交
3828

M
Mr.doob 已提交
3829
		var CORRECT = 'Kaydara FBX Binary  \0';
Y
yamahigashi 已提交
3830

M
Mr.doob 已提交
3831
		return buffer.byteLength >= CORRECT.length && CORRECT === convertArrayBufferToString( buffer, 0, CORRECT.length );
Y
yamahigashi 已提交
3832

M
Mr.doob 已提交
3833
	}
Y
yamahigashi 已提交
3834

M
Mr.doob 已提交
3835
	function isFbxFormatASCII( text ) {
Y
yamahigashi 已提交
3836

M
Mr.doob 已提交
3837
		var CORRECT = [ 'K', 'a', 'y', 'd', 'a', 'r', 'a', '\\', 'F', 'B', 'X', '\\', 'B', 'i', 'n', 'a', 'r', 'y', '\\', '\\' ];
Y
yamahigashi 已提交
3838

M
Mr.doob 已提交
3839
		var cursor = 0;
Y
yamahigashi 已提交
3840

M
Mr.doob 已提交
3841
		function read( offset ) {
Y
yamahigashi 已提交
3842

M
Mr.doob 已提交
3843 3844 3845 3846
			var result = text[ offset - 1 ];
			text = text.slice( cursor + offset );
			cursor ++;
			return result;
Y
yamahigashi 已提交
3847 3848 3849

		}

M
Mr.doob 已提交
3850
		for ( var i = 0; i < CORRECT.length; ++ i ) {
Y
yamahigashi 已提交
3851

M
Mr.doob 已提交
3852
			var num = read( 1 );
M
Mugen87 已提交
3853
			if ( num === CORRECT[ i ] ) {
Y
yamahigashi 已提交
3854

M
Mr.doob 已提交
3855
				return false;
Y
yamahigashi 已提交
3856 3857 3858

			}

M
Mr.doob 已提交
3859
		}
Y
yamahigashi 已提交
3860

M
Mr.doob 已提交
3861
		return true;
Y
yamahigashi 已提交
3862

M
Mr.doob 已提交
3863
	}
Y
yamahigashi 已提交
3864

M
Mr.doob 已提交
3865
	function getFbxVersion( text ) {
Y
yamahigashi 已提交
3866

M
Mr.doob 已提交
3867 3868 3869 3870 3871 3872
		var versionRegExp = /FBXVersion: (\d+)/;
		var match = text.match( versionRegExp );
		if ( match ) {

			var version = parseInt( match[ 1 ] );
			return version;
Y
yamahigashi 已提交
3873 3874

		}
M
Mugen87 已提交
3875
		throw new Error( 'THREE.FBXLoader: Cannot find the version number for the file given.' );
Y
yamahigashi 已提交
3876

M
Mr.doob 已提交
3877 3878
	}

L
Lewy Blue 已提交
3879
	// Converts FBX ticks into real time seconds.
M
Mr.doob 已提交
3880 3881 3882
	function convertFBXTimeToSeconds( time ) {

		return time / 46186158000;
Y
yamahigashi 已提交
3883

K
Kyle Larson 已提交
3884
	}
Y
yamahigashi 已提交
3885

L
Lewy Blue 已提交
3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919
	var dataArray = [];

	// extracts the data from the correct position in the FBX array based on indexing type
	function getData( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {

		var index;

		switch ( infoObject.mappingType ) {

			case 'ByPolygonVertex' :
				index = polygonVertexIndex;
				break;
			case 'ByPolygon' :
				index = polygonIndex;
				break;
			case 'ByVertice' :
				index = vertexIndex;
				break;
			case 'AllSame' :
				index = infoObject.indices[ 0 ];
				break;
			default :
				console.warn( 'THREE.FBXLoader: unknown attribute mapping type ' + infoObject.mappingType );

		}

		if ( infoObject.referenceType === 'IndexToDirect' ) index = infoObject.indices[ index ];

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

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

	}
L
Lewy Blue 已提交
3920

3921 3922 3923 3924
	var tempEuler = new THREE.Euler();
	var tempVec = new THREE.Vector3();

	// generate transformation from FBX transform data
L
Lewy Blue 已提交
3925
	// ref: https://help.autodesk.com/view/FBX/2017/ENU/?guid=__files_GUID_10CDD63C_79C1_4F2D_BB28_AD2BE65A02ED_htm
3926
	// ref: http://docs.autodesk.com/FBX/2014/ENU/FBX-SDK-Documentation/index.html?url=cpp_ref/_transformations_2main_8cxx-example.html,topicNumber=cpp_ref__transformations_2main_8cxx_example_htmlfc10a1e1-b18d-4e72-9dc0-70d0f1959f5e
3927 3928
	function generateTransform( transformData ) {

3929 3930 3931 3932
		var lTranslationM = new THREE.Matrix4();
		var lPreRotationM = new THREE.Matrix4();
		var lRotationM = new THREE.Matrix4();
		var lPostRotationM = new THREE.Matrix4();
3933

3934 3935 3936 3937 3938
		var lScalingM = new THREE.Matrix4();
		var lScalingPivotM = new THREE.Matrix4();
		var lScalingOffsetM = new THREE.Matrix4();
		var lRotationOffsetM = new THREE.Matrix4();
		var lRotationPivotM = new THREE.Matrix4();
3939

3940 3941
		var lParentGX = new THREE.Matrix4();
		var lGlobalT = new THREE.Matrix4();
3942

3943
		var inheritType = ( transformData.inheritType ) ? transformData.inheritType : 0;
3944

3945
		if ( transformData.translation ) lTranslationM.setPosition( tempVec.fromArray( transformData.translation ) );
3946 3947 3948

		if ( transformData.preRotation ) {

M
Mugen87 已提交
3949
			var array = transformData.preRotation.map( THREE.MathUtils.degToRad );
3950
			array.push( transformData.eulerOrder );
3951 3952 3953
			lPreRotationM.makeRotationFromEuler( tempEuler.fromArray( array ) );

		}
3954

3955 3956
		if ( transformData.rotation ) {

M
Mugen87 已提交
3957
			var array = transformData.rotation.map( THREE.MathUtils.degToRad );
3958
			array.push( transformData.eulerOrder );
3959
			lRotationM.makeRotationFromEuler( tempEuler.fromArray( array ) );
3960 3961 3962 3963 3964

		}

		if ( transformData.postRotation ) {

M
Mugen87 已提交
3965
			var array = transformData.postRotation.map( THREE.MathUtils.degToRad );
3966
			array.push( transformData.eulerOrder );
3967
			lPostRotationM.makeRotationFromEuler( tempEuler.fromArray( array ) );
3968

3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988
		}

		if ( transformData.scale ) lScalingM.scale( tempVec.fromArray( transformData.scale ) );

		// Pivots and offsets
		if ( transformData.scalingOffset ) lScalingOffsetM.setPosition( tempVec.fromArray( transformData.scalingOffset ) );
		if ( transformData.scalingPivot ) lScalingPivotM.setPosition( tempVec.fromArray( transformData.scalingPivot ) );
		if ( transformData.rotationOffset ) lRotationOffsetM.setPosition( tempVec.fromArray( transformData.rotationOffset ) );
		if ( transformData.rotationPivot ) lRotationPivotM.setPosition( tempVec.fromArray( transformData.rotationPivot ) );

		// parent transform
		if ( transformData.parentMatrixWorld ) lParentGX = transformData.parentMatrixWorld;

		// Global Rotation
		var lLRM = lPreRotationM.multiply( lRotationM ).multiply( lPostRotationM );
		var lParentGRM = new THREE.Matrix4();
		lParentGX.extractRotation( lParentGRM );

		// Global Shear*Scaling
		var lParentTM = new THREE.Matrix4();
G
gero3 已提交
3989 3990 3991
		var lLSM;
		var lParentGSM;
		var lParentGRSM;
3992 3993 3994 3995 3996

		lParentTM.copyPosition( lParentGX );
		lParentGRSM = lParentTM.getInverse( lParentTM ).multiply( lParentGX );
		lParentGSM = lParentGRM.getInverse( lParentGRM ).multiply( lParentGRSM );
		lLSM = lScalingM;
L
Lewy Blue 已提交
3997

G
cleanup  
gero3 已提交
3998
		var lGlobalRS;
3999 4000 4001
		if ( inheritType === 0 ) {

			lGlobalRS = lParentGRM.multiply( lLRM ).multiply( lParentGSM ).multiply( lLSM );
L
Lewy Blue 已提交
4002

4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013
		} else if ( inheritType === 1 ) {

			lGlobalRS = lParentGRM.multiply( lParentGSM ).multiply( lLRM ).multiply( lLSM );

		} else {

			var lParentLSM = new THREE.Matrix4().copy( lScalingM );

			var lParentGSM_noLocal = lParentGSM.multiply( lParentLSM.getInverse( lParentLSM ) );

			lGlobalRS = lParentGRM.multiply( lLRM ).multiply( lParentGSM_noLocal ).multiply( lLSM );
4014 4015 4016

		}

4017
		// Calculate the local transform matrix
G
cleanup  
gero3 已提交
4018
		var lTransform = lTranslationM.multiply( lRotationOffsetM ).multiply( lRotationPivotM ).multiply( lPreRotationM ).multiply( lRotationM ).multiply( lPostRotationM ).multiply( lRotationPivotM.getInverse( lRotationPivotM ) ).multiply( lScalingOffsetM ).multiply( lScalingPivotM ).multiply( lScalingM ).multiply( lScalingPivotM.getInverse( lScalingPivotM ) );
4019 4020 4021 4022 4023 4024 4025 4026 4027

		var lLocalTWithAllPivotAndOffsetInfo = new THREE.Matrix4().copyPosition( lTransform );

		var lGlobalTranslation = lParentGX.multiply( lLocalTWithAllPivotAndOffsetInfo );
		lGlobalT.copyPosition( lGlobalTranslation );

		lTransform = lGlobalT.multiply( lGlobalRS );

		return lTransform;
4028 4029 4030

	}

L
Lewy Blue 已提交
4031
	// Returns the three.js intrinsic Euler order corresponding to FBX extrinsic Euler order
L
Lewy Blue 已提交
4032
	// ref: http://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_euler_html
4033 4034
	function getEulerOrder( order ) {

4035 4036
		order = order || 0;

4037
		var enums = [
L
Lewy Blue 已提交
4038 4039 4040 4041 4042 4043
			'ZYX', // -> XYZ extrinsic
			'YZX', // -> XZY extrinsic
			'XZY', // -> YZX extrinsic
			'ZXY', // -> YXZ extrinsic
			'YXZ', // -> ZXY extrinsic
			'XYZ', // -> ZYX extrinsic
4044
			//'SphericXYZ', // not possible to support
4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056
		];

		if ( order === 6 ) {

			console.warn( 'THREE.FBXLoader: unsupported Euler Order: Spherical XYZ. Animations and rotations may be incorrect.' );
			return enums[ 0 ];

		}

		return enums[ order ];

	}
L
Lewy Blue 已提交
4057 4058 4059

	// Parses comma separated list of numbers and returns them an array.
	// Used internally by the TextParser
4060
	function parseNumberArray( value ) {
Y
yamahigashi 已提交
4061

L
Lewy Blue 已提交
4062
		var array = value.split( ',' ).map( function ( val ) {
Y
yamahigashi 已提交
4063

L
Lewy Blue 已提交
4064
			return parseFloat( val );
Y
yamahigashi 已提交
4065

L
Lewy Blue 已提交
4066
		} );
Y
yamahigashi 已提交
4067

M
Mr.doob 已提交
4068
		return array;
Y
yamahigashi 已提交
4069

M
Mr.doob 已提交
4070
	}
Y
yamahigashi 已提交
4071

L
Lewy Blue 已提交
4072
	function convertArrayBufferToString( buffer, from, to ) {
M
Mr.doob 已提交
4073

L
Lewy Blue 已提交
4074 4075
		if ( from === undefined ) from = 0;
		if ( to === undefined ) to = buffer.byteLength;
M
Mr.doob 已提交
4076

L
Lewy Blue 已提交
4077
		return THREE.LoaderUtils.decodeText( new Uint8Array( buffer, from, to ) );
Y
yamahigashi 已提交
4078

4079
	}
Y
yamahigashi 已提交
4080

M
Mr.doob 已提交
4081
	function append( a, b ) {
Y
yamahigashi 已提交
4082

M
Mr.doob 已提交
4083
		for ( var i = 0, j = a.length, l = b.length; i < l; i ++, j ++ ) {
Y
yamahigashi 已提交
4084

M
Mr.doob 已提交
4085
			a[ j ] = b[ i ];
Y
yamahigashi 已提交
4086

M
Mr.doob 已提交
4087
		}
Y
yamahigashi 已提交
4088

4089
	}
Y
yamahigashi 已提交
4090

M
Mr.doob 已提交
4091 4092 4093 4094 4095 4096 4097
	function slice( a, b, from, to ) {

		for ( var i = from, j = 0; i < to; i ++, j ++ ) {

			a[ j ] = b[ i ];

		}
Y
yamahigashi 已提交
4098

M
Mr.doob 已提交
4099
		return a;
Y
yamahigashi 已提交
4100

4101
	}
Y
yamahigashi 已提交
4102

4103 4104 4105 4106 4107 4108 4109
	// inject array a2 into array a1 at index
	function inject( a1, index, a2 ) {

		return a1.slice( 0, index ).concat( a2 ).concat( a1.slice( index ) );

	}

4110 4111
	return FBXLoader;

4112
} )();