Browse Source

Change glTF 2 loader to not return until textures are done loading
Don't load the same textures multiple times
Fix issue with textureInfos with different texCoord

Gary Hsu 8 years ago
parent
commit
81f024f5b5

+ 1 - 3
loaders/src/glTF/1.0/babylon.glTFLoader.ts

@@ -1602,7 +1602,7 @@ module BABYLON.GLTF1 {
             return true;
         }
 
-        public loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void): boolean {
+        public loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void): void {
             scene.useRightHandedSystem = true;
 
             GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, gltfRuntime => {
@@ -1628,8 +1628,6 @@ module BABYLON.GLTF1 {
                     }
                 }, onError);
             }, onError);
-
-            return true;
         }
 
         private _loadShadersAsync(gltfRuntime: IGLTFRuntime, onload: () => void): void {

+ 173 - 97
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -477,7 +477,7 @@ module BABYLON.GLTF2 {
         }
 
         return material;
-    }
+    };
 
     /**
     * Imports a mesh and its geometries
@@ -787,7 +787,7 @@ module BABYLON.GLTF2 {
                 traverseNodes(runtime, i, null);
             }
         }
-    }
+    };
 
     /**
     * do stuff after buffers are loaded (e.g. hook up materials, load animations, etc.)
@@ -802,12 +802,12 @@ module BABYLON.GLTF2 {
             var skeleton = runtime.babylonScene.skeletons[i];
             runtime.babylonScene.beginAnimation(skeleton, 0, Number.MAX_VALUE, true, 1.0);
         }
-    };
 
-    var importMaterials = (runtime: IGLTFRuntime): void => {
-        if (runtime.gltf.materials) {
-            for (var i = 0; i < runtime.gltf.materials.length; i++) {
-                GLTFLoaderExtension.LoadMaterial(runtime, i);
+        // Revoke object urls created during load
+        for (var i = 0; i < runtime.gltf.textures.length; i++) {
+            var texture = runtime.gltf.textures[i];
+            if (texture.blobURL) {
+                URL.revokeObjectURL(texture.blobURL);
             }
         }
     };
@@ -873,22 +873,52 @@ module BABYLON.GLTF2 {
             return material;
         }
 
-        public static LoadMetallicRoughnessMaterialProperties = (runtime: IGLTFRuntime, material: IGLTFMaterial): void => {
+        public static LoadMetallicRoughnessMaterialPropertiesAsync(runtime: IGLTFRuntime, material: IGLTFMaterial, onSuccess: () => void, onError: () => void): void {
+            // Ensure metallic workflow
+            material.babylonMaterial.metallic = 1;
+            material.babylonMaterial.roughness = 1;
+
             var properties = material.pbrMetallicRoughness;
-            if (!properties) return;
+            if (!properties) {
+                onSuccess();
+                return;
+            }
+
+            //
+            // Load Factors
+            //
 
             material.babylonMaterial.albedoColor = properties.baseColorFactor ? Color3.FromArray(properties.baseColorFactor) : new Color3(1, 1, 1);
-            material.babylonMaterial.metallic = properties.metallicFactor === undefined ? 1 : properties.metallicFactor;
-            material.babylonMaterial.roughness = properties.roughnessFactor === undefined ? 1 : properties.roughnessFactor;
+            material.babylonMaterial.metallic = properties.metallicFactor || 1;
+            material.babylonMaterial.roughness = properties.roughnessFactor || 1;
+
+            //
+            // Load Textures
+            //
+
+            if (!properties.baseColorTexture && !properties.metallicRoughnessTexture) {
+                onSuccess();
+                return;
+            }
+
+            var checkSuccess = () => {
+                if ((!properties.baseColorTexture || material.babylonMaterial.albedoTexture) &&
+                    (!properties.metallicRoughnessTexture || material.babylonMaterial.metallicTexture))
+                {
+                    onSuccess();
+                }
+            };
 
             if (properties.baseColorTexture) {
                 GLTFLoader.LoadTextureAsync(runtime, properties.baseColorTexture,
                     texture => {
                         material.babylonMaterial.albedoTexture = texture;
                         GLTFLoader.LoadAlphaProperties(runtime, material);
+                        checkSuccess();
                     },
                     () => {
-                        Tools.Warn("Failed to load base color texture");
+                        Tools.Error("Failed to load base color texture");
+                        onError();
                     });
             }
 
@@ -899,21 +929,56 @@ module BABYLON.GLTF2 {
                         material.babylonMaterial.useMetallnessFromMetallicTextureBlue = true;
                         material.babylonMaterial.useRoughnessFromMetallicTextureGreen = true;
                         material.babylonMaterial.useRoughnessFromMetallicTextureAlpha = false;
+                        checkSuccess();
                     },
                     () => {
-                        Tools.Warn("Failed to load metallic roughness texture");
+                        Tools.Error("Failed to load metallic roughness texture");
+                        onError();
                     });
             }
         }
 
-        public static LoadCommonMaterialProperties(runtime: IGLTFRuntime, material: IGLTFMaterial): void {
+        public static LoadCommonMaterialPropertiesAsync(runtime: IGLTFRuntime, material: IGLTFMaterial, onSuccess: () => void, onError: () => void): void {
+            //
+            // Load Factors
+            //
+
+            material.babylonMaterial.useEmissiveAsIllumination = (material.emissiveFactor || material.emissiveTexture) ? true : false;
+            material.babylonMaterial.emissiveColor = material.emissiveFactor ? Color3.FromArray(material.emissiveFactor) : new Color3(0, 0, 0);
+            if (material.doubleSided) {
+                material.babylonMaterial.backFaceCulling = false;
+                material.babylonMaterial.twoSidedLighting = true;
+            }
+
+            //
+            // Load Textures
+            //
+
+            if (!material.normalTexture && !material.occlusionTexture && !material.emissiveTexture) {
+                onSuccess();
+                return;
+            }
+
+            var checkSuccess = () => {
+                if ((!material.normalTexture || material.babylonMaterial.bumpTexture) &&
+                    (!material.occlusionTexture || material.babylonMaterial.ambientTexture) &&
+                    (!material.emissiveTexture || material.babylonMaterial.emissiveTexture)) {
+                    onSuccess();
+                }
+            }
+
             if (material.normalTexture) {
                 GLTFLoader.LoadTextureAsync(runtime, material.normalTexture, babylonTexture => {
                     material.babylonMaterial.bumpTexture = babylonTexture;
                     if (material.normalTexture.scale !== undefined) {
                         material.babylonMaterial.bumpTexture.level = material.normalTexture.scale;
                     }
-                }, () => Tools.Warn("Failed to load normal texture"));
+                    checkSuccess();
+                },
+                () => {
+                    Tools.Error("Failed to load normal texture");
+                    onError();
+                });
             }
 
             if (material.occlusionTexture) {
@@ -923,20 +988,23 @@ module BABYLON.GLTF2 {
                     if (material.occlusionTexture.strength !== undefined) {
                         material.babylonMaterial.ambientTextureStrength = material.occlusionTexture.strength;
                     }
-                }, () => Tools.Warn("Failed to load occlusion texture"));
+                    checkSuccess();
+                },
+                () => {
+                    Tools.Error("Failed to load occlusion texture");
+                    onError();
+                });
             }
 
-            material.babylonMaterial.useEmissiveAsIllumination = (material.emissiveFactor || material.emissiveTexture) ? true : false;
-            material.babylonMaterial.emissiveColor = material.emissiveFactor ? Color3.FromArray(material.emissiveFactor) : new Color3(0, 0, 0);
             if (material.emissiveTexture) {
                 GLTFLoader.LoadTextureAsync(runtime, material.emissiveTexture, babylonTexture => {
                     material.babylonMaterial.emissiveTexture = babylonTexture;
-                }, () => Tools.Warn("Failed to load emissive texture"));
-            }
-
-            if (material.doubleSided) {
-                material.babylonMaterial.backFaceCulling = false;
-                material.babylonMaterial.twoSidedLighting = true;
+                    checkSuccess();
+                },
+                () => {
+                    Tools.Error("Failed to load emissive texture");
+                    onError();
+                });
             }
         }
 
@@ -963,78 +1031,81 @@ module BABYLON.GLTF2 {
 
         public static LoadTextureAsync(runtime: IGLTFRuntime, textureInfo: IGLTFTextureInfo, onSuccess: (babylonTexture: Texture) => void, onError: () => void): void {
             var texture = runtime.gltf.textures[textureInfo.index];
+            var texCoord = textureInfo.texCoord || 0;
 
             if (!texture || texture.source === undefined) {
                 onError();
                 return;
             }
 
-            if (texture.babylonTexture) {
-                onSuccess(texture.babylonTexture);
+            if (texture.babylonTextures) {
+                var babylonTexture = texture.babylonTextures[texCoord];
+                if (!babylonTexture) {
+                    for (var i = 0; i < texture.babylonTextures.length; i++) {
+                        babylonTexture = texture.babylonTextures[i];
+                        if (babylonTexture) {
+                            babylonTexture = babylonTexture.clone();
+                            babylonTexture.coordinatesIndex = texCoord;
+                            break;
+                        }
+                    }
+                }
+
+                onSuccess(babylonTexture);
                 return;
             }
 
             var source = runtime.gltf.images[texture.source];
+            var sourceURL = runtime.rootUrl + source.uri;
 
-            if (source.uri === undefined) {
-                var bufferView: IGLTFBufferView = runtime.gltf.bufferViews[source.bufferView];
-                var buffer = GLTFUtils.GetBufferFromBufferView(runtime, bufferView, 0, bufferView.byteLength, EComponentType.UNSIGNED_BYTE);
-                GLTFLoader.CreateTextureAsync(runtime, textureInfo, buffer, source.mimeType, onSuccess, onError);
-            }
-            else if (GLTFUtils.IsBase64(source.uri)) {
-                GLTFLoader.CreateTextureAsync(runtime, textureInfo, new Uint8Array(GLTFUtils.DecodeBase64(source.uri)), source.mimeType, onSuccess, onError);
+            if (texture.blobURL) {
+                sourceURL = texture.blobURL;
             }
             else {
-                Tools.LoadFile(runtime.rootUrl + source.uri, data => {
-                    GLTFLoader.CreateTextureAsync(runtime, textureInfo, new Uint8Array(data), source.mimeType, onSuccess, onError);
-                }, null, null, true, onError);
-            }
-        }
-
-        public static CreateTextureAsync(runtime: IGLTFRuntime, textureInfo: IGLTFTextureInfo, buffer: ArrayBufferView, mimeType: string, onSuccess: (babylonTexture: Texture) => void, onError: () => void): void {
-            var texture = runtime.gltf.textures[textureInfo.index];
-
-            if (!texture || texture.source === undefined) {
-                onError();
-                return;
+                if (source.uri === undefined) {
+                    var bufferView = runtime.gltf.bufferViews[source.bufferView];
+                    var buffer = GLTFUtils.GetBufferFromBufferView(runtime, bufferView, 0, bufferView.byteLength, EComponentType.UNSIGNED_BYTE);
+                    texture.blobURL = URL.createObjectURL(new Blob([buffer], { type: source.mimeType }));
+                    sourceURL = texture.blobURL;
+                }
+                else if (GLTFUtils.IsBase64(source.uri)) {
+                    var decodedBuffer = new Uint8Array(GLTFUtils.DecodeBase64(source.uri));
+                    texture.blobURL = URL.createObjectURL(new Blob([decodedBuffer], { type: source.mimeType }));
+                    sourceURL = texture.blobURL;
+                }
             }
 
-            if (texture.babylonTexture) {
-                onSuccess(texture.babylonTexture);
-                return;
-            }
+            GLTFLoader._createTextureAsync(runtime, texture, texCoord, sourceURL, onSuccess, onError);
+        }
 
+        private static _createTextureAsync(runtime: IGLTFRuntime, texture: IGLTFTexture, texCoord: number, url: string, onSuccess: (babylonTexture: Texture) => void, onError: () => void): void {
             var sampler: IGLTFSampler = texture.sampler ? runtime.gltf.samplers[texture.sampler] : {};
-
-            var createMipMaps =
-                (sampler.minFilter === ETextureMinFilter.NEAREST_MIPMAP_NEAREST) ||
-                (sampler.minFilter === ETextureMinFilter.NEAREST_MIPMAP_LINEAR) ||
-                (sampler.minFilter === ETextureMinFilter.LINEAR_MIPMAP_NEAREST) ||
-                (sampler.minFilter === ETextureMinFilter.LINEAR_MIPMAP_LINEAR);
-
+            var noMipMaps = (sampler.minFilter === ETextureMinFilter.NEAREST || sampler.minFilter === ETextureMinFilter.LINEAR);
             var samplingMode = Texture.BILINEAR_SAMPLINGMODE;
 
-            var blob = new Blob([buffer], { type: mimeType });
-            var blobURL = URL.createObjectURL(blob);
-            var revokeBlobURL = () => URL.revokeObjectURL(blobURL);
-            texture.babylonTexture = new Texture(blobURL, runtime.babylonScene, !createMipMaps, true, samplingMode, revokeBlobURL, revokeBlobURL);
-            texture.babylonTexture.coordinatesIndex = textureInfo.texCoord === undefined ? 0 : textureInfo.texCoord;
-            texture.babylonTexture.wrapU = GLTFUtils.GetWrapMode(sampler.wrapS);
-            texture.babylonTexture.wrapV = GLTFUtils.GetWrapMode(sampler.wrapT);
-            texture.babylonTexture.name = texture.name;
+            var babylonTexture = new Texture(url, runtime.babylonScene, noMipMaps, true, samplingMode, () => {
+                onSuccess(babylonTexture);
+            }, onError);
+
+            babylonTexture.coordinatesIndex = texCoord;
+            babylonTexture.wrapU = GLTFUtils.GetWrapMode(sampler.wrapS);
+            babylonTexture.wrapV = GLTFUtils.GetWrapMode(sampler.wrapT);
+            babylonTexture.name = texture.name;
 
-            onSuccess(texture.babylonTexture);
+            // Cache the texture
+            texture.babylonTextures = texture.babylonTextures || [];
+            texture.babylonTextures[texCoord] = babylonTexture;
         }
 
         /**
         * Import meshes
         */
-        public importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError?: () => void): boolean {
+        public importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError?: () => void): void {
             scene.useRightHandedSystem = true;
 
-            var runtime = this._createRuntime(scene, data, rootUrl, true);
+            var runtime = GLTFLoader._createRuntime(scene, data, rootUrl, true);
             if (!runtime) {
-                if (onError) onError();
+                onError();
                 return;
             }
 
@@ -1076,69 +1147,57 @@ module BABYLON.GLTF2 {
             }
 
             // Load buffers, materials, etc.
-            this._loadBuffersAsync(runtime, () => {
-                importMaterials(runtime);
-                postLoad(runtime);
-
-                if (!BABYLON.GLTFFileLoader.IncrementalLoading && onSuccess) {
+            GLTFLoader._loadBuffersAsync(runtime, () => {
+                GLTFLoader._loadMaterialsAsync(runtime, () => {
+                    postLoad(runtime);
                     onSuccess(meshes, null, skeletons);
-                }
+                }, onError);
             }, onError);
 
             if (BABYLON.GLTFFileLoader.IncrementalLoading && onSuccess) {
                 onSuccess(meshes, null, skeletons);
             }
-
-            return true;
         }
 
         /**
         * Load scene
         */
-        public loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void): boolean {
+        public loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void): void {
             scene.useRightHandedSystem = true;
 
-            var runtime = this._createRuntime(scene, data, rootUrl, false);
+            var runtime = GLTFLoader._createRuntime(scene, data, rootUrl, false);
             if (!runtime) {
-                if (onError) onError();
-                return false;
+                onError();
+                return;
             }
 
             importScene(runtime);
 
-            this._loadBuffersAsync(runtime, () => {
-                importMaterials(runtime);
-                postLoad(runtime);
-
-                if (!BABYLON.GLTFFileLoader.IncrementalLoading) {
+            GLTFLoader._loadBuffersAsync(runtime, () => {
+                GLTFLoader._loadMaterialsAsync(runtime, () => {
+                    postLoad(runtime);
                     onSuccess();
-                }
+                }, onError);
             }, onError);
-
-            if (BABYLON.GLTFFileLoader.IncrementalLoading) {
-                onSuccess();
-            }
-
-            return true;
         }
 
-        private _loadBuffersAsync(runtime: IGLTFRuntime, onSuccess: () => void, onError: () => void): void {
+        private static _loadBuffersAsync(runtime: IGLTFRuntime, onSuccess: () => void, onError: () => void): void {
             if (runtime.gltf.buffers.length == 0) {
                 onSuccess();
                 return;
             }
 
-            var loadedCount = 0;
+            var successCount = 0;
             runtime.gltf.buffers.forEach((buffer, index) => {
                 this._loadBufferAsync(runtime, index, () => {
-                    if (++loadedCount >= runtime.gltf.buffers.length) {
+                    if (++successCount === runtime.gltf.buffers.length) {
                         onSuccess();
                     }
                 }, onError);
             });
         }
 
-        private _loadBufferAsync(runtime: IGLTFRuntime, index: number, onSuccess: () => void, onError: () => void): void {
+        private static _loadBufferAsync(runtime: IGLTFRuntime, index: number, onSuccess: () => void, onError: () => void): void {
             var buffer = runtime.gltf.buffers[index];
 
             if (buffer.uri === undefined) {
@@ -1160,7 +1219,24 @@ module BABYLON.GLTF2 {
             }
         }
 
-        private _createRuntime(scene: Scene, data: IGLTFLoaderData, rootUrl: string, importOnlyMeshes: boolean): IGLTFRuntime {
+        private static _loadMaterialsAsync(runtime: IGLTFRuntime, onSuccess: () => void, onError: () => void): void {
+            var materials = runtime.gltf.materials;
+            if (!materials) {
+                onSuccess();
+                return;
+            }
+
+            var successCount = 0;
+            for (var i = 0; i < materials.length; i++) {
+                GLTFLoaderExtension.LoadMaterialAsync(runtime, i, () => {
+                    if (++successCount === materials.length) {
+                        onSuccess();
+                    }
+                }, onError);
+            }
+        }
+
+        private static _createRuntime(scene: Scene, data: IGLTFLoaderData, rootUrl: string, importOnlyMeshes: boolean): IGLTFRuntime {
             var runtime: IGLTFRuntime = {
                 gltf: <IGLTF>data.json,
 

+ 25 - 6
loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts

@@ -15,7 +15,7 @@ module BABYLON.GLTF2 {
         protected postCreateRuntime(runtime: IGLTFRuntime): void {}
 
         // Return true to stop other extensions from loading materials.
-        protected loadMaterial(runtime: IGLTFRuntime, index: number): boolean { return false; }
+        protected loadMaterialAsync(runtime: IGLTFRuntime, index: number, onSuccess: () => void, onError: () => void): boolean { return false; }
 
         // ---------
         // Utilities
@@ -28,19 +28,38 @@ module BABYLON.GLTF2 {
             }
         }
 
-        public static LoadMaterial(runtime: IGLTFRuntime, index: number): void {
+        public static LoadMaterialAsync(runtime: IGLTFRuntime, index: number, onSuccess: () => void, onError: () => void): void {
             for (var extensionName in GLTFLoader.Extensions) {
                 var extension = GLTFLoader.Extensions[extensionName];
-                if (extension.loadMaterial(runtime, index)) {
+                if (extension.loadMaterialAsync(runtime, index, onSuccess, onError)) {
                     return;
                 }
             }
 
             var material = GLTFLoader.LoadMaterial(runtime, index);
-            if (material) {
-                GLTFLoader.LoadMetallicRoughnessMaterialProperties(runtime, material);
-                GLTFLoader.LoadCommonMaterialProperties(runtime, material);
+            if (!material) {
+                onSuccess();
+                return;
             }
+
+            var metallicRoughnessPropertiesSuccess = false;
+            var commonPropertiesSuccess = false;
+
+            var checkSuccess = () => {
+                if (metallicRoughnessPropertiesSuccess && commonPropertiesSuccess) {
+                    onSuccess();
+                }
+            }
+
+            GLTFLoader.LoadMetallicRoughnessMaterialPropertiesAsync(runtime, material, () => {
+                metallicRoughnessPropertiesSuccess = true;
+                checkSuccess();
+            }, onError);
+
+            GLTFLoader.LoadCommonMaterialPropertiesAsync(runtime, material, () => {
+                commonPropertiesSuccess = true;
+                checkSuccess();
+            }, onError);
         }
     }
 }

+ 5 - 4
loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts

@@ -54,12 +54,12 @@ module BABYLON.GLTF2 {
 
     export enum ETextureMagFilter {
         NEAREST = 9728,
-        LINEAR = 9728,
+        LINEAR = 9729,
     }
 
     export enum ETextureMinFilter {
         NEAREST = 9728,
-        LINEAR = 9728,
+        LINEAR = 9729,
         NEAREST_MIPMAP_NEAREST = 9984,
         LINEAR_MIPMAP_NEAREST = 9985,
         NEAREST_MIPMAP_LINEAR = 9986,
@@ -293,8 +293,9 @@ module BABYLON.GLTF2 {
         target?: ETextureTarget;
         type?: ETextureType;
 
-        // Babylon.js values (optimize)
-        babylonTexture?: Texture;
+        // Babylon.js values (optimize, one per coordinate index)
+        babylonTextures: Texture[];
+        blobURL: string;
     }
 
     export interface IGLTFTextureInfo {

+ 29 - 2
loaders/src/glTF/2.0/babylon.glTFMaterialsPbrSpecularGlossinessExtension.ts

@@ -14,25 +14,45 @@ module BABYLON.GLTF2 {
             super("KHR_materials_pbrSpecularGlossiness");
         }
 
-        protected loadMaterial(runtime: IGLTFRuntime, index: number): boolean {
+        protected loadMaterialAsync(runtime: IGLTFRuntime, index: number, onSuccess: () => void, onError: () => void): boolean {
             var material = GLTFLoader.LoadMaterial(runtime, index);
             if (!material || !material.extensions) return false;
 
             var properties: IGLTFMaterialsPbrSpecularGlossiness = material.extensions[this.name];
             if (!properties) return false;
 
+            //
+            // Load Factors
+            //
+
             material.babylonMaterial.albedoColor = properties.diffuseFactor ? Color3.FromArray(properties.diffuseFactor) : new Color3(1, 1, 1);
             material.babylonMaterial.reflectivityColor = properties.specularFactor ? Color3.FromArray(properties.specularFactor) : new Color3(1, 1, 1);
             material.babylonMaterial.microSurface = properties.glossinessFactor === undefined ? 1 : properties.glossinessFactor;
 
+            //
+            // Load Textures
+            //
+
+            var commonMaterialPropertiesSuccess = false;
+
+            var checkSuccess = () => {
+                if ((!properties.diffuseTexture || material.babylonMaterial.albedoTexture) &&
+                    (!properties.specularGlossinessTexture || material.babylonMaterial.reflectivityTexture) &&
+                    commonMaterialPropertiesSuccess) {
+                    onSuccess();
+                }
+            };
+
             if (properties.diffuseTexture) {
                 GLTFLoader.LoadTextureAsync(runtime, properties.diffuseTexture,
                     texture => {
                         material.babylonMaterial.albedoTexture = texture;
                         GLTFLoader.LoadAlphaProperties(runtime, material);
+                        checkSuccess();
                     },
                     () => {
                         Tools.Warn("Failed to load diffuse texture");
+                        onError();
                     });
             }
 
@@ -41,13 +61,20 @@ module BABYLON.GLTF2 {
                     texture => {
                         material.babylonMaterial.reflectivityTexture = texture;
                         material.babylonMaterial.useMicroSurfaceFromReflectivityMapAlpha = true;
+                        checkSuccess();
                     },
                     () => {
                         Tools.Warn("Failed to load metallic roughness texture");
+                        onError();
                     });
             }
 
-            GLTFLoader.LoadCommonMaterialProperties(runtime, material);
+            GLTFLoader.LoadCommonMaterialPropertiesAsync(runtime, material,
+                () => {
+                    commonMaterialPropertiesSuccess = true;
+                    checkSuccess();
+                }, onError);
+
             return true;
         }
     }

+ 9 - 7
loaders/src/glTF/babylon.glTFFileLoader.ts

@@ -7,8 +7,8 @@ module BABYLON {
     }
 
     export interface IGLTFLoader {
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onerror?: () => void) => boolean;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onsuccess: () => void, onerror: () => void) => boolean;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onsuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onerror: () => void) => void;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onsuccess: () => void, onerror: () => void) => void;
     }
 
     export class GLTFFileLoader implements ISceneLoaderPluginAsync {
@@ -23,21 +23,23 @@ module BABYLON {
             ".glb": { isBinary: true }
         };
 
-        public importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError?: () => void): boolean {
+        public importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError: () => void): void {
             var loaderData = GLTFFileLoader._parse(data);
             var loader = this._getLoader(loaderData);
             if (!loader) {
-                return false;
+                onError();
+                return;
             }
 
-            return loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onError);
+            loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onError);
         }
 
-        public loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onError: () => void): boolean {
+        public loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onError: () => void): void {
             var loaderData = GLTFFileLoader._parse(data);
             var loader = this._getLoader(loaderData);
             if (!loader) {
-                return false;
+                onError();
+                return;
             }
 
             return loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onError);

+ 2 - 2
src/Loading/babylon.sceneLoader.ts

@@ -13,8 +13,8 @@
 
     export interface ISceneLoaderPluginAsync {
         extensions: string | ISceneLoaderPluginExtensions;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: any, rootUrl: string, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onerror?: () => void) => void;
-        loadAsync: (scene: Scene, data: string, rootUrl: string, onsuccess: () => void, onerror: () => void) => boolean;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: any, rootUrl: string, onsuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onerror: () => void) => void;
+        loadAsync: (scene: Scene, data: string, rootUrl: string, onsuccess: () => void, onerror: () => void) => void;
     }
 
     interface IRegisteredPlugin {

+ 2 - 2
src/Materials/babylon.pbrMaterial.ts

@@ -1360,8 +1360,8 @@
                 this._myScene.ambientColor.multiplyToRef(this.ambientColor, this._globalAmbientColor);
 
                 if (this._defines.METALLICWORKFLOW) {
-                    PBRMaterial._scaledReflectivity.r = this.metallic === undefined ? 1 : this.metallic;
-                    PBRMaterial._scaledReflectivity.g = this.roughness === undefined ? 1 : this.roughness;
+                    PBRMaterial._scaledReflectivity.r = (this.metallic === undefined || this.metallic === null) ? 1 : this.metallic;
+                    PBRMaterial._scaledReflectivity.g = (this.roughness === undefined || this.roughness === null) ? 1 : this.roughness;
                     this._effect.setColor4("vReflectivityColor", PBRMaterial._scaledReflectivity, 0);
                 }
                 else {