├── obj ├── gg.jpg └── jj.mtl ├── .gitattributes ├── pdf └── marker89.pdf ├── data └── camera_para.dat ├── README.md ├── bulid ├── stats.js ├── OBJMTLLoader.js ├── MTLLoader.js └── OBJLoader.js ├── basic.html └── arcode └── marker89.td /obj/gg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webglzhang/WebARDemo/HEAD/obj/gg.jpg -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /pdf/marker89.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webglzhang/WebARDemo/HEAD/pdf/marker89.pdf -------------------------------------------------------------------------------- /data/camera_para.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webglzhang/WebARDemo/HEAD/data/camera_para.dat -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebARDemo 2 | 3 | 这是我大学做WebAR导航试验性的ARdemo,也仅仅作为功能性的验证,没有任何的代码规范和工程结构。Demo开发时间大约在2019年,早已经不在维护。我专注于可视化相关的技术应用,有兴趣的同学,可以加入我的QQ群或者关注我的公众号,公众号正在开发中,qq群经常会交流一些技术问题。 4 | 5 | QQ群:740855975 6 | -------------------------------------------------------------------------------- /obj/jj.mtl: -------------------------------------------------------------------------------- 1 | # 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware 2 | # File Created: 26.05.2017 23:41:18 3 | 4 | newmtl 1d908e75_dds 5 | Ns 10.0000 6 | Ni 1.5000 7 | d 1.0000 8 | Tr 0.0000 9 | Tf 1.0000 1.0000 1.0000 10 | illum 2 11 | Ka 0.7000 0.7000 0.7000 12 | Kd 0.7000 0.7000 0.7000 13 | Ks 0.1000 0.1000 0.1000 14 | Ke 0.0000 0.0000 0.0000 15 | map_Ka gg.jpg 16 | map_Kd gg.jpg 17 | map_d gg.jpg -------------------------------------------------------------------------------- /bulid/stats.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | var Stats = function () { 6 | 7 | var startTime = Date.now(), prevTime = startTime; 8 | var ms = 0, msMin = Infinity, msMax = 0; 9 | var fps = 0, fpsMin = Infinity, fpsMax = 0; 10 | var frames = 0, mode = 0; 11 | 12 | var container = document.createElement( 'div' ); 13 | container.id = 'stats'; 14 | container.addEventListener( 'mousedown', function ( event ) { event.preventDefault(); setMode( ++ mode % 2 ) }, false ); 15 | container.style.cssText = 'width:80px;opacity:0.9;cursor:pointer'; 16 | 17 | var fpsDiv = document.createElement( 'div' ); 18 | fpsDiv.id = 'fps'; 19 | fpsDiv.style.cssText = 'padding:0 0 3px 3px;text-align:left;background-color:#002'; 20 | container.appendChild( fpsDiv ); 21 | 22 | var fpsText = document.createElement( 'div' ); 23 | fpsText.id = 'fpsText'; 24 | fpsText.style.cssText = 'color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px'; 25 | fpsText.innerHTML = 'FPS'; 26 | fpsDiv.appendChild( fpsText ); 27 | 28 | var fpsGraph = document.createElement( 'div' ); 29 | fpsGraph.id = 'fpsGraph'; 30 | fpsGraph.style.cssText = 'position:relative;width:74px;height:30px;background-color:#0ff'; 31 | fpsDiv.appendChild( fpsGraph ); 32 | 33 | while ( fpsGraph.children.length < 74 ) { 34 | 35 | var bar = document.createElement( 'span' ); 36 | bar.style.cssText = 'width:1px;height:30px;float:left;background-color:#113'; 37 | fpsGraph.appendChild( bar ); 38 | 39 | } 40 | 41 | var msDiv = document.createElement( 'div' ); 42 | msDiv.id = 'ms'; 43 | msDiv.style.cssText = 'padding:0 0 3px 3px;text-align:left;background-color:#020;display:none'; 44 | container.appendChild( msDiv ); 45 | 46 | var msText = document.createElement( 'div' ); 47 | msText.id = 'msText'; 48 | msText.style.cssText = 'color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px'; 49 | msText.innerHTML = 'MS'; 50 | msDiv.appendChild( msText ); 51 | 52 | var msGraph = document.createElement( 'div' ); 53 | msGraph.id = 'msGraph'; 54 | msGraph.style.cssText = 'position:relative;width:74px;height:30px;background-color:#0f0'; 55 | msDiv.appendChild( msGraph ); 56 | 57 | while ( msGraph.children.length < 74 ) { 58 | 59 | var bar = document.createElement( 'span' ); 60 | bar.style.cssText = 'width:1px;height:30px;float:left;background-color:#131'; 61 | msGraph.appendChild( bar ); 62 | 63 | } 64 | 65 | var setMode = function ( value ) { 66 | 67 | mode = value; 68 | 69 | switch ( mode ) { 70 | 71 | case 0: 72 | fpsDiv.style.display = 'block'; 73 | msDiv.style.display = 'none'; 74 | break; 75 | case 1: 76 | fpsDiv.style.display = 'none'; 77 | msDiv.style.display = 'block'; 78 | break; 79 | } 80 | 81 | } 82 | 83 | var updateGraph = function ( dom, value ) { 84 | 85 | var child = dom.appendChild( dom.firstChild ); 86 | child.style.height = value + 'px'; 87 | 88 | } 89 | 90 | return { 91 | 92 | REVISION: 11, 93 | 94 | domElement: container, 95 | 96 | setMode: setMode, 97 | 98 | begin: function () { 99 | 100 | startTime = Date.now(); 101 | 102 | }, 103 | 104 | end: function () { 105 | 106 | var time = Date.now(); 107 | 108 | ms = time - startTime; 109 | msMin = Math.min( msMin, ms ); 110 | msMax = Math.max( msMax, ms ); 111 | 112 | msText.textContent = ms + ' MS (' + msMin + '-' + msMax + ')'; 113 | updateGraph( msGraph, Math.min( 30, 30 - ( ms / 200 ) * 30 ) ); 114 | 115 | frames ++; 116 | 117 | if ( time > prevTime + 1000 ) { 118 | 119 | fps = Math.round( ( frames * 1000 ) / ( time - prevTime ) ); 120 | fpsMin = Math.min( fpsMin, fps ); 121 | fpsMax = Math.max( fpsMax, fps ); 122 | 123 | fpsText.textContent = fps + ' FPS (' + fpsMin + '-' + fpsMax + ')'; 124 | updateGraph( fpsGraph, Math.min( 30, 30 - ( fps / 100 ) * 30 ) ); 125 | 126 | prevTime = time; 127 | frames = 0; 128 | 129 | } 130 | 131 | return time; 132 | 133 | }, 134 | 135 | update: function () { 136 | 137 | startTime = this.end(); 138 | 139 | } 140 | 141 | } 142 | 143 | }; 144 | -------------------------------------------------------------------------------- /basic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 |
17 |   18 |
19 |
20 | AR.js - three.js camera transform 21 |
22 | Contact me any time at @jerome_etienne 23 |
24 | 207 | -------------------------------------------------------------------------------- /bulid/OBJMTLLoader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Loads a Wavefront .obj file with materials 3 | * 4 | * @author mrdoob / http://mrdoob.com/ 5 | * @author angelxuanchang 6 | */ 7 | 8 | THREE.OBJMTLLoader = function ( manager ) { 9 | 10 | this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; 11 | 12 | }; 13 | 14 | THREE.OBJMTLLoader.prototype = { 15 | 16 | constructor: THREE.OBJMTLLoader, 17 | 18 | load: function ( url, mtlurl, onLoad, onProgress, onError ) { 19 | 20 | var scope = this; 21 | 22 | var mtlLoader = new THREE.MTLLoader( url.substr( 0, url.lastIndexOf( "/" ) + 1 ) ); 23 | mtlLoader.load( mtlurl, function ( materials ) { 24 | 25 | var materialsCreator = materials; 26 | materialsCreator.preload(); 27 | 28 | var loader = new THREE.XHRLoader( scope.manager ); 29 | loader.setCrossOrigin( this.crossOrigin ); 30 | loader.load( url, function ( text ) { 31 | 32 | var object = scope.parse( text ); 33 | 34 | object.traverse( function ( object ) { 35 | 36 | if ( object instanceof THREE.Mesh ) { 37 | 38 | if ( object.material.name ) { 39 | 40 | var material = materialsCreator.create( object.material.name ); 41 | 42 | if ( material ) object.material = material; 43 | 44 | } 45 | 46 | } 47 | 48 | } ); 49 | 50 | onLoad( object ); 51 | 52 | }, onProgress, onError ); 53 | 54 | }, onProgress, onError ); 55 | 56 | }, 57 | 58 | /** 59 | * Parses loaded .obj file 60 | * @param data - content of .obj file 61 | * @param mtllibCallback - callback to handle mtllib declaration (optional) 62 | * @return {THREE.Object3D} - Object3D (with default material) 63 | */ 64 | 65 | parse: function ( data, mtllibCallback ) { 66 | 67 | function vector( x, y, z ) { 68 | 69 | return new THREE.Vector3( x, y, z ); 70 | 71 | } 72 | 73 | function uv( u, v ) { 74 | 75 | return new THREE.Vector2( u, v ); 76 | 77 | } 78 | 79 | function face3( a, b, c, normals ) { 80 | 81 | return new THREE.Face3( a, b, c, normals ); 82 | 83 | } 84 | 85 | var face_offset = 0; 86 | 87 | function meshN( meshName, materialName ) { 88 | 89 | if ( vertices.length > 0 ) { 90 | 91 | geometry.vertices = vertices; 92 | 93 | geometry.mergeVertices(); 94 | geometry.computeFaceNormals(); 95 | geometry.computeBoundingSphere(); 96 | 97 | object.add( mesh ); 98 | 99 | geometry = new THREE.Geometry(); 100 | mesh = new THREE.Mesh( geometry, material ); 101 | 102 | } 103 | 104 | if ( meshName !== undefined ) mesh.name = meshName; 105 | 106 | if ( materialName !== undefined ) { 107 | 108 | material = new THREE.MeshLambertMaterial(); 109 | material.name = materialName; 110 | 111 | mesh.material = material; 112 | 113 | } 114 | 115 | } 116 | 117 | var group = new THREE.Group(); 118 | var object = group; 119 | 120 | var geometry = new THREE.Geometry(); 121 | var material = new THREE.MeshLambertMaterial(); 122 | var mesh = new THREE.Mesh( geometry, material ); 123 | 124 | var vertices = []; 125 | var normals = []; 126 | var uvs = []; 127 | 128 | function add_face( a, b, c, normals_inds ) { 129 | 130 | if ( normals_inds === undefined ) { 131 | 132 | geometry.faces.push( face3( 133 | parseInt( a ) - (face_offset + 1), 134 | parseInt( b ) - (face_offset + 1), 135 | parseInt( c ) - (face_offset + 1) 136 | ) ); 137 | 138 | } else { 139 | 140 | geometry.faces.push( face3( 141 | parseInt( a ) - (face_offset + 1), 142 | parseInt( b ) - (face_offset + 1), 143 | parseInt( c ) - (face_offset + 1), 144 | [ 145 | normals[ parseInt( normals_inds[ 0 ] ) - 1 ].clone(), 146 | normals[ parseInt( normals_inds[ 1 ] ) - 1 ].clone(), 147 | normals[ parseInt( normals_inds[ 2 ] ) - 1 ].clone() 148 | ] 149 | ) ); 150 | 151 | } 152 | 153 | } 154 | 155 | function add_uvs( a, b, c ) { 156 | 157 | geometry.faceVertexUvs[ 0 ].push( [ 158 | uvs[ parseInt( a ) - 1 ].clone(), 159 | uvs[ parseInt( b ) - 1 ].clone(), 160 | uvs[ parseInt( c ) - 1 ].clone() 161 | ] ); 162 | 163 | } 164 | 165 | function handle_face_line(faces, uvs, normals_inds) { 166 | 167 | if ( faces[ 3 ] === undefined ) { 168 | 169 | add_face( faces[ 0 ], faces[ 1 ], faces[ 2 ], normals_inds ); 170 | 171 | if (!(uvs === undefined) && uvs.length > 0) { 172 | add_uvs( uvs[ 0 ], uvs[ 1 ], uvs[ 2 ] ); 173 | } 174 | 175 | } else { 176 | 177 | if (!(normals_inds === undefined) && normals_inds.length > 0) { 178 | 179 | add_face( faces[ 0 ], faces[ 1 ], faces[ 3 ], [ normals_inds[ 0 ], normals_inds[ 1 ], normals_inds[ 3 ] ]); 180 | add_face( faces[ 1 ], faces[ 2 ], faces[ 3 ], [ normals_inds[ 1 ], normals_inds[ 2 ], normals_inds[ 3 ] ]); 181 | 182 | } else { 183 | 184 | add_face( faces[ 0 ], faces[ 1 ], faces[ 3 ]); 185 | add_face( faces[ 1 ], faces[ 2 ], faces[ 3 ]); 186 | 187 | } 188 | 189 | if (!(uvs === undefined) && uvs.length > 0) { 190 | 191 | add_uvs( uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ); 192 | add_uvs( uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ); 193 | 194 | } 195 | 196 | } 197 | 198 | } 199 | 200 | 201 | // v float float float 202 | 203 | var vertex_pattern = /v( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)/; 204 | 205 | // vn float float float 206 | 207 | var normal_pattern = /vn( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)/; 208 | 209 | // vt float float 210 | 211 | var uv_pattern = /vt( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)/; 212 | 213 | // f vertex vertex vertex ... 214 | 215 | var face_pattern1 = /f( +\d+)( +\d+)( +\d+)( +\d+)?/; 216 | 217 | // f vertex/uv vertex/uv vertex/uv ... 218 | 219 | var face_pattern2 = /f( +(\d+)\/(\d+))( +(\d+)\/(\d+))( +(\d+)\/(\d+))( +(\d+)\/(\d+))?/; 220 | 221 | // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ... 222 | 223 | var face_pattern3 = /f( +(\d+)\/(\d+)\/(\d+))( +(\d+)\/(\d+)\/(\d+))( +(\d+)\/(\d+)\/(\d+))( +(\d+)\/(\d+)\/(\d+))?/; 224 | 225 | // f vertex//normal vertex//normal vertex//normal ... 226 | 227 | var face_pattern4 = /f( +(\d+)\/\/(\d+))( +(\d+)\/\/(\d+))( +(\d+)\/\/(\d+))( +(\d+)\/\/(\d+))?/ 228 | 229 | // 230 | 231 | var lines = data.split( "\n" ); 232 | 233 | for ( var i = 0; i < lines.length; i ++ ) { 234 | 235 | var line = lines[ i ]; 236 | line = line.trim(); 237 | 238 | var result; 239 | 240 | if ( line.length === 0 || line.charAt( 0 ) === '#' ) { 241 | 242 | continue; 243 | 244 | } else if ( ( result = vertex_pattern.exec( line ) ) !== null ) { 245 | 246 | // ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"] 247 | 248 | vertices.push( vector( 249 | parseFloat( result[ 1 ] ), 250 | parseFloat( result[ 2 ] ), 251 | parseFloat( result[ 3 ] ) 252 | ) ); 253 | 254 | } else if ( ( result = normal_pattern.exec( line ) ) !== null ) { 255 | 256 | // ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"] 257 | 258 | normals.push( vector( 259 | parseFloat( result[ 1 ] ), 260 | parseFloat( result[ 2 ] ), 261 | parseFloat( result[ 3 ] ) 262 | ) ); 263 | 264 | } else if ( ( result = uv_pattern.exec( line ) ) !== null ) { 265 | 266 | // ["vt 0.1 0.2", "0.1", "0.2"] 267 | 268 | uvs.push( uv( 269 | parseFloat( result[ 1 ] ), 270 | parseFloat( result[ 2 ] ) 271 | ) ); 272 | 273 | } else if ( ( result = face_pattern1.exec( line ) ) !== null ) { 274 | 275 | // ["f 1 2 3", "1", "2", "3", undefined] 276 | 277 | handle_face_line([ result[ 1 ], result[ 2 ], result[ 3 ], result[ 4 ] ]); 278 | 279 | } else if ( ( result = face_pattern2.exec( line ) ) !== null ) { 280 | 281 | // ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined] 282 | 283 | handle_face_line( 284 | [ result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ] ], //faces 285 | [ result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ] ] //uv 286 | ); 287 | 288 | } else if ( ( result = face_pattern3.exec( line ) ) !== null ) { 289 | 290 | // ["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] 291 | 292 | handle_face_line( 293 | [ result[ 2 ], result[ 6 ], result[ 10 ], result[ 14 ] ], //faces 294 | [ result[ 3 ], result[ 7 ], result[ 11 ], result[ 15 ] ], //uv 295 | [ result[ 4 ], result[ 8 ], result[ 12 ], result[ 16 ] ] //normal 296 | ); 297 | 298 | } else if ( ( result = face_pattern4.exec( line ) ) !== null ) { 299 | 300 | // ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined] 301 | 302 | handle_face_line( 303 | [ result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ] ], //faces 304 | [ ], //uv 305 | [ result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ] ] //normal 306 | ); 307 | 308 | } else if ( /^o /.test( line ) ) { 309 | 310 | // object 311 | 312 | meshN(); 313 | face_offset = face_offset + vertices.length; 314 | vertices = []; 315 | object = new THREE.Object3D(); 316 | object.name = line.substring( 2 ).trim(); 317 | group.add( object ); 318 | 319 | } else if ( /^g /.test( line ) ) { 320 | 321 | // group 322 | 323 | meshN( line.substring( 2 ).trim(), undefined ); 324 | 325 | } else if ( /^usemtl /.test( line ) ) { 326 | 327 | // material 328 | 329 | meshN( undefined, line.substring( 7 ).trim() ); 330 | 331 | } else if ( /^mtllib /.test( line ) ) { 332 | 333 | // mtl file 334 | 335 | if ( mtllibCallback ) { 336 | 337 | var mtlfile = line.substring( 7 ); 338 | mtlfile = mtlfile.trim(); 339 | mtllibCallback( mtlfile ); 340 | 341 | } 342 | 343 | } else if ( /^s /.test( line ) ) { 344 | 345 | // Smooth shading 346 | 347 | } else { 348 | 349 | console.log( "THREE.OBJMTLLoader: Unhandled line " + line ); 350 | 351 | } 352 | 353 | } 354 | 355 | //Add last object 356 | meshN(undefined, undefined); 357 | 358 | return group; 359 | 360 | } 361 | 362 | }; 363 | 364 | THREE.EventDispatcher.prototype.apply( THREE.OBJMTLLoader.prototype ); 365 | -------------------------------------------------------------------------------- /arcode/marker89.td: -------------------------------------------------------------------------------- 1 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 2 | 255 251 255 255 255 0 253 255 0 255 0 255 255 255 251 255 3 | 255 254 0 0 255 0 255 0 254 0 0 255 0 0 254 255 4 | 255 254 0 0 255 0 1 0 254 255 0 255 0 0 254 255 5 | 255 254 255 255 255 0 255 0 254 255 0 255 255 255 254 255 6 | 255 0 0 0 0 0 0 254 252 0 0 0 0 0 0 255 7 | 255 255 0 254 0 0 0 0 254 255 254 255 0 255 254 255 8 | 255 0 254 254 254 254 0 254 2 0 254 0 0 254 0 255 9 | 255 0 254 254 254 254 255 254 2 0 254 0 1 254 0 255 10 | 255 254 0 0 255 0 0 255 255 0 1 0 255 0 0 255 11 | 255 0 0 0 0 0 255 254 253 0 254 255 254 255 255 255 12 | 255 254 255 255 255 0 0 1 1 255 0 255 255 0 0 255 13 | 255 254 0 0 255 0 253 0 0 255 0 0 2 255 2 255 14 | 255 254 0 0 255 0 0 0 0 0 254 0 0 0 254 255 15 | 255 251 255 255 255 0 255 0 1 1 255 0 0 255 255 255 16 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 17 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 18 | 255 251 255 255 255 0 253 255 0 255 0 255 255 255 251 255 19 | 255 254 0 0 255 0 255 0 254 0 0 255 0 0 254 255 20 | 255 254 0 0 255 0 1 0 254 255 0 255 0 0 254 255 21 | 255 254 255 255 255 0 255 0 254 255 0 255 255 255 254 255 22 | 255 0 0 0 0 0 0 254 252 0 0 0 0 0 0 255 23 | 255 255 0 254 0 0 0 0 254 255 254 255 0 255 254 255 24 | 255 0 254 254 254 254 0 254 2 0 254 0 0 254 0 255 25 | 255 0 254 254 254 254 255 254 2 0 254 0 1 254 0 255 26 | 255 254 0 0 255 0 0 255 255 0 1 0 255 0 0 255 27 | 255 0 0 0 0 0 255 254 253 0 254 255 254 255 255 255 28 | 255 254 255 255 255 0 0 1 1 255 0 255 255 0 0 255 29 | 255 254 0 0 255 0 253 0 0 255 0 0 2 255 2 255 30 | 255 254 0 0 255 0 0 0 0 0 254 0 0 0 254 255 31 | 255 251 255 255 255 0 255 0 1 1 255 0 0 255 255 255 32 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 33 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 34 | 255 251 255 255 255 0 253 255 0 255 0 255 255 255 251 255 35 | 255 254 0 0 255 0 255 0 254 0 0 255 0 0 254 255 36 | 255 254 0 0 255 0 1 0 254 255 0 255 0 0 254 255 37 | 255 254 255 255 255 0 255 0 254 255 0 255 255 255 254 255 38 | 255 0 0 0 0 0 0 254 252 0 0 0 0 0 0 255 39 | 255 255 0 254 0 0 0 0 254 255 254 255 0 255 254 255 40 | 255 0 254 254 254 254 0 254 2 0 254 0 0 254 0 255 41 | 255 0 254 254 254 254 255 254 2 0 254 0 1 254 0 255 42 | 255 254 0 0 255 0 0 255 255 0 1 0 255 0 0 255 43 | 255 0 0 0 0 0 255 254 253 0 254 255 254 255 255 255 44 | 255 254 255 255 255 0 0 1 1 255 0 255 255 0 0 255 45 | 255 254 0 0 255 0 253 0 0 255 0 0 2 255 2 255 46 | 255 254 0 0 255 0 0 0 0 0 254 0 0 0 254 255 47 | 255 251 255 255 255 0 255 0 1 1 255 0 0 255 255 255 48 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 49 | 50 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 51 | 255 252 254 254 254 0 255 1 1 0 255 0 2 254 255 255 52 | 255 255 0 0 255 0 255 254 254 0 255 0 255 0 255 255 53 | 255 255 0 0 255 0 0 1 1 255 255 255 2 0 0 255 54 | 255 255 255 255 255 0 255 0 0 0 255 255 0 0 0 255 55 | 255 0 0 0 0 0 255 254 254 2 254 0 0 254 255 255 56 | 255 255 0 255 255 0 255 0 0 0 0 255 255 0 2 255 57 | 255 0 254 254 254 253 254 3 3 255 253 1 0 0 1 255 58 | 255 255 0 0 0 254 0 254 254 255 254 1 0 0 0 255 59 | 255 254 255 2 255 0 0 0 255 0 255 0 254 0 255 255 60 | 255 0 0 0 0 0 0 254 254 0 0 0 0 0 0 255 61 | 255 255 255 255 255 0 0 254 254 255 0 255 255 255 255 255 62 | 255 255 0 0 255 0 255 254 254 0 0 255 0 0 255 255 63 | 255 255 0 0 255 0 0 254 254 0 0 255 0 0 255 255 64 | 255 252 254 254 254 0 255 0 0 255 0 254 254 254 252 255 65 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 66 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 67 | 255 252 254 254 254 0 255 1 1 0 255 0 2 254 255 255 68 | 255 255 0 0 255 0 255 254 254 0 255 0 255 0 255 255 69 | 255 255 0 0 255 0 0 1 1 255 255 255 2 0 0 255 70 | 255 255 255 255 255 0 255 0 0 0 255 255 0 0 0 255 71 | 255 0 0 0 0 0 255 254 254 2 254 0 0 254 255 255 72 | 255 255 0 255 255 0 255 0 0 0 0 255 255 0 2 255 73 | 255 0 254 254 254 253 254 3 3 255 253 1 0 0 1 255 74 | 255 255 0 0 0 254 0 254 254 255 254 1 0 0 0 255 75 | 255 254 255 2 255 0 0 0 255 0 255 0 254 0 255 255 76 | 255 0 0 0 0 0 0 254 254 0 0 0 0 0 0 255 77 | 255 255 255 255 255 0 0 254 254 255 0 255 255 255 255 255 78 | 255 255 0 0 255 0 255 254 254 0 0 255 0 0 255 255 79 | 255 255 0 0 255 0 0 254 254 0 0 255 0 0 255 255 80 | 255 252 254 254 254 0 255 0 0 255 0 254 254 254 252 255 81 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 82 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 83 | 255 252 254 254 254 0 255 1 1 0 255 0 2 254 255 255 84 | 255 255 0 0 255 0 255 254 254 0 255 0 255 0 255 255 85 | 255 255 0 0 255 0 0 1 1 255 255 255 2 0 0 255 86 | 255 255 255 255 255 0 255 0 0 0 255 255 0 0 0 255 87 | 255 0 0 0 0 0 255 254 254 2 254 0 0 254 255 255 88 | 255 255 0 255 255 0 255 0 0 0 0 255 255 0 2 255 89 | 255 0 254 254 254 253 254 3 3 255 253 1 0 0 1 255 90 | 255 255 0 0 0 254 0 254 254 255 254 1 0 0 0 255 91 | 255 254 255 2 255 0 0 0 255 0 255 0 254 0 255 255 92 | 255 0 0 0 0 0 0 254 254 0 0 0 0 0 0 255 93 | 255 255 255 255 255 0 0 254 254 255 0 255 255 255 255 255 94 | 255 255 0 0 255 0 255 254 254 0 0 255 0 0 255 255 95 | 255 255 0 0 255 0 0 254 254 0 0 255 0 0 255 255 96 | 255 252 254 254 254 0 255 0 0 255 0 254 254 254 252 255 97 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 98 | 99 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 100 | 255 255 255 0 0 255 1 1 0 255 0 255 255 255 251 255 101 | 255 254 0 0 0 254 0 0 0 0 0 255 0 0 254 255 102 | 255 2 255 2 0 0 255 0 0 253 0 255 0 0 254 255 103 | 255 0 0 255 255 0 255 1 1 0 0 255 255 255 254 255 104 | 255 255 255 254 255 254 0 253 254 255 0 0 0 0 0 255 105 | 255 0 0 255 0 1 0 255 255 0 0 255 0 0 254 255 106 | 255 0 254 1 0 254 0 2 254 255 254 254 254 254 0 255 107 | 255 0 254 0 0 254 0 2 254 0 254 254 254 254 0 255 108 | 255 254 255 0 255 254 255 254 0 0 0 0 254 0 255 255 109 | 255 0 0 0 0 0 0 252 254 0 0 0 0 0 0 255 110 | 255 254 255 255 255 0 255 254 0 255 0 255 255 255 254 255 111 | 255 254 0 0 255 0 255 254 0 1 0 255 0 0 254 255 112 | 255 254 0 0 255 0 0 254 0 255 0 255 0 0 254 255 113 | 255 251 255 255 255 0 255 0 255 253 0 255 255 255 251 255 114 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 115 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 116 | 255 255 255 0 0 255 1 1 0 255 0 255 255 255 251 255 117 | 255 254 0 0 0 254 0 0 0 0 0 255 0 0 254 255 118 | 255 2 255 2 0 0 255 0 0 253 0 255 0 0 254 255 119 | 255 0 0 255 255 0 255 1 1 0 0 255 255 255 254 255 120 | 255 255 255 254 255 254 0 253 254 255 0 0 0 0 0 255 121 | 255 0 0 255 0 1 0 255 255 0 0 255 0 0 254 255 122 | 255 0 254 1 0 254 0 2 254 255 254 254 254 254 0 255 123 | 255 0 254 0 0 254 0 2 254 0 254 254 254 254 0 255 124 | 255 254 255 0 255 254 255 254 0 0 0 0 254 0 255 255 125 | 255 0 0 0 0 0 0 252 254 0 0 0 0 0 0 255 126 | 255 254 255 255 255 0 255 254 0 255 0 255 255 255 254 255 127 | 255 254 0 0 255 0 255 254 0 1 0 255 0 0 254 255 128 | 255 254 0 0 255 0 0 254 0 255 0 255 0 0 254 255 129 | 255 251 255 255 255 0 255 0 255 253 0 255 255 255 251 255 130 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 131 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 132 | 255 255 255 0 0 255 1 1 0 255 0 255 255 255 251 255 133 | 255 254 0 0 0 254 0 0 0 0 0 255 0 0 254 255 134 | 255 2 255 2 0 0 255 0 0 253 0 255 0 0 254 255 135 | 255 0 0 255 255 0 255 1 1 0 0 255 255 255 254 255 136 | 255 255 255 254 255 254 0 253 254 255 0 0 0 0 0 255 137 | 255 0 0 255 0 1 0 255 255 0 0 255 0 0 254 255 138 | 255 0 254 1 0 254 0 2 254 255 254 254 254 254 0 255 139 | 255 0 254 0 0 254 0 2 254 0 254 254 254 254 0 255 140 | 255 254 255 0 255 254 255 254 0 0 0 0 254 0 255 255 141 | 255 0 0 0 0 0 0 252 254 0 0 0 0 0 0 255 142 | 255 254 255 255 255 0 255 254 0 255 0 255 255 255 254 255 143 | 255 254 0 0 255 0 255 254 0 1 0 255 0 0 254 255 144 | 255 254 0 0 255 0 0 254 0 255 0 255 0 0 254 255 145 | 255 251 255 255 255 0 255 0 255 253 0 255 255 255 251 255 146 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 147 | 148 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 149 | 255 252 254 254 254 0 255 0 0 255 0 254 254 254 252 255 150 | 255 255 0 0 255 0 0 254 254 0 0 255 0 0 255 255 151 | 255 255 0 0 255 0 0 254 254 255 0 255 0 0 255 255 152 | 255 255 255 255 255 0 255 254 254 0 0 255 255 255 255 255 153 | 255 0 0 0 0 0 0 254 254 0 0 0 0 0 0 255 154 | 255 255 0 254 0 255 0 255 0 0 0 255 2 255 254 255 155 | 255 0 0 0 1 254 255 254 254 0 254 0 0 0 255 255 156 | 255 1 0 0 1 253 255 3 3 254 253 254 254 254 0 255 157 | 255 2 0 255 255 0 0 0 0 255 0 255 255 0 255 255 158 | 255 255 254 0 0 254 2 254 254 255 0 0 0 0 0 255 159 | 255 0 0 0 255 255 0 0 0 255 0 255 255 255 255 255 160 | 255 0 0 2 255 255 255 1 1 0 0 255 0 0 255 255 161 | 255 255 0 255 0 255 0 254 254 255 0 255 0 0 255 255 162 | 255 255 254 2 0 255 0 1 1 255 0 254 254 254 252 255 163 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 164 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 165 | 255 252 254 254 254 0 255 0 0 255 0 254 254 254 252 255 166 | 255 255 0 0 255 0 0 254 254 0 0 255 0 0 255 255 167 | 255 255 0 0 255 0 0 254 254 255 0 255 0 0 255 255 168 | 255 255 255 255 255 0 255 254 254 0 0 255 255 255 255 255 169 | 255 0 0 0 0 0 0 254 254 0 0 0 0 0 0 255 170 | 255 255 0 254 0 255 0 255 0 0 0 255 2 255 254 255 171 | 255 0 0 0 1 254 255 254 254 0 254 0 0 0 255 255 172 | 255 1 0 0 1 253 255 3 3 254 253 254 254 254 0 255 173 | 255 2 0 255 255 0 0 0 0 255 0 255 255 0 255 255 174 | 255 255 254 0 0 254 2 254 254 255 0 0 0 0 0 255 175 | 255 0 0 0 255 255 0 0 0 255 0 255 255 255 255 255 176 | 255 0 0 2 255 255 255 1 1 0 0 255 0 0 255 255 177 | 255 255 0 255 0 255 0 254 254 255 0 255 0 0 255 255 178 | 255 255 254 2 0 255 0 1 1 255 0 254 254 254 252 255 179 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 180 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 181 | 255 252 254 254 254 0 255 0 0 255 0 254 254 254 252 255 182 | 255 255 0 0 255 0 0 254 254 0 0 255 0 0 255 255 183 | 255 255 0 0 255 0 0 254 254 255 0 255 0 0 255 255 184 | 255 255 255 255 255 0 255 254 254 0 0 255 255 255 255 255 185 | 255 0 0 0 0 0 0 254 254 0 0 0 0 0 0 255 186 | 255 255 0 254 0 255 0 255 0 0 0 255 2 255 254 255 187 | 255 0 0 0 1 254 255 254 254 0 254 0 0 0 255 255 188 | 255 1 0 0 1 253 255 3 3 254 253 254 254 254 0 255 189 | 255 2 0 255 255 0 0 0 0 255 0 255 255 0 255 255 190 | 255 255 254 0 0 254 2 254 254 255 0 0 0 0 0 255 191 | 255 0 0 0 255 255 0 0 0 255 0 255 255 255 255 255 192 | 255 0 0 2 255 255 255 1 1 0 0 255 0 0 255 255 193 | 255 255 0 255 0 255 0 254 254 255 0 255 0 0 255 255 194 | 255 255 254 2 0 255 0 1 1 255 0 254 254 254 252 255 195 | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 196 | -------------------------------------------------------------------------------- /bulid/MTLLoader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Loads a Wavefront .mtl file specifying materials 3 | * 4 | * @author angelxuanchang 5 | */ 6 | 7 | THREE.MTLLoader = function ( manager ) { 8 | 9 | this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; 10 | 11 | }; 12 | 13 | THREE.MTLLoader.prototype = { 14 | 15 | constructor: THREE.MTLLoader, 16 | 17 | /** 18 | * Loads and parses a MTL asset from a URL. 19 | * 20 | * @param {String} url - URL to the MTL file. 21 | * @param {Function} [onLoad] - Callback invoked with the loaded object. 22 | * @param {Function} [onProgress] - Callback for download progress. 23 | * @param {Function} [onError] - Callback for download errors. 24 | * 25 | * @see setPath setTexturePath 26 | * 27 | * @note In order for relative texture references to resolve correctly 28 | * you must call setPath and/or setTexturePath explicitly prior to load. 29 | */ 30 | load: function ( url, onLoad, onProgress, onError ) { 31 | 32 | var scope = this; 33 | 34 | var loader = new THREE.FileLoader( this.manager ); 35 | loader.setPath( this.path ); 36 | loader.load( url, function ( text ) { 37 | 38 | onLoad( scope.parse( text ) ); 39 | 40 | }, onProgress, onError ); 41 | 42 | }, 43 | 44 | /** 45 | * Set base path for resolving references. 46 | * If set this path will be prepended to each loaded and found reference. 47 | * 48 | * @see setTexturePath 49 | * @param {String} path 50 | * 51 | * @example 52 | * mtlLoader.setPath( 'assets/obj/' ); 53 | * mtlLoader.load( 'my.mtl', ... ); 54 | */ 55 | setPath: function ( path ) { 56 | 57 | this.path = path; 58 | 59 | }, 60 | 61 | /** 62 | * Set base path for resolving texture references. 63 | * If set this path will be prepended found texture reference. 64 | * If not set and setPath is, it will be used as texture base path. 65 | * 66 | * @see setPath 67 | * @param {String} path 68 | * 69 | * @example 70 | * mtlLoader.setPath( 'assets/obj/' ); 71 | * mtlLoader.setTexturePath( 'assets/textures/' ); 72 | * mtlLoader.load( 'my.mtl', ... ); 73 | */ 74 | setTexturePath: function ( path ) { 75 | 76 | this.texturePath = path; 77 | 78 | }, 79 | 80 | setBaseUrl: function ( path ) { 81 | 82 | console.warn( 'THREE.MTLLoader: .setBaseUrl() is deprecated. Use .setTexturePath( path ) for texture path or .setPath( path ) for general base path instead.' ); 83 | 84 | this.setTexturePath( path ); 85 | 86 | }, 87 | 88 | setCrossOrigin: function ( value ) { 89 | 90 | this.crossOrigin = value; 91 | 92 | }, 93 | 94 | setMaterialOptions: function ( value ) { 95 | 96 | this.materialOptions = value; 97 | 98 | }, 99 | 100 | /** 101 | * Parses a MTL file. 102 | * 103 | * @param {String} text - Content of MTL file 104 | * @return {THREE.MTLLoader.MaterialCreator} 105 | * 106 | * @see setPath setTexturePath 107 | * 108 | * @note In order for relative texture references to resolve correctly 109 | * you must call setPath and/or setTexturePath explicitly prior to parse. 110 | */ 111 | parse: function ( text ) { 112 | 113 | var lines = text.split( '\n' ); 114 | var info = {}; 115 | var delimiter_pattern = /\s+/; 116 | var materialsInfo = {}; 117 | 118 | for ( var i = 0; i < lines.length; i ++ ) { 119 | 120 | var line = lines[ i ]; 121 | line = line.trim(); 122 | 123 | if ( line.length === 0 || line.charAt( 0 ) === '#' ) { 124 | 125 | // Blank line or comment ignore 126 | continue; 127 | 128 | } 129 | 130 | var pos = line.indexOf( ' ' ); 131 | 132 | var key = ( pos >= 0 ) ? line.substring( 0, pos ) : line; 133 | key = key.toLowerCase(); 134 | 135 | var value = ( pos >= 0 ) ? line.substring( pos + 1 ) : ''; 136 | value = value.trim(); 137 | 138 | if ( key === 'newmtl' ) { 139 | 140 | // New material 141 | 142 | info = { name: value }; 143 | materialsInfo[ value ] = info; 144 | 145 | } else if ( info ) { 146 | 147 | if ( key === 'ka' || key === 'kd' || key === 'ks' ) { 148 | 149 | var ss = value.split( delimiter_pattern, 3 ); 150 | info[ key ] = [ parseFloat( ss[ 0 ] ), parseFloat( ss[ 1 ] ), parseFloat( ss[ 2 ] ) ]; 151 | 152 | } else { 153 | 154 | info[ key ] = value; 155 | 156 | } 157 | 158 | } 159 | 160 | } 161 | 162 | var materialCreator = new THREE.MTLLoader.MaterialCreator( this.texturePath || this.path, this.materialOptions ); 163 | materialCreator.setCrossOrigin( this.crossOrigin ); 164 | materialCreator.setManager( this.manager ); 165 | materialCreator.setMaterials( materialsInfo ); 166 | return materialCreator; 167 | 168 | } 169 | 170 | }; 171 | 172 | /** 173 | * Create a new THREE-MTLLoader.MaterialCreator 174 | * @param baseUrl - Url relative to which textures are loaded 175 | * @param options - Set of options on how to construct the materials 176 | * side: Which side to apply the material 177 | * THREE.FrontSide (default), THREE.BackSide, THREE.DoubleSide 178 | * wrap: What type of wrapping to apply for textures 179 | * THREE.RepeatWrapping (default), THREE.ClampToEdgeWrapping, THREE.MirroredRepeatWrapping 180 | * normalizeRGB: RGBs need to be normalized to 0-1 from 0-255 181 | * Default: false, assumed to be already normalized 182 | * ignoreZeroRGBs: Ignore values of RGBs (Ka,Kd,Ks) that are all 0's 183 | * Default: false 184 | * @constructor 185 | */ 186 | 187 | THREE.MTLLoader.MaterialCreator = function ( baseUrl, options ) { 188 | 189 | this.baseUrl = baseUrl || ''; 190 | this.options = options; 191 | this.materialsInfo = {}; 192 | this.materials = {}; 193 | this.materialsArray = []; 194 | this.nameLookup = {}; 195 | 196 | this.side = ( this.options && this.options.side ) ? this.options.side : THREE.FrontSide; 197 | this.wrap = ( this.options && this.options.wrap ) ? this.options.wrap : THREE.RepeatWrapping; 198 | 199 | }; 200 | 201 | THREE.MTLLoader.MaterialCreator.prototype = { 202 | 203 | constructor: THREE.MTLLoader.MaterialCreator, 204 | 205 | crossOrigin: 'Anonymous', 206 | 207 | setCrossOrigin: function ( value ) { 208 | 209 | this.crossOrigin = value; 210 | 211 | }, 212 | 213 | setManager: function ( value ) { 214 | 215 | this.manager = value; 216 | 217 | }, 218 | 219 | setMaterials: function ( materialsInfo ) { 220 | 221 | this.materialsInfo = this.convert( materialsInfo ); 222 | this.materials = {}; 223 | this.materialsArray = []; 224 | this.nameLookup = {}; 225 | 226 | }, 227 | 228 | convert: function ( materialsInfo ) { 229 | 230 | if ( ! this.options ) return materialsInfo; 231 | 232 | var converted = {}; 233 | 234 | for ( var mn in materialsInfo ) { 235 | 236 | // Convert materials info into normalized form based on options 237 | 238 | var mat = materialsInfo[ mn ]; 239 | 240 | var covmat = {}; 241 | 242 | converted[ mn ] = covmat; 243 | 244 | for ( var prop in mat ) { 245 | 246 | var save = true; 247 | var value = mat[ prop ]; 248 | var lprop = prop.toLowerCase(); 249 | 250 | switch ( lprop ) { 251 | 252 | case 'kd': 253 | case 'ka': 254 | case 'ks': 255 | 256 | // Diffuse color (color under white light) using RGB values 257 | 258 | if ( this.options && this.options.normalizeRGB ) { 259 | 260 | value = [ value[ 0 ] / 255, value[ 1 ] / 255, value[ 2 ] / 255 ]; 261 | 262 | } 263 | 264 | if ( this.options && this.options.ignoreZeroRGBs ) { 265 | 266 | if ( value[ 0 ] === 0 && value[ 1 ] === 0 && value[ 2 ] === 0 ) { 267 | 268 | // ignore 269 | 270 | save = false; 271 | 272 | } 273 | 274 | } 275 | 276 | break; 277 | 278 | default: 279 | 280 | break; 281 | 282 | } 283 | 284 | if ( save ) { 285 | 286 | covmat[ lprop ] = value; 287 | 288 | } 289 | 290 | } 291 | 292 | } 293 | 294 | return converted; 295 | 296 | }, 297 | 298 | preload: function () { 299 | 300 | for ( var mn in this.materialsInfo ) { 301 | 302 | this.create( mn ); 303 | 304 | } 305 | 306 | }, 307 | 308 | getIndex: function ( materialName ) { 309 | 310 | return this.nameLookup[ materialName ]; 311 | 312 | }, 313 | 314 | getAsArray: function () { 315 | 316 | var index = 0; 317 | 318 | for ( var mn in this.materialsInfo ) { 319 | 320 | this.materialsArray[ index ] = this.create( mn ); 321 | this.nameLookup[ mn ] = index; 322 | index ++; 323 | 324 | } 325 | 326 | return this.materialsArray; 327 | 328 | }, 329 | 330 | create: function ( materialName ) { 331 | 332 | if ( this.materials[ materialName ] === undefined ) { 333 | 334 | this.createMaterial_( materialName ); 335 | 336 | } 337 | 338 | return this.materials[ materialName ]; 339 | 340 | }, 341 | 342 | createMaterial_: function ( materialName ) { 343 | 344 | // Create material 345 | 346 | var scope = this; 347 | var mat = this.materialsInfo[ materialName ]; 348 | var params = { 349 | 350 | name: materialName, 351 | side: this.side 352 | 353 | }; 354 | 355 | function resolveURL( baseUrl, url ) { 356 | 357 | if ( typeof url !== 'string' || url === '' ) 358 | return ''; 359 | 360 | // Absolute URL 361 | if ( /^https?:\/\//i.test( url ) ) return url; 362 | 363 | return baseUrl + url; 364 | 365 | } 366 | 367 | function setMapForType( mapType, value ) { 368 | 369 | if ( params[ mapType ] ) return; // Keep the first encountered texture 370 | 371 | var texParams = scope.getTextureParams( value, params ); 372 | var map = scope.loadTexture( resolveURL( scope.baseUrl, texParams.url ) ); 373 | 374 | map.repeat.copy( texParams.scale ); 375 | map.offset.copy( texParams.offset ); 376 | 377 | map.wrapS = scope.wrap; 378 | map.wrapT = scope.wrap; 379 | 380 | params[ mapType ] = map; 381 | 382 | } 383 | 384 | for ( var prop in mat ) { 385 | 386 | var value = mat[ prop ]; 387 | var n; 388 | 389 | if ( value === '' ) continue; 390 | 391 | switch ( prop.toLowerCase() ) { 392 | 393 | // Ns is material specular exponent 394 | 395 | case 'kd': 396 | 397 | // Diffuse color (color under white light) using RGB values 398 | 399 | params.color = new THREE.Color().fromArray( value ); 400 | 401 | break; 402 | 403 | case 'ks': 404 | 405 | // Specular color (color when light is reflected from shiny surface) using RGB values 406 | params.specular = new THREE.Color().fromArray( value ); 407 | 408 | break; 409 | 410 | case 'map_kd': 411 | 412 | // Diffuse texture map 413 | 414 | setMapForType( "map", value ); 415 | 416 | break; 417 | 418 | case 'map_ks': 419 | 420 | // Specular map 421 | 422 | setMapForType( "specularMap", value ); 423 | 424 | break; 425 | 426 | case 'norm': 427 | 428 | setMapForType( "normalMap", value ); 429 | 430 | break; 431 | 432 | case 'map_bump': 433 | case 'bump': 434 | 435 | // Bump texture map 436 | 437 | setMapForType( "bumpMap", value ); 438 | 439 | break; 440 | 441 | case 'ns': 442 | 443 | // The specular exponent (defines the focus of the specular highlight) 444 | // A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000. 445 | 446 | params.shininess = parseFloat( value ); 447 | 448 | break; 449 | 450 | case 'd': 451 | n = parseFloat( value ); 452 | 453 | if ( n < 1 ) { 454 | 455 | params.opacity = n; 456 | params.transparent = true; 457 | 458 | } 459 | 460 | break; 461 | 462 | case 'tr': 463 | n = parseFloat( value ); 464 | 465 | if ( n > 0 ) { 466 | 467 | params.opacity = 1 - n; 468 | params.transparent = true; 469 | 470 | } 471 | 472 | break; 473 | 474 | default: 475 | break; 476 | 477 | } 478 | 479 | } 480 | 481 | this.materials[ materialName ] = new THREE.MeshPhongMaterial( params ); 482 | return this.materials[ materialName ]; 483 | 484 | }, 485 | 486 | getTextureParams: function ( value, matParams ) { 487 | 488 | var texParams = { 489 | 490 | scale: new THREE.Vector2( 1, 1 ), 491 | offset: new THREE.Vector2( 0, 0 ) 492 | 493 | }; 494 | 495 | var items = value.split( /\s+/ ); 496 | var pos; 497 | 498 | pos = items.indexOf( '-bm' ); 499 | 500 | if ( pos >= 0 ) { 501 | 502 | matParams.bumpScale = parseFloat( items[ pos + 1 ] ); 503 | items.splice( pos, 2 ); 504 | 505 | } 506 | 507 | pos = items.indexOf( '-s' ); 508 | 509 | if ( pos >= 0 ) { 510 | 511 | texParams.scale.set( parseFloat( items[ pos + 1 ] ), parseFloat( items[ pos + 2 ] ) ); 512 | items.splice( pos, 4 ); // we expect 3 parameters here! 513 | 514 | } 515 | 516 | pos = items.indexOf( '-o' ); 517 | 518 | if ( pos >= 0 ) { 519 | 520 | texParams.offset.set( parseFloat( items[ pos + 1 ] ), parseFloat( items[ pos + 2 ] ) ); 521 | items.splice( pos, 4 ); // we expect 3 parameters here! 522 | 523 | } 524 | 525 | texParams.url = items.join( ' ' ).trim(); 526 | return texParams; 527 | 528 | }, 529 | 530 | loadTexture: function ( url, mapping, onLoad, onProgress, onError ) { 531 | 532 | var texture; 533 | var loader = THREE.Loader.Handlers.get( url ); 534 | var manager = ( this.manager !== undefined ) ? this.manager : THREE.DefaultLoadingManager; 535 | 536 | if ( loader === null ) { 537 | 538 | loader = new THREE.TextureLoader( manager ); 539 | 540 | } 541 | 542 | if ( loader.setCrossOrigin ) loader.setCrossOrigin( this.crossOrigin ); 543 | texture = loader.load( url, onLoad, onProgress, onError ); 544 | 545 | if ( mapping !== undefined ) texture.mapping = mapping; 546 | 547 | return texture; 548 | 549 | } 550 | 551 | }; 552 | -------------------------------------------------------------------------------- /bulid/OBJLoader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | THREE.OBJLoader = ( function () { 6 | 7 | // o object_name | g group_name 8 | var object_pattern = /^[og]\s*(.+)?/; 9 | // mtllib file_reference 10 | var material_library_pattern = /^mtllib /; 11 | // usemtl material_name 12 | var material_use_pattern = /^usemtl /; 13 | 14 | function ParserState() { 15 | 16 | var state = { 17 | objects: [], 18 | object: {}, 19 | 20 | vertices: [], 21 | normals: [], 22 | colors: [], 23 | uvs: [], 24 | 25 | materialLibraries: [], 26 | 27 | startObject: function ( name, fromDeclaration ) { 28 | 29 | // If the current object (initial from reset) is not from a g/o declaration in the parsed 30 | // file. We need to use it for the first parsed g/o to keep things in sync. 31 | if ( this.object && this.object.fromDeclaration === false ) { 32 | 33 | this.object.name = name; 34 | this.object.fromDeclaration = ( fromDeclaration !== false ); 35 | return; 36 | 37 | } 38 | 39 | var previousMaterial = ( this.object && typeof this.object.currentMaterial === 'function' ? this.object.currentMaterial() : undefined ); 40 | 41 | if ( this.object && typeof this.object._finalize === 'function' ) { 42 | 43 | this.object._finalize( true ); 44 | 45 | } 46 | 47 | this.object = { 48 | name: name || '', 49 | fromDeclaration: ( fromDeclaration !== false ), 50 | 51 | geometry: { 52 | vertices: [], 53 | normals: [], 54 | colors: [], 55 | uvs: [] 56 | }, 57 | materials: [], 58 | smooth: true, 59 | 60 | startMaterial: function ( name, libraries ) { 61 | 62 | var previous = this._finalize( false ); 63 | 64 | // New usemtl declaration overwrites an inherited material, except if faces were declared 65 | // after the material, then it must be preserved for proper MultiMaterial continuation. 66 | if ( previous && ( previous.inherited || previous.groupCount <= 0 ) ) { 67 | 68 | this.materials.splice( previous.index, 1 ); 69 | 70 | } 71 | 72 | var material = { 73 | index: this.materials.length, 74 | name: name || '', 75 | mtllib: ( Array.isArray( libraries ) && libraries.length > 0 ? libraries[ libraries.length - 1 ] : '' ), 76 | smooth: ( previous !== undefined ? previous.smooth : this.smooth ), 77 | groupStart: ( previous !== undefined ? previous.groupEnd : 0 ), 78 | groupEnd: - 1, 79 | groupCount: - 1, 80 | inherited: false, 81 | 82 | clone: function ( index ) { 83 | 84 | var cloned = { 85 | index: ( typeof index === 'number' ? index : this.index ), 86 | name: this.name, 87 | mtllib: this.mtllib, 88 | smooth: this.smooth, 89 | groupStart: 0, 90 | groupEnd: - 1, 91 | groupCount: - 1, 92 | inherited: false 93 | }; 94 | cloned.clone = this.clone.bind( cloned ); 95 | return cloned; 96 | 97 | } 98 | }; 99 | 100 | this.materials.push( material ); 101 | 102 | return material; 103 | 104 | }, 105 | 106 | currentMaterial: function () { 107 | 108 | if ( this.materials.length > 0 ) { 109 | 110 | return this.materials[ this.materials.length - 1 ]; 111 | 112 | } 113 | 114 | return undefined; 115 | 116 | }, 117 | 118 | _finalize: function ( end ) { 119 | 120 | var lastMultiMaterial = this.currentMaterial(); 121 | if ( lastMultiMaterial && lastMultiMaterial.groupEnd === - 1 ) { 122 | 123 | lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3; 124 | lastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart; 125 | lastMultiMaterial.inherited = false; 126 | 127 | } 128 | 129 | // Ignore objects tail materials if no face declarations followed them before a new o/g started. 130 | if ( end && this.materials.length > 1 ) { 131 | 132 | for ( var mi = this.materials.length - 1; mi >= 0; mi -- ) { 133 | 134 | if ( this.materials[ mi ].groupCount <= 0 ) { 135 | 136 | this.materials.splice( mi, 1 ); 137 | 138 | } 139 | 140 | } 141 | 142 | } 143 | 144 | // Guarantee at least one empty material, this makes the creation later more straight forward. 145 | if ( end && this.materials.length === 0 ) { 146 | 147 | this.materials.push( { 148 | name: '', 149 | smooth: this.smooth 150 | } ); 151 | 152 | } 153 | 154 | return lastMultiMaterial; 155 | 156 | } 157 | }; 158 | 159 | // Inherit previous objects material. 160 | // Spec tells us that a declared material must be set to all objects until a new material is declared. 161 | // If a usemtl declaration is encountered while this new object is being parsed, it will 162 | // overwrite the inherited material. Exception being that there was already face declarations 163 | // to the inherited material, then it will be preserved for proper MultiMaterial continuation. 164 | 165 | if ( previousMaterial && previousMaterial.name && typeof previousMaterial.clone === 'function' ) { 166 | 167 | var declared = previousMaterial.clone( 0 ); 168 | declared.inherited = true; 169 | this.object.materials.push( declared ); 170 | 171 | } 172 | 173 | this.objects.push( this.object ); 174 | 175 | }, 176 | 177 | finalize: function () { 178 | 179 | if ( this.object && typeof this.object._finalize === 'function' ) { 180 | 181 | this.object._finalize( true ); 182 | 183 | } 184 | 185 | }, 186 | 187 | parseVertexIndex: function ( value, len ) { 188 | 189 | var index = parseInt( value, 10 ); 190 | return ( index >= 0 ? index - 1 : index + len / 3 ) * 3; 191 | 192 | }, 193 | 194 | parseNormalIndex: function ( value, len ) { 195 | 196 | var index = parseInt( value, 10 ); 197 | return ( index >= 0 ? index - 1 : index + len / 3 ) * 3; 198 | 199 | }, 200 | 201 | parseUVIndex: function ( value, len ) { 202 | 203 | var index = parseInt( value, 10 ); 204 | return ( index >= 0 ? index - 1 : index + len / 2 ) * 2; 205 | 206 | }, 207 | 208 | addVertex: function ( a, b, c ) { 209 | 210 | var src = this.vertices; 211 | var dst = this.object.geometry.vertices; 212 | 213 | dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); 214 | dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] ); 215 | dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] ); 216 | 217 | }, 218 | 219 | addVertexLine: function ( a ) { 220 | 221 | var src = this.vertices; 222 | var dst = this.object.geometry.vertices; 223 | 224 | dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); 225 | 226 | }, 227 | 228 | addNormal: function ( a, b, c ) { 229 | 230 | var src = this.normals; 231 | var dst = this.object.geometry.normals; 232 | 233 | dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); 234 | dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] ); 235 | dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] ); 236 | 237 | }, 238 | 239 | addColor: function ( a, b, c ) { 240 | 241 | var src = this.colors; 242 | var dst = this.object.geometry.colors; 243 | 244 | dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); 245 | dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] ); 246 | dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] ); 247 | 248 | }, 249 | 250 | addUV: function ( a, b, c ) { 251 | 252 | var src = this.uvs; 253 | var dst = this.object.geometry.uvs; 254 | 255 | dst.push( src[ a + 0 ], src[ a + 1 ] ); 256 | dst.push( src[ b + 0 ], src[ b + 1 ] ); 257 | dst.push( src[ c + 0 ], src[ c + 1 ] ); 258 | 259 | }, 260 | 261 | addUVLine: function ( a ) { 262 | 263 | var src = this.uvs; 264 | var dst = this.object.geometry.uvs; 265 | 266 | dst.push( src[ a + 0 ], src[ a + 1 ] ); 267 | 268 | }, 269 | 270 | addFace: function ( a, b, c, ua, ub, uc, na, nb, nc ) { 271 | 272 | var vLen = this.vertices.length; 273 | 274 | var ia = this.parseVertexIndex( a, vLen ); 275 | var ib = this.parseVertexIndex( b, vLen ); 276 | var ic = this.parseVertexIndex( c, vLen ); 277 | 278 | this.addVertex( ia, ib, ic ); 279 | 280 | if ( ua !== undefined ) { 281 | 282 | var uvLen = this.uvs.length; 283 | 284 | ia = this.parseUVIndex( ua, uvLen ); 285 | ib = this.parseUVIndex( ub, uvLen ); 286 | ic = this.parseUVIndex( uc, uvLen ); 287 | 288 | this.addUV( ia, ib, ic ); 289 | 290 | } 291 | 292 | if ( na !== undefined ) { 293 | 294 | // Normals are many times the same. If so, skip function call and parseInt. 295 | var nLen = this.normals.length; 296 | ia = this.parseNormalIndex( na, nLen ); 297 | 298 | ib = na === nb ? ia : this.parseNormalIndex( nb, nLen ); 299 | ic = na === nc ? ia : this.parseNormalIndex( nc, nLen ); 300 | 301 | this.addNormal( ia, ib, ic ); 302 | 303 | } 304 | 305 | if ( this.colors.length > 0 ) { 306 | 307 | this.addColor( ia, ib, ic ); 308 | 309 | } 310 | 311 | }, 312 | 313 | addLineGeometry: function ( vertices, uvs ) { 314 | 315 | this.object.geometry.type = 'Line'; 316 | 317 | var vLen = this.vertices.length; 318 | var uvLen = this.uvs.length; 319 | 320 | for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) { 321 | 322 | this.addVertexLine( this.parseVertexIndex( vertices[ vi ], vLen ) ); 323 | 324 | } 325 | 326 | for ( var uvi = 0, l = uvs.length; uvi < l; uvi ++ ) { 327 | 328 | this.addUVLine( this.parseUVIndex( uvs[ uvi ], uvLen ) ); 329 | 330 | } 331 | 332 | } 333 | 334 | }; 335 | 336 | state.startObject( '', false ); 337 | 338 | return state; 339 | 340 | } 341 | 342 | // 343 | 344 | function OBJLoader( manager ) { 345 | 346 | this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; 347 | 348 | this.materials = null; 349 | 350 | } 351 | 352 | OBJLoader.prototype = { 353 | 354 | constructor: OBJLoader, 355 | 356 | load: function ( url, onLoad, onProgress, onError ) { 357 | 358 | var scope = this; 359 | 360 | var loader = new THREE.FileLoader( scope.manager ); 361 | loader.setPath( this.path ); 362 | loader.load( url, function ( text ) { 363 | 364 | onLoad( scope.parse( text ) ); 365 | 366 | }, onProgress, onError ); 367 | 368 | }, 369 | 370 | setPath: function ( value ) { 371 | 372 | this.path = value; 373 | 374 | }, 375 | 376 | setMaterials: function ( materials ) { 377 | 378 | this.materials = materials; 379 | 380 | return this; 381 | 382 | }, 383 | 384 | parse: function ( text ) { 385 | 386 | console.time( 'OBJLoader' ); 387 | 388 | var state = new ParserState(); 389 | 390 | if ( text.indexOf( '\r\n' ) !== - 1 ) { 391 | 392 | // This is faster than String.split with regex that splits on both 393 | text = text.replace( /\r\n/g, '\n' ); 394 | 395 | } 396 | 397 | if ( text.indexOf( '\\\n' ) !== - 1 ) { 398 | 399 | // join lines separated by a line continuation character (\) 400 | text = text.replace( /\\\n/g, '' ); 401 | 402 | } 403 | 404 | var lines = text.split( '\n' ); 405 | var line = '', lineFirstChar = ''; 406 | var lineLength = 0; 407 | var result = []; 408 | 409 | // Faster to just trim left side of the line. Use if available. 410 | var trimLeft = ( typeof ''.trimLeft === 'function' ); 411 | 412 | for ( var i = 0, l = lines.length; i < l; i ++ ) { 413 | 414 | line = lines[ i ]; 415 | 416 | line = trimLeft ? line.trimLeft() : line.trim(); 417 | 418 | lineLength = line.length; 419 | 420 | if ( lineLength === 0 ) continue; 421 | 422 | lineFirstChar = line.charAt( 0 ); 423 | 424 | // @todo invoke passed in handler if any 425 | if ( lineFirstChar === '#' ) continue; 426 | 427 | if ( lineFirstChar === 'v' ) { 428 | 429 | var data = line.split( /\s+/ ); 430 | 431 | switch ( data[ 0 ] ) { 432 | 433 | case 'v': 434 | state.vertices.push( 435 | parseFloat( data[ 1 ] ), 436 | parseFloat( data[ 2 ] ), 437 | parseFloat( data[ 3 ] ) 438 | ); 439 | if ( data.length === 8 ) { 440 | 441 | state.colors.push( 442 | parseFloat( data[ 4 ] ), 443 | parseFloat( data[ 5 ] ), 444 | parseFloat( data[ 6 ] ) 445 | 446 | ); 447 | 448 | } 449 | break; 450 | case 'vn': 451 | state.normals.push( 452 | parseFloat( data[ 1 ] ), 453 | parseFloat( data[ 2 ] ), 454 | parseFloat( data[ 3 ] ) 455 | ); 456 | break; 457 | case 'vt': 458 | state.uvs.push( 459 | parseFloat( data[ 1 ] ), 460 | parseFloat( data[ 2 ] ) 461 | ); 462 | break; 463 | 464 | } 465 | 466 | } else if ( lineFirstChar === 'f' ) { 467 | 468 | var lineData = line.substr( 1 ).trim(); 469 | var vertexData = lineData.split( /\s+/ ); 470 | var faceVertices = []; 471 | 472 | // Parse the face vertex data into an easy to work with format 473 | 474 | for ( var j = 0, jl = vertexData.length; j < jl; j ++ ) { 475 | 476 | var vertex = vertexData[ j ]; 477 | 478 | if ( vertex.length > 0 ) { 479 | 480 | var vertexParts = vertex.split( '/' ); 481 | faceVertices.push( vertexParts ); 482 | 483 | } 484 | 485 | } 486 | 487 | // Draw an edge between the first vertex and all subsequent vertices to form an n-gon 488 | 489 | var v1 = faceVertices[ 0 ]; 490 | 491 | for ( var j = 1, jl = faceVertices.length - 1; j < jl; j ++ ) { 492 | 493 | var v2 = faceVertices[ j ]; 494 | var v3 = faceVertices[ j + 1 ]; 495 | 496 | state.addFace( 497 | v1[ 0 ], v2[ 0 ], v3[ 0 ], 498 | v1[ 1 ], v2[ 1 ], v3[ 1 ], 499 | v1[ 2 ], v2[ 2 ], v3[ 2 ] 500 | ); 501 | 502 | } 503 | 504 | } else if ( lineFirstChar === 'l' ) { 505 | 506 | var lineParts = line.substring( 1 ).trim().split( " " ); 507 | var lineVertices = [], lineUVs = []; 508 | 509 | if ( line.indexOf( "/" ) === - 1 ) { 510 | 511 | lineVertices = lineParts; 512 | 513 | } else { 514 | 515 | for ( var li = 0, llen = lineParts.length; li < llen; li ++ ) { 516 | 517 | var parts = lineParts[ li ].split( "/" ); 518 | 519 | if ( parts[ 0 ] !== "" ) lineVertices.push( parts[ 0 ] ); 520 | if ( parts[ 1 ] !== "" ) lineUVs.push( parts[ 1 ] ); 521 | 522 | } 523 | 524 | } 525 | state.addLineGeometry( lineVertices, lineUVs ); 526 | 527 | } else if ( ( result = object_pattern.exec( line ) ) !== null ) { 528 | 529 | // o object_name 530 | // or 531 | // g group_name 532 | 533 | // WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869 534 | // var name = result[ 0 ].substr( 1 ).trim(); 535 | var name = ( " " + result[ 0 ].substr( 1 ).trim() ).substr( 1 ); 536 | 537 | state.startObject( name ); 538 | 539 | } else if ( material_use_pattern.test( line ) ) { 540 | 541 | // material 542 | 543 | state.object.startMaterial( line.substring( 7 ).trim(), state.materialLibraries ); 544 | 545 | } else if ( material_library_pattern.test( line ) ) { 546 | 547 | // mtl file 548 | 549 | state.materialLibraries.push( line.substring( 7 ).trim() ); 550 | 551 | } else if ( lineFirstChar === 's' ) { 552 | 553 | result = line.split( ' ' ); 554 | 555 | // smooth shading 556 | 557 | // @todo Handle files that have varying smooth values for a set of faces inside one geometry, 558 | // but does not define a usemtl for each face set. 559 | // This should be detected and a dummy material created (later MultiMaterial and geometry groups). 560 | // This requires some care to not create extra material on each smooth value for "normal" obj files. 561 | // where explicit usemtl defines geometry groups. 562 | // Example asset: examples/models/obj/cerberus/Cerberus.obj 563 | 564 | /* 565 | * http://paulbourke.net/dataformats/obj/ 566 | * or 567 | * http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf 568 | * 569 | * From chapter "Grouping" Syntax explanation "s group_number": 570 | * "group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off. 571 | * Polygonal elements use group numbers to put elements in different smoothing groups. For free-form 572 | * surfaces, smoothing groups are either turned on or off; there is no difference between values greater 573 | * than 0." 574 | */ 575 | if ( result.length > 1 ) { 576 | 577 | var value = result[ 1 ].trim().toLowerCase(); 578 | state.object.smooth = ( value !== '0' && value !== 'off' ); 579 | 580 | } else { 581 | 582 | // ZBrush can produce "s" lines #11707 583 | state.object.smooth = true; 584 | 585 | } 586 | var material = state.object.currentMaterial(); 587 | if ( material ) material.smooth = state.object.smooth; 588 | 589 | } else { 590 | 591 | // Handle null terminated files without exception 592 | if ( line === '\0' ) continue; 593 | 594 | throw new Error( 'THREE.OBJLoader: Unexpected line: "' + line + '"' ); 595 | 596 | } 597 | 598 | } 599 | 600 | state.finalize(); 601 | 602 | var container = new THREE.Group(); 603 | container.materialLibraries = [].concat( state.materialLibraries ); 604 | 605 | for ( var i = 0, l = state.objects.length; i < l; i ++ ) { 606 | 607 | var object = state.objects[ i ]; 608 | var geometry = object.geometry; 609 | var materials = object.materials; 610 | var isLine = ( geometry.type === 'Line' ); 611 | 612 | // Skip o/g line declarations that did not follow with any faces 613 | if ( geometry.vertices.length === 0 ) continue; 614 | 615 | var buffergeometry = new THREE.BufferGeometry(); 616 | 617 | buffergeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( geometry.vertices, 3 ) ); 618 | 619 | if ( geometry.normals.length > 0 ) { 620 | 621 | buffergeometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( geometry.normals, 3 ) ); 622 | 623 | } else { 624 | 625 | buffergeometry.computeVertexNormals(); 626 | 627 | } 628 | 629 | if ( geometry.colors.length > 0 ) { 630 | 631 | buffergeometry.addAttribute( 'color', new THREE.Float32BufferAttribute( geometry.colors, 3 ) ); 632 | 633 | } 634 | 635 | if ( geometry.uvs.length > 0 ) { 636 | 637 | buffergeometry.addAttribute( 'uv', new THREE.Float32BufferAttribute( geometry.uvs, 2 ) ); 638 | 639 | } 640 | 641 | // Create materials 642 | 643 | var createdMaterials = []; 644 | 645 | for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) { 646 | 647 | var sourceMaterial = materials[ mi ]; 648 | var material = undefined; 649 | 650 | if ( this.materials !== null ) { 651 | 652 | material = this.materials.create( sourceMaterial.name ); 653 | 654 | // mtl etc. loaders probably can't create line materials correctly, copy properties to a line material. 655 | if ( isLine && material && ! ( material instanceof THREE.LineBasicMaterial ) ) { 656 | 657 | var materialLine = new THREE.LineBasicMaterial(); 658 | materialLine.copy( material ); 659 | material = materialLine; 660 | 661 | } 662 | 663 | } 664 | 665 | if ( ! material ) { 666 | 667 | material = ( ! isLine ? new THREE.MeshPhongMaterial() : new THREE.LineBasicMaterial() ); 668 | material.name = sourceMaterial.name; 669 | 670 | } 671 | 672 | material.flatShading = sourceMaterial.smooth ? false : true; 673 | 674 | createdMaterials.push( material ); 675 | 676 | } 677 | 678 | // Create mesh 679 | 680 | var mesh; 681 | 682 | if ( createdMaterials.length > 1 ) { 683 | 684 | for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) { 685 | 686 | var sourceMaterial = materials[ mi ]; 687 | buffergeometry.addGroup( sourceMaterial.groupStart, sourceMaterial.groupCount, mi ); 688 | 689 | } 690 | 691 | mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, createdMaterials ) : new THREE.LineSegments( buffergeometry, createdMaterials ) ); 692 | 693 | } else { 694 | 695 | mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, createdMaterials[ 0 ] ) : new THREE.LineSegments( buffergeometry, createdMaterials[ 0 ] ) ); 696 | 697 | } 698 | 699 | mesh.name = object.name; 700 | 701 | container.add( mesh ); 702 | 703 | } 704 | 705 | console.timeEnd( 'OBJLoader' ); 706 | 707 | return container; 708 | 709 | } 710 | 711 | }; 712 | 713 | return OBJLoader; 714 | 715 | } )(); 716 | --------------------------------------------------------------------------------