diff --git a/docs/api/loaders/GLTFLoader.html b/docs/api/loaders/GLTFLoader.html new file mode 100644 index 0000000000000000000000000000000000000000..fdcfe09578a1316213fd10a6023f2a4e054c4a66 --- /dev/null +++ b/docs/api/loaders/GLTFLoader.html @@ -0,0 +1,105 @@ + + + + + + + + + + + [page:Loader] → +

[name]

+ +
+ A loader for loading a .gltf resource in JSON format. +

+ The glTF file format is a JSON file format to enable rapid delivery and loading of 3D content. +
+ + +

Constructor

+ +

[name]( [page:LoadingManager manager] )

+
+ [page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager]. +
+
+ Creates a new [name]. +
+ +

Properties

+ + +

Methods

+ +

[method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )

+
+ [page:String url] — required
+ [page:Function onLoad] — Will be called when load completes. The argument will be the loaded JSON response returned from [page:Function parse].
+ [page:Function onProgress] — Will be called while load progresses. The argument will be the XMLHttpRequest instance, that contains .[page:Integer total] and .[page:Integer loaded] bytes.
+ [page:Function onError] — Will be called when load errors.
+
+
+ Begin loading from url and call the callback function with the parsed response content. +
+ +

[method:null setPath]( [page:String path] )

+
+ [page:String path] — Base path for loading additional resources e.g. textures, GLSL shaders, .bin data. +
+
+ Set the base path for additional resources. +
+ +

[method:null setCrossOrigin]( [page:String value] )

+
+ [page:String value] — The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS. +
+ +

[method:null parse]( [page:Object json], [page:Function callBack], [page:String path] )

+
+ [page:Object json] — JSON object to parse.
+ [page:Function callBack] — Will be called when parse completes.
+ [page:String path] — The base path from which to find subsequent glTF resources such as textures, GLSL shaders and .bin data files.
+
+
+ Parse a glTF-based JSON structure and fire [page:Function callback] when complete. The argument to [page:Function callback] will be an [page:object] that contains loaded parts: .[page:Scene scene], .[page:Array cameras], .[page:Array animations] and .[page:Array shaders] +
+ + +

Notes

+ +
+ When using custom shaders provided within a glTF file [page:THREE.GLTFLoader.Shaders] should be updated on each render loop. See [example:webgl_loader_gltf] demo source code for example usage. +
+ +
+ This class is often used with [page:THREE.GLTFLoader.Animations THREE.GLTFLoader.Animations] to animate parsed animations. See [example:webgl_loader_gltf] demo source code for example usage. +
+ +

Example

+ + + // instantiate a loader + var loader = new THREE.GLTFLoader(); + + // load a glTF resource + loader.load( + // resource URL + 'models/gltf/duck/duck.json', + // Function when resource is loaded + function ( object ) { + scene.add( object.scene ); + } + ); + + + [example:webgl_loader_gltf] + + +

Source

+ + [link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/GLTFLoader.js examples/js/loaders/GLTFLoader.js] + + diff --git a/docs/api/loaders/glTFLoader.html b/docs/api/loaders/glTFLoader.html deleted file mode 100644 index cc4e29e2ae7266aeaf6b5a6d4b320bff1bd8be3e..0000000000000000000000000000000000000000 --- a/docs/api/loaders/glTFLoader.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - [page:Loader] → -

[name]

- -
- A loader for loading a .gltf resource in JSON format. -

- The glTF file format is a JSON file format to enable rapid delivery and loading of 3D content. -
- - -

Constructor

- -

[name]( )

-
- Creates a new [name]. -
- -

Properties

- - -

Methods

- -

[method:Object3D load]( [page:String url], [page:Function callback] )

-
- [page:String url] — required
- [page:Function callback] — Will be called when load completes. The argument will be an [page:Object] containing the loaded .[page:Object3D scene], .[page:Array cameras] and .[page:Array animations].
-
-
- Begin loading from url and call the callback function with the parsed response content. -
- - -

Notes

- -
- This class is often used with [page:glTFAnimator THREE.glTFAnimator] to animate parsed animations. -
- - -

Example

- - - // instantiate a loader - var loader = new THREE.glTFLoader(); - - // load a glTF resource - loader.load( - // resource URL - 'models/gltf/duck/duck.json', - // Function when resource is loaded - function ( object ) { - scene.add( object.scene ); - } - ); - - - [example:webgl_loader_gltf] - - -

Source

- - [link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/gltf/glTFLoader.js examples/js/loaders/gltf/glTFLoader.js] - - diff --git a/docs/list.js b/docs/list.js index 2e5c06142e920728f4eb9fbcd079004e6ee14cc5..8092a33c461a2bfa4f147d6c71247c0f9cba51bf 100644 --- a/docs/list.js +++ b/docs/list.js @@ -93,7 +93,7 @@ var list = { [ "BufferGeometryLoader", "api/loaders/BufferGeometryLoader" ], [ "Cache", "api/loaders/Cache" ], [ "ColladaLoader", "api/loaders/ColladaLoader" ], - [ "glTFLoader", "api/loaders/glTFLoader" ], + [ "GLTFLoader", "api/loaders/GLTFLoader" ], [ "ImageLoader", "api/loaders/ImageLoader" ], [ "JSONLoader", "api/loaders/JSONLoader" ], [ "Loader", "api/loaders/Loader" ], diff --git a/editor/js/libs/tern-threejs/threejs.js b/editor/js/libs/tern-threejs/threejs.js index b4cc967be2caa4603c0fd1f66f03d1b9d70bf17d..d0268ebb5a72e3c113293b6a2fed738b5ea21d6d 100644 --- a/editor/js/libs/tern-threejs/threejs.js +++ b/editor/js/libs/tern-threejs/threejs.js @@ -2544,8 +2544,8 @@ "!doc": "A low level class for loading resources with XmlHttpRequest, used internaly by most loaders.", "!type": "fn(manager: +THREE.LoadingManager)" }, - "glTFLoader": { - "!url": "http://threejs.org/docs/#Reference/loaders/glTFLoader", + "GLTFLoader": { + "!url": "http://threejs.org/docs/#Reference/loaders/GLTFLoader", "prototype": { "!proto": "THREE.Loader.prototype", "load": { diff --git a/examples/js/loaders/GLTFLoader.js b/examples/js/loaders/GLTFLoader.js index d2bcfa5489506a8399f7ab3ba93c80d373055422..715695beaa66a7d8cf7e4fcde1cfbfb878363ae6 100644 --- a/examples/js/loaders/GLTFLoader.js +++ b/examples/js/loaders/GLTFLoader.js @@ -1,379 +1,1739 @@ /** + * @author Rich Tibbett / https://github.com/richtr * @author mrdoob / http://mrdoob.com/ + * @author Tony Parisi / http://www.tonyparisi.com/ */ -THREE.GLTFLoader = function ( manager ) { +(function() { + +THREE.GLTFLoader = function( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + this.parser = GLTFParser; + }; THREE.GLTFLoader.prototype = { constructor: THREE.GLTFLoader, - load: function ( url, onLoad, onProgress, onError ) { + load: function( url, onLoad, onProgress, onError ) { var scope = this; + var path = this.path && ( typeof this.path === "string" ) ? this.path : THREE.Loader.prototype.extractUrlBase( url ); + var loader = new THREE.XHRLoader( scope.manager ); - loader.load( url, function ( text ) { + loader.load( url, function( text ) { - onLoad( scope.parse( JSON.parse( text ) ) ); + scope.parse( JSON.parse( text ), onLoad, path ); }, onProgress, onError ); }, - setCrossOrigin: function ( value ) { + setCrossOrigin: function( value ) { this.crossOrigin = value; }, - parse: function ( json ) { + setPath: function( value ) { - function stringToArrayBuffer( string ) { + this.path = value; - var bytes = atob( string ); - var buffer = new ArrayBuffer( bytes.length ); - var bufferView = new Uint8Array( buffer ); + }, - for ( var i = 0; i < bytes.length; i ++ ) { + parse: function( json, callback, path ) { - bufferView[ i ] = bytes.charCodeAt( i ); + console.time( 'GLTFLoader' ); - } + var glTFParser = new this.parser( json, { + path: path || this.path, + crossOrigin: !!this.crossOrigin + }); - return buffer; + glTFParser.parse( function( scene, cameras, animations ) { - } + console.timeEnd( 'GLTFLoader' ); - console.time( 'GLTFLoader' ); + var glTF = { + "scene": scene, + "cameras": cameras, + "animations": animations + }; + + callback( glTF ); + + }); + + // Developers should use `callback` argument for async notification on + // completion to prevent side effects. + // Function return is kept only for backward-compatability purposes. + return { + get scene() { + + console.warn( "Synchronous glTF object access is deprecated." + + " Use the asynchronous 'callback' argument instead." ); + return scene; + + }, + set scene( value ) { + + console.warn( "Synchronous glTF object access is deprecated." + + " Use the asynchronous 'callback' argument instead." ); + scene = value; + + } - var library = { - buffers: {}, - bufferViews: {}, - accessors: {}, - textures: {}, - materials: {}, - meshes: {}, - nodes: {}, - scenes: {} }; - // buffers + } + +}; + +/* GLTFREGISTRY */ + +var GLTFRegistry = function() { + + var objects = {}; + + return { + get : function( key ) { + + return objects[ key ]; + + }, + + add : function( key, object ) { + + objects[ key ] = object; + + }, + + remove: function( key ) { + + delete objects[ key ]; + + }, - var buffers = json.buffers; + removeAll: function() { - for ( var bufferId in buffers ) { + objects = {}; - var buffer = buffers[ bufferId ]; + }, - if ( buffer.type === 'arraybuffer' ) { + update : function( scene, camera ) { - var header = 'data:application/octet-stream;base64,'; + _each( objects, function( object ) { - if ( buffer.uri.indexOf( header ) === 0 ) { + if ( object.update ) { - library.buffers[ bufferId ] = stringToArrayBuffer( buffer.uri.substr( header.length ) ); + object.update( scene, camera ); } - } + }); } + }; +}; + +/* GLTFSHADERS */ + +THREE.GLTFLoader.Shaders = new GLTFRegistry(); - // buffer views +/* GLTFSHADER */ - var bufferViews = json.bufferViews; +var GLTFShader = function( targetNode, allNodes ) { - for ( var bufferViewId in bufferViews ) { + this.boundUniforms = {}; - var bufferView = bufferViews[ bufferViewId ]; - var arraybuffer = library.buffers[ bufferView.buffer ]; + // bind each uniform to its source node + _each(targetNode.material.uniforms, function(uniform, uniformId) { + + if (uniform.semantic) { + + var sourceNodeRef = uniform.node; + + var sourceNode = targetNode; + if ( sourceNodeRef ) { + sourceNode = allNodes[ sourceNodeRef ]; + } - library.bufferViews[ bufferViewId ] = arraybuffer.slice( bufferView.byteOffset, bufferView.byteOffset + bufferView.byteLength ); + this.boundUniforms[ uniformId ] = { + semantic: uniform.semantic, + sourceNode: sourceNode, + targetNode: targetNode, + uniform: uniform + }; } - // accessors + }.bind( this )); - var COMPONENT_TYPES = { - 5120: Int8Array, - 5121: Uint8Array, - 5122: Int16Array, - 5123: Uint16Array, - 5125: Uint32Array, - 5126: Float32Array, - }; + this._m4 = new THREE.Matrix4(); - var TYPE_SIZES = { - 'SCALAR': 1, 'VEC2': 2, 'VEC3': 3, 'VEC4': 4, - 'MAT2': 4, 'MAT3': 9, 'MAT4': 16 - }; +} - var accessors = json.accessors; +// Update - update all the uniform values +GLTFShader.prototype.update = function( scene, camera ) { - for ( var accessorId in accessors ) { + // update scene graph - var accessor = accessors[ accessorId ]; + scene.updateMatrixWorld(); - var arraybuffer = library.bufferViews[ accessor.bufferView ]; - var itemSize = TYPE_SIZES[ accessor.type ]; - var TypedArray = COMPONENT_TYPES[ accessor.componentType ]; + // update camera matrices and frustum - var array = new TypedArray( arraybuffer, accessor.byteOffset, accessor.count * itemSize ); + camera.updateMatrixWorld(); + camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + + _each( this.boundUniforms, function( boundUniform ) { + + switch (boundUniform.semantic) { + + case "MODELVIEW": + + var m4 = boundUniform.uniform.value; + m4.multiplyMatrices(camera.matrixWorldInverse, + boundUniform.sourceNode.matrixWorld); + break; + + case "MODELVIEWINVERSETRANSPOSE": - library.accessors[ accessorId ] = new THREE.BufferAttribute( array, itemSize ); + var m3 = boundUniform.uniform.value; + this._m4.multiplyMatrices(camera.matrixWorldInverse, + boundUniform.sourceNode.matrixWorld); + m3.getNormalMatrix(this._m4); + break; + + case "PROJECTION": + + var m4 = boundUniform.uniform.value; + m4.copy(camera.projectionMatrix); + break; + + case "JOINTMATRIX": + + var m4v = boundUniform.uniform.value; + for (var mi = 0; mi < m4v.length; mi++) { + // So it goes like this: + // SkinnedMesh world matrix is already baked into MODELVIEW; + // ransform joints to local space, + // then transform using joint's inverse + m4v[mi] + .getInverse(boundUniform.sourceNode.matrixWorld) + .multiply(boundUniform.targetNode.skeleton.bones[ mi ].matrixWorld) + .multiply(boundUniform.targetNode.skeleton.boneInverses[mi]); + } + break; + + default : + + console.warn("Unhandled shader semantic: " + boundUniform.semantic); + break; } - // textures + }.bind( this )); - var FILTERS = { - 9728: THREE.NearestFilter, - 9729: THREE.LinearFilter, - 9984: THREE.NearestMipMapNearestFilter, - 9985: THREE.LinearMipMapNearestFilter, - 9986: THREE.NearestMipMapLinearFilter, - 9987: THREE.LinearMipMapLinearFilter - }; +}; - var WRAPPINGS = { - 33071: THREE.ClampToEdgeWrapping, - 33648: THREE.MirroredRepeatWrapping, - 10497: THREE.RepeatWrapping - }; - var textures = json.textures; +/* GLTFANIMATION */ - for ( var textureId in textures ) { +THREE.GLTFLoader.Animations = new GLTFRegistry(); - var texture = textures[ textureId ]; +// Construction/initialization +var GLTFAnimation = function( interps ) { - var _texture = new THREE.Texture(); - _texture.flipY = false; + this.running = false; + this.loop = false; + this.duration = 0; + this.startTime = 0; + this.interps = []; - if ( texture.source ) { + this.uuid = THREE.Math.generateUUID(); - var source = json.images[ texture.source ]; + if ( interps ) { - _texture.image = new Image(); - _texture.image.src = source.uri; - _texture.needsUpdate = true; + this.createInterpolators( interps ); - } + } - if ( texture.sampler ) { +}; - var sampler = json.samplers[ texture.sampler ]; +GLTFAnimation.prototype.createInterpolators = function( interps ) { - _texture.magFilter = FILTERS[ sampler.magFilter ]; - _texture.minFilter = FILTERS[ sampler.minFilter ]; - _texture.wrapS = WRAPPINGS[ sampler.wrapS ]; - _texture.wrapT = WRAPPINGS[ sampler.wrapT ]; + for ( var i = 0, len = interps.length; i < len; i ++ ) { - } + var interp = new GLTFInterpolator( interps[ i ] ); + this.interps.push( interp ); + this.duration = Math.max( this.duration, interp.duration ); - library.textures[ textureId ] = _texture; + } - } +} - // materials +// Start/stop +GLTFAnimation.prototype.play = function() { - var materials = json.materials; + if ( this.running ) + return; - for ( var materialId in materials ) { + this.startTime = Date.now(); + this.running = true; + THREE.GLTFLoader.Animations.add( this.uuid, this ); - var material = materials[ materialId ]; +}; - var _material = new THREE.MeshPhongMaterial(); - _material.name = material.name; +GLTFAnimation.prototype.stop = function() { - var values = material.values; + this.running = false; + THREE.GLTFLoader.Animations.remove( this.uuid ); - if ( Array.isArray( values.diffuse ) ) { +}; - _material.color.fromArray( values.diffuse ); +// Update - drive key frame evaluation +GLTFAnimation.prototype.update = function() { - } else if ( typeof( values.diffuse ) === 'string' ) { + if ( !this.running ) + return; - _material.map = library.textures[ values.diffuse ]; + var now = Date.now(); + var deltat = ( now - this.startTime ) / 1000; + var t = deltat % this.duration; + var nCycles = Math.floor( deltat / this.duration ); - } + if ( nCycles >= 1 && ! this.loop ) { - if ( typeof( values.bump ) === 'string' ) { + this.running = false; + _each( this.interps, function( _, i ) { - _material.bumpMap = library.textures[ values.bump ]; + this.interps[ i ].interp( this.duration ); - } + }.bind( this )); + this.stop(); + return; - if ( Array.isArray( values.emission ) ) _material.emissive.fromArray( values.emission ); - if ( Array.isArray( values.specular ) ) _material.specular.fromArray( values.specular ); + } else { - if ( values.shininess !== undefined ) _material.shininess = values.shininess; + _each( this.interps, function( _, i ) { + this.interps[ i ].interp( t ); - library.materials[ materialId ] = _material; + }.bind( this )); - } + } - // meshes +}; - var meshes = json.meshes; +/* GLTFINTERPOLATOR */ - for ( var meshId in meshes ) { +var GLTFInterpolator = function( param ) { - var mesh = meshes[ meshId ]; + this.keys = param.keys; + this.values = param.values; + this.count = param.count; + this.type = param.type; + this.path = param.path; + this.isRot = false; - var group = new THREE.Group(); - group.name = mesh.name; + var node = param.target; + node.updateMatrix(); + node.matrixAutoUpdate = true; + this.targetNode = node; - var primitives = mesh.primitives; + switch ( param.path ) { - for ( var i = 0; i < primitives.length; i ++ ) { + case "translation" : - var primitive = primitives[ i ]; - var attributes = primitive.attributes; + this.target = node.position; + this.originalValue = node.position.clone(); + break; - var geometry = new THREE.BufferGeometry(); + case "rotation" : - if ( primitive.indices ) { + this.target = node.quaternion; + this.originalValue = node.quaternion.clone(); + this.isRot = true; + break; - geometry.setIndex( library.accessors[ primitive.indices ] ); + case "scale" : - } + this.target = node.scale; + this.originalValue = node.scale.clone(); + break; - for ( var attributeId in attributes ) { + } - var attribute = attributes[ attributeId ]; - var bufferAttribute = library.accessors[ attribute ]; + this.duration = this.keys[ this.count - 1 ]; - switch ( attributeId ) { + this.vec1 = new THREE.Vector3(); + this.vec2 = new THREE.Vector3(); + this.vec3 = new THREE.Vector3(); + this.quat1 = new THREE.Quaternion(); + this.quat2 = new THREE.Quaternion(); + this.quat3 = new THREE.Quaternion(); - case 'POSITION': - geometry.addAttribute( 'position', bufferAttribute ); - break; +}; - case 'NORMAL': - geometry.addAttribute( 'normal', bufferAttribute ); - break; +//Interpolation and tweening methods +GLTFInterpolator.prototype.interp = function( t ) { - case 'TEXCOORD_0': - geometry.addAttribute( 'uv', bufferAttribute ); - break; + if ( t == this.keys[ 0 ] ) { - } + if ( this.isRot ) { - } + this.quat3.fromArray( this.values ); - var material = library.materials[ primitive.material ]; + } else { - group.add( new THREE.Mesh( geometry, material ) ); + this.vec3.fromArray( this.values ); - } + } + + } else if ( t < this.keys[ 0 ] ) { + + if ( this.isRot ) { + + this.quat1.copy( this.originalValue ); + this.quat2.fromArray( this.values ); + THREE.Quaternion.slerp( this.quat1, this.quat2, this.quat3, t / this.keys[ 0 ] ); - library.meshes[ meshId ] = group; + } else { + + this.vec3.copy( this.originalValue ); + this.vec2.fromArray( this.values ); + this.vec3.lerp( this.vec2, t / this.keys[ 0 ] ); } - // nodes + } else if ( t >= this.keys[ this.count - 1 ] ) { - var nodes = json.nodes; - var matrix = new THREE.Matrix4(); + if ( this.isRot ) { - for ( var nodeId in nodes ) { + this.quat3.fromArray( this.values, ( this.count - 1 ) * 4 ); - var node = nodes[ nodeId ]; + } else { - var object = new THREE.Group(); - object.name = node.name; + this.vec3.fromArray( this.values, ( this.count - 1 ) * 3 ); - if ( node.translation !== undefined ) { + } - object.position.fromArray( node.translation ); + } else { - } + for ( var i = 0; i < this.count - 1; i ++ ) { - if ( node.rotation !== undefined ) { + var key1 = this.keys[ i ]; + var key2 = this.keys[ i + 1 ]; - object.quaternion.fromArray( node.rotation ); + if ( t >= key1 && t <= key2 ) { - } + if ( this.isRot ) { - if ( node.scale !== undefined ) { + this.quat1.fromArray( this.values, i * 4 ); + this.quat2.fromArray( this.values, ( i + 1 ) * 4 ); + THREE.Quaternion.slerp( this.quat1, this.quat2, this.quat3, ( t - key1 ) / ( key2 - key1 ) ); - object.scale.fromArray( node.scale ); + } else { + + this.vec3.fromArray( this.values, i * 3 ); + this.vec2.fromArray( this.values, ( i + 1 ) * 3 ); + this.vec3.lerp( this.vec2, ( t - key1 ) / ( key2 - key1 ) ); + + } } - if ( node.matrix !== undefined ) { + } + + } + + if ( this.target ) { - matrix.fromArray( node.matrix ); - matrix.decompose( object.position, object.quaternion, object.scale ); + if ( this.isRot ) { - } + this.target.copy( this.quat3 ); + + } else { + + this.target.copy( this.vec3 ); + + } + + } + +}; + + +/*********************************/ +/********** INTERNALS ************/ +/*********************************/ + +/* CONSTANTS */ + +var WEBGL_CONSTANTS = { + FLOAT: 5126, + //FLOAT_MAT2: 35674, + FLOAT_MAT3: 35675, + FLOAT_MAT4: 35676, + FLOAT_VEC2: 35664, + FLOAT_VEC3: 35665, + FLOAT_VEC4: 35666, + LINEAR: 9729, + REPEAT: 10497, + SAMPLER_2D: 35678, + TRIANGLES: 4, + UNSIGNED_BYTE: 5121, + UNSIGNED_SHORT: 5123, + + VERTEX_SHADER: 35633, + FRAGMENT_SHADER: 35632 +}; + +var WEBGL_TYPE = { + 5126: Number, + //35674: THREE.Matrix2, + 35675: THREE.Matrix3, + 35676: THREE.Matrix4, + 35664: THREE.Vector2, + 35665: THREE.Vector3, + 35666: THREE.Vector4, + 35678: THREE.Texture +}; + +var WEBGL_COMPONENT_TYPES = { + 5120: Int8Array, + 5121: Uint8Array, + 5122: Int16Array, + 5123: Uint16Array, + 5125: Uint32Array, + 5126: Float32Array +}; + +var WEBGL_FILTERS = { + 9728: THREE.NearestFilter, + 9729: THREE.LinearFilter, + 9984: THREE.NearestMipMapNearestFilter, + 9985: THREE.LinearMipMapNearestFilter, + 9986: THREE.NearestMipMapLinearFilter, + 9987: THREE.LinearMipMapLinearFilter +}; + +var WEBGL_WRAPPINGS = { + 33071: THREE.ClampToEdgeWrapping, + 33648: THREE.MirroredRepeatWrapping, + 10497: THREE.RepeatWrapping +}; + +var WEBGL_TYPE_SIZES = { + 'SCALAR': 1, + 'VEC2': 2, + 'VEC3': 3, + 'VEC4': 4, + 'MAT2': 4, + 'MAT3': 9, + 'MAT4': 16 +}; + +/* UTILITY FUNCTIONS */ - if ( node.meshes !== undefined ) { +var _each = function( object, callback, thisObj ) { + + if ( !object ) { + return Promise.resolve(); + } - for ( var i = 0; i < node.meshes.length; i ++ ) { + var results; + var fns = []; - var meshId = node.meshes[ i ]; - var group = library.meshes[ meshId ]; + if ( Object.prototype.toString.call( object ) === '[object Array]' ) { - object.add( group.clone() ); + results = []; + var length = object.length; + for ( var idx = 0; idx < length; idx ++ ) { + var value = callback.call( thisObj || this, object[ idx ], idx ); + if ( value ) { + fns.push( value ); + if ( value instanceof Promise ) { + value.then( function( key, value ) { + results[ idx ] = value; + }.bind( this, key )); + } else { + results[ idx ] = value; } + } + } + } else { + + results = {}; + + for ( var key in object ) { + if ( object.hasOwnProperty( key ) ) { + var value = callback.call( thisObj || this, object[ key ], key ); + if ( value ) { + fns.push( value ); + if ( value instanceof Promise ) { + value.then( function( key, value ) { + results[ key ] = value; + }.bind( this, key )); + } else { + results[ key ] = value; + } + } } + } + + } + + return Promise.all( fns ).then( function() { + return results; + }); + +}; + +var resolveURL = function( url, path ) { + + // Invalid URL + if ( typeof url !== 'string' || url === '' ) + return ''; + + // Absolute URL + if ( /^https?:\/\//i.test( url ) ) { + + return url; + + } + + // Data URI + if ( /^data:.*,.*$/i.test( url ) ) { + + return url; + + } - library.nodes[ nodeId ] = object; + // Relative URL + return (path || '') + url; + +}; + +// Three.js seems too dependent on attribute names so globally +// replace those in the shader code +var replaceTHREEShaderAttributes = function( shaderText, technique ) { + + // Expected technique attributes + var attributes = {}; + + _each( technique.attributes, function( pname, attributeId ) { + + var param = technique.parameters[ pname ]; + var atype = param.type; + var semantic = param.semantic; + + attributes[ attributeId ] = { + type : atype, + semantic : semantic + }; + + }); + + // Figure out which attributes to change in technique + + var shaderParams = technique.parameters; + var shaderAttributes = technique.attributes; + var params = {}; + + _each( attributes, function( _, attributeId ) { + + var pname = shaderAttributes[ attributeId ]; + var shaderParam = shaderParams[ pname ]; + var semantic = shaderParam.semantic; + if ( semantic ) { + + params[ attributeId ] = shaderParam; } - for ( var nodeId in nodes ) { + }); - var node = nodes[ nodeId ]; + _each( params, function( param, pname ) { - for ( var i = 0; i < node.children.length; i ++ ) { + var semantic = param.semantic; - var child = node.children[ i ]; + var regEx = eval( "/" + pname + "/g" ); - library.nodes[ nodeId ].add( library.nodes[ child ] ); + switch ( semantic ) { - } + case "POSITION": + + shaderText = shaderText.replace( regEx, 'position' ); + break; + + case "NORMAL": + + shaderText = shaderText.replace( regEx, 'normal' ); + break; + + case 'TEXCOORD_0': + case 'TEXCOORD0': + case 'TEXCOORD': + + shaderText = shaderText.replace( regEx, 'uv' ); + break; + + case "WEIGHT": + + shaderText = shaderText.replace(regEx, 'skinWeight'); + break; + + case "JOINT": + + shaderText = shaderText.replace(regEx, 'skinIndex'); + break; } - // scenes + }); - var scenes = json.scenes; + return shaderText; - for ( var sceneId in scenes ) { +}; - var scene = scenes[ sceneId ]; - var container = new THREE.Scene(); +// Deferred constructor for RawShaderMaterial types +var DeferredShaderMaterial = function( params ) { - for ( var i = 0; i < scene.nodes.length; i ++ ) { + this.isDeferredShaderMaterial = true; - var node = scene.nodes[ i ]; - container.add( library.nodes[ node ] ); + this.params = params; - } +}; + +DeferredShaderMaterial.prototype.create = function() { - library.scenes[ sceneId ] = container; + var uniforms = THREE.UniformsUtils.clone( this.params.uniforms ); + + _each( this.params.uniforms, function( originalUniform, uniformId ) { + + if ( originalUniform.value instanceof THREE.Texture ) { + + uniforms[ uniformId ].value = originalUniform.value; + uniforms[ uniformId ].value.needsUpdate = true; } - console.timeEnd( 'GLTFLoader' ); + uniforms[ uniformId ].semantic = originalUniform.semantic; + uniforms[ uniformId ].node = originalUniform.node; - return { + }); - scene: library.scenes[ json.scene ] + this.params.uniforms = uniforms; - }; + return new THREE.RawShaderMaterial( this.params ); + +}; + +/* GLTF PARSER */ + +var GLTFParser = function(json, options) { + + this.json = json || {}; + this.options = options || {}; + + // loader object cache + this.cache = new GLTFRegistry(); + +}; + +GLTFParser.prototype._withDependencies = function( dependencies ) { + + var _dependencies = {}; + + for ( var i = 0; i < dependencies.length; i ++ ) { + + var dependency = dependencies[ i ]; + var fnName = "load" + dependency.charAt(0).toUpperCase() + dependency.slice(1); + + var cached = this.cache.get( dependency ); + + if ( cached !== undefined ) { + + _dependencies[ dependency ] = cached; + + } else if ( this[ fnName ] ) { + + var fn = this[ fnName ](); + this.cache.add( dependency, fn ); + + _dependencies[ dependency ] = fn; + + } } + return _each( _dependencies, function( dependency, dependencyId ) { + + return dependency; + + }); + +}; + +GLTFParser.prototype.parse = function( callback ) { + + // Clear the loader cache + this.cache.removeAll(); + + // Fire the callback on complete + this._withDependencies([ + "scenes", + "cameras", + "animations" + ]).then(function( dependencies ) { + + var scene = dependencies.scenes[ this.json.scene ]; + + var cameras = []; + _each( dependencies.cameras, function( camera ) { + + cameras.push( camera ); + + }); + + var animations = []; + _each( dependencies.animations, function( animation ) { + + animations.push( animation ); + + }); + + callback( scene, cameras, animations ); + + }.bind( this )); + +}; + +GLTFParser.prototype.loadShaders = function() { + + return _each( this.json.shaders, function( shader, shaderId ) { + + return new Promise( function( resolve ) { + + var loader = new THREE.XHRLoader(); + loader.responseType = 'text'; + loader.load( resolveURL( shader.uri, this.options.path ), function( shaderText ) { + + resolve( shaderText ); + + }); + + }.bind( this )); + + }.bind( this )); + }; + +GLTFParser.prototype.loadBuffers = function() { + + return _each( this.json.buffers, function( buffer, bufferId ) { + + if ( buffer.type === 'arraybuffer' ) { + + return new Promise( function( resolve ) { + + var loader = new THREE.XHRLoader(); + loader.responseType = 'arraybuffer'; + loader.load( resolveURL( buffer.uri, this.options.path ), function( buffer ) { + + resolve( buffer ); + + } ); + + }.bind( this )); + + } + + }.bind( this )); + +}; + +GLTFParser.prototype.loadBufferViews = function() { + + return this._withDependencies([ + "buffers" + ]).then( function( dependencies ) { + + return _each( this.json.bufferViews, function( bufferView, bufferViewId ) { + + var arraybuffer = dependencies.buffers[ bufferView.buffer ]; + + return arraybuffer.slice( bufferView.byteOffset, bufferView.byteOffset + bufferView.byteLength ); + + }); + + }.bind( this )); + +}; + +GLTFParser.prototype.loadAccessors = function() { + + return this._withDependencies([ + "bufferViews" + ]).then( function( dependencies ) { + + return _each( this.json.accessors, function( accessor, accessorId ) { + + var arraybuffer = dependencies.bufferViews[ accessor.bufferView ]; + var itemSize = WEBGL_TYPE_SIZES[ accessor.type ]; + var TypedArray = WEBGL_COMPONENT_TYPES[ accessor.componentType ]; + + var array = new TypedArray( arraybuffer, accessor.byteOffset, accessor.count * itemSize ); + + return new THREE.BufferAttribute( array, itemSize ); + + }); + + }.bind( this )); + +}; + +GLTFParser.prototype.loadTextures = function() { + + return _each( this.json.textures, function( texture, textureId ) { + + if ( texture.source ) { + + return new Promise( function( resolve ) { + + var source = this.json.images[ texture.source ]; + + var textureLoader = THREE.Loader.Handlers.get( source.uri ); + if ( textureLoader === null ) { + + textureLoader = new THREE.TextureLoader(); + + } + textureLoader.crossOrigin = this.options.crossOrigin || false; + + textureLoader.load( resolveURL( source.uri, this.options.path ), function( _texture ) { + + _texture.flipY = false; + + if ( texture.sampler ) { + + var sampler = this.json.samplers[ texture.sampler ]; + + _texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ]; + _texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ]; + _texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ]; + _texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ]; + + } + + resolve( _texture ); + + }.bind( this )); + + }.bind( this )); + + } + + }.bind( this )); + +}; + +GLTFParser.prototype.loadMaterials = function() { + + return this._withDependencies([ + "shaders", + "textures" + ]).then( function( dependencies ) { + + return _each( this.json.materials, function( material, materialId ) { + + var materialType; + var materialValues = {}; + var materialParams = {}; + + var khr_material; + + if ( material.extensions && material.extensions.KHR_materials_common ) { + + khr_material = material.extensions.KHR_materials_common; + + } else if ( this.json.extensions && this.json.extensions.KHR_materials_common ) { + + khr_material = this.json.extensions.KHR_materials_common; + + } + + if ( khr_material ) { + + switch ( khr_material.technique ) + { + case 'BLINN' : + case 'PHONG' : + materialType = THREE.MeshPhongMaterial; + break; + + case 'LAMBERT' : + materialType = THREE.MeshLambertMaterial; + break; + + case 'CONSTANT' : + default : + materialType = THREE.MeshBasicMaterial; + break; + } + + _each( khr_material.values, function( value, prop ) { + + materialValues[ prop ] = value; + + }); + + if ( khr_material.doubleSided || materialValues.doubleSided ) { + + materialParams.side = THREE.DoubleSide; + + } + + if ( khr_material.transparent || materialValues.transparent ) { + + materialParams.transparent = true; + materialParams.opacity = ( materialValues.transparency !== undefined ) ? materialValues.transparency : 1; + + } + + } else if ( material.technique === undefined ) { + + materialType = THREE.MeshPhongMaterial; + + _each( material.values, function( value, prop ) { + + materialValues[ prop ] = value; + + }); + + } else { + + materialType = DeferredShaderMaterial; + + var technique = this.json.techniques[ material.technique ]; + + materialParams.uniforms = {}; + + var program = this.json.programs[ technique.program ]; + + if ( program ) { + + materialParams.fragmentShader = dependencies.shaders[ program.fragmentShader ]; + + if ( ! materialParams.fragmentShader ) { + + console.warn( "ERROR: Missing fragment shader definition:", program.fragmentShader ); + materialType = THREE.MeshPhongMaterial; + + } + + var vertexShader = dependencies.shaders[ program.vertexShader ]; + + if ( ! vertexShader ) { + + console.warn( "ERROR: Missing vertex shader definition:", program.vertexShader ); + materialType = THREE.MeshPhongMaterial; + + } + + // IMPORTANT: FIX VERTEX SHADER ATTRIBUTE DEFINITIONS + materialParams.vertexShader = replaceTHREEShaderAttributes( vertexShader, technique ); + + var uniforms = technique.uniforms; + + _each( uniforms, function( pname, uniformId ) { + + var shaderParam = technique.parameters[ pname ]; + + var ptype = shaderParam.type; + + if ( WEBGL_TYPE[ ptype ] ) { + + var pcount = shaderParam.count; + var value = material.values[ pname ]; + + var uvalue = new WEBGL_TYPE[ ptype ](); + var usemantic = shaderParam.semantic; + var unode = shaderParam.node; + + switch ( ptype ) { + + case WEBGL_CONSTANTS.FLOAT: + + uvalue = shaderParam.value; + + if ( pname == "transparency" ) { + + materialParams.transparent = true; + + } + + if ( value ) { + + uvalue = value; + + } + + break; + + case WEBGL_CONSTANTS.FLOAT_VEC2: + case WEBGL_CONSTANTS.FLOAT_VEC3: + case WEBGL_CONSTANTS.FLOAT_VEC4: + case WEBGL_CONSTANTS.FLOAT_MAT3: + + if ( shaderParam && shaderParam.value ) { + + uvalue.fromArray( shaderParam.value ); + + } + + if ( value ) { + + uvalue.fromArray( value ); + + } + + break; + + case WEBGL_CONSTANTS.FLOAT_MAT2: + + // what to do? + console.warn("FLOAT_MAT2 is not a supported uniform type"); + break; + + case WEBGL_CONSTANTS.FLOAT_MAT4: + + if ( pcount ) { + + uvalue = new Array( pcount ); + + for ( var mi = 0; mi < pcount; mi ++ ) { + + uvalue[ mi ] = new WEBGL_TYPE[ ptype ](); + + } + + if ( shaderParam && shaderParam.value ) { + + var m4v = shaderParam.value; + uvalue.fromArray( m4v ); + + } + + if ( value ) { + + uvalue.fromArray( value ); + + } + + } else { + + if ( shaderParam && shaderParam.value ) { + + var m4 = shaderParam.value; + uvalue.fromArray( m4 ); + + } + + if ( value ) { + + uvalue.fromArray( value ); + + } + + } + + break; + + case WEBGL_CONSTANTS.SAMPLER_2D: + + uvalue = value ? dependencies.textures[ value ] : null; + + break; + + } + + materialParams.uniforms[ uniformId ] = { + value: uvalue, + semantic: usemantic, + node: unode + }; + + } else { + + throw new Error( "Unknown shader uniform param type: " + ptype ); + + } + + }); + + } + + } + + if ( Array.isArray( materialValues.diffuse ) ) { + + materialParams.color = new THREE.Color().fromArray( materialValues.diffuse ); + + } else if ( typeof( materialValues.diffuse ) === 'string' ) { + + materialParams.map = dependencies.textures[ materialValues.diffuse ]; + + } + + delete materialParams.diffuse; + + if ( typeof( materialValues.reflective ) === 'string' ) { + + materialParams.envMap = dependencies.textures[ materialValues.reflective ]; + + } + + if ( typeof( materialValues.bump ) === 'string' ) { + + materialParams.bumpMap = dependencies.textures[ materialValues.bump ]; + + } + + if ( Array.isArray( materialValues.emission ) ) { + + materialParams.emissive = new THREE.Color().fromArray( materialValues.emission ); + + } + + if ( Array.isArray( materialValues.specular ) ) { + + materialParams.specular = new THREE.Color().fromArray( materialValues.specular ); + + } + + if ( materialValues.shininess !== undefined ) { + + materialParams.shininess = materialValues.shininess; + + } + + var _material = new materialType( materialParams ); + _material.name = material.name; + + return _material; + + }.bind( this )); + + }.bind( this )); + +}; + +GLTFParser.prototype.loadMeshes = function() { + + return this._withDependencies([ + "accessors", + "materials" + ]).then( function( dependencies ) { + + return _each( this.json.meshes, function( mesh, meshId ) { + + var group = new THREE.Object3D(); + group.name = mesh.name; + + var primitives = mesh.primitives; + + _each( primitives, function( primitive ) { + + if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES || primitive.mode === undefined ) { + + var geometry = new THREE.BufferGeometry(); + + var attributes = primitive.attributes; + + _each( attributes, function( attributeEntry, attributeId ) { + + if ( !attributeEntry ) { + + return; + + } + + var bufferAttribute = dependencies.accessors[ attributeEntry ]; + + switch ( attributeId ) { + + case 'POSITION': + geometry.addAttribute( 'position', bufferAttribute ); + break; + + case 'NORMAL': + geometry.addAttribute( 'normal', bufferAttribute ); + break; + + case 'TEXCOORD_0': + case 'TEXCOORD0': + case 'TEXCOORD': + geometry.addAttribute( 'uv', bufferAttribute ); + break; + + case 'WEIGHT': + geometry.addAttribute( 'skinWeight', bufferAttribute ); + break; + + case 'JOINT': + geometry.addAttribute( 'skinIndex', bufferAttribute ); + break; + + } + + }); + + if ( primitive.indices ) { + + var indexArray = dependencies.accessors[ primitive.indices ]; + + geometry.setIndex( indexArray ); + + var offset = { + start: 0, + index: 0, + count: indexArray.count + }; + + geometry.groups.push( offset ); + + geometry.computeBoundingSphere(); + + } + + + var material = dependencies.materials[ primitive.material ]; + + var meshNode = new THREE.Mesh( geometry, material ); + meshNode.castShadow = true; + + group.add( meshNode ); + + } else { + + console.warn("Non-triangular primitives are not supported"); + + } + + }); + + return group; + + }); + + }.bind( this )); + +}; + +GLTFParser.prototype.loadCameras = function() { + + return _each( this.json.cameras, function( camera, cameraId ) { + + if ( camera.type == "perspective" && camera.perspective ) { + + var yfov = camera.perspective.yfov; + var xfov = camera.perspective.xfov; + var aspect_ratio = camera.perspective.aspect_ratio || 1; + + // According to COLLADA spec... + // aspect_ratio = xfov / yfov + xfov = ( xfov === undefined && yfov ) ? yfov * aspect_ratio : xfov; + + // According to COLLADA spec... + // aspect_ratio = xfov / yfov + // yfov = ( yfov === undefined && xfov ) ? xfov / aspect_ratio : yfov; + + var _camera = new THREE.PerspectiveCamera( THREE.Math.radToDeg( xfov ), aspect_ratio, camera.perspective.znear || 1, camera.perspective.zfar || 2e6 ); + _camera.name = camera.name; + + return _camera; + + } else if ( camera.type == "orthographic" && camera.orthographic ) { + + var _camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, camera.orthographic.znear, camera.orthographic.zfar ); + _camera.name = camera.name; + + return _camera; + + } + + }.bind( this )); + +}; + +GLTFParser.prototype.loadSkins = function() { + + return this._withDependencies([ + "accessors" + ]).then( function( dependencies ) { + + return _each( this.json.skins, function( skin, skinId ) { + + var _skin = { + bindShapeMatrix: new THREE.Matrix4().fromArray( skin.bindShapeMatrix ), + jointNames: skin.jointNames, + inverseBindMatrices: dependencies.accessors[ skin.inverseBindMatrices ] + }; + + return _skin; + + }); + + }.bind( this )); + +}; + +GLTFParser.prototype.loadAnimations = function() { + + return this._withDependencies([ + "accessors", + "nodes" + ]).then( function( dependencies ) { + + return _each( this.json.animations, function( animation, animationId ) { + + var interps = []; + + _each( animation.channels, function( channel ) { + + var sampler = animation.samplers[ channel.sampler ]; + + if (sampler && animation.parameters) { + + var target = channel.target; + var name = target.id; + var input = animation.parameters[sampler.input]; + var output = animation.parameters[sampler.output]; + + var inputAccessor = dependencies.accessors[ input ]; + var outputAccessor = dependencies.accessors[ output ]; + + var node = dependencies.nodes[ name ]; + + if ( node ) { + + var interp = { + keys : inputAccessor.array, + values : outputAccessor.array, + count : inputAccessor.count, + target : node, + path : target.path, + type : sampler.interpolation + }; + + interps.push( interp ); + + } + + } + + }); + + var _animation = new GLTFAnimation(interps); + _animation.name = "animation_" + animationId; + + return _animation; + + }); + + }.bind( this )); + +}; + +GLTFParser.prototype.loadNodes = function() { + + return _each( this.json.nodes, function( node, nodeId ) { + + var matrix = new THREE.Matrix4(); + + var _node; + + if ( node.jointName ) { + + _node = new THREE.Bone(); + _node.jointName = node.jointName; + + } else { + + _node = new THREE.Object3D() + + } + + _node.name = node.name; + + _node.matrixAutoUpdate = false; + + if ( node.matrix !== undefined ) { + + matrix.fromArray( node.matrix ); + _node.applyMatrix( matrix ); + + } else { + + if ( node.translation !== undefined ) { + + _node.position.fromArray( node.translation ); + + } + + if ( node.rotation !== undefined ) { + + _node.quaternion.fromArray( node.rotation ); + + } + + if ( node.scale !== undefined ) { + + _node.scale.fromArray( node.scale ); + + } + + } + + return _node; + + }.bind( this )).then( function( __nodes ) { + + return this._withDependencies([ + "meshes", + "skins", + "cameras", + "extensions" + ]).then( function( dependencies ) { + + return _each( __nodes, function( _node, nodeId ) { + + var node = this.json.nodes[ nodeId ]; + + if ( node.meshes !== undefined ) { + + _each( node.meshes, function( meshId ) { + + var group = dependencies.meshes[ meshId ]; + + _each( group.children, function( mesh ) { + + // clone Mesh to add to _node + + var originalMaterial = mesh.material; + var originalGeometry = mesh.geometry; + + var material; + if(originalMaterial.isDeferredShaderMaterial) { + originalMaterial = material = originalMaterial.create(); + } else { + material = originalMaterial; + } + + mesh = new THREE.Mesh( originalGeometry, material ); + mesh.castShadow = true; + + var skinEntry; + if ( node.skin ) { + + skinEntry = dependencies.skins[ node.skin ]; + + } + + // Replace Mesh with SkinnedMesh in library + if (skinEntry) { + + var geometry = originalGeometry; + var material = originalMaterial; + material.skinning = true; + + mesh = new THREE.SkinnedMesh( geometry, material, false ); + mesh.castShadow = true; + + var bones = []; + var boneInverses = []; + + _each( skinEntry.jointNames, function( jointId, i ) { + + var jointNode = __nodes[ jointId ]; + + if ( jointNode ) { + + jointNode.skin = mesh; + bones.push(jointNode); + + var m = skinEntry.inverseBindMatrices.array; + var mat = new THREE.Matrix4().fromArray( m, i * 16 ); + boneInverses.push(mat); + + } else { + console.warn( "WARNING: joint: ''" + jointId + "' could not be found" ); + } + + }); + + mesh.bind( new THREE.Skeleton( bones, boneInverses, false ), skinEntry.bindShapeMatrix ); + + } + + _node.add( mesh ); + + }); + + }); + + } + + if ( node.camera !== undefined ) { + + var camera = dependencies.cameras[ node.camera ]; + + _node.add( camera ); + + } + + if (node.extensions && node.extensions.KHR_materials_common + && node.extensions.KHR_materials_common.light) { + + var light = dependencies.extensions.KHR_materials_common.lights[ node.extensions.KHR_materials_common.light ]; + + _node.add(light); + + } + + return _node; + + }.bind( this )); + + }.bind( this )); + + }.bind( this )); + +}; + +GLTFParser.prototype.loadExtensions = function() { + + return _each( this.json.extensions, function( extension, extensionId ) { + + switch ( extensionId ) { + + case "KHR_materials_common": + + var extensionNode = { + lights: {} + }; + + var lights = extension.lights; + + _each( lights, function( light, lightID ) { + + var lightNode; + + var lightParams = light[light.type]; + var color = new THREE.Color().fromArray( lightParams.color ); + + switch ( light.type ) { + + case "directional": + lightNode = new THREE.DirectionalLight( color ); + lightNode.position.set( 0, 0, 1 ); + break; + + case "point": + lightNode = new THREE.PointLight( color ); + break; + + case "spot ": + lightNode = new THREE.SpotLight( color ); + lightNode.position.set( 0, 0, 1 ); + break; + + case "ambient": + lightNode = new THREE.AmbientLight( color ); + break; + + } + + if ( lightNode ) { + + extensionNode.lights[ lightID ] = lightNode; + + } + + }); + + return extensionNode; + + break; + + } + + }.bind( this )); + +}; + +GLTFParser.prototype.loadScenes = function() { + + // scene node hierachy builder + + var buildNodeHierachy = function( nodeId, parentObject, allNodes ) { + + var _node = allNodes[ nodeId ]; + parentObject.add( _node ); + + var node = this.json.nodes[ nodeId ]; + + if ( node.children ) { + + _each( node.children, function( child ) { + + buildNodeHierachy( child, _node, allNodes ); + + }); + + } + + }.bind( this ); + + return this._withDependencies([ + "nodes" + ]).then( function( dependencies ) { + + return _each( this.json.scenes, function( scene, sceneId ) { + + var _scene = new THREE.Scene(); + _scene.name = scene.name; + + _each( scene.nodes, function( nodeId ) { + + buildNodeHierachy( nodeId, _scene, dependencies.nodes ); + + }); + + _scene.traverse( function( child ) { + + // Register raw material meshes with GLTFLoader.Shaders + if (child.material && child.material.isRawShaderMaterial) { + var xshader = new GLTFShader( child, dependencies.nodes ); + THREE.GLTFLoader.Shaders.add( child.uuid, xshader ); + } + + }); + + return _scene; + + }); + + }.bind( this )); + +}; + +})(); diff --git a/examples/js/loaders/gltf/glTF-parser.js b/examples/js/loaders/deprecated/gltf/glTF-parser.js similarity index 100% rename from examples/js/loaders/gltf/glTF-parser.js rename to examples/js/loaders/deprecated/gltf/glTF-parser.js diff --git a/examples/js/loaders/gltf/glTFAnimation.js b/examples/js/loaders/deprecated/gltf/glTFAnimation.js similarity index 100% rename from examples/js/loaders/gltf/glTFAnimation.js rename to examples/js/loaders/deprecated/gltf/glTFAnimation.js diff --git a/examples/js/loaders/gltf/glTFLoader.js b/examples/js/loaders/deprecated/gltf/glTFLoader.js similarity index 100% rename from examples/js/loaders/gltf/glTFLoader.js rename to examples/js/loaders/deprecated/gltf/glTFLoader.js diff --git a/examples/js/loaders/gltf/glTFLoaderUtils.js b/examples/js/loaders/deprecated/gltf/glTFLoaderUtils.js similarity index 100% rename from examples/js/loaders/gltf/glTFLoaderUtils.js rename to examples/js/loaders/deprecated/gltf/glTFLoaderUtils.js diff --git a/examples/js/loaders/gltf/glTFShaders.js b/examples/js/loaders/deprecated/gltf/glTFShaders.js similarity index 100% rename from examples/js/loaders/gltf/glTFShaders.js rename to examples/js/loaders/deprecated/gltf/glTFShaders.js diff --git a/examples/js/loaders/gltf/gltfUtilities.js b/examples/js/loaders/deprecated/gltf/gltfUtilities.js similarity index 100% rename from examples/js/loaders/gltf/gltfUtilities.js rename to examples/js/loaders/deprecated/gltf/gltfUtilities.js diff --git a/examples/webgl_loader_gltf.html b/examples/webgl_loader_gltf.html index bfcc1fe36d171ae54151827c2737a539b82e82f6..6b03bd7ed6496b52d85af09315dbf3a19c024cb1 100644 --- a/examples/webgl_loader_gltf.html +++ b/examples/webgl_loader_gltf.html @@ -126,11 +126,7 @@ - - - - - +