OBJLoader.js
1 /** 2 * @author mrdoob / http://mrdoob.com/ 3 */ 4 5 THREE.OBJLoader = function ( manager ) { 6 7 this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; 8 9 }; 10 11 THREE.OBJLoader.prototype = { 12 13 constructor: THREE.OBJLoader, 14 15 load: function ( url, onLoad, onProgress, onError ) { 16 17 var scope = this; 18 19 var loader = new THREE.XHRLoader( scope.manager ); 20 loader.setCrossOrigin( this.crossOrigin ); 21 loader.load( url, function ( text ) { 22 23 onLoad( scope.parse( text ) ); 24 25 }, onProgress, onError ); 26 27 }, 28 29 parse: function ( text ) { 30 31 console.time( 'OBJLoader' ); 32 33 var object, objects = []; 34 var geometry, material; 35 36 function parseVertexIndex( value ) { 37 38 var index = parseInt( value ); 39 40 return ( index >= 0 ? index - 1 : index + vertices.length / 3 ) * 3; 41 42 } 43 44 function parseNormalIndex( value ) { 45 46 var index = parseInt( value ); 47 48 return ( index >= 0 ? index - 1 : index + normals.length / 3 ) * 3; 49 50 } 51 52 function parseUVIndex( value ) { 53 54 var index = parseInt( value ); 55 56 return ( index >= 0 ? index - 1 : index + uvs.length / 2 ) * 2; 57 58 } 59 60 function addVertex( a, b, c ) { 61 62 geometry.vertices.push( 63 vertices[ a ], vertices[ a + 1 ], vertices[ a + 2 ], 64 vertices[ b ], vertices[ b + 1 ], vertices[ b + 2 ], 65 vertices[ c ], vertices[ c + 1 ], vertices[ c + 2 ] 66 ); 67 68 } 69 70 function addNormal( a, b, c ) { 71 72 geometry.normals.push( 73 normals[ a ], normals[ a + 1 ], normals[ a + 2 ], 74 normals[ b ], normals[ b + 1 ], normals[ b + 2 ], 75 normals[ c ], normals[ c + 1 ], normals[ c + 2 ] 76 ); 77 78 } 79 80 function addUV( a, b, c ) { 81 82 geometry.uvs.push( 83 uvs[ a ], uvs[ a + 1 ], 84 uvs[ b ], uvs[ b + 1 ], 85 uvs[ c ], uvs[ c + 1 ] 86 ); 87 88 } 89 90 function addFace( a, b, c, d, ua, ub, uc, ud, na, nb, nc, nd ) { 91 92 var ia = parseVertexIndex( a ); 93 var ib = parseVertexIndex( b ); 94 var ic = parseVertexIndex( c ); 95 var id; 96 97 if ( d === undefined ) { 98 99 addVertex( ia, ib, ic ); 100 101 } else { 102 103 id = parseVertexIndex( d ); 104 105 addVertex( ia, ib, id ); 106 addVertex( ib, ic, id ); 107 108 } 109 110 if ( ua !== undefined ) { 111 112 ia = parseUVIndex( ua ); 113 ib = parseUVIndex( ub ); 114 ic = parseUVIndex( uc ); 115 116 if ( d === undefined ) { 117 118 addUV( ia, ib, ic ); 119 120 } else { 121 122 id = parseUVIndex( ud ); 123 124 addUV( ia, ib, id ); 125 addUV( ib, ic, id ); 126 127 } 128 129 } 130 131 if ( na !== undefined ) { 132 133 ia = parseNormalIndex( na ); 134 ib = parseNormalIndex( nb ); 135 ic = parseNormalIndex( nc ); 136 137 if ( d === undefined ) { 138 139 addNormal( ia, ib, ic ); 140 141 } else { 142 143 id = parseNormalIndex( nd ); 144 145 addNormal( ia, ib, id ); 146 addNormal( ib, ic, id ); 147 148 } 149 150 } 151 152 } 153 154 // create mesh if no objects in text 155 156 if ( /^o /gm.test( text ) === false ) { 157 158 geometry = { 159 vertices: [], 160 normals: [], 161 uvs: [] 162 }; 163 164 material = { 165 name: '' 166 }; 167 168 object = { 169 name: '', 170 geometry: geometry, 171 material: material 172 }; 173 174 objects.push( object ); 175 176 } 177 178 var vertices = []; 179 var normals = []; 180 var uvs = []; 181 182 // v float float float 183 184 var vertex_pattern = /v( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; 185 186 // vn float float float 187 188 var normal_pattern = /vn( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; 189 190 // vt float float 191 192 var uv_pattern = /vt( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; 193 194 // f vertex vertex vertex ... 195 196 var face_pattern1 = /f( +-?\d+)( +-?\d+)( +-?\d+)( +-?\d+)?/; 197 198 // f vertex/uv vertex/uv vertex/uv ... 199 200 var face_pattern2 = /f( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))?/; 201 202 // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ... 203 204 var face_pattern3 = /f( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))?/; 205 206 // f vertex//normal vertex//normal vertex//normal ... 207 208 var face_pattern4 = /f( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))?/ 209 210 // 211 212 var lines = text.split( '\n' ); 213 214 for ( var i = 0; i < lines.length; i ++ ) { 215 216 var line = lines[ i ]; 217 line = line.trim(); 218 219 var result; 220 221 if ( line.length === 0 || line.charAt( 0 ) === '#' ) { 222 223 continue; 224 225 } else if ( ( result = vertex_pattern.exec( line ) ) !== null ) { 226 227 // ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"] 228 229 vertices.push( 230 parseFloat( result[ 1 ] ), 231 parseFloat( result[ 2 ] ), 232 parseFloat( result[ 3 ] ) 233 ); 234 235 } else if ( ( result = normal_pattern.exec( line ) ) !== null ) { 236 237 // ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"] 238 239 normals.push( 240 parseFloat( result[ 1 ] ), 241 parseFloat( result[ 2 ] ), 242 parseFloat( result[ 3 ] ) 243 ); 244 245 } else if ( ( result = uv_pattern.exec( line ) ) !== null ) { 246 247 // ["vt 0.1 0.2", "0.1", "0.2"] 248 249 uvs.push( 250 parseFloat( result[ 1 ] ), 251 parseFloat( result[ 2 ] ) 252 ); 253 254 } else if ( ( result = face_pattern1.exec( line ) ) !== null ) { 255 256 // ["f 1 2 3", "1", "2", "3", undefined] 257 258 addFace( 259 result[ 1 ], result[ 2 ], result[ 3 ], result[ 4 ] 260 ); 261 262 } else if ( ( result = face_pattern2.exec( line ) ) !== null ) { 263 264 // ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined] 265 266 addFace( 267 result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ], 268 result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ] 269 ); 270 271 } else if ( ( result = face_pattern3.exec( line ) ) !== null ) { 272 273 // ["f 1/1/1 2/2/2 3/3/3", " 1/1/1", "1", "1", "1", " 2/2/2", "2", "2", "2", " 3/3/3", "3", "3", "3", undefined, undefined, undefined, undefined] 274 275 addFace( 276 result[ 2 ], result[ 6 ], result[ 10 ], result[ 14 ], 277 result[ 3 ], result[ 7 ], result[ 11 ], result[ 15 ], 278 result[ 4 ], result[ 8 ], result[ 12 ], result[ 16 ] 279 ); 280 281 } else if ( ( result = face_pattern4.exec( line ) ) !== null ) { 282 283 // ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined] 284 285 addFace( 286 result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ], 287 undefined, undefined, undefined, undefined, 288 result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ] 289 ); 290 291 } else if ( /^o /.test( line ) ) { 292 293 geometry = { 294 vertices: [], 295 normals: [], 296 uvs: [] 297 }; 298 299 material = { 300 name: '' 301 }; 302 303 object = { 304 name: line.substring( 2 ).trim(), 305 geometry: geometry, 306 material: material 307 }; 308 309 objects.push( object ) 310 311 } else if ( /^g /.test( line ) ) { 312 313 // group 314 315 } else if ( /^usemtl /.test( line ) ) { 316 317 // material 318 319 material.name = line.substring( 7 ).trim(); 320 321 } else if ( /^mtllib /.test( line ) ) { 322 323 // mtl file 324 325 } else if ( /^s /.test( line ) ) { 326 327 // smooth shading 328 329 } else { 330 331 // console.log( "THREE.OBJLoader: Unhandled line " + line ); 332 333 } 334 335 } 336 337 var container = new THREE.Object3D(); 338 339 for ( var i = 0, l = objects.length; i < l; i ++ ) { 340 341 object = objects[ i ]; 342 geometry = object.geometry; 343 344 var buffergeometry = new THREE.BufferGeometry(); 345 346 buffergeometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( geometry.vertices ), 3 ) ); 347 348 if ( geometry.normals.length > 0 ) { 349 buffergeometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( geometry.normals ), 3 ) ); 350 } 351 352 if ( geometry.uvs.length > 0 ) { 353 buffergeometry.addAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( geometry.uvs ), 2 ) ); 354 } 355 356 material = new THREE.MeshLambertMaterial(); 357 material.name = object.material.name; 358 359 var mesh = new THREE.Mesh( buffergeometry, material ); 360 mesh.name = object.name; 361 362 container.add( mesh ); 363 364 } 365 366 console.timeEnd( 'OBJLoader' ); 367 368 return container; 369 370 } 371 372 };