Bläddra i källkod

Removed SceneUtils.traverseHierarchy and SceneUtils.showHierarchy. Added object.traverse.
Is not exactly the same beaviour. object.traverse also applied the callback to object.
But I think it's better like this, because now we can do object.traverse( function ( node ) { node.visible = false } ) and it will also take care of the parent. However, if this creates any problem we can revert the behaviour.
I also prefer this behaviour because the code is simpler/cleaner :P

Mr.doob 13 år sedan
förälder
incheckning
de9958b642

+ 11 - 12
build/three.min.js

@@ -72,10 +72,10 @@ THREE.Object3D=function(){this.id=THREE.Object3DCount++;this.name="";this.proper
 true;this.quaternion=new THREE.Quaternion;this.useQuaternion=false;this.boundRadius=0;this.boundRadiusScale=1;this.visible=true;this.receiveShadow=this.castShadow=false;this.frustumCulled=true;this._vector=new THREE.Vector3};
 THREE.Object3D.prototype={constructor:THREE.Object3D,applyMatrix:function(a){this.matrix.multiply(a,this.matrix);this.scale.getScaleFromMatrix(this.matrix);a=(new THREE.Matrix4).extractRotation(this.matrix);this.rotation.setEulerFromRotationMatrix(a,this.eulerOrder);this.position.getPositionFromMatrix(this.matrix)},translate:function(a,b){this.matrix.rotateAxis(b);this.position.addSelf(b.multiplyScalar(a))},translateX:function(a){this.translate(a,this._vector.set(1,0,0))},translateY:function(a){this.translate(a,
 this._vector.set(0,1,0))},translateZ:function(a){this.translate(a,this._vector.set(0,0,1))},localToWorld:function(a){return this.matrixWorld.multiplyVector3(a)},worldToLocal:function(a){return THREE.Object3D.__m1.getInverse(this.matrixWorld).multiplyVector3(a)},lookAt:function(a){this.matrix.lookAt(a,this.position,this.up);this.rotationAutoUpdate&&this.rotation.setEulerFromRotationMatrix(this.matrix,this.eulerOrder)},add:function(a){if(a===this)console.warn("THREE.Object3D.add: An object can't be added as a child of itself.");
-else if(a instanceof THREE.Object3D){a.parent!==void 0&&a.parent.remove(a);a.parent=this;this.children.push(a);for(var b=this;b.parent!==void 0;)b=b.parent;b!==void 0&&b instanceof THREE.Scene&&b.__addObject(a)}},remove:function(a){var b=this.children.indexOf(a);if(b!==-1){a.parent=void 0;this.children.splice(b,1);for(b=this;b.parent!==void 0;)b=b.parent;b!==void 0&&b instanceof THREE.Scene&&b.__removeObject(a)}},getChildByName:function(a,b){var c,d,f;c=0;for(d=this.children.length;c<d;c++){f=this.children[c];
-if(f.name===a)return f;if(b){f=f.getChildByName(a,b);if(f!==void 0)return f}}},getDescendants:function(a){a===void 0&&(a=[]);Array.prototype.push.apply(a,this.children);for(var b=0,c=this.children.length;b<c;b++)this.children[b].getDescendants(a);return a},updateMatrix:function(){this.matrix.setPosition(this.position);this.useQuaternion===false?this.matrix.setRotationFromEuler(this.rotation,this.eulerOrder):this.matrix.setRotationFromQuaternion(this.quaternion);if(this.scale.x!==1||this.scale.y!==
-1||this.scale.z!==1){this.matrix.scale(this.scale);this.boundRadiusScale=Math.max(this.scale.x,Math.max(this.scale.y,this.scale.z))}this.matrixWorldNeedsUpdate=true},updateMatrixWorld:function(a){this.matrixAutoUpdate===true&&this.updateMatrix();if(this.matrixWorldNeedsUpdate===true||a===true){this.parent===void 0?this.matrixWorld.copy(this.matrix):this.matrixWorld.multiply(this.parent.matrixWorld,this.matrix);this.matrixWorldNeedsUpdate=false;a=true}for(var b=0,c=this.children.length;b<c;b++)this.children[b].updateMatrixWorld(a)},
-clone:function(){}};THREE.Object3D.__m1=new THREE.Matrix4;THREE.Object3D.defaultEulerOrder="XYZ";THREE.Object3DCount=0;
+else if(a instanceof THREE.Object3D){a.parent!==void 0&&a.parent.remove(a);a.parent=this;this.children.push(a);for(var b=this;b.parent!==void 0;)b=b.parent;b!==void 0&&b instanceof THREE.Scene&&b.__addObject(a)}},remove:function(a){var b=this.children.indexOf(a);if(b!==-1){a.parent=void 0;this.children.splice(b,1);for(b=this;b.parent!==void 0;)b=b.parent;b!==void 0&&b instanceof THREE.Scene&&b.__removeObject(a)}},traverse:function(a){a(this);for(var b=0,c=this.children.length;b<c;b++)this.children[b].traverse(a)},
+getChildByName:function(a,b){for(var c=0,d=this.children.length;c<d;c++){var f=this.children[c];if(f.name===a)return f;if(b===true){f=f.getChildByName(a,b);if(f!==void 0)return f}}},getDescendants:function(a){a===void 0&&(a=[]);Array.prototype.push.apply(a,this.children);for(var b=0,c=this.children.length;b<c;b++)this.children[b].getDescendants(a);return a},updateMatrix:function(){this.matrix.setPosition(this.position);this.useQuaternion===false?this.matrix.setRotationFromEuler(this.rotation,this.eulerOrder):
+this.matrix.setRotationFromQuaternion(this.quaternion);if(this.scale.x!==1||this.scale.y!==1||this.scale.z!==1){this.matrix.scale(this.scale);this.boundRadiusScale=Math.max(this.scale.x,Math.max(this.scale.y,this.scale.z))}this.matrixWorldNeedsUpdate=true},updateMatrixWorld:function(a){this.matrixAutoUpdate===true&&this.updateMatrix();if(this.matrixWorldNeedsUpdate===true||a===true){this.parent===void 0?this.matrixWorld.copy(this.matrix):this.matrixWorld.multiply(this.parent.matrixWorld,this.matrix);
+this.matrixWorldNeedsUpdate=false;a=true}for(var b=0,c=this.children.length;b<c;b++)this.children[b].updateMatrixWorld(a)},clone:function(){}};THREE.Object3D.__m1=new THREE.Matrix4;THREE.Object3D.defaultEulerOrder="XYZ";THREE.Object3DCount=0;
 THREE.Projector=function(){function a(){if(e===h){var a=new THREE.RenderableObject;g.push(a);h++;e++;return a}return g[e++]}function b(){if(j===n){var a=new THREE.RenderableVertex;l.push(a);n++;j++;return a}return l[j++]}function c(a,b){return b.z-a.z}function d(a,b){var c=0,d=1,f=a.z+a.w,e=b.z+b.w,g=-a.z+a.w,h=-b.z+b.w;if(f>=0&&e>=0&&g>=0&&h>=0)return true;if(f<0&&e<0||g<0&&h<0)return false;f<0?c=Math.max(c,f/(f-e)):e<0&&(d=Math.min(d,f/(f-e)));g<0?c=Math.max(c,g/(g-h)):h<0&&(d=Math.min(d,g/(g-h)));
 if(d<c)return false;a.lerpSelf(b,c);b.lerpSelf(a,1-d);return true}var f,e,g=[],h=0,i,j,l=[],n=0,m,q,o=[],p=0,r,t=[],u=0,v,s,z=[],w=0,A,J,D=[],F=0,B={objects:[],sprites:[],lights:[],elements:[]},E=new THREE.Vector3,H=new THREE.Vector4,Q=new THREE.Matrix4,L=new THREE.Matrix4,K=new THREE.Frustum,I=new THREE.Vector4,M=new THREE.Vector4;this.projectVector=function(a,b){b.matrixWorldInverse.getInverse(b.matrixWorld);Q.multiply(b.projectionMatrix,b.matrixWorldInverse);Q.multiplyVector3(a);return a};this.unprojectVector=
 function(a,b){b.projectionMatrixInverse.getInverse(b.projectionMatrix);Q.multiply(b.matrixWorld,b.projectionMatrixInverse);Q.multiplyVector3(a);return a};this.pickingRay=function(a,b){var c;a.z=-1;c=new THREE.Vector3(a.x,a.y,1);this.unprojectVector(a,b);this.unprojectVector(c,b);c.subSelf(a).normalize();return new THREE.Ray(a,c)};this.projectScene=function(g,h,n,N){var fa=h.near,S=h.far,ra=false,wa,O,ga,P,X,ia,$,ca,Ja,ua,La,Wa,oa,Xa,kb,Ta;J=s=r=q=0;B.elements.length=0;g.updateMatrixWorld();h.parent===
@@ -519,14 +519,13 @@ h[7]);d.width=h[4];d.height=h[3];h=h[1]+4;e=d.width;g=d.height;for(i=0;i<d.mipma
 for(var h=g.getImageData(0,0,d,f).data,i=g.createImageData(d,f),j=i.data,l=0;l<d;l++)for(var n=0;n<f;n++){var m=n-1<0?0:n-1,q=n+1>f-1?f-1:n+1,o=l-1<0?0:l-1,p=l+1>d-1?d-1:l+1,r=[],t=[0,0,h[(n*d+l)*4]/255*b];r.push([-1,0,h[(n*d+o)*4]/255*b]);r.push([-1,-1,h[(m*d+o)*4]/255*b]);r.push([0,-1,h[(m*d+l)*4]/255*b]);r.push([1,-1,h[(m*d+p)*4]/255*b]);r.push([1,0,h[(n*d+p)*4]/255*b]);r.push([1,1,h[(q*d+p)*4]/255*b]);r.push([0,1,h[(q*d+l)*4]/255*b]);r.push([-1,1,h[(q*d+o)*4]/255*b]);m=[];o=r.length;for(q=0;q<
 o;q++){var p=r[q],u=r[(q+1)%o],p=[p[0]-t[0],p[1]-t[1],p[2]-t[2]],u=[u[0]-t[0],u[1]-t[1],u[2]-t[2]];m.push(c([p[1]*u[2]-p[2]*u[1],p[2]*u[0]-p[0]*u[2],p[0]*u[1]-p[1]*u[0]]))}r=[0,0,0];for(q=0;q<m.length;q++){r[0]=r[0]+m[q][0];r[1]=r[1]+m[q][1];r[2]=r[2]+m[q][2]}r[0]=r[0]/m.length;r[1]=r[1]/m.length;r[2]=r[2]/m.length;t=(n*d+l)*4;j[t]=(r[0]+1)/2*255|0;j[t+1]=(r[1]+1)/2*255|0;j[t+2]=r[2]*255|0;j[t+3]=255}g.putImageData(i,0,0);return e},generateDataTexture:function(a,b,c){for(var d=a*b,f=new Uint8Array(3*
 d),e=Math.floor(c.r*255),g=Math.floor(c.g*255),c=Math.floor(c.b*255),h=0;h<d;h++){f[h*3]=e;f[h*3+1]=g;f[h*3+2]=c}a=new THREE.DataTexture(f,a,b,THREE.RGBFormat);a.needsUpdate=true;return a}};
-THREE.SceneUtils={showHierarchy:function(a,b){THREE.SceneUtils.traverseHierarchy(a,function(a){a.visible=b})},traverseHierarchy:function(a,b){var c,d,f=a.children.length;for(d=0;d<f;d++){c=a.children[d];b(c);THREE.SceneUtils.traverseHierarchy(c,b)}},createMultiMaterialObject:function(a,b){var c,d=b.length,f=new THREE.Object3D;for(c=0;c<d;c++){var e=new THREE.Mesh(a,b[c]);f.add(e)}return f},cloneObject:function(a){var b;if(a instanceof THREE.MorphAnimMesh){b=new THREE.MorphAnimMesh(a.geometry,a.material);
-b.duration=a.duration;b.mirroredLoop=a.mirroredLoop;b.time=a.time;b.lastKeyframe=a.lastKeyframe;b.currentKeyframe=a.currentKeyframe;b.direction=a.direction;b.directionBackwards=a.directionBackwards}else if(a instanceof THREE.SkinnedMesh)b=new THREE.SkinnedMesh(a.geometry,a.material,a.useVertexTexture);else if(a instanceof THREE.Mesh)b=new THREE.Mesh(a.geometry,a.material);else if(a instanceof THREE.Line)b=new THREE.Line(a.geometry,a.material,a.type);else if(a instanceof THREE.Ribbon)b=new THREE.Ribbon(a.geometry,
-a.material);else if(a instanceof THREE.ParticleSystem){b=new THREE.ParticleSystem(a.geometry,a.material);b.sortParticles=a.sortParticles}else if(a instanceof THREE.Particle)b=new THREE.Particle(a.material);else if(a instanceof THREE.Sprite){b=new THREE.Sprite({});b.color.copy(a.color);b.map=a.map;b.blending=a.blending;b.useScreenCoordinates=a.useScreenCoordinates;b.mergeWith3D=a.mergeWith3D;b.affectedByDistance=a.affectedByDistance;b.scaleByViewport=a.scaleByViewport;b.alignment=a.alignment;b.rotation3d.copy(a.rotation3d);
-b.rotation=a.rotation;b.opacity=a.opacity;b.uvOffset.copy(a.uvOffset);b.uvScale.copy(a.uvScale)}else a instanceof THREE.LOD?b=new THREE.LOD:a instanceof THREE.Object3D&&(b=new THREE.Object3D);b.name=a.name;b.parent=a.parent;b.up.copy(a.up);b.position.copy(a.position);b.rotation instanceof THREE.Vector3&&b.rotation.copy(a.rotation);b.eulerOrder=a.eulerOrder;b.scale.copy(a.scale);b.dynamic=a.dynamic;b.renderDepth=a.renderDepth;b.rotationAutoUpdate=a.rotationAutoUpdate;b.matrix.copy(a.matrix);b.matrixWorld.copy(a.matrixWorld);
-b.matrixRotationWorld.copy(a.matrixRotationWorld);b.matrixAutoUpdate=a.matrixAutoUpdate;b.matrixWorldNeedsUpdate=a.matrixWorldNeedsUpdate;b.quaternion.copy(a.quaternion);b.useQuaternion=a.useQuaternion;b.boundRadius=a.boundRadius;b.boundRadiusScale=a.boundRadiusScale;b.visible=a.visible;b.castShadow=a.castShadow;b.receiveShadow=a.receiveShadow;b.frustumCulled=a.frustumCulled;for(var c=0;c<a.children.length;c++){var d=THREE.SceneUtils.cloneObject(a.children[c]);b.children[c]=d;d.parent=b}if(a instanceof
-THREE.LOD)for(c=0;c<a.LODs.length;c++)b.LODs[c]={visibleAtDistance:a.LODs[c].visibleAtDistance,object3D:b.children[c]};return b},detach:function(a,b,c){a.applyMatrix(b.matrixWorld);b.remove(a);c.add(a)},attach:function(a,b,c){var d=new THREE.Matrix4;d.getInverse(c.matrixWorld);a.applyMatrix(d);b.remove(a);c.add(a)}};
-THREE.WebGLRenderer&&(THREE.ShaderUtils={lib:{fresnel:{uniforms:{mRefractionRatio:{type:"f",value:1.02},mFresnelBias:{type:"f",value:0.1},mFresnelPower:{type:"f",value:2},mFresnelScale:{type:"f",value:1},tCube:{type:"t",value:null}},fragmentShader:"uniform samplerCube tCube;\nvarying vec3 vReflect;\nvarying vec3 vRefract[3];\nvarying float vReflectionFactor;\nvoid main() {\nvec4 reflectedColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );\nvec4 refractedColor = vec4( 1.0, 1.0, 1.0, 1.0 );\nrefractedColor.r = textureCube( tCube, vec3( -vRefract[0].x, vRefract[0].yz ) ).r;\nrefractedColor.g = textureCube( tCube, vec3( -vRefract[1].x, vRefract[1].yz ) ).g;\nrefractedColor.b = textureCube( tCube, vec3( -vRefract[2].x, vRefract[2].yz ) ).b;\nrefractedColor.a = 1.0;\ngl_FragColor = mix( refractedColor, reflectedColor, clamp( vReflectionFactor, 0.0, 1.0 ) );\n}",
-vertexShader:"uniform float mRefractionRatio;\nuniform float mFresnelBias;\nuniform float mFresnelScale;\nuniform float mFresnelPower;\nvarying vec3 vReflect;\nvarying vec3 vRefract[3];\nvarying float vReflectionFactor;\nvoid main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\nvec4 mPosition = modelMatrix * vec4( position, 1.0 );\nvec3 nWorld = normalize( mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal );\nvec3 I = mPosition.xyz - cameraPosition;\nvReflect = reflect( I, nWorld );\nvRefract[0] = refract( normalize( I ), nWorld, mRefractionRatio );\nvRefract[1] = refract( normalize( I ), nWorld, mRefractionRatio * 0.99 );\nvRefract[2] = refract( normalize( I ), nWorld, mRefractionRatio * 0.98 );\nvReflectionFactor = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( I ), nWorld ), mFresnelPower );\ngl_Position = projectionMatrix * mvPosition;\n}"},
+THREE.SceneUtils={createMultiMaterialObject:function(a,b){for(var c=new THREE.Object3D,d=0,f=b.length;d<f;d++)c.add(new THREE.Mesh(a,b[d]));return c},cloneObject:function(a){var b;if(a instanceof THREE.MorphAnimMesh){b=new THREE.MorphAnimMesh(a.geometry,a.material);b.duration=a.duration;b.mirroredLoop=a.mirroredLoop;b.time=a.time;b.lastKeyframe=a.lastKeyframe;b.currentKeyframe=a.currentKeyframe;b.direction=a.direction;b.directionBackwards=a.directionBackwards}else if(a instanceof THREE.SkinnedMesh)b=
+new THREE.SkinnedMesh(a.geometry,a.material,a.useVertexTexture);else if(a instanceof THREE.Mesh)b=new THREE.Mesh(a.geometry,a.material);else if(a instanceof THREE.Line)b=new THREE.Line(a.geometry,a.material,a.type);else if(a instanceof THREE.Ribbon)b=new THREE.Ribbon(a.geometry,a.material);else if(a instanceof THREE.ParticleSystem){b=new THREE.ParticleSystem(a.geometry,a.material);b.sortParticles=a.sortParticles}else if(a instanceof THREE.Particle)b=new THREE.Particle(a.material);else if(a instanceof
+THREE.Sprite){b=new THREE.Sprite({});b.color.copy(a.color);b.map=a.map;b.blending=a.blending;b.useScreenCoordinates=a.useScreenCoordinates;b.mergeWith3D=a.mergeWith3D;b.affectedByDistance=a.affectedByDistance;b.scaleByViewport=a.scaleByViewport;b.alignment=a.alignment;b.rotation3d.copy(a.rotation3d);b.rotation=a.rotation;b.opacity=a.opacity;b.uvOffset.copy(a.uvOffset);b.uvScale.copy(a.uvScale)}else a instanceof THREE.LOD?b=new THREE.LOD:a instanceof THREE.Object3D&&(b=new THREE.Object3D);b.name=a.name;
+b.parent=a.parent;b.up.copy(a.up);b.position.copy(a.position);b.rotation instanceof THREE.Vector3&&b.rotation.copy(a.rotation);b.eulerOrder=a.eulerOrder;b.scale.copy(a.scale);b.dynamic=a.dynamic;b.renderDepth=a.renderDepth;b.rotationAutoUpdate=a.rotationAutoUpdate;b.matrix.copy(a.matrix);b.matrixWorld.copy(a.matrixWorld);b.matrixRotationWorld.copy(a.matrixRotationWorld);b.matrixAutoUpdate=a.matrixAutoUpdate;b.matrixWorldNeedsUpdate=a.matrixWorldNeedsUpdate;b.quaternion.copy(a.quaternion);b.useQuaternion=
+a.useQuaternion;b.boundRadius=a.boundRadius;b.boundRadiusScale=a.boundRadiusScale;b.visible=a.visible;b.castShadow=a.castShadow;b.receiveShadow=a.receiveShadow;b.frustumCulled=a.frustumCulled;for(var c=0;c<a.children.length;c++){var d=THREE.SceneUtils.cloneObject(a.children[c]);b.children[c]=d;d.parent=b}if(a instanceof THREE.LOD)for(c=0;c<a.LODs.length;c++)b.LODs[c]={visibleAtDistance:a.LODs[c].visibleAtDistance,object3D:b.children[c]};return b},detach:function(a,b,c){a.applyMatrix(b.matrixWorld);
+b.remove(a);c.add(a)},attach:function(a,b,c){var d=new THREE.Matrix4;d.getInverse(c.matrixWorld);a.applyMatrix(d);b.remove(a);c.add(a)}};
+THREE.WebGLRenderer&&(THREE.ShaderUtils={lib:{fresnel:{uniforms:{mRefractionRatio:{type:"f",value:1.02},mFresnelBias:{type:"f",value:0.1},mFresnelPower:{type:"f",value:2},mFresnelScale:{type:"f",value:1},tCube:{type:"t",value:null}},fragmentShader:"uniform samplerCube tCube;\nvarying vec3 vReflect;\nvarying vec3 vRefract[3];\nvarying float vReflectionFactor;\nvoid main() {\nvec4 reflectedColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );\nvec4 refractedColor = vec4( 1.0, 1.0, 1.0, 1.0 );\nrefractedColor.r = textureCube( tCube, vec3( -vRefract[0].x, vRefract[0].yz ) ).r;\nrefractedColor.g = textureCube( tCube, vec3( -vRefract[1].x, vRefract[1].yz ) ).g;\nrefractedColor.b = textureCube( tCube, vec3( -vRefract[2].x, vRefract[2].yz ) ).b;\nrefractedColor.a = 1.0;\ngl_FragColor = mix( refractedColor, reflectedColor, clamp( vReflectionFactor, 0.0, 1.0 ) );\n}",vertexShader:"uniform float mRefractionRatio;\nuniform float mFresnelBias;\nuniform float mFresnelScale;\nuniform float mFresnelPower;\nvarying vec3 vReflect;\nvarying vec3 vRefract[3];\nvarying float vReflectionFactor;\nvoid main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\nvec4 mPosition = modelMatrix * vec4( position, 1.0 );\nvec3 nWorld = normalize( mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal );\nvec3 I = mPosition.xyz - cameraPosition;\nvReflect = reflect( I, nWorld );\nvRefract[0] = refract( normalize( I ), nWorld, mRefractionRatio );\nvRefract[1] = refract( normalize( I ), nWorld, mRefractionRatio * 0.99 );\nvRefract[2] = refract( normalize( I ), nWorld, mRefractionRatio * 0.98 );\nvReflectionFactor = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( I ), nWorld ), mFresnelPower );\ngl_Position = projectionMatrix * mvPosition;\n}"},
 normal:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{enableAO:{type:"i",value:0},enableDiffuse:{type:"i",value:0},enableSpecular:{type:"i",value:0},enableReflection:{type:"i",value:0},enableDisplacement:{type:"i",value:0},tDisplacement:{type:"t",value:null},tDiffuse:{type:"t",value:null},tCube:{type:"t",value:null},tNormal:{type:"t",value:null},tSpecular:{type:"t",value:null},tAO:{type:"t",value:null},uNormalScale:{type:"v2",value:new THREE.Vector2(1,
 1)},uDisplacementBias:{type:"f",value:0},uDisplacementScale:{type:"f",value:1},uDiffuseColor:{type:"c",value:new THREE.Color(16777215)},uSpecularColor:{type:"c",value:new THREE.Color(1118481)},uAmbientColor:{type:"c",value:new THREE.Color(16777215)},uShininess:{type:"f",value:30},uOpacity:{type:"f",value:1},useRefract:{type:"i",value:0},uRefractionRatio:{type:"f",value:0.98},uReflectivity:{type:"f",value:0.5},uOffset:{type:"v2",value:new THREE.Vector2(0,0)},uRepeat:{type:"v2",value:new THREE.Vector2(1,
 1)},wrapRGB:{type:"v3",value:new THREE.Vector3(1,1,1)}}]),fragmentShader:["uniform vec3 uAmbientColor;\nuniform vec3 uDiffuseColor;\nuniform vec3 uSpecularColor;\nuniform float uShininess;\nuniform float uOpacity;\nuniform bool enableDiffuse;\nuniform bool enableSpecular;\nuniform bool enableAO;\nuniform bool enableReflection;\nuniform sampler2D tDiffuse;\nuniform sampler2D tNormal;\nuniform sampler2D tSpecular;\nuniform sampler2D tAO;\nuniform samplerCube tCube;\nuniform vec2 uNormalScale;\nuniform bool useRefract;\nuniform float uRefractionRatio;\nuniform float uReflectivity;\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\nuniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_HEMI_LIGHTS > 0\nuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightPosition[ MAX_HEMI_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngle[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif\nvarying vec3 vWorldPosition;\nvarying vec3 vViewPosition;",

+ 218 - 216
examples/js/loaders/MTLLoader.js

@@ -6,127 +6,127 @@
 
 THREE.MTLLoader = function( baseUrl, options ) {
 
-    THREE.EventTarget.call( this );
-    this.baseUrl = baseUrl;
-    this.options = options;
+	THREE.EventTarget.call( this );
+	this.baseUrl = baseUrl;
+	this.options = options;
 
 };
 
 THREE.MTLLoader.prototype = {
 
-    /**
-     * Loads a MTL file
-     *
-     * Loading progress is indicated by the following events:
-     *   "load" event (successful loading): type = 'load', content = THREE.MTLLoader.MaterialCreator
-     *   "error" event (error loading): type = 'load', message
-     *   "progress" event (progress loading): type = 'progress', loaded, total
-     *
-     * @param url - location of MTL file
-     */
-    load: function( url ) {
+	/**
+	 * Loads a MTL file
+	 *
+	 * Loading progress is indicated by the following events:
+	 *   "load" event (successful loading): type = 'load', content = THREE.MTLLoader.MaterialCreator
+	 *   "error" event (error loading): type = 'load', message
+	 *   "progress" event (progress loading): type = 'progress', loaded, total
+	 *
+	 * @param url - location of MTL file
+	 */
+	load: function( url ) {
 
-        var scope = this;
-        var xhr = new XMLHttpRequest();
+		var scope = this;
+		var xhr = new XMLHttpRequest();
 
-        function onloaded( event ) {
+		function onloaded( event ) {
 
-            if ( event.target.status === 200 || event.target.status === 0 ) {
+			if ( event.target.status === 200 || event.target.status === 0 ) {
 
-                var materialCreator = scope.parse( event.target.responseText );
+				var materialCreator = scope.parse( event.target.responseText );
 
-                // Notify caller, that I'm done
+				// Notify caller, that I'm done
 
-                scope.dispatchEvent( { type: 'load', content: materialCreator } );
+				scope.dispatchEvent( { type: 'load', content: materialCreator } );
 
-            } else {
+			} else {
 
-                scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']',
-                    response: event.target.responseText } );
+				scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']',
+					response: event.target.responseText } );
 
-            }
+			}
 
-        }
+		}
 
-        xhr.addEventListener( 'load', onloaded, false );
+		xhr.addEventListener( 'load', onloaded, false );
 
-        xhr.addEventListener( 'progress', function ( event ) {
+		xhr.addEventListener( 'progress', function ( event ) {
 
-            scope.dispatchEvent( { type: 'progress', loaded: event.loaded, total: event.total } );
+			scope.dispatchEvent( { type: 'progress', loaded: event.loaded, total: event.total } );
 
-        }, false );
+		}, false );
 
-        xhr.addEventListener( 'error', function () {
+		xhr.addEventListener( 'error', function () {
 
-            scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']' } );
+			scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']' } );
 
-        }, false );
+		}, false );
 
-        xhr.open( 'GET', url, true );
-        xhr.send( null );
-    },
+		xhr.open( 'GET', url, true );
+		xhr.send( null );
+	},
 
-    /**
-     * Parses loaded MTL file
-     * @param text - Content of MTL file
-     * @return {THREE.MTLLoader.MaterialCreator}
-     */
-    parse: function( text ) {
+	/**
+	 * Parses loaded MTL file
+	 * @param text - Content of MTL file
+	 * @return {THREE.MTLLoader.MaterialCreator}
+	 */
+	parse: function( text ) {
 
-        var lines = text.split( "\n" );
-        var info = {};
-        var delimiter_pattern = /\s+/;
-        var materialsInfo = {};
+		var lines = text.split( "\n" );
+		var info = {};
+		var delimiter_pattern = /\s+/;
+		var materialsInfo = {};
 
 			for ( var i = 0; i < lines.length; i ++ ) {
 
 			var line = lines[ i ];
-            line = line.trim();
+			line = line.trim();
 
-            if ( line.length === 0 || line.charAt( 0 ) === '#' ) {
+			if ( line.length === 0 || line.charAt( 0 ) === '#' ) {
 
-                // Blank line or comment ignore
-                continue;
+				// Blank line or comment ignore
+				continue;
 
-            }
+			}
 
-            var pos = line.indexOf( ' ' );
+			var pos = line.indexOf( ' ' );
 
 			var key = ( pos >= 0 ) ? line.substring( 0, pos) : line;
-            key = key.toLowerCase();
+			key = key.toLowerCase();
 
-            var value = ( pos >= 0 ) ? line.substring( pos + 1 ) : "";
-            value = value.trim();
+			var value = ( pos >= 0 ) ? line.substring( pos + 1 ) : "";
+			value = value.trim();
 
-            if ( key === "newmtl" ) {
+			if ( key === "newmtl" ) {
 
-                // New material
+				// New material
 
-                info = { name: value };
-                materialsInfo[ value ] = info;
+				info = { name: value };
+				materialsInfo[ value ] = info;
 
-            } else if ( info ) {
+			} else if ( info ) {
 
-                if ( key === "ka" || key === "kd" || key === "ks" ) {
+				if ( key === "ka" || key === "kd" || key === "ks" ) {
 
-                    var ss = value.split( delimiter_pattern, 3 );
-                    info[ key ] = [ parseFloat( ss[0] ), parseFloat( ss[1] ), parseFloat( ss[2] ) ];
+					var ss = value.split( delimiter_pattern, 3 );
+					info[ key ] = [ parseFloat( ss[0] ), parseFloat( ss[1] ), parseFloat( ss[2] ) ];
 
-                } else {
+				} else {
 
-                    info[ key ] = value;
+					info[ key ] = value;
 
-                }
+				}
 
-            }
+			}
 
-        }
+		}
 
-        var materialCreator = new THREE.MTLLoader.MaterialCreator( this.baseUrl, this.options );
-        materialCreator.setMaterials( materialsInfo );
-        return materialCreator;
+		var materialCreator = new THREE.MTLLoader.MaterialCreator( this.baseUrl, this.options );
+		materialCreator.setMaterials( materialsInfo );
+		return materialCreator;
 
-    }
+	}
 
 };
 
@@ -146,179 +146,181 @@ THREE.MTLLoader.prototype = {
  *                                      Default: false (d = 1 is fully opaque)
  * @constructor
  */
+
 THREE.MTLLoader.MaterialCreator = function( baseUrl, options ) {
 
-    THREE.EventTarget.call( this );
-    this.baseUrl = baseUrl;
-    this.options = options;
-    this.materialsInfo = {};
-    this.materials = {};
-    this.materialsArray = [];
-    this.nameLookup = {};
+	THREE.EventTarget.call( this );
+
+	this.baseUrl = baseUrl;
+	this.options = options;
+	this.materialsInfo = {};
+	this.materials = {};
+	this.materialsArray = [];
+	this.nameLookup = {};
 
-    this.side = ( this.options && this.options.side )? this.options.side: THREE.FrontSide;
-    this.wrap = ( this.options && this.options.wrap )? this.options.wrap: THREE.RepeatWrapping;
+	this.side = ( this.options && this.options.side )? this.options.side: THREE.FrontSide;
+	this.wrap = ( this.options && this.options.wrap )? this.options.wrap: THREE.RepeatWrapping;
 
 };
 
 THREE.MTLLoader.MaterialCreator.prototype = {
 
-    setMaterials: function( materialsInfo ) {
+	setMaterials: function( materialsInfo ) {
 
-        this.materialsInfo = this.convert( materialsInfo );
-        this.materials = {};
-        this.materialsArray = [];
-        this.nameLookup = {};
+		this.materialsInfo = this.convert( materialsInfo );
+		this.materials = {};
+		this.materialsArray = [];
+		this.nameLookup = {};
 
-    },
+	},
 
-    convert: function( materialsInfo ) {
+	convert: function( materialsInfo ) {
 
-        if ( !this.options ) return materialsInfo;
+		if ( !this.options ) return materialsInfo;
 
-        var converted = {};
+		var converted = {};
 
-        for ( var mn in materialsInfo ) {
+		for ( var mn in materialsInfo ) {
 
-            // Convert materials info into normalized form based on options
+			// Convert materials info into normalized form based on options
 
-            var mat = materialsInfo[ mn ];
+			var mat = materialsInfo[ mn ];
 
-            var covmat = {};
+			var covmat = {};
 
-            converted[ mn ] = covmat;
+			converted[ mn ] = covmat;
 
-            for ( var prop in mat ) {
+			for ( var prop in mat ) {
 
-                var save = true;
-                var value = mat[ prop ];
-                var lprop = prop.toLowerCase();
+				var save = true;
+				var value = mat[ prop ];
+				var lprop = prop.toLowerCase();
 
-                switch ( lprop ) {
+				switch ( lprop ) {
 
-                    case 'kd':
-                    case 'ka':
-                    case 'ks':
+					case 'kd':
+					case 'ka':
+					case 'ks':
 
-                        // Diffuse color (color under white light) using RGB values
+						// Diffuse color (color under white light) using RGB values
 
-                        if ( this.options && this.options.normalizeRGB ) {
+						if ( this.options && this.options.normalizeRGB ) {
 
-                            value =  [ value[0]/255, value[1]/255, value[2]/255 ];
+							value = [ value[ 0 ] / 255, value[ 1 ] / 255, value[ 2 ] / 255 ];
 
-                        }
+						}
 
-                        if ( this.options && this.options.ignoreZeroRGBs ) {
+						if ( this.options && this.options.ignoreZeroRGBs ) {
 
-                            if ( value[0] === 0.0 && value[1] === 0.0 && value[1] === 0.0 ) {
+							if ( value[ 0 ] === 0 && value[ 1 ] === 0 && value[ 1 ] === 0 ) {
 
-                                // ignore
+								// ignore
 
-                                save = false;
+								save = false;
 
-                            }
-                        }
+							}
+						}
 
-                        break;
+						break;
 
-                    case 'd':
+					case 'd':
 
-                        // According to MTL format (http://paulbourke.net/dataformats/mtl/):
-                        //   d is dissolve for current material
-                        //   factor of 1.0 is fully opaque, a factor of 0 is fully dissolved (completely transparent)
+						// According to MTL format (http://paulbourke.net/dataformats/mtl/):
+						//   d is dissolve for current material
+						//   factor of 1.0 is fully opaque, a factor of 0 is fully dissolved (completely transparent)
 
-                        if ( this.options && this.options.invertTransparency ) {
+						if ( this.options && this.options.invertTransparency ) {
 
-                            value = 1 - value;
+							value = 1 - value;
 
-                        }
+						}
 
-                        break;
+						break;
 
-                    default:
+					default:
 
-                        break;
-                }
+						break;
+				}
 
-                if ( save ) {
+				if ( save ) {
 
-                    covmat[lprop] = value;
+					covmat[ lprop ] = value;
 
-                }
+				}
 
-            }
+			}
 
-        }
+		}
 
-        return converted;
+		return converted;
 
-    },
+	},
 
-    preload: function () {
+	preload: function () {
 
-        for ( var mn in this.materialsInfo ) {
+		for ( var mn in this.materialsInfo ) {
 
-            this.create( mn );
+			this.create( mn );
 
-        }
+		}
 
-    },
+	},
 
-    getIndex: function( materialName ) {
+	getIndex: function( materialName ) {
 
-        return this.nameLookup[ materialName ];
+		return this.nameLookup[ materialName ];
 
-    },
+	},
 
-    getAsArray: function() {
+	getAsArray: function() {
 
-        var index = 0;
+		var index = 0;
 
-        for ( var mn in this.materialsInfo ) {
+		for ( var mn in this.materialsInfo ) {
 
-            this.materialsArray[ index ] = this.create( mn );
-            this.nameLookup[ mn ] = index;
-            index ++;
+			this.materialsArray[ index ] = this.create( mn );
+			this.nameLookup[ mn ] = index;
+			index ++;
 
-        }
+		}
 
-        return this.materialsArray;
+		return this.materialsArray;
 
-    },
+	},
 
-    create: function ( materialName ) {
+	create: function ( materialName ) {
 
-        if ( this.materials[ materialName ] === undefined ) {
+		if ( this.materials[ materialName ] === undefined ) {
 
-            this.createMaterial_( materialName );
+			this.createMaterial_( materialName );
 
-        }
+		}
 
-        return this.materials[ materialName ];
+		return this.materials[ materialName ];
 
-    },
+	},
 
-    createMaterial_: function ( materialName ) {
+	createMaterial_: function ( materialName ) {
 
-        // Create material
+		// Create material
 
-        var mat = this.materialsInfo[ materialName ];
-        var params = {
+		var mat = this.materialsInfo[ materialName ];
+		var params = {
 
-            name: materialName,
-            side: this.side
+			name: materialName,
+			side: this.side
 
-        };
+		};
 
-        for ( var prop in mat ) {
+		for ( var prop in mat ) {
 
-            var value = mat[ prop ];
+			var value = mat[ prop ];
 
-            switch ( prop.toLowerCase() ) {
+			switch ( prop.toLowerCase() ) {
 
-                // Ns is material specular exponent
+				// Ns is material specular exponent
 
-                case 'kd':
+				case 'kd':
 
 					// Diffuse color (color under white light) using RGB values
 
@@ -326,73 +328,73 @@ THREE.MTLLoader.MaterialCreator.prototype = {
 
 					break;
 
-                case 'ka':
+				case 'ka':
 
-                    // Ambient color (color under shadow) using RGB values
+					// Ambient color (color under shadow) using RGB values
 
-                    params[ 'ambient' ] = new THREE.Color().setRGB( value[0], value[1], value[2] );
+					params[ 'ambient' ] = new THREE.Color().setRGB( value[0], value[1], value[2] );
 
 					break;
 
-                case 'ks':
+				case 'ks':
 
-                    // Specular color (color when light is reflected from shiny surface) using RGB values
-                    params[ 'specular' ] = new THREE.Color().setRGB( value[0], value[1], value[2] );
+					// Specular color (color when light is reflected from shiny surface) using RGB values
+					params[ 'specular' ] = new THREE.Color().setRGB( value[0], value[1], value[2] );
 
-                    break;
+					break;
 
-                case 'map_kd':
+				case 'map_kd':
 
-                    // Diffuse texture map
+					// Diffuse texture map
 
-                    params[ 'map' ] = THREE.MTLLoader.loadTexture( this.baseUrl + value );
-                    params[ 'map' ].wrapS = this.wrap;
-                    params[ 'map' ].wrapT = this.wrap;
+					params[ 'map' ] = THREE.MTLLoader.loadTexture( this.baseUrl + value );
+					params[ 'map' ].wrapS = this.wrap;
+					params[ 'map' ].wrapT = this.wrap;
 
 					break;
 
-                case 'ns':
+				case 'ns':
 
-                    // The specular exponent (defines the focus of the specular highlight)
-                    // A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000.
+					// The specular exponent (defines the focus of the specular highlight)
+					// A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000.
 
 					params['shininess'] = value;
 
 					break;
 
-                case 'd':
+				case 'd':
 
-                    // According to MTL format (http://paulbourke.net/dataformats/mtl/):
-                    //   d is dissolve for current material
-                    //   factor of 1.0 is fully opaque, a factor of 0 is fully dissolved (completely transparent)
+					// According to MTL format (http://paulbourke.net/dataformats/mtl/):
+					//   d is dissolve for current material
+					//   factor of 1.0 is fully opaque, a factor of 0 is fully dissolved (completely transparent)
 
-                    if ( value < 1 ) {
+					if ( value < 1 ) {
 
-                        params['transparent'] = true;
-                        params['opacity'] = value;
+						params['transparent'] = true;
+						params['opacity'] = value;
 
-                    }
+					}
 
-                    break;
+					break;
 
-                default:
-                    break;
+				default:
+					break;
 
-            }
+			}
 
-        }
+		}
 
-        if ( params[ 'diffuse' ] ) {
+		if ( params[ 'diffuse' ] ) {
 
-            if ( !params[ 'ambient' ]) params[ 'ambient' ] = params[ 'diffuse' ];
-            params[ 'color' ] = params[ 'diffuse' ];
+			if ( !params[ 'ambient' ]) params[ 'ambient' ] = params[ 'diffuse' ];
+			params[ 'color' ] = params[ 'diffuse' ];
 
-        }
+		}
 
-        this.materials[ materialName ] = new THREE.MeshPhongMaterial( params );
-        return this.materials[ materialName ];
+		this.materials[ materialName ] = new THREE.MeshPhongMaterial( params );
+		return this.materials[ materialName ];
 
-    }
+	}
 
 };
 
@@ -436,19 +438,19 @@ THREE.MTLLoader.loadTexture = function ( url, mapping, onLoad, onError ) {
 
 THREE.MTLLoader.ensurePowerOfTwo_ = function ( image ) {
 
-    if ( ! THREE.MTLLoader.isPowerOfTwo_( image.width ) || ! THREE.MTLLoader.isPowerOfTwo_( image.height ) ) {
+	if ( ! THREE.MTLLoader.isPowerOfTwo_( image.width ) || ! THREE.MTLLoader.isPowerOfTwo_( image.height ) ) {
 
-        var canvas = document.createElement( "canvas" );
-        canvas.width = THREE.MTLLoader.nextHighestPowerOfTwo_( image.width );
-        canvas.height = THREE.MTLLoader.nextHighestPowerOfTwo_( image.height );
+		var canvas = document.createElement( "canvas" );
+		canvas.width = THREE.MTLLoader.nextHighestPowerOfTwo_( image.width );
+		canvas.height = THREE.MTLLoader.nextHighestPowerOfTwo_( image.height );
 
-        var ctx = canvas.getContext("2d");
-        ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height );
-        return canvas;
+		var ctx = canvas.getContext("2d");
+		ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height );
+		return canvas;
 
-    }
+	}
 
-    return image;
+	return image;
 
 };
 
@@ -460,15 +462,15 @@ THREE.MTLLoader.isPowerOfTwo_ = function ( x ) {
 
 THREE.MTLLoader.nextHighestPowerOfTwo_ = function( x ) {
 
-    --x;
+	--x;
 
-    for ( var i = 1; i < 32; i <<= 1 ) {
+	for ( var i = 1; i < 32; i <<= 1 ) {
 
-        x = x | x >> i;
+		x = x | x >> i;
 
-    }
+	}
 
-    return x + 1;
+	return x + 1;
 
 };
 

+ 330 - 310
examples/js/loaders/OBJMTLLoader.js

@@ -15,139 +15,144 @@ THREE.OBJMTLLoader.prototype = {
 
 	constructor: THREE.OBJMTLLoader,
 
-    /**
-     * Load a Wavefront OBJ file with materials (MTL file)
-     *
-     * Loading progress is indicated by the following events:
-     *   "load" event (successful loading): type = 'load', content = THREE.Object3D
-     *   "error" event (error loading): type = 'load', message
-     *   "progress" event (progress loading): type = 'progress', loaded, total
-     *
-     * If the MTL file cannot be loaded, then a MeshLambertMaterial is used as a default
-     * @param url - Location of OBJ file to load
-     * @param mtlfileurl - MTL file to load (optional, if not specified, attempts to use MTL specified in OBJ file)
-     * @param options - Options on how to interpret the material (see THREE.MTLLoader.MaterialCreator )
-     *
-     */
+	/**
+	 * Load a Wavefront OBJ file with materials (MTL file)
+	 *
+	 * Loading progress is indicated by the following events:
+	 *   "load" event (successful loading): type = 'load', content = THREE.Object3D
+	 *   "error" event (error loading): type = 'load', message
+	 *   "progress" event (progress loading): type = 'progress', loaded, total
+	 *
+	 * If the MTL file cannot be loaded, then a MeshLambertMaterial is used as a default
+	 * @param url - Location of OBJ file to load
+	 * @param mtlfileurl - MTL file to load (optional, if not specified, attempts to use MTL specified in OBJ file)
+	 * @param options - Options on how to interpret the material (see THREE.MTLLoader.MaterialCreator )
+	 */
 
 	load: function ( url, mtlfileurl, options ) {
 
 		var scope = this;
 		var xhr = new XMLHttpRequest();
 
-        var mtlDone;  // Is the MTL done (true if no MTL, error loading MTL, or MTL actually loaded)
-        var obj3d;    // Loaded model (from obj file)
-        var materialsCreator;  // Material creator is created when MTL file is loaded
+		var mtlDone;           // Is the MTL done (true if no MTL, error loading MTL, or MTL actually loaded)
+		var obj3d;             // Loaded model (from obj file)
+		var materialsCreator;  // Material creator is created when MTL file is loaded
 
-        // Loader for MTL
+		// Loader for MTL
 
-        var mtlLoader = new THREE.MTLLoader( url.substr( 0, url.lastIndexOf( "/" ) + 1 ), options );
-        mtlLoader.addEventListener( 'load', waitReady );
-        mtlLoader.addEventListener( 'error', waitReady );
+		var mtlLoader = new THREE.MTLLoader( url.substr( 0, url.lastIndexOf( "/" ) + 1 ), options );
+		mtlLoader.addEventListener( 'load', waitReady );
+		mtlLoader.addEventListener( 'error', waitReady );
 
-        // Try to load mtlfile
+		// Try to load mtlfile
 
-        if ( mtlfileurl ) {
+		if ( mtlfileurl ) {
 
-            mtlLoader.load( mtlfileurl );
-            mtlDone = false;
+			mtlLoader.load( mtlfileurl );
+			mtlDone = false;
 
-        } else {
+		} else {
 
-            mtlDone = true;
+			mtlDone = true;
 
-        }
+		}
+
+		function waitReady( event ) {
 
-        function waitReady( event ) {
+			if ( event.type === 'load' ) {
 
-            if ( event.type === 'load' ) {
+				if ( event.content instanceof THREE.MTLLoader.MaterialCreator ) {
 
-                if ( event.content instanceof THREE.MTLLoader.MaterialCreator ) {
+					// MTL file is loaded
 
-                    // MTL file is loaded
+					mtlDone = true;
+					materialsCreator = event.content;
+					materialsCreator.preload();
 
-                    mtlDone = true;
-                    materialsCreator = event.content;
-                    materialsCreator.preload();
+				} else {
 
-                } else {
+					// OBJ file is loaded
 
-                    // OBJ file is loaded
+					if ( event.target.status === 200 || event.target.status === 0 ) {
 
-                    if ( event.target.status === 200 || event.target.status === 0 ) {
+						var objContent = event.target.responseText;
 
-                        var objContent = event.target.responseText;
+						if ( mtlfileurl ) {
 
-                        if ( mtlfileurl ) {
+							// Parse with passed in MTL file
 
-                            // Parse with passed in MTL file
+							obj3d = scope.parse( objContent );
 
-                            obj3d = scope.parse( objContent );
+						} else {
 
-                        } else {
+							// No passed in MTL file, look for mtlfile in obj file
 
-                            // No passed in MTL file, look for mtlfile in obj file
+							obj3d = scope.parse( objContent, function( mtlfile ) {
 
-                            obj3d = scope.parse( objContent, function( mtlfile ) {
+								mtlDone = false;
+								mtlLoader.load( mtlLoader.baseUrl + mtlfile );
 
-                                mtlDone = false;
-                                mtlLoader.load( mtlLoader.baseUrl + mtlfile );
+							} );
+
+						}
 
-                            } );
+					} else {
 
-                        }
+						// Error loading OBJ file....
 
-                    } else {
+						scope.dispatchEvent( {
+							type: 'error',
+							message: 'Couldn\'t load URL [' + url + ']',
+							response: event.target.responseText } );
 
-                        // Error loading OBJ file....
+					}
 
-                        scope.dispatchEvent( {
-                            type: 'error',
-                            message: 'Couldn\'t load URL [' + url + ']',
-                            response: event.target.responseText } );
+				}
 
-                    }
+			} else if ( event.type === 'error' ) {
 
-                }
+				// MTL failed to load -- oh well, we will just not have material ...
 
-            } else if ( event.type === 'error' ) {
+				mtlDone = true;
 
-                // MTL failed to load -- oh well, we will just not have material ...
+			}
 
-                mtlDone = true;
+			if ( mtlDone && obj3d ) {
 
-            }
+				// MTL file is loaded and OBJ file is loaded
+				// Apply materials to model
 
-            if ( mtlDone && obj3d ) {
+				if ( materialsCreator ) {
 
-                // MTL file is loaded and OBJ file is loaded
-                // Apply materials to model
+					obj3d.traverse( function( object ) {
 
-                if ( materialsCreator ) {
+						if ( object instanceof THREE.Mesh ) {
 
-                    THREE.SceneUtils.traverseHierarchy( obj3d, function( node ) {
+							if ( object.material.name ) {
 
-						if ( node instanceof THREE.Mesh ) {
+								var material = materialsCreator.create( object.material.name );
+								if ( material ) {
 
-							if ( node.material.name ) {
+									object.material = material;
+
+								}
 
-								var material = materialsCreator.create( node.material.name );
-								if  (material ) node.material = material;
 							}
+
 						}
 
 					} );
 
-                }
+				}
 
-                // Notify listeners
+				// Notify listeners
 
-                scope.dispatchEvent( { type: 'load', content: obj3d } );
-            }
+				scope.dispatchEvent( { type: 'load', content: obj3d } );
+			}
 
-        }
+		}
 
-        xhr.addEventListener( 'load', waitReady, false );
+		xhr.addEventListener( 'load', waitReady, false );
 
 		xhr.addEventListener( 'progress', function ( event ) {
 
@@ -164,17 +169,18 @@ THREE.OBJMTLLoader.prototype = {
 		xhr.open( 'GET', url, true );
 		xhr.send( null );
 
-    },
+	},
+
+	/**
+	 * Parses loaded .obj file
+	 * @param data - content of .obj file
+	 * @param mtllibCallback - callback to handle mtllib declaration (optional)
+	 * @return {THREE.Object3D} - Object3D (with default material)
+	 */
 
-    /**
-     * Parses loaded .obj file
-     * @param data - content of .obj file
-     * @param mtllibCallback - callback to handle mtllib declaration (optional)
-     * @return {THREE.Object3D} - Object3D (with default material)
-     */
 	parse: function ( data, mtllibCallback ) {
 
-        function vector( x, y, z ) {
+		function vector( x, y, z ) {
 
 			return new THREE.Vector3( x, y, z );
 
@@ -198,293 +204,307 @@ THREE.OBJMTLLoader.prototype = {
 
 		}
 
-        function finalize_mesh( group, mesh_info ) {
+		function finalize_mesh( group, mesh_info ) {
 
-            mesh_info.geometry.computeCentroids();
-            mesh_info.geometry.computeFaceNormals();
-            mesh_info.geometry.computeBoundingSphere();
-            group.add( new THREE.Mesh( mesh_info.geometry, mesh_info.material ) );
+			mesh_info.geometry.computeCentroids();
+			mesh_info.geometry.computeFaceNormals();
+			mesh_info.geometry.computeBoundingSphere();
+			group.add( new THREE.Mesh( mesh_info.geometry, mesh_info.material ) );
 
-        }
+		}
 
 		var vertices = [];
 		var normals = [];
 		var uvs = [];
 
-        // v float float float
+		// v float float float
 
-        var vertex_pattern = /v( +[\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)/;
+		var vertex_pattern = /v( +[\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)/;
 
 		// vn float float float
 
-        var normal_pattern = /vn( +[\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)/;
+		var normal_pattern = /vn( +[\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)/;
 
 		// vt float float
 
-        var uv_pattern = /vt( +[\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)/;
+		var uv_pattern = /vt( +[\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)/;
 
 		// f vertex vertex vertex ...
 
-        var face_pattern1 = /f( +[\d]+)( [\d]+)( [\d]+)( [\d]+)?/;
+		var face_pattern1 = /f( +[\d]+)( [\d]+)( [\d]+)( [\d]+)?/;
 
 		// f vertex/uv vertex/uv vertex/uv ...
 
-        var face_pattern2 = /f( +([\d]+)\/([\d]+))( ([\d]+)\/([\d]+))( ([\d]+)\/([\d]+))( ([\d]+)\/([\d]+))?/;
+		var face_pattern2 = /f( +([\d]+)\/([\d]+))( ([\d]+)\/([\d]+))( ([\d]+)\/([\d]+))( ([\d]+)\/([\d]+))?/;
 
 		// f vertex/uv/normal vertex/uv/normal vertex/uv/normal ...
 
-        var face_pattern3 = /f( +([\d]+)\/([\d]+)\/([\d]+))( ([\d]+)\/([\d]+)\/([\d]+))( ([\d]+)\/([\d]+)\/([\d]+))( ([\d]+)\/([\d]+)\/([\d]+))?/;
+		var face_pattern3 = /f( +([\d]+)\/([\d]+)\/([\d]+))( ([\d]+)\/([\d]+)\/([\d]+))( ([\d]+)\/([\d]+)\/([\d]+))( ([\d]+)\/([\d]+)\/([\d]+))?/;
 
 		// f vertex//normal vertex//normal vertex//normal ...
 
-        var face_pattern4 = /f( +([\d]+)\/\/([\d]+))( ([\d]+)\/\/([\d]+))( ([\d]+)\/\/([\d]+))( ([\d]+)\/\/([\d]+))?/;
+		var face_pattern4 = /f( +([\d]+)\/\/([\d]+))( ([\d]+)\/\/([\d]+))( ([\d]+)\/\/([\d]+))( ([\d]+)\/\/([\d]+))?/;
 
-        var final_model = new THREE.Object3D();
+		var final_model = new THREE.Object3D();
 
 		var geometry = new THREE.Geometry();
-        geometry.vertices = vertices;
+		geometry.vertices = vertices;
 
 		var cur_mesh = {
 
-            material: new THREE.MeshLambertMaterial(),
-            geometry: geometry
+			material: new THREE.MeshLambertMaterial(),
+			geometry: geometry
 
-        };
+		};
 
-        var lines = data.split( "\n" );
+		var lines = data.split( "\n" );
 
-        for ( var i = 0; i < lines.length; i ++ ) {
+		for ( var i = 0; i < lines.length; i ++ ) {
 
-            var line = lines[ i ];
-            line = line.trim();
+			var line = lines[ i ];
+			line = line.trim();
 
-            // temporary variable storing pattern matching result
+			// temporary variable storing pattern matching result
 
-            var result;
+			var result;
 
-            if ( line.length === 0 || line.charAt( 0 ) === '#' ) {
+			if ( line.length === 0 || line.charAt( 0 ) === '#' ) {
 
-                continue;
+				continue;
 
-            } else if ( ( result = vertex_pattern.exec( line ) ) !== null ) {
+			} else if ( ( result = vertex_pattern.exec( line ) ) !== null ) {
 
-                // ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
+				// ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
 
-                vertices.push( vector(
-                    parseFloat( result[ 1 ] ),
-                    parseFloat( result[ 2 ] ),
-                    parseFloat( result[ 3 ] )
-                ) );
+				vertices.push( vector(
+					parseFloat( result[ 1 ] ),
+					parseFloat( result[ 2 ] ),
+					parseFloat( result[ 3 ] )
+				) );
 
-            } else if ( ( result = normal_pattern.exec( line ) ) !== null ) {
+			} else if ( ( result = normal_pattern.exec( line ) ) !== null ) {
 
 				// ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
 
 				normals.push( vector(
-                    parseFloat( result[ 1 ] ),
-                    parseFloat( result[ 2 ] ),
-                    parseFloat( result[ 3 ] )
-                ) );
+					parseFloat( result[ 1 ] ),
+					parseFloat( result[ 2 ] ),
+					parseFloat( result[ 3 ] )
+				) );
+
+			} else if ( ( result = uv_pattern.exec( line ) ) !== null ) {
+
+				// ["vt 0.1 0.2", "0.1", "0.2"]
+
+				uvs.push( uv(
+					parseFloat( result[ 1 ] ),
+					parseFloat( result[ 2 ] )
+				) );
+
+			} else if ( ( result = face_pattern1.exec( line ) ) !== null ) {
+
+				// ["f 1 2 3", "1", "2", "3", undefined]
+
+				if ( result[ 4 ] === undefined ) {
+
+					geometry.faces.push( face3(
+						parseInt( result[ 1 ] ) - 1,
+						parseInt( result[ 2 ] ) - 1,
+						parseInt( result[ 3 ] ) - 1
+					) );
+
+				} else {
+
+					geometry.faces.push( face4(
+						parseInt( result[ 1 ] ) - 1,
+						parseInt( result[ 2 ] ) - 1,
+						parseInt( result[ 3 ] ) - 1,
+						parseInt( result[ 4 ] ) - 1
+					) );
+
+				}
+
+			} else if ( ( result = face_pattern2.exec( line ) ) !== null ) {
+
+				// ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined]
+
+				if ( result[ 10 ] === undefined ) {
+
+					geometry.faces.push( face3(
+						parseInt( result[ 2 ] ) - 1,
+						parseInt( result[ 5 ] ) - 1,
+						parseInt( result[ 8 ] ) - 1
+					) );
+
+					geometry.faceVertexUvs[ 0 ].push( [
+						uvs[ parseInt( result[ 3 ] ) - 1 ],
+						uvs[ parseInt( result[ 6 ] ) - 1 ],
+						uvs[ parseInt( result[ 9 ] ) - 1 ]
+					] );
+
+				} else {
+
+					geometry.faces.push( face4(
+						parseInt( result[ 2 ] ) - 1,
+						parseInt( result[ 5 ] ) - 1,
+						parseInt( result[ 8 ] ) - 1,
+						parseInt( result[ 11 ] ) - 1
+					) );
+
+					geometry.faceVertexUvs[ 0 ].push( [
+						uvs[ parseInt( result[ 3 ] ) - 1 ],
+						uvs[ parseInt( result[ 6 ] ) - 1 ],
+						uvs[ parseInt( result[ 9 ] ) - 1 ],
+						uvs[ parseInt( result[ 12 ] ) - 1 ]
+					] );
+
+				}
+
+			} else if ( ( result = face_pattern3.exec( line ) ) !== null ) {
+
+				// ["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]
+
+				if ( result[ 13 ] === undefined ) {
+
+					geometry.faces.push( face3(
+						parseInt( result[ 2 ] ) - 1,
+						parseInt( result[ 6 ] ) - 1,
+						parseInt( result[ 10 ] ) - 1,
+						[
+							normals[ parseInt( result[ 4 ] ) - 1 ],
+							normals[ parseInt( result[ 8 ] ) - 1 ],
+							normals[ parseInt( result[ 12 ] ) - 1 ]
+						]
+					) );
+
+					geometry.faceVertexUvs[ 0 ].push( [
+						uvs[ parseInt( result[ 3 ] ) - 1 ],
+						uvs[ parseInt( result[ 7 ] ) - 1 ],
+						uvs[ parseInt( result[ 11 ] ) - 1 ]
+					] );
+
+				} else {
+
+					geometry.faces.push( face4(
+						parseInt( result[ 2 ] ) - 1,
+						parseInt( result[ 6 ] ) - 1,
+						parseInt( result[ 10 ] ) - 1,
+						parseInt( result[ 14 ] ) - 1,
+						[
+							normals[ parseInt( result[ 4 ] ) - 1 ],
+							normals[ parseInt( result[ 8 ] ) - 1 ],
+							normals[ parseInt( result[ 12 ] ) - 1 ],
+							normals[ parseInt( result[ 16 ] ) - 1 ]
+						]
+					) );
+
+					geometry.faceVertexUvs[ 0 ].push( [
+						uvs[ parseInt( result[ 3 ] ) - 1 ],
+						uvs[ parseInt( result[ 7 ] ) - 1 ],
+						uvs[ parseInt( result[ 11 ] ) - 1 ],
+						uvs[ parseInt( result[ 15 ] ) - 1 ]
+					] );
+
+				}
+
+			} else if ( ( result = face_pattern4.exec( line ) ) !== null ) {
 
-            } else if ( ( result = uv_pattern.exec( line ) ) !== null ) {
+				// ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined]
 
-                // ["vt 0.1 0.2", "0.1", "0.2"]
-
-                uvs.push( uv(
-                    parseFloat( result[ 1 ] ),
-                    parseFloat( result[ 2 ] )
-                ) );
-
-            } else if ( ( result = face_pattern1.exec( line ) ) !== null ) {
-
-                // ["f 1 2 3", "1", "2", "3", undefined]
-
-                if ( result[ 4 ] === undefined ) {
-
-                    geometry.faces.push( face3(
-                        parseInt( result[ 1 ] ) - 1,
-                        parseInt( result[ 2 ] ) - 1,
-                        parseInt( result[ 3 ] ) - 1
-                    ) );
+				if ( result[ 10 ] === undefined ) {
 
-                } else {
+					geometry.faces.push( face3(
+						parseInt( result[ 2 ] ) - 1,
+						parseInt( result[ 5 ] ) - 1,
+						parseInt( result[ 8 ] ) - 1,
+						[
+							normals[ parseInt( result[ 3 ] ) - 1 ],
+							normals[ parseInt( result[ 6 ] ) - 1 ],
+							normals[ parseInt( result[ 9 ] ) - 1 ]
+						]
+					) );
 
-                    geometry.faces.push( face4(
-                        parseInt( result[ 1 ] ) - 1,
-                        parseInt( result[ 2 ] ) - 1,
-                        parseInt( result[ 3 ] ) - 1,
-                        parseInt( result[ 4 ] ) - 1
-                    ) );
-
-                }
-
-            } else if ( ( result = face_pattern2.exec( line ) ) !== null ) {
+				} else {
 
-                // ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined]
-
-                if ( result[ 10 ] === undefined ) {
-
-                    geometry.faces.push( face3(
-                        parseInt( result[ 2 ] ) - 1,
-                        parseInt( result[ 5 ] ) - 1,
-                        parseInt( result[ 8 ] ) - 1
-                    ) );
-
-                    geometry.faceVertexUvs[ 0 ].push( [
-                        uvs[ parseInt( result[ 3 ] ) - 1 ],
-                        uvs[ parseInt( result[ 6 ] ) - 1 ],
-                        uvs[ parseInt( result[ 9 ] ) - 1 ]
-                    ] );
-
-                } else {
-
-                    geometry.faces.push( face4(
-                        parseInt( result[ 2 ] ) - 1,
-                        parseInt( result[ 5 ] ) - 1,
-                        parseInt( result[ 8 ] ) - 1,
-                        parseInt( result[ 11 ] ) - 1
-                    ) );
-
-                    geometry.faceVertexUvs[ 0 ].push( [
-                        uvs[ parseInt( result[ 3 ] ) - 1 ],
-                        uvs[ parseInt( result[ 6 ] ) - 1 ],
-                        uvs[ parseInt( result[ 9 ] ) - 1 ],
-                        uvs[ parseInt( result[ 12 ] ) - 1 ]
-                    ] );
+					geometry.faces.push( face4(
+						parseInt( result[ 2 ] ) - 1,
+						parseInt( result[ 5 ] ) - 1,
+						parseInt( result[ 8 ] ) - 1,
+						parseInt( result[ 11 ] ) - 1,
+						[
+							normals[ parseInt( result[ 3 ] ) - 1 ],
+							normals[ parseInt( result[ 6 ] ) - 1 ],
+							normals[ parseInt( result[ 9 ] ) - 1 ],
+							normals[ parseInt( result[ 12 ] ) - 1 ]
+						]
+					) );
 
-                }
+				}
 
-            } else if ( ( result = face_pattern3.exec( line ) ) !== null ) {
+			} else if ( line.startsWith( "usemtl " ) ) {
 
-                // ["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]
+				var material_name = line.substring( 7 );
+				material_name = material_name.trim();
 
-                if ( result[ 13 ] === undefined ) {
+				var material = new THREE.MeshLambertMaterial();
+				material.name = material_name;
 
-                    geometry.faces.push( face3(
-                        parseInt( result[ 2 ] ) - 1,
-                        parseInt( result[ 6 ] ) - 1,
-                        parseInt( result[ 10 ] ) - 1,
-                        [
-                            normals[ parseInt( result[ 4 ] ) - 1 ],
-                            normals[ parseInt( result[ 8 ] ) - 1 ],
-                            normals[ parseInt( result[ 12 ] ) - 1 ]
-                        ]
-                    ) );
+				if ( geometry.faces.length > 0 ) {
 
-                    geometry.faceVertexUvs[ 0 ].push( [
-                        uvs[ parseInt( result[ 3 ] ) - 1 ],
-                        uvs[ parseInt( result[ 7 ] ) - 1 ],
-                        uvs[ parseInt( result[ 11 ] ) - 1 ]
-                    ] );
+					// Finalize previous geometry and add to model
 
-                } else {
+					finalize_mesh( final_model, cur_mesh );
+					geometry = new THREE.Geometry();
+					geometry.vertices = vertices;
+
+					cur_mesh = {  geometry: geometry };
+
+				}
+
+				cur_mesh.material = material;
+				//material_index = materialsCreator.getIndex( material_name );
+
+			} else if ( line.startsWith( "g " ) ) {
+
+				// Polygon group for object
+
+				var group_name = line.substring( 2 );
+				group_name = group_name.trim();
+
+			} else if ( line.startsWith( "o " ) ) {
+
+				// Object
+				var object_name = line.substring(2);
+				//object_name = $.trim(object_name);
+
+			} else if (line.startsWith("s ")) {
+
+				// Smooth shading
+
+			} else if (line.startsWith("mtllib ")) {
+
+				// mtl file
+
+				if (mtllibCallback) {
+
+					var mtlfile = line.substring(7);
+					mtlfile = $.trim(mtlfile);
+					mtllibCallback(mtlfile);
+
+				}
+
+			} else {
+
+				console.error("Unhandled line " + line);
+
+			}
+
+		}
+
+		finalize_mesh(final_model, cur_mesh);
 
-                    geometry.faces.push( face4(
-                        parseInt( result[ 2 ] ) - 1,
-                        parseInt( result[ 6 ] ) - 1,
-                        parseInt( result[ 10 ] ) - 1,
-                        parseInt( result[ 14 ] ) - 1,
-                        [
-                            normals[ parseInt( result[ 4 ] ) - 1 ],
-                            normals[ parseInt( result[ 8 ] ) - 1 ],
-                            normals[ parseInt( result[ 12 ] ) - 1 ],
-                            normals[ parseInt( result[ 16 ] ) - 1 ]
-                        ]
-                    ) );
-
-                    geometry.faceVertexUvs[ 0 ].push( [
-                        uvs[ parseInt( result[ 3 ] ) - 1 ],
-                        uvs[ parseInt( result[ 7 ] ) - 1 ],
-                        uvs[ parseInt( result[ 11 ] ) - 1 ],
-                        uvs[ parseInt( result[ 15 ] ) - 1 ]
-                    ] );
-
-                }
-
-            } else if ( ( result = face_pattern4.exec( line ) ) !== null ) {
-
-                // ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined]
-
-                if ( result[ 10 ] === undefined ) {
-
-                    geometry.faces.push( face3(
-                        parseInt( result[ 2 ] ) - 1,
-                        parseInt( result[ 5 ] ) - 1,
-                        parseInt( result[ 8 ] ) - 1,
-                        [
-                            normals[ parseInt( result[ 3 ] ) - 1 ],
-                            normals[ parseInt( result[ 6 ] ) - 1 ],
-                            normals[ parseInt( result[ 9 ] ) - 1 ]
-                        ]
-                    ) );
-
-                } else {
-
-                    geometry.faces.push( face4(
-                        parseInt( result[ 2 ] ) - 1,
-                        parseInt( result[ 5 ] ) - 1,
-                        parseInt( result[ 8 ] ) - 1,
-                        parseInt( result[ 11 ] ) - 1,
-                        [
-                            normals[ parseInt( result[ 3 ] ) - 1 ],
-                            normals[ parseInt( result[ 6 ] ) - 1 ],
-                            normals[ parseInt( result[ 9 ] ) - 1 ],
-                            normals[ parseInt( result[ 12 ] ) - 1 ]
-                        ]
-                    ) );
-
-                }
-
-            } else if ( line.startsWith( "usemtl " ) ) {
-
-                var material_name = line.substring( 7 );
-                material_name = material_name.trim();
-
-                var material = new THREE.MeshLambertMaterial();
-                material.name = material_name;
-
-                if ( geometry.faces.length > 0 ) {
-
-                    // Finalize previous geometry and add to model
-
-                    finalize_mesh( final_model, cur_mesh );
-                    geometry = new THREE.Geometry();
-                    geometry.vertices = vertices;
-
-                    cur_mesh = {  geometry: geometry };
-
-                }
-
-                cur_mesh.material = material;
-                //material_index = materialsCreator.getIndex( material_name );
-
-            } else if ( line.startsWith( "g " ) ) {
-
-                // Polygon group for object
-
-                var group_name = line.substring( 2 );
-                group_name = group_name.trim();
-
-            } else if ( line.startsWith( "o " ) ) {
-
-                // Object
-                var object_name = line.substring(2);
-                //object_name = $.trim(object_name);
-            } else if (line.startsWith("s ")) {
-                // Smooth shading
-            } else if (line.startsWith("mtllib ")) {
-                // mtl file
-                if (mtllibCallback) {
-                    var mtlfile = line.substring(7);
-                    mtlfile = $.trim(mtlfile);
-                    mtllibCallback(mtlfile);
-                }
-            } else {
-                console.error("Unhandled line " + line);
-            }
-        }
-        finalize_mesh(final_model, cur_mesh);
 		return final_model;
+
 	}
-};
 
+};

+ 4 - 4
examples/webgl_geometry_hierarchy2.html

@@ -177,16 +177,16 @@
 
 				var time = Date.now() * 0.001;
 
-				var rx = Math.sin( time * 0.7 ) * 0.2,
-					ry = Math.sin( time * 0.3 ) * 0.1,
-					rz = Math.sin( time * 0.2 ) * 0.1;
+				var rx = Math.sin( time * 0.7 ) * 0.2;
+				var ry = Math.sin( time * 0.3 ) * 0.1;
+				var rz = Math.sin( time * 0.2 ) * 0.1;
 
 				camera.position.x += ( mouseX - camera.position.x ) * .05;
 				camera.position.y += ( - mouseY - camera.position.y ) * .05;
 
 				camera.lookAt( scene.position );
 
-				THREE.SceneUtils.traverseHierarchy( root, function ( object ) {
+				root.traverse( function ( object ) {
 
 					object.rotation.x = rx;
 					object.rotation.y = ry;

+ 5 - 5
examples/webgl_loader_scene.html

@@ -310,17 +310,17 @@
 
 					handle_update( result, 1 );
 
-					THREE.SceneUtils.traverseHierarchy( result.scene, function ( child ) {
+					result.scene.traverse( function ( object ) {
 
-						if ( child.properties.rotating === true ) {
+						if ( object.properties.rotating === true ) {
 
-							rotatingObjects.push( child );
+							rotatingObjects.push( object );
 
 						}
 
-						if ( child instanceof THREE.MorphAnimMesh ) {
+						if ( object instanceof THREE.MorphAnimMesh ) {
 
-							morphAnimatedObjects.push( child );
+							morphAnimatedObjects.push( object );
 
 						}
 

+ 2 - 2
examples/webgl_loader_utf8.html

@@ -152,7 +152,7 @@
 					object.position.y = -125;
 					scene.add( object );
 
-					THREE.SceneUtils.traverseHierarchy( object, function( node ) {
+					object.traverse( function( node ) {
 
 						node.castShadow = true;
 						node.receiveShadow = true;
@@ -179,7 +179,7 @@
 					object.position.y = -125;
 					scene.add( object );
 
-					THREE.SceneUtils.traverseHierarchy( object, function( node ) {
+					object.traverse( function( node ) {
 
 						node.castShadow = true;
 						node.receiveShadow = true;

+ 9 - 1
examples/webgl_lod.html

@@ -165,7 +165,15 @@
 				camera.lookAt( scene.position );
 
 				scene.updateMatrixWorld();
-				THREE.SceneUtils.traverseHierarchy( scene, function ( node ) { if ( node instanceof THREE.LOD ) node.update( camera ) } );
+				scene.traverse( function ( object ) {
+
+					if ( object instanceof THREE.LOD ) {
+
+						object.update( camera );
+
+					}
+
+				} );
 
 				renderer.render( scene, camera );
 

+ 15 - 5
src/core/Object3D.js

@@ -187,13 +187,23 @@ THREE.Object3D.prototype = {
 
 	},
 
-	getChildByName: function ( name, recursive ) {
+	traverse: function ( callback ) {
+
+		callback( this );
+
+		for ( var i = 0, l = this.children.length; i < l; i ++ ) {
+
+			this.children[ i ].traverse( callback );
 
-		var c, cl, child;
+		}
 
-		for ( c = 0, cl = this.children.length; c < cl; c ++ ) {
+	},
+
+	getChildByName: function ( name, recursive ) {
+
+		for ( var i = 0, l = this.children.length; i < l; i ++ ) {
 
-			child = this.children[ c ];
+			var child = this.children[ i ];
 
 			if ( child.name === name ) {
 
@@ -201,7 +211,7 @@ THREE.Object3D.prototype = {
 
 			}
 
-			if ( recursive ) {
+			if ( recursive === true ) {
 
 				child = child.getChildByName( name, recursive );
 

+ 4 - 28
src/extras/SceneUtils.js

@@ -4,37 +4,13 @@
 
 THREE.SceneUtils = {
 
-	showHierarchy : function ( root, visible ) {
+	createMultiMaterialObject: function ( geometry, materials ) {
 
-		THREE.SceneUtils.traverseHierarchy( root, function( node ) { node.visible = visible; } );
+		var group = new THREE.Object3D();
 
-	},
-
-	traverseHierarchy : function ( root, callback ) {
-
-		var n, i, l = root.children.length;
-
-		for ( i = 0; i < l; i ++ ) {
-
-			n = root.children[ i ];
-
-			callback( n );
-
-			THREE.SceneUtils.traverseHierarchy( n, callback );
-
-		}
-
-	},
-
-	createMultiMaterialObject : function ( geometry, materials ) {
-
-		var i, il = materials.length,
-			group = new THREE.Object3D();
-
-		for ( i = 0; i < il; i ++ ) {
+		for ( var i = 0, l = materials.length; i < l; i ++ ) {
 
-			var object = new THREE.Mesh( geometry, materials[ i ] );
-			group.add( object );
+			group.add( new THREE.Mesh( geometry, materials[ i ] ) );
 
 		}