Prechádzať zdrojové kódy

Add support for reordering glTF loader extensions

Gary Hsu 5 rokov pred
rodič
commit
9a5884d77e

+ 1 - 0
dist/preview release/what's new.md

@@ -95,6 +95,7 @@
 - Added support for morph target names via `mesh.extras.targetNames` when loading a glTF ([zeux](https://github.com/zeux))
 - Added support for using HTTP range requests when loading `MSFT_lod` extension from a glTF binary. ([bghgary](https://github.com/bghgary))
 - Added a flag to enable/disable creation of instances for glTF loader. ([bghgary](https://github.com/bghgary))
+- Added an order property to glTF loader extensions to support reordering. ([bghgary](https://github.com/bghgary))
 
 ### Materials
 

+ 6 - 2
loaders/src/glTF/2.0/Extensions/EXT_lights_image_based.ts

@@ -35,10 +35,14 @@ interface ILights {
  * [Specification](https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Vendor/EXT_lights_image_based/README.md)
  */
 export class EXT_lights_image_based implements IGLTFLoaderExtension {
-    /** The name of this extension. */
+    /**
+     * The name of this extension.
+     */
     public readonly name = NAME;
 
-    /** Defines whether this extension is enabled. */
+    /**
+     * Defines whether this extension is enabled.
+     */
     public enabled: boolean;
 
     private _loader: GLTFLoader;

+ 6 - 2
loaders/src/glTF/2.0/Extensions/ExtrasAsMetadata.ts

@@ -18,10 +18,14 @@ interface ObjectWithMetadata {
  * Store glTF extras (if present) in BJS objects' metadata
  */
 export class ExtrasAsMetadata implements IGLTFLoaderExtension {
-    /** The name of this extension. */
+    /**
+     * The name of this extension.
+     */
     public readonly name = NAME;
 
-    /** Defines whether this extension is enabled. */
+    /**
+     * Defines whether this extension is enabled.
+     */
     public enabled = true;
 
     private _loader: GLTFLoader;

+ 9 - 3
loaders/src/glTF/2.0/Extensions/KHR_draco_mesh_compression.ts

@@ -24,13 +24,19 @@ interface IBufferViewDraco extends IBufferView {
  * [Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression)
  */
 export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
-    /** The name of this extension. */
+    /**
+     * The name of this extension.
+     */
     public readonly name = NAME;
 
-    /** The draco compression used to decode vertex data or DracoCompression.Default if not defined */
+    /**
+     * The draco compression used to decode vertex data or DracoCompression.Default if not defined
+     */
     public dracoCompression?: DracoCompression;
 
-    /** Defines whether this extension is enabled. */
+    /**
+     * Defines whether this extension is enabled.
+     */
     public enabled: boolean;
 
     private _loader: GLTFLoader;

+ 6 - 2
loaders/src/glTF/2.0/Extensions/KHR_lights_punctual.ts

@@ -42,10 +42,14 @@ interface ILights {
  * [Specification](https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_lights_punctual/README.md)
  */
 export class KHR_lights implements IGLTFLoaderExtension {
-    /** The name of this extension. */
+    /**
+     * The name of this extension.
+     */
     public readonly name = NAME;
 
-    /** Defines whether this extension is enabled. */
+    /**
+     * Defines whether this extension is enabled.
+     */
     public enabled: boolean;
 
     private _loader: GLTFLoader;

+ 11 - 2
loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts

@@ -21,12 +21,21 @@ interface IKHRMaterialsPbrSpecularGlossiness {
  * [Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness)
  */
 export class KHR_materials_pbrSpecularGlossiness implements IGLTFLoaderExtension {
-    /** The name of this extension. */
+    /**
+     * The name of this extension.
+     */
     public readonly name = NAME;
 
-    /** Defines whether this extension is enabled. */
+    /**
+     * Defines whether this extension is enabled.
+     */
     public enabled: boolean;
 
+    /**
+     * Defines a number that determines the order the extensions are applied.
+     */
+    public order = 200;
+
     private _loader: GLTFLoader;
 
     /** @hidden */

+ 11 - 2
loaders/src/glTF/2.0/Extensions/KHR_materials_unlit.ts

@@ -13,12 +13,21 @@ const NAME = "KHR_materials_unlit";
  * [Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit)
  */
 export class KHR_materials_unlit implements IGLTFLoaderExtension {
-    /** The name of this extension. */
+    /**
+     * The name of this extension.
+     */
     public readonly name = NAME;
 
-    /** Defines whether this extension is enabled. */
+    /**
+     * Defines whether this extension is enabled.
+     */
     public enabled: boolean;
 
+    /**
+     * Defines a number that determines the order the extensions are applied.
+     */
+    public order = 210;
+
     private _loader: GLTFLoader;
 
     /** @hidden */

+ 6 - 2
loaders/src/glTF/2.0/Extensions/KHR_texture_transform.ts

@@ -19,10 +19,14 @@ interface IKHRTextureTransform {
  * [Specification](https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_texture_transform/README.md)
  */
 export class KHR_texture_transform implements IGLTFLoaderExtension {
-    /** The name of this extension. */
+    /**
+     * The name of this extension.
+     */
     public readonly name = NAME;
 
-    /** Defines whether this extension is enabled. */
+    /**
+     * Defines whether this extension is enabled.
+     */
     public enabled: boolean;
 
     private _loader: GLTFLoader;

+ 6 - 2
loaders/src/glTF/2.0/Extensions/MSFT_audio_emitter.ts

@@ -93,10 +93,14 @@ interface ILoaderAnimationEvents {
  * [Specification](https://github.com/najadojo/glTF/tree/MSFT_audio_emitter/extensions/2.0/Vendor/MSFT_audio_emitter)
  */
 export class MSFT_audio_emitter implements IGLTFLoaderExtension {
-    /** The name of this extension. */
+    /**
+     * The name of this extension.
+     */
     public readonly name = NAME;
 
-    /** Defines whether this extension is enabled. */
+    /**
+     * Defines whether this extension is enabled.
+     */
     public enabled: boolean;
 
     private _loader: GLTFLoader;

+ 11 - 2
loaders/src/glTF/2.0/Extensions/MSFT_lod.ts

@@ -20,13 +20,22 @@ interface IMSFTLOD {
  * [Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_lod)
  */
 export class MSFT_lod implements IGLTFLoaderExtension {
-    /** The name of this extension. */
+    /**
+     * The name of this extension.
+     */
     public readonly name = NAME;
 
-    /** Defines whether this extension is enabled. */
+    /**
+     * Defines whether this extension is enabled.
+     */
     public enabled: boolean;
 
     /**
+     * Defines a number that determines the order the extensions are applied.
+     */
+    public order = 100;
+
+    /**
      * Maximum number of LODs to load, starting from the lowest LOD.
      */
     public maxLODsToLoad = 10;

+ 35 - 39
loaders/src/glTF/2.0/glTFLoader.ts

@@ -31,6 +31,7 @@ import { IAnimationKey, AnimationKeyInterpolation } from 'babylonjs/Animations/a
 import { IAnimatable } from 'babylonjs/Animations/animatable.interface';
 import { IDataBuffer } from '../dataReader';
 import { LoadFileError } from 'babylonjs/Misc/fileTools';
+import { Logger } from 'babylonjs';
 
 interface TypedArrayLike extends ArrayBufferView {
     readonly length: number;
@@ -54,6 +55,10 @@ interface ILoaderProperty extends IProperty {
     };
 }
 
+interface IRegisteredExtension {
+    factory: (loader: GLTFLoader) => IGLTFLoaderExtension;
+}
+
 /**
  * Helper class for working with arrays when loading the glTF asset
  */
@@ -96,7 +101,7 @@ export class GLTFLoader implements IGLTFLoader {
     private _disposed = false;
     private _parent: GLTFFileLoader;
     private _state: Nullable<GLTFLoaderState> = null;
-    private _extensions: { [name: string]: IGLTFLoaderExtension } = {};
+    private _extensions = new Array<IGLTFLoaderExtension>();
     private _rootUrl: string;
     private _fileName: string;
     private _uniqueRootUrl: string;
@@ -110,8 +115,7 @@ export class GLTFLoader implements IGLTFLoader {
 
     private static readonly _DefaultSampler: ISampler = { index: -1 };
 
-    private static _ExtensionNames = new Array<string>();
-    private static _ExtensionFactories: { [name: string]: (loader: GLTFLoader) => IGLTFLoaderExtension } = {};
+    private static _RegisteredExtensions: { [name: string]: IRegisteredExtension } = {};
 
     /**
      * Registers a loader extension.
@@ -120,32 +124,25 @@ export class GLTFLoader implements IGLTFLoader {
      */
     public static RegisterExtension(name: string, factory: (loader: GLTFLoader) => IGLTFLoaderExtension): void {
         if (GLTFLoader.UnregisterExtension(name)) {
-            Tools.Warn(`Extension with the name '${name}' already exists`);
+            Logger.Warn(`Extension with the name '${name}' already exists`);
         }
 
-        GLTFLoader._ExtensionFactories[name] = factory;
-
-        // Keep the order of registration so that extensions registered first are called first.
-        GLTFLoader._ExtensionNames.push(name);
+        GLTFLoader._RegisteredExtensions[name] = {
+            factory: factory
+        };
     }
 
     /**
      * Unregisters a loader extension.
-     * @param name The name of the loader extenion.
+     * @param name The name of the loader extension.
      * @returns A boolean indicating whether the extension has been unregistered
      */
     public static UnregisterExtension(name: string): boolean {
-        if (!GLTFLoader._ExtensionFactories[name]) {
+        if (!GLTFLoader._RegisteredExtensions[name]) {
             return false;
         }
 
-        delete GLTFLoader._ExtensionFactories[name];
-
-        const index = GLTFLoader._ExtensionNames.indexOf(name);
-        if (index !== -1) {
-            GLTFLoader._ExtensionNames.splice(index, 1);
-        }
-
+        delete GLTFLoader._RegisteredExtensions[name];
         return true;
     }
 
@@ -214,13 +211,10 @@ export class GLTFLoader implements IGLTFLoader {
 
         for (const name in this._extensions) {
             const extension = this._extensions[name];
-            if (extension.dispose) {
-                this._extensions[name].dispose();
-            }
+            extension.dispose && extension.dispose();
+            delete this._extensions[name];
         }
 
-        this._extensions = {};
-
         delete this._gltf;
         delete this._babylonScene;
         delete this._rootBabylonMesh;
@@ -384,13 +378,13 @@ export class GLTFLoader implements IGLTFLoader {
             if (buffers && buffers[0] && !buffers[0].uri) {
                 const binaryBuffer = buffers[0];
                 if (binaryBuffer.byteLength < data.bin.byteLength - 3 || binaryBuffer.byteLength > data.bin.byteLength) {
-                    Tools.Warn(`Binary buffer length (${binaryBuffer.byteLength}) from JSON does not match chunk length (${data.bin.byteLength})`);
+                    Logger.Warn(`Binary buffer length (${binaryBuffer.byteLength}) from JSON does not match chunk length (${data.bin.byteLength})`);
                 }
 
                 this._bin = data.bin;
             }
             else {
-                Tools.Warn("Unexpected BIN chunk");
+                Logger.Warn("Unexpected BIN chunk");
             }
         }
     }
@@ -429,20 +423,24 @@ export class GLTFLoader implements IGLTFLoader {
     }
 
     private _loadExtensions(): void {
-        for (const name of GLTFLoader._ExtensionNames) {
-            const extension = GLTFLoader._ExtensionFactories[name](this);
-            this._extensions[name] = extension;
+        for (const name in GLTFLoader._RegisteredExtensions) {
+            const extension = GLTFLoader._RegisteredExtensions[name].factory(this);
+            if (extension.name !== name) {
+                Logger.Warn(`The name of the glTF loader extension instance does not match the registered name: ${extension.name} !== ${name}`);
+            }
 
+            this._extensions.push(extension);
             this._parent.onExtensionLoadedObservable.notifyObservers(extension);
         }
 
+        this._extensions.sort((a, b) => (a.order || Number.MAX_VALUE) - (b.order || Number.MAX_VALUE));
         this._parent.onExtensionLoadedObservable.clear();
     }
 
     private _checkExtensions(): void {
         if (this._gltf.extensionsRequired) {
             for (const name of this._gltf.extensionsRequired) {
-                const extension = this._extensions[name];
+                const extension = this._extensions.find((extension) => extension.name === name);
                 if (!extension || !extension.enabled) {
                     throw new Error(`Require extension ${name} is not available`);
                 }
@@ -607,7 +605,7 @@ export class GLTFLoader implements IGLTFLoader {
                 break;
             }
             default: {
-                Tools.Error(`Invalid animation start mode (${this._parent.animationStartMode})`);
+                Logger.Error(`Invalid animation start mode (${this._parent.animationStartMode})`);
                 return;
             }
         }
@@ -1572,7 +1570,7 @@ export class GLTFLoader implements IGLTFLoader {
         }
         // HACK: If byte offset is not a multiple of component type byte length then load as a float array instead of using Babylon buffers.
         else if (accessor.byteOffset && accessor.byteOffset % VertexBuffer.GetTypeByteLength(accessor.componentType) !== 0) {
-            Tools.Warn("Accessor byte offset is not a multiple of component type byte length");
+            Logger.Warn("Accessor byte offset is not a multiple of component type byte length");
             accessor._babylonVertexBuffer = this._loadFloatAccessorAsync(`/accessors/${accessor.index}`, accessor).then((data) => {
                 return new VertexBuffer(this._babylonScene.getEngine(), data, kind, false);
             });
@@ -2061,7 +2059,7 @@ export class GLTFLoader implements IGLTFLoader {
             case TextureWrapMode.MIRRORED_REPEAT: return Texture.MIRROR_ADDRESSMODE;
             case TextureWrapMode.REPEAT: return Texture.WRAP_ADDRESSMODE;
             default:
-                Tools.Warn(`${context}: Invalid value (${mode})`);
+                Logger.Warn(`${context}: Invalid value (${mode})`);
                 return Texture.WRAP_ADDRESSMODE;
         }
     }
@@ -2080,13 +2078,13 @@ export class GLTFLoader implements IGLTFLoader {
                 case TextureMinFilter.NEAREST_MIPMAP_LINEAR: return Texture.LINEAR_NEAREST_MIPLINEAR;
                 case TextureMinFilter.LINEAR_MIPMAP_LINEAR: return Texture.LINEAR_LINEAR_MIPLINEAR;
                 default:
-                    Tools.Warn(`${context}/minFilter: Invalid value (${minFilter})`);
+                    Logger.Warn(`${context}/minFilter: Invalid value (${minFilter})`);
                     return Texture.LINEAR_LINEAR_MIPLINEAR;
             }
         }
         else {
             if (magFilter !== TextureMagFilter.NEAREST) {
-                Tools.Warn(`${context}/magFilter: Invalid value (${magFilter})`);
+                Logger.Warn(`${context}/magFilter: Invalid value (${magFilter})`);
             }
 
             switch (minFilter) {
@@ -2097,7 +2095,7 @@ export class GLTFLoader implements IGLTFLoader {
                 case TextureMinFilter.NEAREST_MIPMAP_LINEAR: return Texture.NEAREST_NEAREST_MIPLINEAR;
                 case TextureMinFilter.LINEAR_MIPMAP_LINEAR: return Texture.NEAREST_LINEAR_MIPLINEAR;
                 default:
-                    Tools.Warn(`${context}/minFilter: Invalid value (${minFilter})`);
+                    Logger.Warn(`${context}/minFilter: Invalid value (${minFilter})`);
                     return Texture.NEAREST_NEAREST_MIPNEAREST;
             }
         }
@@ -2216,8 +2214,7 @@ export class GLTFLoader implements IGLTFLoader {
     }
 
     private _forEachExtensions(action: (extension: IGLTFLoaderExtension) => void): void {
-        for (const name of GLTFLoader._ExtensionNames) {
-            const extension = this._extensions[name];
+        for (const extension of this._extensions) {
             if (extension.enabled) {
                 action(extension);
             }
@@ -2225,10 +2222,9 @@ export class GLTFLoader implements IGLTFLoader {
     }
 
     private _applyExtensions<T>(property: IProperty, functionName: string, actionAsync: (extension: IGLTFLoaderExtension) => Nullable<T> | undefined): Nullable<T> {
-        for (const name of GLTFLoader._ExtensionNames) {
-            const extension = this._extensions[name];
+        for (const extension of this._extensions) {
             if (extension.enabled) {
-                const id = `${name}.${functionName}`;
+                const id = `${extension.name}.${functionName}`;
                 const loaderProperty = property as ILoaderProperty;
                 loaderProperty._activeLoaderExtensionFunctions = loaderProperty._activeLoaderExtensionFunctions || {};
                 const activeLoaderExtensionFunctions = loaderProperty._activeLoaderExtensionFunctions;

+ 55 - 97
loaders/src/glTF/glTFFileLoader.ts

@@ -85,6 +85,12 @@ export interface IGLTFLoaderExtension {
      * Defines whether this extension is enabled.
      */
     enabled: boolean;
+
+    /**
+     * Defines the order of this extension.
+     * The loader sorts the extensions using these values when loading.
+     */
+    order?: number;
 }
 
 /**
@@ -433,9 +439,7 @@ export class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISc
      */
     public name = "gltf";
 
-    /**
-     * Supported file extensions of the loader (.gltf, .glb)
-     */
+    /** @hidden */
     public extensions: ISceneLoaderPluginExtensions = {
         ".gltf": { isBinary: false },
         ".glb": { isBinary: true }
@@ -468,16 +472,7 @@ export class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISc
         this.onExtensionLoadedObservable.clear();
     }
 
-    /**
-     * The callback called when loading from a url.
-     * @param scene scene loading this url
-     * @param url url to load
-     * @param onSuccess callback called when the file successfully loads
-     * @param onProgress callback called while file is loading (if the server supports this mode)
-     * @param useArrayBuffer defines a boolean indicating that date must be returned as ArrayBuffer
-     * @param onError callback called when the file fails to load
-     * @returns a file request object
-     */
+    /** @hidden */
     public requestFile(scene: Scene, url: string, onSuccess: (data: any, request?: WebRequest) => void, onProgress?: (ev: ProgressEvent) => void, useArrayBuffer?: boolean, onError?: (error: any) => void): IFileRequest {
         if (useArrayBuffer) {
             if (this.useRangeRequests) {
@@ -532,16 +527,7 @@ export class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISc
         }, onProgress, true, false, onError);
     }
 
-    /**
-     * The callback called when loading from a file object.
-     * @param scene scene loading this file
-     * @param file defines the file to load
-     * @param onSuccess defines the callback to call when data is loaded
-     * @param onProgress defines the callback to call during loading process
-     * @param useArrayBuffer defines a boolean indicating that data must be returned as an ArrayBuffer
-     * @param onError defines the callback to call when an error occurs
-     * @returns a file request object
-     */
+    /** @hidden */
     public readFile(scene: Scene, file: File, onSuccess: (data: any) => void, onProgress?: (ev: ProgressEvent) => any, useArrayBuffer?: boolean, onError?: (error: any) => void): IFileRequest {
         return scene._readFile(file, (data) => {
             this._validateAsync(scene, data, "file:", file.name);
@@ -558,94 +544,69 @@ export class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISc
         }, onProgress, useArrayBuffer, onError);
     }
 
-    /**
-     * Imports one or more meshes from the loaded glTF data and adds them to the scene
-     * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
-     * @param scene the scene the meshes should be added to
-     * @param data the glTF data to load
-     * @param rootUrl root url to load from
-     * @param onProgress event that fires when loading progress has occured
-     * @param fileName Defines the name of the file to load
-     * @returns a promise containg the loaded meshes, particles, skeletons and animations
-     */
+    /** @hidden */
     public importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<{ meshes: AbstractMesh[], particleSystems: IParticleSystem[], skeletons: Skeleton[], animationGroups: AnimationGroup[] }> {
-        this.onParsedObservable.notifyObservers(data);
-        this.onParsedObservable.clear();
+        return Promise.resolve().then(() => {
+            this.onParsedObservable.notifyObservers(data);
+            this.onParsedObservable.clear();
 
-        this._log(`Loading ${fileName || ""}`);
-        this._loader = this._getLoader(data);
-        return this._loader.importMeshAsync(meshesNames, scene, data, rootUrl, onProgress, fileName);
+            this._log(`Loading ${fileName || ""}`);
+            this._loader = this._getLoader(data);
+            return this._loader.importMeshAsync(meshesNames, scene, data, rootUrl, onProgress, fileName);
+        });
     }
 
-    /**
-     * Imports all objects from the loaded glTF data and adds them to the scene
-     * @param scene the scene the objects should be added to
-     * @param data the glTF data to load
-     * @param rootUrl root url to load from
-     * @param onProgress event that fires when loading progress has occured
-     * @param fileName Defines the name of the file to load
-     * @returns a promise which completes when objects have been loaded to the scene
-     */
+    /** @hidden */
     public loadAsync(scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<void> {
-        this.onParsedObservable.notifyObservers(data);
-        this.onParsedObservable.clear();
+        return Promise.resolve().then(() => {
+            this.onParsedObservable.notifyObservers(data);
+            this.onParsedObservable.clear();
 
-        this._log(`Loading ${fileName || ""}`);
-        this._loader = this._getLoader(data);
-        return this._loader.loadAsync(scene, data, rootUrl, onProgress, fileName);
+            this._log(`Loading ${fileName || ""}`);
+            this._loader = this._getLoader(data);
+            return this._loader.loadAsync(scene, data, rootUrl, onProgress, fileName);
+        });
     }
 
-    /**
-     * Load into an asset container.
-     * @param scene The scene to load into
-     * @param data The data to import
-     * @param rootUrl The root url for scene and resources
-     * @param onProgress The callback when the load progresses
-     * @param fileName Defines the name of the file to load
-     * @returns The loaded asset container
-     */
+    /** @hidden */
     public loadAssetContainerAsync(scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<AssetContainer> {
-        this._log(`Loading ${fileName || ""}`);
-        this._loader = this._getLoader(data);
+        return Promise.resolve().then(() => {
+            this.onParsedObservable.notifyObservers(data);
+            this.onParsedObservable.clear();
 
-        // Get materials/textures when loading to add to container
-        const materials: Array<Material> = [];
-        this.onMaterialLoadedObservable.add((material) => {
-            materials.push(material);
-        });
-        const textures: Array<BaseTexture> = [];
-        this.onTextureLoadedObservable.add((texture) => {
-            textures.push(texture);
-        });
+            this._log(`Loading ${fileName || ""}`);
+            this._loader = this._getLoader(data);
 
-        return this._loader.importMeshAsync(null, scene, data, rootUrl, onProgress, fileName).then((result) => {
-            const container = new AssetContainer(scene);
-            Array.prototype.push.apply(container.meshes, result.meshes);
-            Array.prototype.push.apply(container.particleSystems, result.particleSystems);
-            Array.prototype.push.apply(container.skeletons, result.skeletons);
-            Array.prototype.push.apply(container.animationGroups, result.animationGroups);
-            Array.prototype.push.apply(container.materials, materials);
-            Array.prototype.push.apply(container.textures, textures);
-            container.removeAllFromScene();
-            return container;
+            // Get materials/textures when loading to add to container
+            const materials: Array<Material> = [];
+            this.onMaterialLoadedObservable.add((material) => {
+                materials.push(material);
+            });
+            const textures: Array<BaseTexture> = [];
+            this.onTextureLoadedObservable.add((texture) => {
+                textures.push(texture);
+            });
+
+            return this._loader.importMeshAsync(null, scene, data, rootUrl, onProgress, fileName).then((result) => {
+                const container = new AssetContainer(scene);
+                Array.prototype.push.apply(container.meshes, result.meshes);
+                Array.prototype.push.apply(container.particleSystems, result.particleSystems);
+                Array.prototype.push.apply(container.skeletons, result.skeletons);
+                Array.prototype.push.apply(container.animationGroups, result.animationGroups);
+                Array.prototype.push.apply(container.materials, materials);
+                Array.prototype.push.apply(container.textures, textures);
+                container.removeAllFromScene();
+                return container;
+            });
         });
     }
 
-    /**
-     * The callback that returns true if the data can be directly loaded.
-     * @param data string containing the file data
-     * @returns if the data can be loaded directly
-     */
+    /** @hidden */
     public canDirectLoad(data: string): boolean {
         return data.indexOf("asset") !== -1 && data.indexOf("version") !== -1;
     }
 
-    /**
-     * The callback that returns the data to pass to the plugin if the data can be directly loaded.
-     * @param scene scene loading this data
-     * @param data string containing the data
-     * @returns data to pass to the plugin
-     */
+    /** @hidden */
     public directLoad(scene: Scene, data: string): any {
         this._validateAsync(scene, data);
         return { json: this._parseJson(data) };
@@ -659,10 +620,7 @@ export class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISc
      */
     public rewriteRootURL?(rootUrl: string, responseURL?: string): string;
 
-    /**
-     * Instantiates a glTF file loader plugin.
-     * @returns the created plugin
-     */
+    /** @hidden */
     public createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync {
         return new GLTFFileLoader();
     }