OBJLoader.js 18.1 KB
Newer Older
M
Mr.doob 已提交
1 2 3 4
/**
 * @author mrdoob / http://mrdoob.com/
 */

M
r59  
Mr.doob 已提交
5 6 7 8
THREE.OBJLoader = function ( manager ) {

	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;

M
r74  
Mr.doob 已提交
9 10
	this.materials = null;

M
r76  
Mr.doob 已提交
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
	this.regexp = {
		// v float float float
		vertex_pattern           : /^v\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/,
		// vn float float float
		normal_pattern           : /^vn\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/,
		// vt float float
		uv_pattern               : /^vt\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/,
		// f vertex vertex vertex
		face_vertex              : /^f\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)(?:\s+(-?\d+))?/,
		// f vertex/uv vertex/uv vertex/uv
		face_vertex_uv           : /^f\s+(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)(?:\s+(-?\d+)\/(-?\d+))?/,
		// f vertex/uv/normal vertex/uv/normal vertex/uv/normal
		face_vertex_uv_normal    : /^f\s+(-?\d+)\/(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)\/(-?\d+)(?:\s+(-?\d+)\/(-?\d+)\/(-?\d+))?/,
		// f vertex//normal vertex//normal vertex//normal
		face_vertex_normal       : /^f\s+(-?\d+)\/\/(-?\d+)\s+(-?\d+)\/\/(-?\d+)\s+(-?\d+)\/\/(-?\d+)(?:\s+(-?\d+)\/\/(-?\d+))?/,
		// o object_name | g group_name
		object_pattern           : /^[og]\s*(.+)?/,
		// s boolean
		smoothing_pattern        : /^s\s+(\d+|on|off)/,
		// mtllib file_reference
		material_library_pattern : /^mtllib /,
		// usemtl material_name
		material_use_pattern     : /^usemtl /
	};

M
r59  
Mr.doob 已提交
36
};
M
Mr.doob 已提交
37 38 39 40 41

THREE.OBJLoader.prototype = {

	constructor: THREE.OBJLoader,

M
r59  
Mr.doob 已提交
42
	load: function ( url, onLoad, onProgress, onError ) {
M
Mr.doob 已提交
43 44 45

		var scope = this;

M
r59  
Mr.doob 已提交
46
		var loader = new THREE.XHRLoader( scope.manager );
M
r74  
Mr.doob 已提交
47
		loader.setPath( this.path );
M
r59  
Mr.doob 已提交
48
		loader.load( url, function ( text ) {
M
Mr.doob 已提交
49

M
r59  
Mr.doob 已提交
50
			onLoad( scope.parse( text ) );
M
Mr.doob 已提交
51

M
r69  
Mr.doob 已提交
52
		}, onProgress, onError );
M
Mr.doob 已提交
53 54 55

	},

M
r74  
Mr.doob 已提交
56 57 58 59 60 61 62
	setPath: function ( value ) {

		this.path = value;

	},

	setMaterials: function ( materials ) {
M
r72  
Mr.doob 已提交
63

M
r74  
Mr.doob 已提交
64
		this.materials = materials;
M
r72  
Mr.doob 已提交
65 66 67

	},

M
r76  
Mr.doob 已提交
68
	_createParserState : function () {
M
Mr.doob 已提交
69

M
r76  
Mr.doob 已提交
70 71 72
		var state = {
			objects  : [],
			object   : {},
M
Mr.doob 已提交
73

M
r76  
Mr.doob 已提交
74 75 76
			vertices : [],
			normals  : [],
			uvs      : [],
M
r74  
Mr.doob 已提交
77

M
r76  
Mr.doob 已提交
78
			materialLibraries : [],
M
r74  
Mr.doob 已提交
79

M
r76  
Mr.doob 已提交
80
			startObject: function ( name, fromDeclaration ) {
M
r74  
Mr.doob 已提交
81

M
r76  
Mr.doob 已提交
82 83 84
				// If the current object (initial from reset) is not from a g/o declaration in the parsed
				// file. We need to use it for the first parsed g/o to keep things in sync.
				if ( this.object && this.object.fromDeclaration === false ) {
M
r74  
Mr.doob 已提交
85

M
r76  
Mr.doob 已提交
86 87 88
					this.object.name = name;
					this.object.fromDeclaration = ( fromDeclaration !== false );
					return;
M
r74  
Mr.doob 已提交
89

M
r76  
Mr.doob 已提交
90
				}
M
r74  
Mr.doob 已提交
91

M
r77  
Mr.doob 已提交
92 93 94 95 96 97
				if ( this.object && typeof this.object._finalize === 'function' ) {

					this.object._finalize();

				}

M
Mr.doob 已提交
98 99
				var previousMaterial = ( this.object && typeof this.object.currentMaterial === 'function' ? this.object.currentMaterial() : undefined );

M
r76  
Mr.doob 已提交
100 101
				this.object = {
					name : name || '',
M
r77  
Mr.doob 已提交
102 103
					fromDeclaration : ( fromDeclaration !== false ),

M
r76  
Mr.doob 已提交
104 105 106 107 108
					geometry : {
						vertices : [],
						normals  : [],
						uvs      : []
					},
M
r77  
Mr.doob 已提交
109 110 111 112 113 114 115
					materials : [],
					smooth : true,

					startMaterial : function( name, libraries ) {

						var previous = this._finalize( false );

M
Mr.doob 已提交
116 117 118 119 120 121 122 123
						// New usemtl declaration overwrites an inherited material, except if faces were declared
						// after the material, then it must be preserved for proper MultiMaterial continuation.
						if ( previous && ( previous.inherited || previous.groupCount <= 0 ) ) {

							this.materials.splice( previous.index, 1 );

						}

M
r77  
Mr.doob 已提交
124 125 126 127 128 129 130
						var material = {
							index      : this.materials.length,
							name       : name || '',
							mtllib     : ( Array.isArray( libraries ) && libraries.length > 0 ? libraries[ libraries.length - 1 ] : '' ),
							smooth     : ( previous !== undefined ? previous.smooth : this.smooth ),
							groupStart : ( previous !== undefined ? previous.groupEnd : 0 ),
							groupEnd   : -1,
M
Mr.doob 已提交
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
							groupCount : -1,
							inherited  : false,

							clone : function( index ) {
								return {
									index      : ( typeof index === 'number' ? index : this.index ),
									name       : this.name,
									mtllib     : this.mtllib,
									smooth     : this.smooth,
									groupStart : this.groupEnd,
									groupEnd   : -1,
									groupCount : -1,
									inherited  : false
								};
							}
M
r77  
Mr.doob 已提交
146 147 148 149 150 151
						};

						this.materials.push( material );

						return material;

M
r76  
Mr.doob 已提交
152
					},
M
r77  
Mr.doob 已提交
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170

					currentMaterial : function() {

						if ( this.materials.length > 0 ) {
							return this.materials[ this.materials.length - 1 ];
						}

						return undefined;

					},

					_finalize : function( end ) {

						var lastMultiMaterial = this.currentMaterial();
						if ( lastMultiMaterial && lastMultiMaterial.groupEnd === -1 ) {

							lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3;
							lastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart;
M
Mr.doob 已提交
171
							lastMultiMaterial.inherited = false;
M
r77  
Mr.doob 已提交
172 173 174 175 176 177 178 179 180 181 182 183 184 185

						}

						// Guarantee at least one empty material, this makes the creation later more straight forward.
						if ( end !== false && this.materials.length === 0 ) {
							this.materials.push({
								name   : '',
								smooth : this.smooth
							});
						}

						return lastMultiMaterial;

					}
M
r76  
Mr.doob 已提交
186
				};
M
Mr.doob 已提交
187

M
Mr.doob 已提交
188 189 190 191 192 193 194 195 196 197 198 199 200 201
				// Inherit previous objects material.
				// Spec tells us that a declared material must be set to all objects until a new material is declared.
				// If a usemtl declaration is encountered while this new object is being parsed, it will
				// overwrite the inherited material. Exception being that there was already face declarations
				// to the inherited material, then it will be preserved for proper MultiMaterial continuation.

				if ( previousMaterial && previousMaterial.name && typeof previousMaterial.clone === "function" ) {

					var declared = previousMaterial.clone( 0 );
					declared.inherited = true;
					this.object.materials.push( declared );

				}

M
r76  
Mr.doob 已提交
202
				this.objects.push( this.object );
M
Mr.doob 已提交
203

M
r76  
Mr.doob 已提交
204
			},
M
Mr.doob 已提交
205

M
r77  
Mr.doob 已提交
206 207 208 209 210 211 212 213 214 215
			finalize : function() {

				if ( this.object && typeof this.object._finalize === 'function' ) {

					this.object._finalize();

				}

			},

M
r76  
Mr.doob 已提交
216
			parseVertexIndex: function ( value, len ) {
M
Mr.doob 已提交
217

M
r76  
Mr.doob 已提交
218 219
				var index = parseInt( value, 10 );
				return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
M
Mr.doob 已提交
220

M
r76  
Mr.doob 已提交
221
			},
M
r69  
Mr.doob 已提交
222

M
r76  
Mr.doob 已提交
223
			parseNormalIndex: function ( value, len ) {
M
Mr.doob 已提交
224

M
r76  
Mr.doob 已提交
225 226
				var index = parseInt( value, 10 );
				return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
M
Mr.doob 已提交
227

M
r76  
Mr.doob 已提交
228
			},
M
r66  
Mr.doob 已提交
229

M
r76  
Mr.doob 已提交
230
			parseUVIndex: function ( value, len ) {
M
r66  
Mr.doob 已提交
231

M
r76  
Mr.doob 已提交
232 233
				var index = parseInt( value, 10 );
				return ( index >= 0 ? index - 1 : index + len / 2 ) * 2;
M
r66  
Mr.doob 已提交
234

M
r76  
Mr.doob 已提交
235
			},
M
r66  
Mr.doob 已提交
236

M
r76  
Mr.doob 已提交
237
			addVertex: function ( a, b, c ) {
M
r66  
Mr.doob 已提交
238

M
r76  
Mr.doob 已提交
239 240
				var src = this.vertices;
				var dst = this.object.geometry.vertices;
M
r66  
Mr.doob 已提交
241

M
r76  
Mr.doob 已提交
242 243 244 245 246 247 248 249 250
				dst.push( src[ a + 0 ] );
				dst.push( src[ a + 1 ] );
				dst.push( src[ a + 2 ] );
				dst.push( src[ b + 0 ] );
				dst.push( src[ b + 1 ] );
				dst.push( src[ b + 2 ] );
				dst.push( src[ c + 0 ] );
				dst.push( src[ c + 1 ] );
				dst.push( src[ c + 2 ] );
M
r66  
Mr.doob 已提交
251

M
r76  
Mr.doob 已提交
252
			},
M
r66  
Mr.doob 已提交
253

M
r76  
Mr.doob 已提交
254
			addVertexLine: function ( a ) {
M
r69  
Mr.doob 已提交
255

M
r76  
Mr.doob 已提交
256 257
				var src = this.vertices;
				var dst = this.object.geometry.vertices;
M
r69  
Mr.doob 已提交
258

M
r76  
Mr.doob 已提交
259 260 261
				dst.push( src[ a + 0 ] );
				dst.push( src[ a + 1 ] );
				dst.push( src[ a + 2 ] );
M
r66  
Mr.doob 已提交
262

M
r76  
Mr.doob 已提交
263
			},
M
r66  
Mr.doob 已提交
264

M
r76  
Mr.doob 已提交
265
			addNormal : function ( a, b, c ) {
M
r66  
Mr.doob 已提交
266

M
r76  
Mr.doob 已提交
267 268
				var src = this.normals;
				var dst = this.object.geometry.normals;
M
r63  
Mr.doob 已提交
269

M
r76  
Mr.doob 已提交
270 271 272 273 274 275 276 277 278
				dst.push( src[ a + 0 ] );
				dst.push( src[ a + 1 ] );
				dst.push( src[ a + 2 ] );
				dst.push( src[ b + 0 ] );
				dst.push( src[ b + 1 ] );
				dst.push( src[ b + 2 ] );
				dst.push( src[ c + 0 ] );
				dst.push( src[ c + 1 ] );
				dst.push( src[ c + 2 ] );
M
r63  
Mr.doob 已提交
279

M
r76  
Mr.doob 已提交
280
			},
M
r69  
Mr.doob 已提交
281

M
r76  
Mr.doob 已提交
282
			addUV: function ( a, b, c ) {
M
r69  
Mr.doob 已提交
283

M
r76  
Mr.doob 已提交
284 285
				var src = this.uvs;
				var dst = this.object.geometry.uvs;
M
r63  
Mr.doob 已提交
286

M
r76  
Mr.doob 已提交
287 288 289 290 291 292
				dst.push( src[ a + 0 ] );
				dst.push( src[ a + 1 ] );
				dst.push( src[ b + 0 ] );
				dst.push( src[ b + 1 ] );
				dst.push( src[ c + 0 ] );
				dst.push( src[ c + 1 ] );
M
r63  
Mr.doob 已提交
293

M
r76  
Mr.doob 已提交
294
			},
M
r69  
Mr.doob 已提交
295

M
r76  
Mr.doob 已提交
296
			addUVLine: function ( a ) {
M
r63  
Mr.doob 已提交
297

M
r76  
Mr.doob 已提交
298 299 300 301 302
				var src = this.uvs;
				var dst = this.object.geometry.uvs;

				dst.push( src[ a + 0 ] );
				dst.push( src[ a + 1 ] );
M
r63  
Mr.doob 已提交
303

M
r76  
Mr.doob 已提交
304
			},
M
r63  
Mr.doob 已提交
305

M
r76  
Mr.doob 已提交
306 307 308 309 310 311 312 313
			addFace: function ( a, b, c, d, ua, ub, uc, ud, na, nb, nc, nd ) {

				var vLen = this.vertices.length;

				var ia = this.parseVertexIndex( a, vLen );
				var ib = this.parseVertexIndex( b, vLen );
				var ic = this.parseVertexIndex( c, vLen );
				var id;
M
r63  
Mr.doob 已提交
314

M
r69  
Mr.doob 已提交
315 316
				if ( d === undefined ) {

M
r76  
Mr.doob 已提交
317
					this.addVertex( ia, ib, ic );
M
r69  
Mr.doob 已提交
318 319 320

				} else {

M
r76  
Mr.doob 已提交
321
					id = this.parseVertexIndex( d, vLen );
M
r63  
Mr.doob 已提交
322

M
r76  
Mr.doob 已提交
323 324
					this.addVertex( ia, ib, id );
					this.addVertex( ib, ic, id );
M
r63  
Mr.doob 已提交
325 326 327

				}

M
r76  
Mr.doob 已提交
328
				if ( ua !== undefined ) {
M
r63  
Mr.doob 已提交
329

M
r76  
Mr.doob 已提交
330
					var uvLen = this.uvs.length;
M
r63  
Mr.doob 已提交
331

M
r76  
Mr.doob 已提交
332 333 334
					ia = this.parseUVIndex( ua, uvLen );
					ib = this.parseUVIndex( ub, uvLen );
					ic = this.parseUVIndex( uc, uvLen );
M
r63  
Mr.doob 已提交
335

M
r76  
Mr.doob 已提交
336
					if ( d === undefined ) {
M
r63  
Mr.doob 已提交
337

M
r76  
Mr.doob 已提交
338
						this.addUV( ia, ib, ic );
M
r69  
Mr.doob 已提交
339

M
r76  
Mr.doob 已提交
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
					} else {

						id = this.parseUVIndex( ud, uvLen );

						this.addUV( ia, ib, id );
						this.addUV( ib, ic, id );

					}

				}

				if ( na !== undefined ) {

					// Normals are many times the same. If so, skip function call and parseInt.
					var nLen = this.normals.length;
					ia = this.parseNormalIndex( na, nLen );

					ib = na === nb ? ia : this.parseNormalIndex( nb, nLen );
					ic = na === nc ? ia : this.parseNormalIndex( nc, nLen );

					if ( d === undefined ) {

						this.addNormal( ia, ib, ic );

					} else {

						id = this.parseNormalIndex( nd, nLen );

						this.addNormal( ia, ib, id );
						this.addNormal( ib, ic, id );

					}

				}

			},

			addLineGeometry: function ( vertices, uvs ) {

				this.object.geometry.type = 'Line';

				var vLen = this.vertices.length;
				var uvLen = this.uvs.length;

				for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) {

					this.addVertexLine( this.parseVertexIndex( vertices[ vi ], vLen ) );
M
r63  
Mr.doob 已提交
387

M
r76  
Mr.doob 已提交
388 389 390
				}

				for ( var uvi = 0, l = uvs.length; uvi < l; uvi ++ ) {
M
r69  
Mr.doob 已提交
391

M
r76  
Mr.doob 已提交
392
					this.addUVLine( this.parseUVIndex( uvs[ uvi ], uvLen ) );
M
r63  
Mr.doob 已提交
393 394 395 396

				}

			}
M
r69  
Mr.doob 已提交
397

M
r76  
Mr.doob 已提交
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
		};

		state.startObject( '', false );

		return state;

	},

	parse: function ( text ) {

		console.time( 'OBJLoader' );

		var state = this._createParserState();

		if ( text.indexOf( '\r\n' ) !== - 1 ) {

			// This is faster than String.split with regex that splits on both
			text = text.replace( '\r\n', '\n' );

M
r63  
Mr.doob 已提交
417
		}
M
Mr.doob 已提交
418

M
r76  
Mr.doob 已提交
419 420 421 422
		var lines = text.split( '\n' );
		var line = '', lineFirstChar = '', lineSecondChar = '';
		var lineLength = 0;
		var result = [];
M
Mr.doob 已提交
423

M
r76  
Mr.doob 已提交
424 425
		// Faster to just trim left side of the line. Use if available.
		var trimLeft = ( typeof ''.trimLeft === 'function' );
M
Mr.doob 已提交
426

M
r76  
Mr.doob 已提交
427
		for ( var i = 0, l = lines.length; i < l; i ++ ) {
M
Mr.doob 已提交
428

M
r76  
Mr.doob 已提交
429
			line = lines[ i ];
M
Mr.doob 已提交
430

M
r76  
Mr.doob 已提交
431
			line = trimLeft ? line.trimLeft() : line.trim();
M
Mr.doob 已提交
432

M
r76  
Mr.doob 已提交
433
			lineLength = line.length;
M
Mr.doob 已提交
434

M
r76  
Mr.doob 已提交
435
			if ( lineLength === 0 ) continue;
M
Mr.doob 已提交
436

M
r76  
Mr.doob 已提交
437
			lineFirstChar = line.charAt( 0 );
M
Mr.doob 已提交
438

M
r76  
Mr.doob 已提交
439 440
			// @todo invoke passed in handler if any
			if ( lineFirstChar === '#' ) continue;
M
r74  
Mr.doob 已提交
441

M
r76  
Mr.doob 已提交
442
			if ( lineFirstChar === 'v' ) {
M
Mr.doob 已提交
443

M
r76  
Mr.doob 已提交
444
				lineSecondChar = line.charAt( 1 );
M
Mr.doob 已提交
445

M
r76  
Mr.doob 已提交
446
				if ( lineSecondChar === ' ' && ( result = this.regexp.vertex_pattern.exec( line ) ) !== null ) {
M
Mr.doob 已提交
447

M
r76  
Mr.doob 已提交
448 449
					// 0                  1      2      3
					// ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
M
Mr.doob 已提交
450

M
r76  
Mr.doob 已提交
451 452 453 454 455
					state.vertices.push(
						parseFloat( result[ 1 ] ),
						parseFloat( result[ 2 ] ),
						parseFloat( result[ 3 ] )
					);
M
Mr.doob 已提交
456

M
r76  
Mr.doob 已提交
457
				} else if ( lineSecondChar === 'n' && ( result = this.regexp.normal_pattern.exec( line ) ) !== null ) {
M
Mr.doob 已提交
458

M
r76  
Mr.doob 已提交
459 460
					// 0                   1      2      3
					// ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
M
Mr.doob 已提交
461

M
r76  
Mr.doob 已提交
462 463 464 465 466
					state.normals.push(
						parseFloat( result[ 1 ] ),
						parseFloat( result[ 2 ] ),
						parseFloat( result[ 3 ] )
					);
M
Mr.doob 已提交
467

M
r76  
Mr.doob 已提交
468
				} else if ( lineSecondChar === 't' && ( result = this.regexp.uv_pattern.exec( line ) ) !== null ) {
M
Mr.doob 已提交
469

M
r76  
Mr.doob 已提交
470 471
					// 0               1      2
					// ["vt 0.1 0.2", "0.1", "0.2"]
M
Mr.doob 已提交
472

M
r76  
Mr.doob 已提交
473 474 475 476
					state.uvs.push(
						parseFloat( result[ 1 ] ),
						parseFloat( result[ 2 ] )
					);
M
Mr.doob 已提交
477

M
r76  
Mr.doob 已提交
478
				} else {
M
Mr.doob 已提交
479

M
r76  
Mr.doob 已提交
480
					throw new Error( "Unexpected vertex/normal/uv line: '" + line  + "'" );
M
Mr.doob 已提交
481

M
r76  
Mr.doob 已提交
482
				}
M
Mr.doob 已提交
483

M
r76  
Mr.doob 已提交
484
			} else if ( lineFirstChar === "f" ) {
M
Mr.doob 已提交
485

M
r76  
Mr.doob 已提交
486
				if ( ( result = this.regexp.face_vertex_uv_normal.exec( line ) ) !== null ) {
M
Mr.doob 已提交
487

M
r76  
Mr.doob 已提交
488 489 490
					// f vertex/uv/normal vertex/uv/normal vertex/uv/normal
					// 0                        1    2    3    4    5    6    7    8    9   10         11         12
					// ["f 1/1/1 2/2/2 3/3/3", "1", "1", "1", "2", "2", "2", "3", "3", "3", undefined, undefined, undefined]
M
Mr.doob 已提交
491

M
r76  
Mr.doob 已提交
492 493 494 495 496
					state.addFace(
						result[ 1 ], result[ 4 ], result[ 7 ], result[ 10 ],
						result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ],
						result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ]
					);
M
Mr.doob 已提交
497

M
r76  
Mr.doob 已提交
498
				} else if ( ( result = this.regexp.face_vertex_uv.exec( line ) ) !== null ) {
M
Mr.doob 已提交
499

M
r76  
Mr.doob 已提交
500 501 502
					// f vertex/uv vertex/uv vertex/uv
					// 0                  1    2    3    4    5    6   7          8
					// ["f 1/1 2/2 3/3", "1", "1", "2", "2", "3", "3", undefined, undefined]
M
r62  
Mr.doob 已提交
503

M
r76  
Mr.doob 已提交
504 505 506 507
					state.addFace(
						result[ 1 ], result[ 3 ], result[ 5 ], result[ 7 ],
						result[ 2 ], result[ 4 ], result[ 6 ], result[ 8 ]
					);
M
r60  
Mr.doob 已提交
508

M
r76  
Mr.doob 已提交
509
				} else if ( ( result = this.regexp.face_vertex_normal.exec( line ) ) !== null ) {
M
r71  
Mr.doob 已提交
510

M
r76  
Mr.doob 已提交
511 512 513
					// f vertex//normal vertex//normal vertex//normal
					// 0                     1    2    3    4    5    6   7          8
					// ["f 1//1 2//2 3//3", "1", "1", "2", "2", "3", "3", undefined, undefined]
M
r62  
Mr.doob 已提交
514

M
r76  
Mr.doob 已提交
515 516 517 518 519
					state.addFace(
						result[ 1 ], result[ 3 ], result[ 5 ], result[ 7 ],
						undefined, undefined, undefined, undefined,
						result[ 2 ], result[ 4 ], result[ 6 ], result[ 8 ]
					);
M
r62  
Mr.doob 已提交
520

M
r76  
Mr.doob 已提交
521
				} else if ( ( result = this.regexp.face_vertex.exec( line ) ) !== null ) {
M
r62  
Mr.doob 已提交
522

M
r76  
Mr.doob 已提交
523 524 525
					// f vertex vertex vertex
					// 0            1    2    3   4
					// ["f 1 2 3", "1", "2", "3", undefined]
M
Mr.doob 已提交
526

M
r76  
Mr.doob 已提交
527 528 529
					state.addFace(
						result[ 1 ], result[ 2 ], result[ 3 ], result[ 4 ]
					);
M
Mr.doob 已提交
530

M
r76  
Mr.doob 已提交
531
				} else {
M
r62  
Mr.doob 已提交
532

M
r76  
Mr.doob 已提交
533
					throw new Error( "Unexpected face line: '" + line  + "'" );
M
Mr.doob 已提交
534

M
r76  
Mr.doob 已提交
535
				}
M
Mr.doob 已提交
536

M
r76  
Mr.doob 已提交
537
			} else if ( lineFirstChar === "l" ) {
M
r69  
Mr.doob 已提交
538

M
r76  
Mr.doob 已提交
539 540
				var lineParts = line.substring( 1 ).trim().split( " " );
				var lineVertices = [], lineUVs = [];
M
r69  
Mr.doob 已提交
541

M
r76  
Mr.doob 已提交
542
				if ( line.indexOf( "/" ) === - 1 ) {
M
r61  
Mr.doob 已提交
543

M
r76  
Mr.doob 已提交
544
					lineVertices = lineParts;
M
r61  
Mr.doob 已提交
545

M
r74  
Mr.doob 已提交
546
				} else {
M
Mr.doob 已提交
547

M
r76  
Mr.doob 已提交
548 549 550 551 552 553 554 555
					for ( var li = 0, llen = lineParts.length; li < llen; li ++ ) {

						var parts = lineParts[ li ].split( "/" );

						if ( parts[ 0 ] !== "" ) lineVertices.push( parts[ 0 ] );
						if ( parts[ 1 ] !== "" ) lineUVs.push( parts[ 1 ] );

					}
M
r74  
Mr.doob 已提交
556 557

				}
M
r76  
Mr.doob 已提交
558 559 560 561 562 563 564 565 566 567
				state.addLineGeometry( lineVertices, lineUVs );

			} else if ( ( result = this.regexp.object_pattern.exec( line ) ) !== null ) {

				// o object_name
				// or
				// g group_name

				var name = result[ 0 ].substr( 1 ).trim();
				state.startObject( name );
M
Mr.doob 已提交
568

M
r76  
Mr.doob 已提交
569
			} else if ( this.regexp.material_use_pattern.test( line ) ) {
M
Mr.doob 已提交
570 571 572

				// material

M
r77  
Mr.doob 已提交
573
				state.object.startMaterial( line.substring( 7 ).trim(), state.materialLibraries );
M
Mr.doob 已提交
574

M
r76  
Mr.doob 已提交
575
			} else if ( this.regexp.material_library_pattern.test( line ) ) {
M
Mr.doob 已提交
576 577 578

				// mtl file

M
r76  
Mr.doob 已提交
579 580 581
				state.materialLibraries.push( line.substring( 7 ).trim() );

			} else if ( ( result = this.regexp.smoothing_pattern.exec( line ) ) !== null ) {
M
Mr.doob 已提交
582 583 584

				// smooth shading

M
r77  
Mr.doob 已提交
585 586 587 588 589 590 591
				// @todo Handle files that have varying smooth values for a set of faces inside one geometry,
				// but does not define a usemtl for each face set.
				// This should be detected and a dummy material created (later MultiMaterial and geometry groups).
				// This requires some care to not create extra material on each smooth value for "normal" obj files.
				// where explicit usemtl defines geometry groups.
				// Example asset: examples/models/obj/cerberus/Cerberus.obj

M
r76  
Mr.doob 已提交
592
				var value = result[ 1 ].trim().toLowerCase();
M
r77  
Mr.doob 已提交
593 594 595 596 597 598 599 600
				state.object.smooth = ( value === '1' || value === 'on' );

				var material = state.object.currentMaterial();
				if ( material ) {

					material.smooth = state.object.smooth;

				}
M
r74  
Mr.doob 已提交
601

M
Mr.doob 已提交
602 603
			} else {

M
r76  
Mr.doob 已提交
604 605 606 607
				// Handle null terminated files without exception
				if ( line === '\0' ) continue;

				throw new Error( "Unexpected line: '" + line  + "'" );
M
Mr.doob 已提交
608 609 610 611 612

			}

		}

M
r77  
Mr.doob 已提交
613 614
		state.finalize();

M
r74  
Mr.doob 已提交
615
		var container = new THREE.Group();
M
r76  
Mr.doob 已提交
616
		container.materialLibraries = [].concat( state.materialLibraries );
M
r66  
Mr.doob 已提交
617

M
r76  
Mr.doob 已提交
618
		for ( var i = 0, l = state.objects.length; i < l; i ++ ) {
M
r61  
Mr.doob 已提交
619

M
r76  
Mr.doob 已提交
620
			var object = state.objects[ i ];
M
r74  
Mr.doob 已提交
621
			var geometry = object.geometry;
M
r77  
Mr.doob 已提交
622
			var materials = object.materials;
M
r76  
Mr.doob 已提交
623 624 625 626
			var isLine = ( geometry.type === 'Line' );

			// Skip o/g line declarations that did not follow with any faces
			if ( geometry.vertices.length === 0 ) continue;
M
r61  
Mr.doob 已提交
627

M
r69  
Mr.doob 已提交
628 629 630 631 632
			var buffergeometry = new THREE.BufferGeometry();

			buffergeometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( geometry.vertices ), 3 ) );

			if ( geometry.normals.length > 0 ) {
M
r72  
Mr.doob 已提交
633

M
r69  
Mr.doob 已提交
634
				buffergeometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( geometry.normals ), 3 ) );
M
r72  
Mr.doob 已提交
635

M
r74  
Mr.doob 已提交
636 637 638 639
			} else {

				buffergeometry.computeVertexNormals();

M
r69  
Mr.doob 已提交
640 641 642
			}

			if ( geometry.uvs.length > 0 ) {
M
r72  
Mr.doob 已提交
643

M
r69  
Mr.doob 已提交
644
				buffergeometry.addAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( geometry.uvs ), 2 ) );
M
r72  
Mr.doob 已提交
645

M
r69  
Mr.doob 已提交
646 647
			}

M
r77  
Mr.doob 已提交
648 649 650 651 652 653 654 655
			// Create materials

			var createdMaterials = [];

			for ( var mi = 0, miLen = materials.length; mi < miLen ; mi++ ) {

				var sourceMaterial = materials[mi];
				var material = undefined;
M
r74  
Mr.doob 已提交
656

M
r77  
Mr.doob 已提交
657
				if ( this.materials !== null ) {
M
r74  
Mr.doob 已提交
658

M
r77  
Mr.doob 已提交
659
					material = this.materials.create( sourceMaterial.name );
M
r74  
Mr.doob 已提交
660

M
r77  
Mr.doob 已提交
661 662
					// mtl etc. loaders probably can't create line materials correctly, copy properties to a line material.
					if ( isLine && material && ! ( material instanceof THREE.LineBasicMaterial ) ) {
M
r76  
Mr.doob 已提交
663

M
r77  
Mr.doob 已提交
664 665 666 667 668
						var materialLine = new THREE.LineBasicMaterial();
						materialLine.copy( material );
						material = materialLine;

					}
M
r76  
Mr.doob 已提交
669 670 671

				}

M
r77  
Mr.doob 已提交
672
				if ( ! material ) {
M
r74  
Mr.doob 已提交
673

M
r77  
Mr.doob 已提交
674 675
					material = ( ! isLine ? new THREE.MeshPhongMaterial() : new THREE.LineBasicMaterial() );
					material.name = sourceMaterial.name;
M
r74  
Mr.doob 已提交
676

M
r77  
Mr.doob 已提交
677 678 679 680 681
				}

				material.shading = sourceMaterial.smooth ? THREE.SmoothShading : THREE.FlatShading;

				createdMaterials.push(material);
M
r74  
Mr.doob 已提交
682 683 684

			}

M
r77  
Mr.doob 已提交
685 686 687 688 689 690 691 692 693 694 695 696 697 698
			// Create mesh

			var mesh;

			if ( createdMaterials.length > 1 ) {

				for ( var mi = 0, miLen = materials.length; mi < miLen ; mi++ ) {

					var sourceMaterial = materials[mi];
					buffergeometry.addGroup( sourceMaterial.groupStart, sourceMaterial.groupCount, mi );

				}

				var multiMaterial = new THREE.MultiMaterial( createdMaterials );
M
r80  
Mr.doob 已提交
699
				mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, multiMaterial ) : new THREE.LineSegments( buffergeometry, multiMaterial ) );
M
r77  
Mr.doob 已提交
700 701 702

			} else {

M
r80  
Mr.doob 已提交
703
				mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, createdMaterials[ 0 ] ) : new THREE.LineSegments( buffergeometry, createdMaterials[ 0 ] ) );
M
r77  
Mr.doob 已提交
704
			}
M
r69  
Mr.doob 已提交
705 706 707 708

			mesh.name = object.name;

			container.add( mesh );
M
r61  
Mr.doob 已提交
709 710

		}
M
r69  
Mr.doob 已提交
711 712 713 714

		console.timeEnd( 'OBJLoader' );

		return container;
M
Mr.doob 已提交
715 716 717

	}

M
r68  
Mr.doob 已提交
718
};