Browse Source

[glTF] Implement loadTexture(texIndex).

Don McCurdy 8 years ago
parent
commit
5ff4d48dee
1 changed files with 201 additions and 127 deletions
  1. 201 127
      examples/js/loaders/GLTF2Loader.js

+ 201 - 127
examples/js/loaders/GLTF2Loader.js

@@ -316,10 +316,12 @@ THREE.GLTF2Loader = ( function () {
 
 	};
 
-	GLTFMaterialsCommonExtension.prototype.extendParams = function ( materialParams, material, dependencies ) {
+	GLTFMaterialsCommonExtension.prototype.extendParams = function ( materialParams, material, parser ) {
 
 		var khrMaterial = material.extensions[ this.name ];
 
+		var pending = [];
+
 		var keys = [];
 
 		// TODO: Currently ignored: 'ambientFactor', 'ambientTexture'
@@ -357,7 +359,7 @@ THREE.GLTF2Loader = ( function () {
 
 		if ( materialValues.diffuseTexture !== undefined ) {
 
-			materialParams.map = dependencies.textures[ materialValues.diffuseTexture.index ];
+			pending.push( parser.assignTexture( materialParams, 'map', materialValues.diffuseTexture.index ) );
 
 		}
 
@@ -369,7 +371,7 @@ THREE.GLTF2Loader = ( function () {
 
 		if ( materialValues.specularTexture !== undefined ) {
 
-			materialParams.specularMap = dependencies.textures[ materialValues.specularTexture.index ];
+			pending.push( parser.assignTexture( materialParams, 'specularMap', materialValues.specularTexture.index ) );
 
 		}
 
@@ -379,6 +381,8 @@ THREE.GLTF2Loader = ( function () {
 
 		}
 
+		return Promise.all( pending );
+
 	};
 
 	/* BINARY EXTENSION */
@@ -466,10 +470,7 @@ THREE.GLTF2Loader = ( function () {
 
 			},
 
-			extendParams: function ( params, material, dependencies ) {
-
-				// specification
-				// https://github.com/sbtron/glTF/tree/KHRpbrSpecGloss/extensions/Khronos/KHR_materials_pbrSpecularGlossiness
+			extendParams: function ( params, material, parser ) {
 
 				var pbrSpecularGlossiness = material.extensions[ this.name ];
 
@@ -542,6 +543,8 @@ THREE.GLTF2Loader = ( function () {
 				params.color = new THREE.Color( 1.0, 1.0, 1.0 );
 				params.opacity = 1.0;
 
+				var pending = [];
+
 				if ( Array.isArray( pbrSpecularGlossiness.diffuseFactor ) ) {
 
 					var array = pbrSpecularGlossiness.diffuseFactor;
@@ -553,7 +556,7 @@ THREE.GLTF2Loader = ( function () {
 
 				if ( pbrSpecularGlossiness.diffuseTexture !== undefined ) {
 
-					params.map = dependencies.textures[ pbrSpecularGlossiness.diffuseTexture.index ];
+					pending.push( parser.assignTexture( params, 'map', pbrSpecularGlossiness.diffuseTexture.index ) );
 
 				}
 
@@ -569,11 +572,14 @@ THREE.GLTF2Loader = ( function () {
 
 				if ( pbrSpecularGlossiness.specularGlossinessTexture !== undefined ) {
 
-					params.glossinessMap = dependencies.textures[ pbrSpecularGlossiness.specularGlossinessTexture.index ];
-					params.specularMap = dependencies.textures[ pbrSpecularGlossiness.specularGlossinessTexture.index ];
+					var specGlossIndex = pbrSpecularGlossiness.specularGlossinessTexture.index;
+					pending.push( parser.assignTexture( params, 'glossinessMap', specGlossIndex ) );
+					pending.push( parser.assignTexture( params, 'specularMap', specGlossIndex ) );
 
 				}
 
+				return Promise.all( pending );
+
 			},
 
 			createMaterial: function ( params ) {
@@ -1290,6 +1296,29 @@ THREE.GLTF2Loader = ( function () {
 
 	};
 
+	/**
+	 * Requests the specified dependency asynchronously, with caching.
+	 * @param {string} type
+	 * @param {number} index
+	 * @return {Promise<Object>}
+	 */
+	GLTFParser.prototype.getDependency = function ( type, index ) {
+
+		var cacheKey = type + ':' + index;
+		var dependency = this.cache.get( cacheKey );
+
+		if ( !dependency ) {
+
+			var fnName = 'load' + type.charAt( 0 ).toUpperCase() + type.slice( 1 );
+			dependency = this[ fnName ]( index );
+			this.cache.add( cacheKey, dependency );
+
+		}
+
+		return dependency;
+
+	};
+
 	GLTFParser.prototype.loadBuffers = function () {
 
 		var json = this.json;
@@ -1329,6 +1358,26 @@ THREE.GLTF2Loader = ( function () {
 
 	};
 
+	/**
+	 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views
+	 * @param {number} bufferViewIndex
+	 * @return {Promise<ArrayBuffer>}
+	 */
+	GLTFParser.prototype.loadBufferView = function ( bufferViewIndex ) {
+
+		return this._withDependencies( [
+
+			'bufferViews'
+
+		] ).then( function ( dependencies ) {
+
+			return dependencies.bufferViews[ bufferViewIndex ];
+
+		} );
+
+	};
+
+	/** @deprecated */
 	GLTFParser.prototype.loadBufferViews = function () {
 
 		var json = this.json;
@@ -1401,230 +1450,255 @@ THREE.GLTF2Loader = ( function () {
 
 	};
 
-	GLTFParser.prototype.loadTextures = function () {
+	var URL = window.URL || window.webkitURL;
+
+	/**
+	 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#textures
+	 * @param {number} textureIndex
+	 * @return {Promise<THREE.Texture>}
+	 */
+	GLTFParser.prototype.loadTexture = function ( textureIndex ) {
 
+		var parser = this;
 		var json = this.json;
 		var options = this.options;
 
-		return this._withDependencies( [
+		var textureDef = this.json.textures[ textureIndex ];
 
-			'bufferViews'
+		if ( textureDef.source === undefined ) {
 
-		] ).then( function ( dependencies ) {
+			throw new Error( 'THREE.GLTF2Loader: Unknown texture for index ' + textureIndex );
 
-			return _each( json.textures, function ( texture ) {
+		}
 
-				if ( texture.source !== undefined ) {
+		var source = json.images[ textureDef.source ];
+		var sourceURI = source.uri;
+		var isObjectURL = false;
 
-					return new Promise( function ( resolve ) {
+		if ( source.bufferView !== undefined ) {
 
-						var source = json.images[ texture.source ];
-						var sourceUri = source.uri;
+			// Load binary image data from bufferView, if provided.
 
-						var urlCreator;
+			sourceURI = parser.loadBufferView( source.bufferView )
+				.then( function ( bufferView ) {
 
-						if ( source.bufferView !== undefined ) {
+					isObjectURL = true;
+					var blob = new Blob( [ bufferView ], { type: source.mimeType } );
+					sourceURI = URL.createObjectURL( blob );
+					return sourceURI;
 
-							var bufferView = dependencies.bufferViews[ source.bufferView ];
-							var blob = new Blob( [ bufferView ], { type: source.mimeType } );
-							urlCreator = window.URL || window.webkitURL;
-							sourceUri = urlCreator.createObjectURL( blob );
+				} );
 
-						}
+		}
 
-						var textureLoader = THREE.Loader.Handlers.get( sourceUri );
+		return Promise.resolve( sourceURI ).then( function ( sourceURI ) {
 
-						if ( textureLoader === null ) {
+			// Load Texture resource.
 
-							textureLoader = new THREE.TextureLoader();
+			var textureLoader = THREE.Loader.Handlers.get( sourceURI ) || new THREE.TextureLoader();
+			textureLoader.setCrossOrigin( options.crossOrigin );
 
-						}
+			return new Promise( function ( resolve, reject ) {
 
-						textureLoader.setCrossOrigin( options.crossOrigin );
+				textureLoader.load( resolveURL( sourceURI, options.path ), resolve, undefined, reject );
 
-						textureLoader.load( resolveURL( sourceUri, options.path ), function ( _texture ) {
+			} );
 
-							if ( urlCreator !== undefined ) {
+		} ).then( function ( texture ) {
 
-								urlCreator.revokeObjectURL( sourceUri );
+			// Clean up resources and configure Texture.
 
-							}
+			if ( isObjectURL !== undefined ) {
 
-							_texture.flipY = false;
+				URL.revokeObjectURL( sourceURI );
 
-							if ( texture.name !== undefined ) _texture.name = texture.name;
+			}
 
-							_texture.format = texture.format !== undefined ? WEBGL_TEXTURE_FORMATS[ texture.format ] : THREE.RGBAFormat;
+			texture.flipY = false;
 
-							if ( texture.internalFormat !== undefined && _texture.format !== WEBGL_TEXTURE_FORMATS[ texture.internalFormat ] ) {
+			if ( textureDef.name !== undefined ) texture.name = textureDef.name;
 
-								console.warn( 'THREE.GLTF2Loader: Three.js does not support texture internalFormat which is different from texture format. ' +
-															'internalFormat will be forced to be the same value as format.' );
+			texture.format = textureDef.format !== undefined ? WEBGL_TEXTURE_FORMATS[ textureDef.format ] : THREE.RGBAFormat;
 
-							}
+			if ( textureDef.internalFormat !== undefined && texture.format !== WEBGL_TEXTURE_FORMATS[ textureDef.internalFormat ] ) {
 
-							_texture.type = texture.type !== undefined ? WEBGL_TEXTURE_DATATYPES[ texture.type ] : THREE.UnsignedByteType;
+				console.warn( 'THREE.GLTF2Loader: Three.js does not support texture internalFormat which is different from texture format. ' +
+											'internalFormat will be forced to be the same value as format.' );
 
-							var samplers = json.samplers || {};
-							var sampler = samplers[ texture.sampler ] || {};
+			}
 
-							_texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || THREE.LinearFilter;
-							_texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || THREE.LinearMipMapLinearFilter;
-							_texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || THREE.RepeatWrapping;
-							_texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || THREE.RepeatWrapping;
+			texture.type = textureDef.type !== undefined ? WEBGL_TEXTURE_DATATYPES[ textureDef.type ] : THREE.UnsignedByteType;
 
-							resolve( _texture );
+			var samplers = json.samplers || {};
+			var sampler = samplers[ textureDef.sampler ] || {};
 
-						}, undefined, function () {
+			texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || THREE.LinearFilter;
+			texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || THREE.LinearMipMapLinearFilter;
+			texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || THREE.RepeatWrapping;
+			texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || THREE.RepeatWrapping;
 
-							resolve();
+			return texture;
 
-						} );
+		} );
 
-					} );
+	};
 
-				}
+	/**
+	 * Asynchronously assigns a texture to the given material parameters.
+	 * @param {Object} materialParams
+	 * @param {string} textureName
+	 * @param {number} textureIndex
+	 * @return {Promise}
+	 */
+	GLTFParser.prototype.assignTexture = function ( materialParams, textureName, textureIndex ) {
 
-			} );
+		return this.getDependency( 'texture', textureIndex ).then( function ( texture ) {
+
+			materialParams[ textureName ] = texture;
 
 		} );
 
 	};
 
+	/**
+	 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials
+	 * @return {Promise<Array<THREE.Material>>}
+	 */
 	GLTFParser.prototype.loadMaterials = function () {
 
+		var parser = this;
 		var json = this.json;
 		var extensions = this.extensions;
 
-		return this._withDependencies( [
+		return _each( json.materials, function ( material ) {
 
-			'textures'
+			var materialType;
+			var materialParams = {};
+			var materialExtensions = material.extensions || {};
 
-		] ).then( function ( dependencies ) {
+			var pending = [];
 
-			return _each( json.materials, function ( material ) {
+			if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] ) {
 
-				var materialType;
-				var materialParams = {};
-				var materialExtensions = material.extensions || {};
+				var khcExtension = extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ];
+				materialType = khcExtension.getMaterialType( material );
+				pending.push( khcExtension.extendParams( materialParams, material, parser ) );
 
-				if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] ) {
+			} else if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ] ) {
 
-					materialType = extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ].getMaterialType( material );
-					extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ].extendParams( materialParams, material, dependencies );
+				var sgExtension = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ];
+				materialType = sgExtension.getMaterialType( material );
+				pending.push( sgExtension.extendParams( materialParams, material, parser ) );
 
-				} else if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ] ) {
+			} else if ( materialExtensions[ EXTENSIONS.KHR_TECHNIQUE_WEBGL ] ) {
 
-					materialType = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].getMaterialType( material );
-					extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].extendParams( materialParams, material, dependencies );
+				materialType = extensions[ EXTENSIONS.KHR_TECHNIQUE_WEBGL ].getMaterialType( material );
+				extensions[ EXTENSIONS.KHR_TECHNIQUE_WEBGL ].extendParams( materialParams, material, dependencies );
 
-				} else if ( materialExtensions[ EXTENSIONS.KHR_TECHNIQUE_WEBGL ] ) {
+			} else if ( material.pbrMetallicRoughness !== undefined ) {
 
-					materialType = extensions[ EXTENSIONS.KHR_TECHNIQUE_WEBGL ].getMaterialType( material );
-					extensions[ EXTENSIONS.KHR_TECHNIQUE_WEBGL ].extendParams( materialParams, material, dependencies );
+				// Specification:
+				// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material
 
-				} else if ( material.pbrMetallicRoughness !== undefined ) {
+				materialType = THREE.MeshStandardMaterial;
 
-					// Specification:
-					// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material
+				var metallicRoughness = material.pbrMetallicRoughness;
 
-					materialType = THREE.MeshStandardMaterial;
+				materialParams.color = new THREE.Color( 1.0, 1.0, 1.0 );
+				materialParams.opacity = 1.0;
 
-					var metallicRoughness = material.pbrMetallicRoughness;
+				if ( Array.isArray( metallicRoughness.baseColorFactor ) ) {
 
-					materialParams.color = new THREE.Color( 1.0, 1.0, 1.0 );
-					materialParams.opacity = 1.0;
+					var array = metallicRoughness.baseColorFactor;
 
-					if ( Array.isArray( metallicRoughness.baseColorFactor ) ) {
+					materialParams.color.fromArray( array );
+					materialParams.opacity = array[ 3 ];
 
-						var array = metallicRoughness.baseColorFactor;
-
-						materialParams.color.fromArray( array );
-						materialParams.opacity = array[ 3 ];
-
-					}
+				}
 
-					if ( metallicRoughness.baseColorTexture !== undefined ) {
+				if ( metallicRoughness.baseColorTexture !== undefined ) {
 
-						materialParams.map = dependencies.textures[ metallicRoughness.baseColorTexture.index ];
+					pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture.index ) );
 
-					}
+				}
 
-					materialParams.metalness = metallicRoughness.metallicFactor !== undefined ? metallicRoughness.metallicFactor : 1.0;
-					materialParams.roughness = metallicRoughness.roughnessFactor !== undefined ? metallicRoughness.roughnessFactor : 1.0;
+				materialParams.metalness = metallicRoughness.metallicFactor !== undefined ? metallicRoughness.metallicFactor : 1.0;
+				materialParams.roughness = metallicRoughness.roughnessFactor !== undefined ? metallicRoughness.roughnessFactor : 1.0;
 
-					if ( metallicRoughness.metallicRoughnessTexture !== undefined ) {
+				if ( metallicRoughness.metallicRoughnessTexture !== undefined ) {
 
-						var textureIndex = metallicRoughness.metallicRoughnessTexture.index;
-						materialParams.metalnessMap = dependencies.textures[ textureIndex ];
-						materialParams.roughnessMap = dependencies.textures[ textureIndex ];
+					var textureIndex = metallicRoughness.metallicRoughnessTexture.index;
+					pending.push( parser.assignTexture( materialParams, 'metalnessMap', textureIndex ) );
+					pending.push( parser.assignTexture( materialParams, 'roughnessMap', textureIndex ) );
 
-					}
+				}
 
-				} else {
+			} else {
 
-					materialType = THREE.MeshPhongMaterial;
+				materialType = THREE.MeshPhongMaterial;
 
-				}
+			}
 
-				if ( material.doubleSided === true ) {
+			if ( material.doubleSided === true ) {
 
-					materialParams.side = THREE.DoubleSide;
+				materialParams.side = THREE.DoubleSide;
 
-				}
+			}
 
-				var alphaMode = material.alphaMode || ALPHA_MODES.OPAQUE;
+			var alphaMode = material.alphaMode || ALPHA_MODES.OPAQUE;
 
-				if ( alphaMode !== ALPHA_MODES.OPAQUE ) {
+			if ( alphaMode !== ALPHA_MODES.OPAQUE ) {
 
-					materialParams.transparent = true;
+				materialParams.transparent = true;
 
-				} else {
+			} else {
 
-					materialParams.transparent = false;
+				materialParams.transparent = false;
 
-				}
-
-				if ( material.normalTexture !== undefined ) {
+			}
 
-					materialParams.normalMap = dependencies.textures[ material.normalTexture.index ];
+			if ( material.normalTexture !== undefined ) {
 
-				}
+				pending.push( parser.assignTexture( materialParams, 'normalMap', material.normalTexture.index ) );
 
-				if ( material.occlusionTexture !== undefined ) {
+			}
 
-					materialParams.aoMap = dependencies.textures[ material.occlusionTexture.index ];
+			if ( material.occlusionTexture !== undefined ) {
 
-				}
+				pending.push( parser.assignTexture( materialParams, 'aoMap', material.occlusionTexture.index ) );
 
-				if ( material.emissiveFactor !== undefined ) {
+			}
 
-					if ( materialType === THREE.MeshBasicMaterial ) {
+			if ( material.emissiveFactor !== undefined ) {
 
-						materialParams.color = new THREE.Color().fromArray( material.emissiveFactor );
+				if ( materialType === THREE.MeshBasicMaterial ) {
 
-					} else {
+					materialParams.color = new THREE.Color().fromArray( material.emissiveFactor );
 
-						materialParams.emissive = new THREE.Color().fromArray( material.emissiveFactor );
+				} else {
 
-					}
+					materialParams.emissive = new THREE.Color().fromArray( material.emissiveFactor );
 
 				}
 
-				if ( material.emissiveTexture !== undefined ) {
+			}
 
-					if ( materialType === THREE.MeshBasicMaterial ) {
+			if ( material.emissiveTexture !== undefined ) {
 
-						materialParams.map = dependencies.textures[ material.emissiveTexture.index ];
+				if ( materialType === THREE.MeshBasicMaterial ) {
 
-					} else {
+					pending.push( parser.assignTexture( materialParams, 'map', material.emissiveTexture.index ) );
 
-						materialParams.emissiveMap = dependencies.textures[ material.emissiveTexture.index ];
+				} else {
 
-					}
+					pending.push( parser.assignTexture( materialParams, 'emissiveMap', material.emissiveTexture.index ) );
 
 				}
 
+			}
+
+			return Promise.all( pending ).then( function () {
+
 				var _material;
 
 				if ( materialType === THREE.ShaderMaterial ) {