|
@@ -2,70 +2,32 @@
|
|
|
* @author mrdoob / http://mrdoob.com/
|
|
|
*/
|
|
|
|
|
|
-THREE.OBJLoader = function ( manager ) {
|
|
|
-
|
|
|
- this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
|
|
|
-
|
|
|
- this.materials = null;
|
|
|
-
|
|
|
- this.regexp = {
|
|
|
- // v float float float
|
|
|
- vertex_pattern : /^v\s+([\d\.\+\-eE]+)\s+([\d\.\+\-eE]+)\s+([\d\.\+\-eE]+)/,
|
|
|
- // vn float float float
|
|
|
- normal_pattern : /^vn\s+([\d\.\+\-eE]+)\s+([\d\.\+\-eE]+)\s+([\d\.\+\-eE]+)/,
|
|
|
- // vt float float
|
|
|
- uv_pattern : /^vt\s+([\d\.\+\-eE]+)\s+([\d\.\+\-eE]+)/,
|
|
|
- // 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 /
|
|
|
- };
|
|
|
-
|
|
|
-};
|
|
|
-
|
|
|
-THREE.OBJLoader.prototype = {
|
|
|
-
|
|
|
- constructor: THREE.OBJLoader,
|
|
|
-
|
|
|
- load: function ( url, onLoad, onProgress, onError ) {
|
|
|
-
|
|
|
- var scope = this;
|
|
|
-
|
|
|
- var loader = new THREE.FileLoader( scope.manager );
|
|
|
- loader.setPath( this.path );
|
|
|
- loader.load( url, function ( text ) {
|
|
|
-
|
|
|
- onLoad( scope.parse( text ) );
|
|
|
-
|
|
|
- }, onProgress, onError );
|
|
|
-
|
|
|
- },
|
|
|
-
|
|
|
- setPath: function ( value ) {
|
|
|
-
|
|
|
- this.path = value;
|
|
|
-
|
|
|
- },
|
|
|
-
|
|
|
- setMaterials: function ( materials ) {
|
|
|
-
|
|
|
- this.materials = materials;
|
|
|
-
|
|
|
- },
|
|
|
-
|
|
|
- _createParserState : function () {
|
|
|
+THREE.OBJLoader = ( function () {
|
|
|
+
|
|
|
+ // v float float float
|
|
|
+ var vertex_pattern = /^v\s+([\d\.\+\-eE]+)\s+([\d\.\+\-eE]+)\s+([\d\.\+\-eE]+)/;
|
|
|
+ // vn float float float
|
|
|
+ var normal_pattern = /^vn\s+([\d\.\+\-eE]+)\s+([\d\.\+\-eE]+)\s+([\d\.\+\-eE]+)/;
|
|
|
+ // vt float float
|
|
|
+ var uv_pattern = /^vt\s+([\d\.\+\-eE]+)\s+([\d\.\+\-eE]+)/;
|
|
|
+ // f vertex vertex vertex
|
|
|
+ var face_vertex = /^f\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)(?:\s+(-?\d+))?/;
|
|
|
+ // f vertex/uv vertex/uv vertex/uv
|
|
|
+ var 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
|
|
|
+ var 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
|
|
|
+ var face_vertex_normal = /^f\s+(-?\d+)\/\/(-?\d+)\s+(-?\d+)\/\/(-?\d+)\s+(-?\d+)\/\/(-?\d+)(?:\s+(-?\d+)\/\/(-?\d+))?/;
|
|
|
+ // o object_name | g group_name
|
|
|
+ var object_pattern = /^[og]\s*(.+)?/;
|
|
|
+ // s boolean
|
|
|
+ var smoothing_pattern = /^s\s+(\d+|on|off)/;
|
|
|
+ // mtllib file_reference
|
|
|
+ var material_library_pattern = /^mtllib /;
|
|
|
+ // usemtl material_name
|
|
|
+ var material_use_pattern = /^usemtl /;
|
|
|
+
|
|
|
+ function ParserState() {
|
|
|
|
|
|
var state = {
|
|
|
objects : [],
|
|
@@ -178,7 +140,7 @@ THREE.OBJLoader.prototype = {
|
|
|
if ( end && this.materials.length > 1 ) {
|
|
|
|
|
|
for ( var mi = this.materials.length - 1; mi >= 0; mi-- ) {
|
|
|
- if ( this.materials[mi].groupCount <= 0 ) {
|
|
|
+ if ( this.materials[ mi ].groupCount <= 0 ) {
|
|
|
this.materials.splice( mi, 1 );
|
|
|
}
|
|
|
}
|
|
@@ -254,15 +216,9 @@ THREE.OBJLoader.prototype = {
|
|
|
var src = this.vertices;
|
|
|
var dst = this.object.geometry.vertices;
|
|
|
|
|
|
- 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 ] );
|
|
|
+ dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
|
|
|
+ dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
|
|
|
+ dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
|
|
|
|
|
|
},
|
|
|
|
|
@@ -271,9 +227,7 @@ THREE.OBJLoader.prototype = {
|
|
|
var src = this.vertices;
|
|
|
var dst = this.object.geometry.vertices;
|
|
|
|
|
|
- dst.push( src[ a + 0 ] );
|
|
|
- dst.push( src[ a + 1 ] );
|
|
|
- dst.push( src[ a + 2 ] );
|
|
|
+ dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
|
|
|
|
|
|
},
|
|
|
|
|
@@ -282,15 +236,9 @@ THREE.OBJLoader.prototype = {
|
|
|
var src = this.normals;
|
|
|
var dst = this.object.geometry.normals;
|
|
|
|
|
|
- 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 ] );
|
|
|
+ dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
|
|
|
+ dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
|
|
|
+ dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
|
|
|
|
|
|
},
|
|
|
|
|
@@ -299,12 +247,9 @@ THREE.OBJLoader.prototype = {
|
|
|
var src = this.uvs;
|
|
|
var dst = this.object.geometry.uvs;
|
|
|
|
|
|
- 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 ] );
|
|
|
+ dst.push( src[ a + 0 ], src[ a + 1 ] );
|
|
|
+ dst.push( src[ b + 0 ], src[ b + 1 ] );
|
|
|
+ dst.push( src[ c + 0 ], src[ c + 1 ] );
|
|
|
|
|
|
},
|
|
|
|
|
@@ -313,8 +258,7 @@ THREE.OBJLoader.prototype = {
|
|
|
var src = this.uvs;
|
|
|
var dst = this.object.geometry.uvs;
|
|
|
|
|
|
- dst.push( src[ a + 0 ] );
|
|
|
- dst.push( src[ a + 1 ] );
|
|
|
+ dst.push( src[ a + 0 ], src[ a + 1 ] );
|
|
|
|
|
|
},
|
|
|
|
|
@@ -416,338 +360,382 @@ THREE.OBJLoader.prototype = {
|
|
|
|
|
|
return state;
|
|
|
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
- parse: function ( text ) {
|
|
|
+ //
|
|
|
|
|
|
- console.time( 'OBJLoader' );
|
|
|
+ function OBJLoader( manager ) {
|
|
|
|
|
|
- var state = this._createParserState();
|
|
|
+ this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
|
|
|
|
|
|
- if ( text.indexOf( '\r\n' ) !== - 1 ) {
|
|
|
+ this.materials = null;
|
|
|
|
|
|
- // This is faster than String.split with regex that splits on both
|
|
|
- text = text.replace( /\r\n/g, '\n' );
|
|
|
+ };
|
|
|
|
|
|
- }
|
|
|
+ OBJLoader.prototype = {
|
|
|
|
|
|
- if ( text.indexOf( '\\\n' ) !== - 1) {
|
|
|
+ constructor: OBJLoader,
|
|
|
|
|
|
- // join lines separated by a line continuation character (\)
|
|
|
- text = text.replace( /\\\n/g, '' );
|
|
|
+ load: function ( url, onLoad, onProgress, onError ) {
|
|
|
|
|
|
- }
|
|
|
+ var scope = this;
|
|
|
|
|
|
- var lines = text.split( '\n' );
|
|
|
- var line = '', lineFirstChar = '', lineSecondChar = '';
|
|
|
- var lineLength = 0;
|
|
|
- var result = [];
|
|
|
+ var loader = new THREE.FileLoader( scope.manager );
|
|
|
+ loader.setPath( this.path );
|
|
|
+ loader.load( url, function ( text ) {
|
|
|
|
|
|
- // Faster to just trim left side of the line. Use if available.
|
|
|
- var trimLeft = ( typeof ''.trimLeft === 'function' );
|
|
|
+ onLoad( scope.parse( text ) );
|
|
|
|
|
|
- for ( var i = 0, l = lines.length; i < l; i ++ ) {
|
|
|
+ }, onProgress, onError );
|
|
|
|
|
|
- line = lines[ i ];
|
|
|
+ },
|
|
|
|
|
|
- line = trimLeft ? line.trimLeft() : line.trim();
|
|
|
+ setPath: function ( value ) {
|
|
|
|
|
|
- lineLength = line.length;
|
|
|
+ this.path = value;
|
|
|
|
|
|
- if ( lineLength === 0 ) continue;
|
|
|
+ },
|
|
|
|
|
|
- lineFirstChar = line.charAt( 0 );
|
|
|
+ setMaterials: function ( materials ) {
|
|
|
|
|
|
- // @todo invoke passed in handler if any
|
|
|
- if ( lineFirstChar === '#' ) continue;
|
|
|
+ this.materials = materials;
|
|
|
|
|
|
- if ( lineFirstChar === 'v' ) {
|
|
|
+ },
|
|
|
|
|
|
- lineSecondChar = line.charAt( 1 );
|
|
|
+ parse: function ( text ) {
|
|
|
|
|
|
- if ( lineSecondChar === ' ' && ( result = this.regexp.vertex_pattern.exec( line ) ) !== null ) {
|
|
|
+ console.time( 'OBJLoader' );
|
|
|
|
|
|
- // 0 1 2 3
|
|
|
- // ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
|
|
|
+ var state = new ParserState();
|
|
|
|
|
|
- state.vertices.push(
|
|
|
- parseFloat( result[ 1 ] ),
|
|
|
- parseFloat( result[ 2 ] ),
|
|
|
- parseFloat( result[ 3 ] )
|
|
|
- );
|
|
|
+ if ( text.indexOf( '\r\n' ) !== - 1 ) {
|
|
|
|
|
|
- } else if ( lineSecondChar === 'n' && ( result = this.regexp.normal_pattern.exec( line ) ) !== null ) {
|
|
|
+ // This is faster than String.split with regex that splits on both
|
|
|
+ text = text.replace( /\r\n/g, '\n' );
|
|
|
|
|
|
- // 0 1 2 3
|
|
|
- // ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
|
|
|
+ }
|
|
|
|
|
|
- state.normals.push(
|
|
|
- parseFloat( result[ 1 ] ),
|
|
|
- parseFloat( result[ 2 ] ),
|
|
|
- parseFloat( result[ 3 ] )
|
|
|
- );
|
|
|
+ if ( text.indexOf( '\\\n' ) !== - 1) {
|
|
|
|
|
|
- } else if ( lineSecondChar === 't' && ( result = this.regexp.uv_pattern.exec( line ) ) !== null ) {
|
|
|
+ // join lines separated by a line continuation character (\)
|
|
|
+ text = text.replace( /\\\n/g, '' );
|
|
|
|
|
|
- // 0 1 2
|
|
|
- // ["vt 0.1 0.2", "0.1", "0.2"]
|
|
|
+ }
|
|
|
|
|
|
- state.uvs.push(
|
|
|
- parseFloat( result[ 1 ] ),
|
|
|
- parseFloat( result[ 2 ] )
|
|
|
- );
|
|
|
+ var lines = text.split( '\n' );
|
|
|
+ var line = '', lineFirstChar = '', lineSecondChar = '';
|
|
|
+ var lineLength = 0;
|
|
|
+ var result = [];
|
|
|
|
|
|
- } else {
|
|
|
+ // Faster to just trim left side of the line. Use if available.
|
|
|
+ var trimLeft = ( typeof ''.trimLeft === 'function' );
|
|
|
|
|
|
- throw new Error( "Unexpected vertex/normal/uv line: '" + line + "'" );
|
|
|
+ for ( var i = 0, l = lines.length; i < l; i ++ ) {
|
|
|
|
|
|
- }
|
|
|
+ line = lines[ i ];
|
|
|
|
|
|
- } else if ( lineFirstChar === "f" ) {
|
|
|
+ line = trimLeft ? line.trimLeft() : line.trim();
|
|
|
|
|
|
- if ( ( result = this.regexp.face_vertex_uv_normal.exec( line ) ) !== null ) {
|
|
|
+ lineLength = line.length;
|
|
|
|
|
|
- // 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]
|
|
|
+ if ( lineLength === 0 ) continue;
|
|
|
|
|
|
- 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 ]
|
|
|
- );
|
|
|
+ lineFirstChar = line.charAt( 0 );
|
|
|
|
|
|
- } else if ( ( result = this.regexp.face_vertex_uv.exec( line ) ) !== null ) {
|
|
|
+ // @todo invoke passed in handler if any
|
|
|
+ if ( lineFirstChar === '#' ) continue;
|
|
|
|
|
|
- // 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]
|
|
|
+ if ( lineFirstChar === 'v' ) {
|
|
|
|
|
|
- state.addFace(
|
|
|
- result[ 1 ], result[ 3 ], result[ 5 ], result[ 7 ],
|
|
|
- result[ 2 ], result[ 4 ], result[ 6 ], result[ 8 ]
|
|
|
- );
|
|
|
+ lineSecondChar = line.charAt( 1 );
|
|
|
|
|
|
- } else if ( ( result = this.regexp.face_vertex_normal.exec( line ) ) !== null ) {
|
|
|
+ if ( lineSecondChar === ' ' && ( result = vertex_pattern.exec( line ) ) !== null ) {
|
|
|
|
|
|
- // 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]
|
|
|
+ // 0 1 2 3
|
|
|
+ // ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
|
|
|
|
|
|
- state.addFace(
|
|
|
- result[ 1 ], result[ 3 ], result[ 5 ], result[ 7 ],
|
|
|
- undefined, undefined, undefined, undefined,
|
|
|
- result[ 2 ], result[ 4 ], result[ 6 ], result[ 8 ]
|
|
|
- );
|
|
|
+ state.vertices.push(
|
|
|
+ parseFloat( result[ 1 ] ),
|
|
|
+ parseFloat( result[ 2 ] ),
|
|
|
+ parseFloat( result[ 3 ] )
|
|
|
+ );
|
|
|
|
|
|
- } else if ( ( result = this.regexp.face_vertex.exec( line ) ) !== null ) {
|
|
|
+ } else if ( lineSecondChar === 'n' && ( result = normal_pattern.exec( line ) ) !== null ) {
|
|
|
|
|
|
- // f vertex vertex vertex
|
|
|
- // 0 1 2 3 4
|
|
|
- // ["f 1 2 3", "1", "2", "3", undefined]
|
|
|
+ // 0 1 2 3
|
|
|
+ // ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
|
|
|
|
|
|
- state.addFace(
|
|
|
- result[ 1 ], result[ 2 ], result[ 3 ], result[ 4 ]
|
|
|
- );
|
|
|
+ state.normals.push(
|
|
|
+ parseFloat( result[ 1 ] ),
|
|
|
+ parseFloat( result[ 2 ] ),
|
|
|
+ parseFloat( result[ 3 ] )
|
|
|
+ );
|
|
|
|
|
|
- } else {
|
|
|
+ } else if ( lineSecondChar === 't' && ( result = uv_pattern.exec( line ) ) !== null ) {
|
|
|
|
|
|
- throw new Error( "Unexpected face line: '" + line + "'" );
|
|
|
+ // 0 1 2
|
|
|
+ // ["vt 0.1 0.2", "0.1", "0.2"]
|
|
|
|
|
|
- }
|
|
|
+ state.uvs.push(
|
|
|
+ parseFloat( result[ 1 ] ),
|
|
|
+ parseFloat( result[ 2 ] )
|
|
|
+ );
|
|
|
|
|
|
- } else if ( lineFirstChar === "l" ) {
|
|
|
+ } else {
|
|
|
|
|
|
- var lineParts = line.substring( 1 ).trim().split( " " );
|
|
|
- var lineVertices = [], lineUVs = [];
|
|
|
+ throw new Error( "Unexpected vertex/normal/uv line: '" + line + "'" );
|
|
|
|
|
|
- if ( line.indexOf( "/" ) === - 1 ) {
|
|
|
+ }
|
|
|
|
|
|
- lineVertices = lineParts;
|
|
|
+ } else if ( lineFirstChar === "f" ) {
|
|
|
|
|
|
- } else {
|
|
|
+ if ( ( result = face_vertex_uv_normal.exec( line ) ) !== null ) {
|
|
|
+
|
|
|
+ // 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]
|
|
|
+
|
|
|
+ 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 ]
|
|
|
+ );
|
|
|
+
|
|
|
+ } else if ( ( result = face_vertex_uv.exec( line ) ) !== null ) {
|
|
|
+
|
|
|
+ // 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]
|
|
|
+
|
|
|
+ state.addFace(
|
|
|
+ result[ 1 ], result[ 3 ], result[ 5 ], result[ 7 ],
|
|
|
+ result[ 2 ], result[ 4 ], result[ 6 ], result[ 8 ]
|
|
|
+ );
|
|
|
+
|
|
|
+ } else if ( ( result = face_vertex_normal.exec( line ) ) !== null ) {
|
|
|
+
|
|
|
+ // 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]
|
|
|
+
|
|
|
+ state.addFace(
|
|
|
+ result[ 1 ], result[ 3 ], result[ 5 ], result[ 7 ],
|
|
|
+ undefined, undefined, undefined, undefined,
|
|
|
+ result[ 2 ], result[ 4 ], result[ 6 ], result[ 8 ]
|
|
|
+ );
|
|
|
+
|
|
|
+ } else if ( ( result = face_vertex.exec( line ) ) !== null ) {
|
|
|
|
|
|
- for ( var li = 0, llen = lineParts.length; li < llen; li ++ ) {
|
|
|
+ // f vertex vertex vertex
|
|
|
+ // 0 1 2 3 4
|
|
|
+ // ["f 1 2 3", "1", "2", "3", undefined]
|
|
|
|
|
|
- var parts = lineParts[ li ].split( "/" );
|
|
|
+ state.addFace(
|
|
|
+ result[ 1 ], result[ 2 ], result[ 3 ], result[ 4 ]
|
|
|
+ );
|
|
|
|
|
|
- if ( parts[ 0 ] !== "" ) lineVertices.push( parts[ 0 ] );
|
|
|
- if ( parts[ 1 ] !== "" ) lineUVs.push( parts[ 1 ] );
|
|
|
+ } else {
|
|
|
+
|
|
|
+ throw new Error( "Unexpected face line: '" + line + "'" );
|
|
|
|
|
|
}
|
|
|
|
|
|
- }
|
|
|
- state.addLineGeometry( lineVertices, lineUVs );
|
|
|
+ } else if ( lineFirstChar === "l" ) {
|
|
|
+
|
|
|
+ var lineParts = line.substring( 1 ).trim().split( " " );
|
|
|
+ var lineVertices = [], lineUVs = [];
|
|
|
+
|
|
|
+ if ( line.indexOf( "/" ) === - 1 ) {
|
|
|
|
|
|
- } else if ( ( result = this.regexp.object_pattern.exec( line ) ) !== null ) {
|
|
|
+ lineVertices = lineParts;
|
|
|
|
|
|
- // o object_name
|
|
|
- // or
|
|
|
- // g group_name
|
|
|
+ } else {
|
|
|
|
|
|
- // WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869
|
|
|
- // var name = result[ 0 ].substr( 1 ).trim();
|
|
|
- var name = ( " " + result[ 0 ].substr( 1 ).trim() ).substr( 1 );
|
|
|
+ for ( var li = 0, llen = lineParts.length; li < llen; li ++ ) {
|
|
|
|
|
|
- state.startObject( name );
|
|
|
+ var parts = lineParts[ li ].split( "/" );
|
|
|
|
|
|
- } else if ( this.regexp.material_use_pattern.test( line ) ) {
|
|
|
+ if ( parts[ 0 ] !== "" ) lineVertices.push( parts[ 0 ] );
|
|
|
+ if ( parts[ 1 ] !== "" ) lineUVs.push( parts[ 1 ] );
|
|
|
|
|
|
- // material
|
|
|
+ }
|
|
|
|
|
|
- state.object.startMaterial( line.substring( 7 ).trim(), state.materialLibraries );
|
|
|
+ }
|
|
|
+ state.addLineGeometry( lineVertices, lineUVs );
|
|
|
|
|
|
- } else if ( this.regexp.material_library_pattern.test( line ) ) {
|
|
|
+ } else if ( ( result = object_pattern.exec( line ) ) !== null ) {
|
|
|
|
|
|
- // mtl file
|
|
|
+ // o object_name
|
|
|
+ // or
|
|
|
+ // g group_name
|
|
|
|
|
|
- state.materialLibraries.push( line.substring( 7 ).trim() );
|
|
|
+ // WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869
|
|
|
+ // var name = result[ 0 ].substr( 1 ).trim();
|
|
|
+ var name = ( " " + result[ 0 ].substr( 1 ).trim() ).substr( 1 );
|
|
|
|
|
|
- } else if ( ( result = this.regexp.smoothing_pattern.exec( line ) ) !== null ) {
|
|
|
+ state.startObject( name );
|
|
|
|
|
|
- // smooth shading
|
|
|
+ } else if ( material_use_pattern.test( line ) ) {
|
|
|
|
|
|
- // @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
|
|
|
+ // material
|
|
|
|
|
|
- var value = result[ 1 ].trim().toLowerCase();
|
|
|
- /*
|
|
|
- * http://paulbourke.net/dataformats/obj/
|
|
|
- * or
|
|
|
- * http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf
|
|
|
- *
|
|
|
- * From chapter "Grouping" Syntax explanation "s group_number":
|
|
|
- * "group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off.
|
|
|
- * Polygonal elements use group numbers to put elements in different smoothing groups. For free-form
|
|
|
- * surfaces, smoothing groups are either turned on or off; there is no difference between values greater
|
|
|
- * than 0."
|
|
|
- */
|
|
|
- state.object.smooth = ( value !== '0' && value !== 'off' );
|
|
|
+ state.object.startMaterial( line.substring( 7 ).trim(), state.materialLibraries );
|
|
|
|
|
|
- var material = state.object.currentMaterial();
|
|
|
- if ( material ) {
|
|
|
+ } else if ( material_library_pattern.test( line ) ) {
|
|
|
|
|
|
- material.smooth = state.object.smooth;
|
|
|
+ // mtl file
|
|
|
|
|
|
- }
|
|
|
+ state.materialLibraries.push( line.substring( 7 ).trim() );
|
|
|
+
|
|
|
+ } else if ( ( result = smoothing_pattern.exec( line ) ) !== null ) {
|
|
|
|
|
|
- } else {
|
|
|
+ // smooth shading
|
|
|
|
|
|
- // Handle null terminated files without exception
|
|
|
- if ( line === '\0' ) continue;
|
|
|
+ // @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
|
|
|
|
|
|
- throw new Error( "Unexpected line: '" + line + "'" );
|
|
|
+ var value = result[ 1 ].trim().toLowerCase();
|
|
|
+ /*
|
|
|
+ * http://paulbourke.net/dataformats/obj/
|
|
|
+ * or
|
|
|
+ * http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf
|
|
|
+ *
|
|
|
+ * From chapter "Grouping" Syntax explanation "s group_number":
|
|
|
+ * "group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off.
|
|
|
+ * Polygonal elements use group numbers to put elements in different smoothing groups. For free-form
|
|
|
+ * surfaces, smoothing groups are either turned on or off; there is no difference between values greater
|
|
|
+ * than 0."
|
|
|
+ */
|
|
|
+ state.object.smooth = ( value !== '0' && value !== 'off' );
|
|
|
+
|
|
|
+ var material = state.object.currentMaterial();
|
|
|
+ if ( material ) {
|
|
|
+
|
|
|
+ material.smooth = state.object.smooth;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ // Handle null terminated files without exception
|
|
|
+ if ( line === '\0' ) continue;
|
|
|
+
|
|
|
+ throw new Error( "Unexpected line: '" + line + "'" );
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
|
- }
|
|
|
+ state.finalize();
|
|
|
|
|
|
- state.finalize();
|
|
|
+ var container = new THREE.Group();
|
|
|
+ container.materialLibraries = [].concat( state.materialLibraries );
|
|
|
|
|
|
- var container = new THREE.Group();
|
|
|
- container.materialLibraries = [].concat( state.materialLibraries );
|
|
|
+ for ( var i = 0, l = state.objects.length; i < l; i ++ ) {
|
|
|
|
|
|
- for ( var i = 0, l = state.objects.length; i < l; i ++ ) {
|
|
|
+ var object = state.objects[ i ];
|
|
|
+ var geometry = object.geometry;
|
|
|
+ var materials = object.materials;
|
|
|
+ var isLine = ( geometry.type === 'Line' );
|
|
|
|
|
|
- var object = state.objects[ i ];
|
|
|
- var geometry = object.geometry;
|
|
|
- var materials = object.materials;
|
|
|
- var isLine = ( geometry.type === 'Line' );
|
|
|
+ // Skip o/g line declarations that did not follow with any faces
|
|
|
+ if ( geometry.vertices.length === 0 ) continue;
|
|
|
|
|
|
- // Skip o/g line declarations that did not follow with any faces
|
|
|
- if ( geometry.vertices.length === 0 ) continue;
|
|
|
+ var buffergeometry = new THREE.BufferGeometry();
|
|
|
|
|
|
- var buffergeometry = new THREE.BufferGeometry();
|
|
|
+ buffergeometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( geometry.vertices ), 3 ) );
|
|
|
|
|
|
- buffergeometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( geometry.vertices ), 3 ) );
|
|
|
+ if ( geometry.normals.length > 0 ) {
|
|
|
|
|
|
- if ( geometry.normals.length > 0 ) {
|
|
|
+ buffergeometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( geometry.normals ), 3 ) );
|
|
|
|
|
|
- buffergeometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( geometry.normals ), 3 ) );
|
|
|
+ } else {
|
|
|
|
|
|
- } else {
|
|
|
+ buffergeometry.computeVertexNormals();
|
|
|
|
|
|
- buffergeometry.computeVertexNormals();
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ if ( geometry.uvs.length > 0 ) {
|
|
|
|
|
|
- if ( geometry.uvs.length > 0 ) {
|
|
|
+ buffergeometry.addAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( geometry.uvs ), 2 ) );
|
|
|
|
|
|
- buffergeometry.addAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( geometry.uvs ), 2 ) );
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ // Create materials
|
|
|
|
|
|
- // Create materials
|
|
|
+ var createdMaterials = [];
|
|
|
|
|
|
- var createdMaterials = [];
|
|
|
+ for ( var mi = 0, miLen = materials.length; mi < miLen ; mi++ ) {
|
|
|
|
|
|
- for ( var mi = 0, miLen = materials.length; mi < miLen ; mi++ ) {
|
|
|
+ var sourceMaterial = materials[ mi ];
|
|
|
+ var material = undefined;
|
|
|
|
|
|
- var sourceMaterial = materials[mi];
|
|
|
- var material = undefined;
|
|
|
+ if ( this.materials !== null ) {
|
|
|
|
|
|
- if ( this.materials !== null ) {
|
|
|
+ material = this.materials.create( sourceMaterial.name );
|
|
|
|
|
|
- material = this.materials.create( sourceMaterial.name );
|
|
|
+ // mtl etc. loaders probably can't create line materials correctly, copy properties to a line material.
|
|
|
+ if ( isLine && material && ! ( material instanceof THREE.LineBasicMaterial ) ) {
|
|
|
|
|
|
- // mtl etc. loaders probably can't create line materials correctly, copy properties to a line material.
|
|
|
- if ( isLine && material && ! ( material instanceof THREE.LineBasicMaterial ) ) {
|
|
|
+ var materialLine = new THREE.LineBasicMaterial();
|
|
|
+ materialLine.copy( material );
|
|
|
+ material = materialLine;
|
|
|
|
|
|
- var materialLine = new THREE.LineBasicMaterial();
|
|
|
- materialLine.copy( material );
|
|
|
- material = materialLine;
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
|
- }
|
|
|
+ if ( ! material ) {
|
|
|
|
|
|
- if ( ! material ) {
|
|
|
+ material = ( ! isLine ? new THREE.MeshPhongMaterial() : new THREE.LineBasicMaterial() );
|
|
|
+ material.name = sourceMaterial.name;
|
|
|
|
|
|
- material = ( ! isLine ? new THREE.MeshPhongMaterial() : new THREE.LineBasicMaterial() );
|
|
|
- material.name = sourceMaterial.name;
|
|
|
+ }
|
|
|
+
|
|
|
+ material.shading = sourceMaterial.smooth ? THREE.SmoothShading : THREE.FlatShading;
|
|
|
+
|
|
|
+ createdMaterials.push(material);
|
|
|
|
|
|
}
|
|
|
|
|
|
- material.shading = sourceMaterial.smooth ? THREE.SmoothShading : THREE.FlatShading;
|
|
|
+ // Create mesh
|
|
|
|
|
|
- createdMaterials.push(material);
|
|
|
+ var mesh;
|
|
|
|
|
|
- }
|
|
|
+ if ( createdMaterials.length > 1 ) {
|
|
|
|
|
|
- // Create mesh
|
|
|
+ for ( var mi = 0, miLen = materials.length; mi < miLen ; mi++ ) {
|
|
|
|
|
|
- var mesh;
|
|
|
+ var sourceMaterial = materials[ mi ];
|
|
|
+ buffergeometry.addGroup( sourceMaterial.groupStart, sourceMaterial.groupCount, mi );
|
|
|
|
|
|
- if ( createdMaterials.length > 1 ) {
|
|
|
+ }
|
|
|
|
|
|
- for ( var mi = 0, miLen = materials.length; mi < miLen ; mi++ ) {
|
|
|
+ mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, createdMaterials ) : new THREE.LineSegments( buffergeometry, createdMaterials ) );
|
|
|
|
|
|
- var sourceMaterial = materials[mi];
|
|
|
- buffergeometry.addGroup( sourceMaterial.groupStart, sourceMaterial.groupCount, mi );
|
|
|
+ } else {
|
|
|
|
|
|
+ mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, createdMaterials[ 0 ] ) : new THREE.LineSegments( buffergeometry, createdMaterials[ 0 ] ) );
|
|
|
}
|
|
|
|
|
|
- mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, createdMaterials ) : new THREE.LineSegments( buffergeometry, createdMaterials ) );
|
|
|
+ mesh.name = object.name;
|
|
|
|
|
|
- } else {
|
|
|
+ container.add( mesh );
|
|
|
|
|
|
- mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, createdMaterials[ 0 ] ) : new THREE.LineSegments( buffergeometry, createdMaterials[ 0 ] ) );
|
|
|
}
|
|
|
|
|
|
- mesh.name = object.name;
|
|
|
+ console.timeEnd( 'OBJLoader' );
|
|
|
|
|
|
- container.add( mesh );
|
|
|
+ return container;
|
|
|
|
|
|
}
|
|
|
|
|
|
- console.timeEnd( 'OBJLoader' );
|
|
|
-
|
|
|
- return container;
|
|
|
+ };
|
|
|
|
|
|
- }
|
|
|
+ return OBJLoader;
|
|
|
|
|
|
-};
|
|
|
+} )();
|