/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.GeometryLoader = function () { THREE.EventTarget.call( this ); this.crossOrigin = null; this.path = null; }; THREE.GeometryLoader.prototype = { constructor: THREE.GeometryLoader, load: function ( url ) { var scope = this; var geometry = null; if ( scope.path === null ) { var parts = url.split( '/' ); parts.pop(); scope.path = ( parts.length < 1 ? '.' : parts.join( '/' ) ); } // var xhr = new XMLHttpRequest(); xhr.addEventListener( 'load', function ( event ) { if ( event.target.responseText ) { geometry = scope.parse( JSON.parse( event.target.responseText ), monitor ); } else { scope.dispatchEvent( { type: 'error', message: 'Invalid file [' + url + ']' } ); } }, false ); xhr.addEventListener( 'error', function () { scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']' } ); }, false ); xhr.open( 'GET', url, true ); xhr.send( null ); // var monitor = new THREE.LoadingMonitor(); monitor.addEventListener( 'load', function ( event ) { scope.dispatchEvent( { type: 'load', content: geometry } ); } ); monitor.add( xhr ); }, parse: function ( data, monitor ) { var scope = this; var geometry = new THREE.Geometry(); var scale = ( data.scale !== undefined ) ? 1 / data.scale : 1; // materials if ( data.materials ) { geometry.materials = []; for ( var i = 0; i < data.materials.length; ++ i ) { var m = data.materials[ i ]; function isPow2( n ) { var l = Math.log( n ) / Math.LN2; return Math.floor( l ) == l; } function nearestPow2( n ) { var l = Math.log( n ) / Math.LN2; return Math.pow( 2, Math.round( l ) ); } function createTexture( where, name, sourceFile, repeat, offset, wrap ) { where[ name ] = new THREE.Texture(); where[ name ].sourceFile = sourceFile; if ( repeat ) { where[ name ].repeat.set( repeat[ 0 ], repeat[ 1 ] ); if ( repeat[ 0 ] != 1 ) where[ name ].wrapS = THREE.RepeatWrapping; if ( repeat[ 1 ] != 1 ) where[ name ].wrapT = THREE.RepeatWrapping; } if ( offset ) { where[ name ].offset.set( offset[ 0 ], offset[ 1 ] ); } if ( wrap ) { var wrapMap = { "repeat": THREE.RepeatWrapping, "mirror": THREE.MirroredRepeatWrapping } if ( wrapMap[ wrap[ 0 ] ] !== undefined ) where[ name ].wrapS = wrapMap[ wrap[ 0 ] ]; if ( wrapMap[ wrap[ 1 ] ] !== undefined ) where[ name ].wrapT = wrapMap[ wrap[ 1 ] ]; } // load image var texture = where[ name ]; var loader = new THREE.ImageLoader(); loader.addEventListener( 'load', function ( event ) { var image = event.content; if ( !isPow2( image.width ) || !isPow2( image.height ) ) { var width = nearestPow2( image.width ); var height = nearestPow2( image.height ); texture.image = document.createElement( 'canvas' ); texture.image.width = width; texture.image.height = height; texture.image.getContext( '2d' ).drawImage( image, 0, 0, width, height ); } else { texture.image = image; } texture.needsUpdate = true; } ); loader.crossOrigin = scope.crossOrigin; loader.load( scope.path + '/' + sourceFile ); if ( monitor ) monitor.add( loader ); } function rgb2hex( rgb ) { return ( rgb[ 0 ] * 255 << 16 ) + ( rgb[ 1 ] * 255 << 8 ) + rgb[ 2 ] * 255; } // defaults var mtype = "MeshLambertMaterial"; var mpars = { color: 0xeeeeee, opacity: 1.0, map: null, lightMap: null, normalMap: null, wireframe: m.wireframe }; // parameters from model file if ( m.shading ) { var shading = m.shading.toLowerCase(); if ( shading === "phong" ) mtype = "MeshPhongMaterial"; else if ( shading === "basic" ) mtype = "MeshBasicMaterial"; } if ( m.blending !== undefined && THREE[ m.blending ] !== undefined ) { mpars.blending = THREE[ m.blending ]; } if ( m.transparent !== undefined || m.opacity < 1.0 ) { mpars.transparent = m.transparent; } if ( m.depthTest !== undefined ) { mpars.depthTest = m.depthTest; } if ( m.depthWrite !== undefined ) { mpars.depthWrite = m.depthWrite; } if ( m.vertexColors !== undefined ) { if ( m.vertexColors == "face" ) { mpars.vertexColors = THREE.FaceColors; } else if ( m.vertexColors ) { mpars.vertexColors = THREE.VertexColors; } } // colors if ( m.colorDiffuse ) { mpars.color = rgb2hex( m.colorDiffuse ); } else if ( m.DbgColor ) { mpars.color = m.DbgColor; } if ( m.colorSpecular ) { mpars.specular = rgb2hex( m.colorSpecular ); } if ( m.colorAmbient ) { mpars.ambient = rgb2hex( m.colorAmbient ); } // modifiers if ( m.transparency ) { mpars.opacity = m.transparency; } if ( m.specularCoef ) { mpars.shininess = m.specularCoef; } // textures if ( m.mapDiffuse ) { createTexture( mpars, "map", m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap ); } if ( m.mapLight ) { createTexture( mpars, "lightMap", m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap ); } if ( m.mapNormal ) { createTexture( mpars, "normalMap", m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap ); } if ( m.mapSpecular ) { createTexture( mpars, "specularMap", m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap ); } // special case for normal mapped material if ( m.mapNormal ) { var shader = THREE.ShaderUtils.lib[ "normal" ]; var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); uniforms[ "tNormal" ].texture = mpars.normalMap; if ( m.mapNormalFactor ) { uniforms[ "uNormalScale" ].value = m.mapNormalFactor; } if ( mpars.map ) { uniforms[ "tDiffuse" ].texture = mpars.map; uniforms[ "enableDiffuse" ].value = true; } if ( mpars.specularMap ) { uniforms[ "tSpecular" ].texture = mpars.specularMap; uniforms[ "enableSpecular" ].value = true; } if ( mpars.lightMap ) { uniforms[ "tAO" ].texture = mpars.lightMap; uniforms[ "enableAO" ].value = true; } // for the moment don't handle displacement texture uniforms[ "uDiffuseColor" ].value.setHex( mpars.color ); uniforms[ "uSpecularColor" ].value.setHex( mpars.specular ); uniforms[ "uAmbientColor" ].value.setHex( mpars.ambient ); uniforms[ "uShininess" ].value = mpars.shininess; if ( mpars.opacity !== undefined ) { uniforms[ "uOpacity" ].value = mpars.opacity; } var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true }; var material = new THREE.ShaderMaterial( parameters ); } else { var material = new THREE[ mtype ]( mpars ); } if ( m.DbgName !== undefined ) material.name = m.DbgName; geometry.materials[ i ] = material; } } // geometry function isBitSet( value, position ) { return value & ( 1 << position ); } var faces = data.faces; var vertices = data.vertices; var normals = data.normals; var colors = data.colors; var nUvLayers = 0; // disregard empty arrays if ( data.uvs ) { for ( var i = 0; i < data.uvs.length; i ++ ) { if ( data.uvs[ i ].length ) nUvLayers ++; } } for ( var i = 0; i < nUvLayers; i ++ ) { geometry.faceUvs[ i ] = []; geometry.faceVertexUvs[ i ] = []; } var offset = 0; var zLength = vertices.length; while ( offset < zLength ) { var vertex = new THREE.Vector3(); vertex.x = vertices[ offset ++ ] * scale; vertex.y = vertices[ offset ++ ] * scale; vertex.z = vertices[ offset ++ ] * scale; geometry.vertices.push( vertex ); } offset = 0; zLength = faces.length; while ( offset < zLength ) { var type = faces[ offset ++ ]; var isQuad = isBitSet( type, 0 ); var hasMaterial = isBitSet( type, 1 ); var hasFaceUv = isBitSet( type, 2 ); var hasFaceVertexUv = isBitSet( type, 3 ); var hasFaceNormal = isBitSet( type, 4 ); var hasFaceVertexNormal = isBitSet( type, 5 ); var hasFaceColor = isBitSet( type, 6 ); var hasFaceVertexColor = isBitSet( type, 7 ); // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceUv, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); if ( isQuad ) { var face = new THREE.Face4(); face.a = faces[ offset ++ ]; face.b = faces[ offset ++ ]; face.c = faces[ offset ++ ]; face.d = faces[ offset ++ ]; var nVertices = 4; } else { var face = new THREE.Face3(); face.a = faces[ offset ++ ]; face.b = faces[ offset ++ ]; face.c = faces[ offset ++ ]; var nVertices = 3; } if ( hasMaterial ) { var materialIndex = faces[ offset ++ ]; face.materialIndex = materialIndex; } // to get face <=> uv index correspondence var fi = geometry.faces.length; if ( hasFaceUv ) { for ( var i = 0; i < nUvLayers; i ++ ) { var uvLayer = data.uvs[ i ]; var uvIndex = faces[ offset ++ ]; var u = uvLayer[ uvIndex * 2 ]; var v = uvLayer[ uvIndex * 2 + 1 ]; geometry.faceUvs[ i ][ fi ] = new THREE.UV( u, v ); } } if ( hasFaceVertexUv ) { for ( var i = 0; i < nUvLayers; i ++ ) { var uvLayer = data.uvs[ i ]; var uvs = []; for ( var j = 0; j < nVertices; j ++ ) { var uvIndex = faces[ offset ++ ]; var u = uvLayer[ uvIndex * 2 ]; var v = uvLayer[ uvIndex * 2 + 1 ]; uvs[ j ] = new THREE.UV( u, v ); } geometry.faceVertexUvs[ i ][ fi ] = uvs; } } if ( hasFaceNormal ) { var normalIndex = faces[ offset ++ ] * 3; var normal = new THREE.Vector3(); normal.x = normals[ normalIndex ++ ]; normal.y = normals[ normalIndex ++ ]; normal.z = normals[ normalIndex ]; face.normal = normal; } if ( hasFaceVertexNormal ) { for ( i = 0; i < nVertices; i ++ ) { var normalIndex = faces[ offset ++ ] * 3; var normal = new THREE.Vector3(); normal.x = normals[ normalIndex ++ ]; normal.y = normals[ normalIndex ++ ]; normal.z = normals[ normalIndex ]; face.vertexNormals.push( normal ); } } if ( hasFaceColor ) { var colorIndex = faces[ offset ++ ]; face.color = new THREE.Color( colors[ colorIndex ] ); } if ( hasFaceVertexColor ) { for ( var i = 0; i < nVertices; i ++ ) { var colorIndex = faces[ offset ++ ]; face.vertexColors.push( new THREE.Color( colors[ colorIndex ] ) ); } } geometry.faces.push( face ); } // skin if ( data.skinWeights ) { for ( var i = 0, l = data.skinWeights.length; i < l; i += 2 ) { var x = data.skinWeights[ i ]; var y = data.skinWeights[ i + 1 ]; var z = 0; var w = 0; geometry.skinWeights.push( new THREE.Vector4( x, y, z, w ) ); } } if ( data.skinIndices ) { for ( var i = 0, l = data.skinIndices.length; i < l; i += 2 ) { var a = data.skinIndices[ i ]; var b = data.skinIndices[ i + 1 ]; var c = 0; var d = 0; geometry.skinIndices.push( new THREE.Vector4( a, b, c, d ) ); } } geometry.bones = data.bones; geometry.animation = data.animation; // morphing if ( data.morphTargets ) { for ( var i = 0, l = data.morphTargets.length; i < l; i ++ ) { geometry.morphTargets[ i ] = {}; geometry.morphTargets[ i ].name = data.morphTargets[ i ].name; geometry.morphTargets[ i ].vertices = []; var dstVertices = geometry.morphTargets[ i ].vertices; var srcVertices = data.morphTargets [ i ].vertices; for( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) { var vertex = new THREE.Vector3(); vertex.x = srcVertices[ v ] * scale; vertex.y = srcVertices[ v + 1 ] * scale; vertex.z = srcVertices[ v + 2 ] * scale; dstVertices.push( vertex ); } } } if ( data.morphColors ) { for ( var i = 0, l = data.morphColors.length; i < l; i++ ) { geometry.morphColors[ i ] = {}; geometry.morphColors[ i ].name = data.morphColors[ i ].name; geometry.morphColors[ i ].colors = []; var dstColors = geometry.morphColors[ i ].colors; var srcColors = data.morphColors [ i ].colors; for ( var c = 0, cl = srcColors.length; c < cl; c += 3 ) { var color = new THREE.Color( 0xffaa00 ); color.setRGB( srcColors[ c ], srcColors[ c + 1 ], srcColors[ c + 2 ] ); dstColors.push( color ); } } } geometry.computeCentroids(); geometry.computeFaceNormals(); return geometry; } };