|
@@ -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 ));
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
+})();
|