Browse Source

Nightly + move BBrendering to RenderingGroup

David Catuhe 7 years ago
parent
commit
aacd44de01
36 changed files with 18987 additions and 17869 deletions
  1. 10909 10790
      Playground/babylon.d.txt
  2. 744 732
      dist/preview release/babylon.d.ts
  3. 1 1
      dist/preview release/babylon.js
  4. 191 155
      dist/preview release/babylon.max.js
  5. 191 155
      dist/preview release/babylon.no-module.max.js
  6. 1 1
      dist/preview release/babylon.worker.js
  7. 191 155
      dist/preview release/es6.js
  8. 8 8
      dist/preview release/loaders/babylon.glTF1FileLoader.d.ts
  9. 12 9
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  10. 1 1
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  11. 12 11
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  12. 19 14
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  13. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  14. 12 11
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  15. 19 14
      dist/preview release/loaders/babylon.glTFFileLoader.js
  16. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  17. 6 6
      dist/preview release/loaders/babylon.objFileLoader.d.ts
  18. 6 6
      dist/preview release/loaders/babylon.objFileLoader.js
  19. 18 17
      dist/preview release/loaders/babylonjs.loaders.d.ts
  20. 25 20
      dist/preview release/loaders/babylonjs.loaders.js
  21. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  22. 18 17
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  23. 125 15
      dist/preview release/serializers/babylon.glTF2Serializer.d.ts
  24. 3086 2825
      dist/preview release/serializers/babylon.glTF2Serializer.js
  25. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  26. 125 15
      dist/preview release/serializers/babylonjs.serializers.d.ts
  27. 3086 2825
      dist/preview release/serializers/babylonjs.serializers.js
  28. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  29. 125 15
      dist/preview release/serializers/babylonjs.serializers.module.d.ts
  30. 2 37
      dist/preview release/typedocValidationBaseline.json
  31. 15 1
      dist/preview release/viewer/babylon.viewer.d.ts
  32. 1 1
      dist/preview release/viewer/babylon.viewer.js
  33. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  34. 18 1
      dist/preview release/viewer/babylon.viewer.module.d.ts
  35. 5 0
      src/Culling/babylon.boundingBox.ts
  36. 8 4
      src/Rendering/babylon.boundingBoxRenderer.ts

File diff suppressed because it is too large
+ 10909 - 10790
Playground/babylon.d.txt


File diff suppressed because it is too large
+ 744 - 732
dist/preview release/babylon.d.ts


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/babylon.js


+ 191 - 155
dist/preview release/babylon.max.js

@@ -33689,12 +33689,14 @@ var BABYLON;
          * Creates a ground mesh from a height map.
          * tuto : http://doc.babylonjs.com/babylon101/height_map
          * Please consider using the same method from the MeshBuilder class instead.
-         * The parameter `url` sets the URL of the height map image resource.
-         * The parameters `width` and `height` (positive floats, default 10) set the ground width and height sizes.
-         * The parameter `subdivisions` (positive integer, default 1) sets the number of subdivision per side.
-         * The parameter `minHeight` (float, default 0) is the minimum altitude on the ground.
-         * The parameter `maxHeight` (float, default 1) is the maximum altitude on the ground.
-         * The parameter `onReady` is a javascript callback function that will be called  once the mesh is just built (the height map download can last some time).
+         * @param url sets the URL of the height map image resource.
+         * @param width (positive float, default 10) set the ground width size.
+         * @param height (positive float, default 10) set the ground height size.
+         * @param subdivisions (positive integer, default 1) sets the number of subdivision per side.
+         * @param minHeight (float, default 0) is the minimum altitude on the ground.
+         * @param maxHeight (float, default 1) is the maximum altitude on the ground.
+         * @param onReady is a javascript callback function that will be called  once the mesh is just built (the height map download can last some time).
+         * @param alphaFilter will filter any data where the alpha channel is below this value, defaults 0 (all data visible).
          * This function is passed the newly built mesh :
          * ```javascript
          * function(mesh) { // do things
@@ -33702,7 +33704,7 @@ var BABYLON;
          * ```
          * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.
          */
-        Mesh.CreateGroundFromHeightMap = function (name, url, width, height, subdivisions, minHeight, maxHeight, scene, updatable, onReady) {
+        Mesh.CreateGroundFromHeightMap = function (name, url, width, height, subdivisions, minHeight, maxHeight, scene, updatable, onReady, alphaFilter) {
             var options = {
                 width: width,
                 height: height,
@@ -33710,7 +33712,8 @@ var BABYLON;
                 minHeight: minHeight,
                 maxHeight: maxHeight,
                 updatable: updatable,
-                onReady: onReady
+                onReady: onReady,
+                alphaFilter: alphaFilter
             };
             return BABYLON.MeshBuilder.CreateGroundFromHeightMap(name, url, options, scene);
         };
@@ -37639,6 +37642,7 @@ var BABYLON;
           * * buffer the array holding the image color data
           * * bufferWidth the width of image
           * * bufferHeight the height of image
+          * * alphaFilter Remove any data where the alpha channel is below this value, defaults 0 (all data visible)
          * @returns the VertexData of the Ground designed from a heightmap
          */
         VertexData.CreateGroundFromHeightMap = function (options) {
@@ -37648,6 +37652,7 @@ var BABYLON;
             var uvs = [];
             var row, col;
             var filter = options.colorFilter || new BABYLON.Color3(0.3, 0.59, 0.11);
+            var alphaFilter = options.alphaFilter || 0.0;
             // Vertices
             for (row = 0; row <= options.subdivisions; row++) {
                 for (col = 0; col <= options.subdivisions; col++) {
@@ -37659,8 +37664,15 @@ var BABYLON;
                     var r = options.buffer[pos] / 255.0;
                     var g = options.buffer[pos + 1] / 255.0;
                     var b = options.buffer[pos + 2] / 255.0;
+                    var a = options.buffer[pos + 3] / 255.0;
                     var gradient = r * filter.r + g * filter.g + b * filter.b;
-                    position.y = options.minHeight + (options.maxHeight - options.minHeight) * gradient;
+                    // If our alpha channel is not within our filter then we will assign a 'special' height 
+                    // Then when building the indices, we will ignore any vertex that is using the special height
+                    if (a >= alphaFilter)
+                        position.y = options.minHeight + (options.maxHeight - options.minHeight) * gradient;
+                    else {
+                        position.y = options.minHeight - BABYLON.Epsilon; // We can't have a height below minHeight, normally.
+                    }
                     // Add  vertex
                     positions.push(position.x, position.y, position.z);
                     normals.push(0, 0, 0);
@@ -37670,12 +37682,28 @@ var BABYLON;
             // Indices
             for (row = 0; row < options.subdivisions; row++) {
                 for (col = 0; col < options.subdivisions; col++) {
-                    indices.push(col + 1 + (row + 1) * (options.subdivisions + 1));
-                    indices.push(col + 1 + row * (options.subdivisions + 1));
-                    indices.push(col + row * (options.subdivisions + 1));
-                    indices.push(col + (row + 1) * (options.subdivisions + 1));
-                    indices.push(col + 1 + (row + 1) * (options.subdivisions + 1));
-                    indices.push(col + row * (options.subdivisions + 1));
+                    // Calculate Indices
+                    var idx1 = (col + 1 + (row + 1) * (options.subdivisions + 1));
+                    var idx2 = (col + 1 + row * (options.subdivisions + 1));
+                    var idx3 = (col + row * (options.subdivisions + 1));
+                    var idx4 = (col + (row + 1) * (options.subdivisions + 1));
+                    // Check that all indices are visible (based on our special height)
+                    // Only display the vertex if all Indices are visible
+                    // Positions are stored x,y,z for each vertex, hence the * 3 and + 1 for height
+                    var isVisibleIdx1 = positions[idx1 * 3 + 1] >= options.minHeight;
+                    var isVisibleIdx2 = positions[idx2 * 3 + 1] >= options.minHeight;
+                    var isVisibleIdx3 = positions[idx3 * 3 + 1] >= options.minHeight;
+                    if (isVisibleIdx1 && isVisibleIdx2 && isVisibleIdx3) {
+                        indices.push(idx1);
+                        indices.push(idx2);
+                        indices.push(idx3);
+                    }
+                    var isVisibleIdx4 = positions[idx4 * 3 + 1] >= options.minHeight;
+                    if (isVisibleIdx4 && isVisibleIdx1 && isVisibleIdx3) {
+                        indices.push(idx4);
+                        indices.push(idx1);
+                        indices.push(idx3);
+                    }
                 }
             }
             // Normals
@@ -56875,9 +56903,6 @@ var BABYLON;
             else {
                 var emitterPosition = subEmitter.particleSystem.emitter;
                 emitterPosition.copyFrom(particle.position);
-                if (subEmitter.inheritDirection) {
-                    BABYLON.Tools.Warn("subEmitter.inheritDirection is not supported with non-mesh emitter type");
-                }
             }
             // Set inheritedVelocityOffset to be used when new particles are created
             particle.direction.scaleToRef(subEmitter.inheritedVelocityAmount / 2, BABYLON.Tmp.Vector3[0]);
@@ -57413,6 +57438,11 @@ var BABYLON;
                     else if (subEmitter instanceof Array) {
                         _this._subEmitters.push(subEmitter);
                     }
+                    _this._subEmitters[_this._subEmitters.length - 1].forEach(function (se) {
+                        if (!(se.particleSystem.emitter instanceof BABYLON.AbstractMesh) && se.inheritDirection) {
+                            BABYLON.Tools.Warn("subEmitter.inheritDirection is not supported with non-mesh emitter type");
+                        }
+                    });
                 });
             }
             this._started = true;
@@ -58010,8 +58040,8 @@ var BABYLON;
                 this._rampGradientsTexture = null;
             }
             this._removeFromRoot();
-            if (this._disposeEmitterOnDispose && !this.emitter.isDisposed) {
-                this.emitter.dispose();
+            if (this._disposeEmitterOnDispose && this.emitter && this.emitter.dispose) {
+                this.emitter.dispose(true);
             }
             // Remove from scene
             var index = this._scene.particleSystems.indexOf(this);
@@ -61849,12 +61879,13 @@ var BABYLON;
             this.scene._beforeEvaluateActiveMeshStage.registerStep(BABYLON.SceneComponentConstants.STEP_BEFOREEVALUATEACTIVEMESH_BOUNDINGBOXRENDERER, this, this.reset);
             this.scene._activeMeshStage.registerStep(BABYLON.SceneComponentConstants.STEP_ACTIVEMESH_BOUNDINGBOXRENDERER, this, this._activeMesh);
             this.scene._evaluateSubMeshStage.registerStep(BABYLON.SceneComponentConstants.STEP_EVALUATESUBMESH_BOUNDINGBOXRENDERER, this, this._evaluateSubMesh);
-            this.scene._afterCameraDrawStage.registerStep(BABYLON.SceneComponentConstants.STEP_AFTERCAMERADRAW_BOUNDINGBOXRENDERER, this, this.render);
+            this.scene._afterRenderingGroupDrawStage.registerStep(BABYLON.SceneComponentConstants.STEP_AFTERCAMERADRAW_BOUNDINGBOXRENDERER, this, this.render);
         };
         BoundingBoxRenderer.prototype._evaluateSubMesh = function (mesh, subMesh) {
             if (mesh.showSubMeshesBoundingBox) {
                 var boundingInfo = subMesh.getBoundingInfo();
                 if (boundingInfo !== null && boundingInfo !== undefined) {
+                    boundingInfo.boundingBox._tag = mesh.renderingGroupId;
                     this.renderList.push(boundingInfo.boundingBox);
                 }
             }
@@ -61862,6 +61893,7 @@ var BABYLON;
         BoundingBoxRenderer.prototype._activeMesh = function (sourceMesh, mesh) {
             if (sourceMesh.showBoundingBox || this.scene.forceShowBoundingBoxes) {
                 var boundingInfo = sourceMesh.getBoundingInfo();
+                boundingInfo.boundingBox._tag = mesh.renderingGroupId;
                 this.renderList.push(boundingInfo.boundingBox);
             }
         };
@@ -61896,7 +61928,7 @@ var BABYLON;
         BoundingBoxRenderer.prototype.reset = function () {
             this.renderList.reset();
         };
-        BoundingBoxRenderer.prototype.render = function () {
+        BoundingBoxRenderer.prototype.render = function (renderingGroupId) {
             if (this.renderList.length === 0) {
                 return;
             }
@@ -61909,6 +61941,9 @@ var BABYLON;
             this._colorShader._preBind();
             for (var boundingBoxIndex = 0; boundingBoxIndex < this.renderList.length; boundingBoxIndex++) {
                 var boundingBox = this.renderList.data[boundingBoxIndex];
+                if (boundingBox._tag !== renderingGroupId) {
+                    continue;
+                }
                 var min = boundingBox.minimum;
                 var max = boundingBox.maximum;
                 var diff = max.subtract(min);
@@ -65316,6 +65351,7 @@ var BABYLON;
          * * The parameter `maxHeight` (float, default 1) is the maximum altitude on the ground.
          * * The parameter `colorFilter` (optional Color3, default (0.3, 0.59, 0.11) ) is the filter to apply to the image pixel colors to compute the height.
          * * The parameter `onReady` is a javascript callback function that will be called  once the mesh is just built (the height map download can last some time).
+         * * The parameter `alphaFilter` will filter any data where the alpha channel is below this value, defaults 0 (all data visible)
          * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.
          * @param name defines the name of the mesh
          * @param url defines the url to the height map
@@ -65332,6 +65368,7 @@ var BABYLON;
             var minHeight = options.minHeight || 0.0;
             var maxHeight = options.maxHeight || 1.0;
             var filter = options.colorFilter || new BABYLON.Color3(0.3, 0.59, 0.11);
+            var alphaFilter = options.alphaFilter || 0.0;
             var updatable = options.updatable;
             var onReady = options.onReady;
             var ground = new BABYLON.GroundMesh(name, scene);
@@ -65366,7 +65403,8 @@ var BABYLON;
                     width: width, height: height,
                     subdivisions: subdivisions,
                     minHeight: minHeight, maxHeight: maxHeight, colorFilter: filter,
-                    buffer: buffer, bufferWidth: bufferWidth, bufferHeight: bufferHeight
+                    buffer: buffer, bufferWidth: bufferWidth, bufferHeight: bufferHeight,
+                    alphaFilter: alphaFilter
                 });
                 vertexData.applyToMesh(ground, updatable);
                 //execute ready callback, if set
@@ -71975,9 +72013,6 @@ var BABYLON;
             return SceneLoader._getDefaultPlugin();
         };
         SceneLoader._getPluginForFilename = function (sceneFilename) {
-            if (sceneFilename.name) {
-                sceneFilename = sceneFilename.name;
-            }
             var queryStringPosition = sceneFilename.indexOf("?");
             if (queryStringPosition !== -1) {
                 sceneFilename = sceneFilename.substring(0, queryStringPosition);
@@ -71988,14 +72023,14 @@ var BABYLON;
         };
         // use babylon file loader directly if sceneFilename is prefixed with "data:"
         SceneLoader._getDirectLoad = function (sceneFilename) {
-            if (sceneFilename.substr && sceneFilename.substr(0, 5) === "data:") {
+            if (sceneFilename.substr(0, 5) === "data:") {
                 return sceneFilename.substr(5);
             }
             return null;
         };
-        SceneLoader._loadData = function (rootUrl, sceneFilename, scene, onSuccess, onProgress, onError, onDispose, pluginExtension) {
-            var directLoad = SceneLoader._getDirectLoad(sceneFilename);
-            var registeredPlugin = pluginExtension ? SceneLoader._getPluginForExtension(pluginExtension) : (directLoad ? SceneLoader._getPluginForDirectLoad(sceneFilename) : SceneLoader._getPluginForFilename(sceneFilename));
+        SceneLoader._loadData = function (fileInfo, scene, onSuccess, onProgress, onError, onDispose, pluginExtension) {
+            var directLoad = SceneLoader._getDirectLoad(fileInfo.name);
+            var registeredPlugin = pluginExtension ? SceneLoader._getPluginForExtension(pluginExtension) : (directLoad ? SceneLoader._getPluginForDirectLoad(fileInfo.name) : SceneLoader._getPluginForFilename(fileInfo.name));
             var plugin;
             if (registeredPlugin.plugin.createPlugin) {
                 plugin = registeredPlugin.plugin.createPlugin();
@@ -72031,8 +72066,7 @@ var BABYLON;
                 if (pluginDisposed) {
                     return;
                 }
-                var url = rootUrl + sceneFilename;
-                request = BABYLON.Tools.LoadFile(url, dataCallback, onProgress ? function (event) {
+                request = BABYLON.Tools.LoadFile(fileInfo.url, dataCallback, onProgress ? function (event) {
                     onProgress(SceneLoaderProgressEvent.FromProgressEvent(event));
                 } : undefined, database, useArrayBuffer, function (request, exception) {
                     onError("Failed to load scene." + (exception ? "" : " " + exception.message), exception);
@@ -72042,7 +72076,7 @@ var BABYLON;
                 dataCallback(directLoad);
                 return plugin;
             }
-            if (rootUrl.indexOf("file:") === -1) {
+            if (fileInfo.rootUrl.indexOf("file:") === -1) {
                 var engine = scene.getEngine();
                 var canUseOfflineSupport = engine.enableOfflineSupport;
                 if (canUseOfflineSupport) {
@@ -72050,7 +72084,7 @@ var BABYLON;
                     var exceptionFound = false;
                     for (var _i = 0, _a = scene.disableOfflineSupportExceptionRules; _i < _a.length; _i++) {
                         var regex = _a[_i];
-                        if (regex.test(rootUrl + sceneFilename)) {
+                        if (regex.test(fileInfo.url)) {
                             exceptionFound = true;
                             break;
                         }
@@ -72059,7 +72093,7 @@ var BABYLON;
                 }
                 if (canUseOfflineSupport) {
                     // Checking if a manifest file has been set for this scene and if offline mode has been requested
-                    database = new BABYLON.Database(rootUrl + sceneFilename, manifestChecked, engine.disableManifestCheck);
+                    database = new BABYLON.Database(fileInfo.url, manifestChecked, engine.disableManifestCheck);
                 }
                 else {
                     manifestChecked();
@@ -72067,19 +72101,39 @@ var BABYLON;
             }
             // Loading file from disk via input file or drag'n'drop
             else {
-                var fileOrString = sceneFilename;
-                if (fileOrString.name) { // File
-                    request = BABYLON.Tools.ReadFile(fileOrString, dataCallback, onProgress, useArrayBuffer);
-                }
-                else if (BABYLON.FilesInput.FilesToLoad[sceneFilename]) {
-                    request = BABYLON.Tools.ReadFile(BABYLON.FilesInput.FilesToLoad[sceneFilename], dataCallback, onProgress, useArrayBuffer);
+                var file = BABYLON.FilesInput.FilesToLoad[fileInfo.name.toLowerCase()];
+                if (file) {
+                    request = BABYLON.Tools.ReadFile(file, dataCallback, onProgress, useArrayBuffer);
                 }
                 else {
-                    onError("Unable to find file named " + sceneFilename);
+                    onError("Unable to find file named " + fileInfo.name);
                 }
             }
             return plugin;
         };
+        SceneLoader._getFileInfo = function (rootUrl, sceneFilename) {
+            var url;
+            var name;
+            if (!sceneFilename) {
+                url = rootUrl;
+                name = BABYLON.Tools.GetFilename(rootUrl);
+                rootUrl = BABYLON.Tools.GetFolderPath(rootUrl);
+            }
+            else {
+                if (sceneFilename.substr(0, 1) === "/") {
+                    BABYLON.Tools.Error("Wrong sceneFilename parameter");
+                    return null;
+                }
+                url = rootUrl + sceneFilename;
+                name = sceneFilename;
+            }
+            ;
+            return {
+                url: url,
+                rootUrl: rootUrl,
+                name: name
+            };
+        };
         // Public functions
         SceneLoader.GetPluginForExtension = function (extension) {
             return SceneLoader._getPluginForExtension(extension).plugin;
@@ -72108,8 +72162,8 @@ var BABYLON;
         /**
          * Import meshes into a scene
          * @param meshNames an array of mesh names, a single mesh name, or empty string for all meshes that filter what meshes are imported
-         * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-         * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
          * @param scene the instance of BABYLON.Scene to append to
          * @param onSuccess a callback with a list of imported meshes, particleSystems, and skeletons when import succeeds
          * @param onProgress a callback with a progress event for each file being loaded
@@ -72128,12 +72182,8 @@ var BABYLON;
                 BABYLON.Tools.Error("No scene available to import mesh to");
                 return null;
             }
-            if (!sceneFilename) {
-                sceneFilename = BABYLON.Tools.GetFilename(rootUrl);
-                rootUrl = BABYLON.Tools.GetFolderPath(rootUrl);
-            }
-            if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
-                BABYLON.Tools.Error("Wrong sceneFilename parameter");
+            var fileInfo = SceneLoader._getFileInfo(rootUrl, sceneFilename);
+            if (!fileInfo) {
                 return null;
             }
             var loadingToken = {};
@@ -72142,7 +72192,7 @@ var BABYLON;
                 scene._removePendingData(loadingToken);
             };
             var errorHandler = function (message, exception) {
-                var errorMessage = "Unable to import meshes from " + rootUrl + sceneFilename + ": " + message;
+                var errorMessage = "Unable to import meshes from " + fileInfo.url + ": " + message;
                 if (onError) {
                     onError(scene, errorMessage, exception);
                 }
@@ -72161,7 +72211,7 @@ var BABYLON;
                 }
             } : undefined;
             var successHandler = function (meshes, particleSystems, skeletons, animationGroups) {
-                scene.importedMeshesFiles.push(rootUrl + sceneFilename);
+                scene.importedMeshesFiles.push(fileInfo.url);
                 if (onSuccess) {
                     try {
                         onSuccess(meshes, particleSystems, skeletons, animationGroups);
@@ -72172,21 +72222,16 @@ var BABYLON;
                 }
                 scene._removePendingData(loadingToken);
             };
-            return SceneLoader._loadData(rootUrl, sceneFilename, scene, function (plugin, data, responseURL) {
+            return SceneLoader._loadData(fileInfo, scene, function (plugin, data, responseURL) {
                 if (plugin.rewriteRootURL) {
-                    rootUrl = plugin.rewriteRootURL(rootUrl, responseURL);
-                }
-                if (sceneFilename === "") {
-                    if (sceneFilename === "") {
-                        rootUrl = BABYLON.Tools.GetFolderPath(rootUrl, true);
-                    }
+                    fileInfo.rootUrl = plugin.rewriteRootURL(fileInfo.rootUrl, responseURL);
                 }
                 if (plugin.importMesh) {
                     var syncedPlugin = plugin;
                     var meshes = new Array();
                     var particleSystems = new Array();
                     var skeletons = new Array();
-                    if (!syncedPlugin.importMesh(meshNames, scene, data, rootUrl, meshes, particleSystems, skeletons, errorHandler)) {
+                    if (!syncedPlugin.importMesh(meshNames, scene, data, fileInfo.rootUrl, meshes, particleSystems, skeletons, errorHandler)) {
                         return;
                     }
                     scene.loadingPluginName = plugin.name;
@@ -72194,7 +72239,7 @@ var BABYLON;
                 }
                 else {
                     var asyncedPlugin = plugin;
-                    asyncedPlugin.importMeshAsync(meshNames, scene, data, rootUrl, progressHandler, rootUrl + sceneFilename).then(function (result) {
+                    asyncedPlugin.importMeshAsync(meshNames, scene, data, fileInfo.rootUrl, progressHandler, fileInfo.name).then(function (result) {
                         scene.loadingPluginName = plugin.name;
                         successHandler(result.meshes, result.particleSystems, result.skeletons, result.animationGroups);
                     }).catch(function (error) {
@@ -72204,15 +72249,15 @@ var BABYLON;
             }, progressHandler, errorHandler, disposeHandler, pluginExtension);
         };
         /**
-        * Import meshes into a scene
-        * @param meshNames an array of mesh names, a single mesh name, or empty string for all meshes that filter what meshes are imported
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param scene the instance of BABYLON.Scene to append to
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The loaded list of imported meshes, particle systems, skeletons, and animation groups
-        */
+         * Import meshes into a scene
+         * @param meshNames an array of mesh names, a single mesh name, or empty string for all meshes that filter what meshes are imported
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param scene the instance of BABYLON.Scene to append to
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The loaded list of imported meshes, particle systems, skeletons, and animation groups
+         */
         SceneLoader.ImportMeshAsync = function (meshNames, rootUrl, sceneFilename, scene, onProgress, pluginExtension) {
             if (sceneFilename === void 0) { sceneFilename = ""; }
             if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
@@ -72232,16 +72277,16 @@ var BABYLON;
             });
         };
         /**
-        * Load a scene
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param engine is the instance of BABYLON.Engine to use to create the scene
-        * @param onSuccess a callback with the scene when import succeeds
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param onError a callback with the scene, a message, and possibly an exception when import fails
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The loaded plugin
-        */
+         * Load a scene
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param engine is the instance of BABYLON.Engine to use to create the scene
+         * @param onSuccess a callback with the scene when import succeeds
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param onError a callback with the scene, a message, and possibly an exception when import fails
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The loaded plugin
+         */
         SceneLoader.Load = function (rootUrl, sceneFilename, engine, onSuccess, onProgress, onError, pluginExtension) {
             if (onSuccess === void 0) { onSuccess = null; }
             if (onProgress === void 0) { onProgress = null; }
@@ -72250,14 +72295,14 @@ var BABYLON;
             return SceneLoader.Append(rootUrl, sceneFilename, new BABYLON.Scene(engine), onSuccess, onProgress, onError, pluginExtension);
         };
         /**
-        * Load a scene
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param engine is the instance of BABYLON.Engine to use to create the scene
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The loaded scene
-        */
+         * Load a scene
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param engine is the instance of BABYLON.Engine to use to create the scene
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The loaded scene
+         */
         SceneLoader.LoadAsync = function (rootUrl, sceneFilename, engine, onProgress, pluginExtension) {
             if (onProgress === void 0) { onProgress = null; }
             if (pluginExtension === void 0) { pluginExtension = null; }
@@ -72270,16 +72315,16 @@ var BABYLON;
             });
         };
         /**
-        * Append a scene
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param scene is the instance of BABYLON.Scene to append to
-        * @param onSuccess a callback with the scene when import succeeds
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param onError a callback with the scene, a message, and possibly an exception when import fails
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The loaded plugin
-        */
+         * Append a scene
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param scene is the instance of BABYLON.Scene to append to
+         * @param onSuccess a callback with the scene when import succeeds
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param onError a callback with the scene, a message, and possibly an exception when import fails
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The loaded plugin
+         */
         SceneLoader.Append = function (rootUrl, sceneFilename, scene, onSuccess, onProgress, onError, pluginExtension) {
             if (sceneFilename === void 0) { sceneFilename = ""; }
             if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
@@ -72291,12 +72336,8 @@ var BABYLON;
                 BABYLON.Tools.Error("No scene available to append to");
                 return null;
             }
-            if (!sceneFilename) {
-                sceneFilename = BABYLON.Tools.GetFilename(rootUrl);
-                rootUrl = BABYLON.Tools.GetFolderPath(rootUrl);
-            }
-            if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
-                BABYLON.Tools.Error("Wrong sceneFilename parameter");
+            var fileInfo = SceneLoader._getFileInfo(rootUrl, sceneFilename);
+            if (!fileInfo) {
                 return null;
             }
             if (SceneLoader.ShowLoadingScreen) {
@@ -72309,7 +72350,7 @@ var BABYLON;
                 scene.getEngine().hideLoadingUI();
             };
             var errorHandler = function (message, exception) {
-                var errorMessage = "Unable to load from " + rootUrl + sceneFilename + (message ? ": " + message : "");
+                var errorMessage = "Unable to load from " + fileInfo.url + (message ? ": " + message : "");
                 if (onError) {
                     onError(scene, errorMessage, exception);
                 }
@@ -72338,13 +72379,10 @@ var BABYLON;
                 }
                 scene._removePendingData(loadingToken);
             };
-            return SceneLoader._loadData(rootUrl, sceneFilename, scene, function (plugin, data, responseURL) {
-                if (sceneFilename === "") {
-                    rootUrl = BABYLON.Tools.GetFolderPath(rootUrl, true);
-                }
+            return SceneLoader._loadData(fileInfo, scene, function (plugin, data, responseURL) {
                 if (plugin.load) {
                     var syncedPlugin = plugin;
-                    if (!syncedPlugin.load(scene, data, rootUrl, errorHandler)) {
+                    if (!syncedPlugin.load(scene, data, fileInfo.rootUrl, errorHandler)) {
                         return;
                     }
                     scene.loadingPluginName = plugin.name;
@@ -72352,7 +72390,7 @@ var BABYLON;
                 }
                 else {
                     var asyncedPlugin = plugin;
-                    asyncedPlugin.loadAsync(scene, data, rootUrl, progressHandler, rootUrl + sceneFilename).then(function () {
+                    asyncedPlugin.loadAsync(scene, data, fileInfo.rootUrl, progressHandler, fileInfo.name).then(function () {
                         scene.loadingPluginName = plugin.name;
                         successHandler();
                     }).catch(function (error) {
@@ -72367,14 +72405,14 @@ var BABYLON;
             }, progressHandler, errorHandler, disposeHandler, pluginExtension);
         };
         /**
-        * Append a scene
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param scene is the instance of BABYLON.Scene to append to
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The given scene
-        */
+         * Append a scene
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param scene is the instance of BABYLON.Scene to append to
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The given scene
+         */
         SceneLoader.AppendAsync = function (rootUrl, sceneFilename, scene, onProgress, pluginExtension) {
             if (sceneFilename === void 0) { sceneFilename = ""; }
             if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
@@ -72389,16 +72427,16 @@ var BABYLON;
             });
         };
         /**
-        * Load a scene into an asset container
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param scene is the instance of BABYLON.Scene to append to (default: last created scene)
-        * @param onSuccess a callback with the scene when import succeeds
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param onError a callback with the scene, a message, and possibly an exception when import fails
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The loaded plugin
-        */
+         * Load a scene into an asset container
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param scene is the instance of BABYLON.Scene to append to (default: last created scene)
+         * @param onSuccess a callback with the scene when import succeeds
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param onError a callback with the scene, a message, and possibly an exception when import fails
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The loaded plugin
+         */
         SceneLoader.LoadAssetContainer = function (rootUrl, sceneFilename, scene, onSuccess, onProgress, onError, pluginExtension) {
             if (sceneFilename === void 0) { sceneFilename = ""; }
             if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
@@ -72410,12 +72448,8 @@ var BABYLON;
                 BABYLON.Tools.Error("No scene available to load asset container to");
                 return null;
             }
-            if (!sceneFilename) {
-                sceneFilename = BABYLON.Tools.GetFilename(rootUrl);
-                rootUrl = BABYLON.Tools.GetFolderPath(rootUrl);
-            }
-            if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
-                BABYLON.Tools.Error("Wrong sceneFilename parameter");
+            var fileInfo = SceneLoader._getFileInfo(rootUrl, sceneFilename);
+            if (!fileInfo) {
                 return null;
             }
             var loadingToken = {};
@@ -72424,7 +72458,7 @@ var BABYLON;
                 scene._removePendingData(loadingToken);
             };
             var errorHandler = function (message, exception) {
-                var errorMessage = "Unable to load assets from " + rootUrl + sceneFilename + (message ? ": " + message : "");
+                var errorMessage = "Unable to load assets from " + fileInfo.url + (message ? ": " + message : "");
                 if (onError) {
                     onError(scene, errorMessage, exception);
                 }
@@ -72453,10 +72487,10 @@ var BABYLON;
                 }
                 scene._removePendingData(loadingToken);
             };
-            return SceneLoader._loadData(rootUrl, sceneFilename, scene, function (plugin, data, responseURL) {
+            return SceneLoader._loadData(fileInfo, scene, function (plugin, data, responseURL) {
                 if (plugin.loadAssetContainer) {
                     var syncedPlugin = plugin;
-                    var assetContainer = syncedPlugin.loadAssetContainer(scene, data, rootUrl, errorHandler);
+                    var assetContainer = syncedPlugin.loadAssetContainer(scene, data, fileInfo.rootUrl, errorHandler);
                     if (!assetContainer) {
                         return;
                     }
@@ -72465,7 +72499,7 @@ var BABYLON;
                 }
                 else if (plugin.loadAssetContainerAsync) {
                     var asyncedPlugin = plugin;
-                    asyncedPlugin.loadAssetContainerAsync(scene, data, rootUrl, progressHandler, rootUrl + sceneFilename).then(function (assetContainer) {
+                    asyncedPlugin.loadAssetContainerAsync(scene, data, fileInfo.rootUrl, progressHandler, fileInfo.name).then(function (assetContainer) {
                         scene.loadingPluginName = plugin.name;
                         successHandler(assetContainer);
                     }).catch(function (error) {
@@ -72483,14 +72517,14 @@ var BABYLON;
             }, progressHandler, errorHandler, disposeHandler, pluginExtension);
         };
         /**
-        * Load a scene into an asset container
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param scene is the instance of BABYLON.Scene to append to
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The loaded asset container
-        */
+         * Load a scene into an asset container
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param scene is the instance of BABYLON.Scene to append to
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The loaded asset container
+         */
         SceneLoader.LoadAssetContainerAsync = function (rootUrl, sceneFilename, scene, onProgress, pluginExtension) {
             if (sceneFilename === void 0) { sceneFilename = ""; }
             if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
@@ -73280,9 +73314,7 @@ var BABYLON;
                     && name.indexOf(".binary.babylon") === -1 && name.indexOf(".incremental.babylon") === -1) {
                     this._sceneFileToLoad = files[i];
                 }
-                else {
-                    FilesInput.FilesToLoad[name] = files[i];
-                }
+                FilesInput.FilesToLoad[name] = files[i];
             }
         };
         FilesInput.prototype.loadFiles = function (event) {
@@ -73367,7 +73399,7 @@ var BABYLON;
                     }
                     this._engine.stopRenderLoop();
                 }
-                BABYLON.SceneLoader.LoadAsync("file:", this._sceneFileToLoad, this._engine, function (progress) {
+                BABYLON.SceneLoader.LoadAsync("file:", this._sceneFileToLoad.name, this._engine, function (progress) {
                     if (_this._progressCallback) {
                         _this._progressCallback(progress);
                     }
@@ -107639,10 +107671,14 @@ var BABYLON;
             this._onBeforeParticlesRenderingObserver = null;
             this.scene.onAfterParticlesRenderingObservable.remove(this._onAfterParticlesRenderingObserver);
             this._onAfterParticlesRenderingObserver = null;
-            this.scene.onBeforeSpritesRenderingObservable.remove(this._onBeforeSpritesRenderingObserver);
-            this._onBeforeSpritesRenderingObserver = null;
-            this.scene.onAfterSpritesRenderingObservable.remove(this._onAfterSpritesRenderingObserver);
-            this._onAfterSpritesRenderingObserver = null;
+            if (this._onBeforeSpritesRenderingObserver) {
+                this.scene.onBeforeSpritesRenderingObservable.remove(this._onBeforeSpritesRenderingObserver);
+                this._onBeforeSpritesRenderingObserver = null;
+            }
+            if (this._onAfterSpritesRenderingObserver) {
+                this.scene.onAfterSpritesRenderingObservable.remove(this._onAfterSpritesRenderingObserver);
+                this._onAfterSpritesRenderingObserver = null;
+            }
             this.scene.onBeforeDrawPhaseObservable.remove(this._onBeforeDrawPhaseObserver);
             this._onBeforeDrawPhaseObserver = null;
             this.scene.onAfterDrawPhaseObservable.remove(this._onAfterDrawPhaseObserver);

+ 191 - 155
dist/preview release/babylon.no-module.max.js

@@ -33656,12 +33656,14 @@ var BABYLON;
          * Creates a ground mesh from a height map.
          * tuto : http://doc.babylonjs.com/babylon101/height_map
          * Please consider using the same method from the MeshBuilder class instead.
-         * The parameter `url` sets the URL of the height map image resource.
-         * The parameters `width` and `height` (positive floats, default 10) set the ground width and height sizes.
-         * The parameter `subdivisions` (positive integer, default 1) sets the number of subdivision per side.
-         * The parameter `minHeight` (float, default 0) is the minimum altitude on the ground.
-         * The parameter `maxHeight` (float, default 1) is the maximum altitude on the ground.
-         * The parameter `onReady` is a javascript callback function that will be called  once the mesh is just built (the height map download can last some time).
+         * @param url sets the URL of the height map image resource.
+         * @param width (positive float, default 10) set the ground width size.
+         * @param height (positive float, default 10) set the ground height size.
+         * @param subdivisions (positive integer, default 1) sets the number of subdivision per side.
+         * @param minHeight (float, default 0) is the minimum altitude on the ground.
+         * @param maxHeight (float, default 1) is the maximum altitude on the ground.
+         * @param onReady is a javascript callback function that will be called  once the mesh is just built (the height map download can last some time).
+         * @param alphaFilter will filter any data where the alpha channel is below this value, defaults 0 (all data visible).
          * This function is passed the newly built mesh :
          * ```javascript
          * function(mesh) { // do things
@@ -33669,7 +33671,7 @@ var BABYLON;
          * ```
          * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.
          */
-        Mesh.CreateGroundFromHeightMap = function (name, url, width, height, subdivisions, minHeight, maxHeight, scene, updatable, onReady) {
+        Mesh.CreateGroundFromHeightMap = function (name, url, width, height, subdivisions, minHeight, maxHeight, scene, updatable, onReady, alphaFilter) {
             var options = {
                 width: width,
                 height: height,
@@ -33677,7 +33679,8 @@ var BABYLON;
                 minHeight: minHeight,
                 maxHeight: maxHeight,
                 updatable: updatable,
-                onReady: onReady
+                onReady: onReady,
+                alphaFilter: alphaFilter
             };
             return BABYLON.MeshBuilder.CreateGroundFromHeightMap(name, url, options, scene);
         };
@@ -37606,6 +37609,7 @@ var BABYLON;
           * * buffer the array holding the image color data
           * * bufferWidth the width of image
           * * bufferHeight the height of image
+          * * alphaFilter Remove any data where the alpha channel is below this value, defaults 0 (all data visible)
          * @returns the VertexData of the Ground designed from a heightmap
          */
         VertexData.CreateGroundFromHeightMap = function (options) {
@@ -37615,6 +37619,7 @@ var BABYLON;
             var uvs = [];
             var row, col;
             var filter = options.colorFilter || new BABYLON.Color3(0.3, 0.59, 0.11);
+            var alphaFilter = options.alphaFilter || 0.0;
             // Vertices
             for (row = 0; row <= options.subdivisions; row++) {
                 for (col = 0; col <= options.subdivisions; col++) {
@@ -37626,8 +37631,15 @@ var BABYLON;
                     var r = options.buffer[pos] / 255.0;
                     var g = options.buffer[pos + 1] / 255.0;
                     var b = options.buffer[pos + 2] / 255.0;
+                    var a = options.buffer[pos + 3] / 255.0;
                     var gradient = r * filter.r + g * filter.g + b * filter.b;
-                    position.y = options.minHeight + (options.maxHeight - options.minHeight) * gradient;
+                    // If our alpha channel is not within our filter then we will assign a 'special' height 
+                    // Then when building the indices, we will ignore any vertex that is using the special height
+                    if (a >= alphaFilter)
+                        position.y = options.minHeight + (options.maxHeight - options.minHeight) * gradient;
+                    else {
+                        position.y = options.minHeight - BABYLON.Epsilon; // We can't have a height below minHeight, normally.
+                    }
                     // Add  vertex
                     positions.push(position.x, position.y, position.z);
                     normals.push(0, 0, 0);
@@ -37637,12 +37649,28 @@ var BABYLON;
             // Indices
             for (row = 0; row < options.subdivisions; row++) {
                 for (col = 0; col < options.subdivisions; col++) {
-                    indices.push(col + 1 + (row + 1) * (options.subdivisions + 1));
-                    indices.push(col + 1 + row * (options.subdivisions + 1));
-                    indices.push(col + row * (options.subdivisions + 1));
-                    indices.push(col + (row + 1) * (options.subdivisions + 1));
-                    indices.push(col + 1 + (row + 1) * (options.subdivisions + 1));
-                    indices.push(col + row * (options.subdivisions + 1));
+                    // Calculate Indices
+                    var idx1 = (col + 1 + (row + 1) * (options.subdivisions + 1));
+                    var idx2 = (col + 1 + row * (options.subdivisions + 1));
+                    var idx3 = (col + row * (options.subdivisions + 1));
+                    var idx4 = (col + (row + 1) * (options.subdivisions + 1));
+                    // Check that all indices are visible (based on our special height)
+                    // Only display the vertex if all Indices are visible
+                    // Positions are stored x,y,z for each vertex, hence the * 3 and + 1 for height
+                    var isVisibleIdx1 = positions[idx1 * 3 + 1] >= options.minHeight;
+                    var isVisibleIdx2 = positions[idx2 * 3 + 1] >= options.minHeight;
+                    var isVisibleIdx3 = positions[idx3 * 3 + 1] >= options.minHeight;
+                    if (isVisibleIdx1 && isVisibleIdx2 && isVisibleIdx3) {
+                        indices.push(idx1);
+                        indices.push(idx2);
+                        indices.push(idx3);
+                    }
+                    var isVisibleIdx4 = positions[idx4 * 3 + 1] >= options.minHeight;
+                    if (isVisibleIdx4 && isVisibleIdx1 && isVisibleIdx3) {
+                        indices.push(idx4);
+                        indices.push(idx1);
+                        indices.push(idx3);
+                    }
                 }
             }
             // Normals
@@ -56842,9 +56870,6 @@ var BABYLON;
             else {
                 var emitterPosition = subEmitter.particleSystem.emitter;
                 emitterPosition.copyFrom(particle.position);
-                if (subEmitter.inheritDirection) {
-                    BABYLON.Tools.Warn("subEmitter.inheritDirection is not supported with non-mesh emitter type");
-                }
             }
             // Set inheritedVelocityOffset to be used when new particles are created
             particle.direction.scaleToRef(subEmitter.inheritedVelocityAmount / 2, BABYLON.Tmp.Vector3[0]);
@@ -57380,6 +57405,11 @@ var BABYLON;
                     else if (subEmitter instanceof Array) {
                         _this._subEmitters.push(subEmitter);
                     }
+                    _this._subEmitters[_this._subEmitters.length - 1].forEach(function (se) {
+                        if (!(se.particleSystem.emitter instanceof BABYLON.AbstractMesh) && se.inheritDirection) {
+                            BABYLON.Tools.Warn("subEmitter.inheritDirection is not supported with non-mesh emitter type");
+                        }
+                    });
                 });
             }
             this._started = true;
@@ -57977,8 +58007,8 @@ var BABYLON;
                 this._rampGradientsTexture = null;
             }
             this._removeFromRoot();
-            if (this._disposeEmitterOnDispose && !this.emitter.isDisposed) {
-                this.emitter.dispose();
+            if (this._disposeEmitterOnDispose && this.emitter && this.emitter.dispose) {
+                this.emitter.dispose(true);
             }
             // Remove from scene
             var index = this._scene.particleSystems.indexOf(this);
@@ -61816,12 +61846,13 @@ var BABYLON;
             this.scene._beforeEvaluateActiveMeshStage.registerStep(BABYLON.SceneComponentConstants.STEP_BEFOREEVALUATEACTIVEMESH_BOUNDINGBOXRENDERER, this, this.reset);
             this.scene._activeMeshStage.registerStep(BABYLON.SceneComponentConstants.STEP_ACTIVEMESH_BOUNDINGBOXRENDERER, this, this._activeMesh);
             this.scene._evaluateSubMeshStage.registerStep(BABYLON.SceneComponentConstants.STEP_EVALUATESUBMESH_BOUNDINGBOXRENDERER, this, this._evaluateSubMesh);
-            this.scene._afterCameraDrawStage.registerStep(BABYLON.SceneComponentConstants.STEP_AFTERCAMERADRAW_BOUNDINGBOXRENDERER, this, this.render);
+            this.scene._afterRenderingGroupDrawStage.registerStep(BABYLON.SceneComponentConstants.STEP_AFTERCAMERADRAW_BOUNDINGBOXRENDERER, this, this.render);
         };
         BoundingBoxRenderer.prototype._evaluateSubMesh = function (mesh, subMesh) {
             if (mesh.showSubMeshesBoundingBox) {
                 var boundingInfo = subMesh.getBoundingInfo();
                 if (boundingInfo !== null && boundingInfo !== undefined) {
+                    boundingInfo.boundingBox._tag = mesh.renderingGroupId;
                     this.renderList.push(boundingInfo.boundingBox);
                 }
             }
@@ -61829,6 +61860,7 @@ var BABYLON;
         BoundingBoxRenderer.prototype._activeMesh = function (sourceMesh, mesh) {
             if (sourceMesh.showBoundingBox || this.scene.forceShowBoundingBoxes) {
                 var boundingInfo = sourceMesh.getBoundingInfo();
+                boundingInfo.boundingBox._tag = mesh.renderingGroupId;
                 this.renderList.push(boundingInfo.boundingBox);
             }
         };
@@ -61863,7 +61895,7 @@ var BABYLON;
         BoundingBoxRenderer.prototype.reset = function () {
             this.renderList.reset();
         };
-        BoundingBoxRenderer.prototype.render = function () {
+        BoundingBoxRenderer.prototype.render = function (renderingGroupId) {
             if (this.renderList.length === 0) {
                 return;
             }
@@ -61876,6 +61908,9 @@ var BABYLON;
             this._colorShader._preBind();
             for (var boundingBoxIndex = 0; boundingBoxIndex < this.renderList.length; boundingBoxIndex++) {
                 var boundingBox = this.renderList.data[boundingBoxIndex];
+                if (boundingBox._tag !== renderingGroupId) {
+                    continue;
+                }
                 var min = boundingBox.minimum;
                 var max = boundingBox.maximum;
                 var diff = max.subtract(min);
@@ -65283,6 +65318,7 @@ var BABYLON;
          * * The parameter `maxHeight` (float, default 1) is the maximum altitude on the ground.
          * * The parameter `colorFilter` (optional Color3, default (0.3, 0.59, 0.11) ) is the filter to apply to the image pixel colors to compute the height.
          * * The parameter `onReady` is a javascript callback function that will be called  once the mesh is just built (the height map download can last some time).
+         * * The parameter `alphaFilter` will filter any data where the alpha channel is below this value, defaults 0 (all data visible)
          * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.
          * @param name defines the name of the mesh
          * @param url defines the url to the height map
@@ -65299,6 +65335,7 @@ var BABYLON;
             var minHeight = options.minHeight || 0.0;
             var maxHeight = options.maxHeight || 1.0;
             var filter = options.colorFilter || new BABYLON.Color3(0.3, 0.59, 0.11);
+            var alphaFilter = options.alphaFilter || 0.0;
             var updatable = options.updatable;
             var onReady = options.onReady;
             var ground = new BABYLON.GroundMesh(name, scene);
@@ -65333,7 +65370,8 @@ var BABYLON;
                     width: width, height: height,
                     subdivisions: subdivisions,
                     minHeight: minHeight, maxHeight: maxHeight, colorFilter: filter,
-                    buffer: buffer, bufferWidth: bufferWidth, bufferHeight: bufferHeight
+                    buffer: buffer, bufferWidth: bufferWidth, bufferHeight: bufferHeight,
+                    alphaFilter: alphaFilter
                 });
                 vertexData.applyToMesh(ground, updatable);
                 //execute ready callback, if set
@@ -71942,9 +71980,6 @@ var BABYLON;
             return SceneLoader._getDefaultPlugin();
         };
         SceneLoader._getPluginForFilename = function (sceneFilename) {
-            if (sceneFilename.name) {
-                sceneFilename = sceneFilename.name;
-            }
             var queryStringPosition = sceneFilename.indexOf("?");
             if (queryStringPosition !== -1) {
                 sceneFilename = sceneFilename.substring(0, queryStringPosition);
@@ -71955,14 +71990,14 @@ var BABYLON;
         };
         // use babylon file loader directly if sceneFilename is prefixed with "data:"
         SceneLoader._getDirectLoad = function (sceneFilename) {
-            if (sceneFilename.substr && sceneFilename.substr(0, 5) === "data:") {
+            if (sceneFilename.substr(0, 5) === "data:") {
                 return sceneFilename.substr(5);
             }
             return null;
         };
-        SceneLoader._loadData = function (rootUrl, sceneFilename, scene, onSuccess, onProgress, onError, onDispose, pluginExtension) {
-            var directLoad = SceneLoader._getDirectLoad(sceneFilename);
-            var registeredPlugin = pluginExtension ? SceneLoader._getPluginForExtension(pluginExtension) : (directLoad ? SceneLoader._getPluginForDirectLoad(sceneFilename) : SceneLoader._getPluginForFilename(sceneFilename));
+        SceneLoader._loadData = function (fileInfo, scene, onSuccess, onProgress, onError, onDispose, pluginExtension) {
+            var directLoad = SceneLoader._getDirectLoad(fileInfo.name);
+            var registeredPlugin = pluginExtension ? SceneLoader._getPluginForExtension(pluginExtension) : (directLoad ? SceneLoader._getPluginForDirectLoad(fileInfo.name) : SceneLoader._getPluginForFilename(fileInfo.name));
             var plugin;
             if (registeredPlugin.plugin.createPlugin) {
                 plugin = registeredPlugin.plugin.createPlugin();
@@ -71998,8 +72033,7 @@ var BABYLON;
                 if (pluginDisposed) {
                     return;
                 }
-                var url = rootUrl + sceneFilename;
-                request = BABYLON.Tools.LoadFile(url, dataCallback, onProgress ? function (event) {
+                request = BABYLON.Tools.LoadFile(fileInfo.url, dataCallback, onProgress ? function (event) {
                     onProgress(SceneLoaderProgressEvent.FromProgressEvent(event));
                 } : undefined, database, useArrayBuffer, function (request, exception) {
                     onError("Failed to load scene." + (exception ? "" : " " + exception.message), exception);
@@ -72009,7 +72043,7 @@ var BABYLON;
                 dataCallback(directLoad);
                 return plugin;
             }
-            if (rootUrl.indexOf("file:") === -1) {
+            if (fileInfo.rootUrl.indexOf("file:") === -1) {
                 var engine = scene.getEngine();
                 var canUseOfflineSupport = engine.enableOfflineSupport;
                 if (canUseOfflineSupport) {
@@ -72017,7 +72051,7 @@ var BABYLON;
                     var exceptionFound = false;
                     for (var _i = 0, _a = scene.disableOfflineSupportExceptionRules; _i < _a.length; _i++) {
                         var regex = _a[_i];
-                        if (regex.test(rootUrl + sceneFilename)) {
+                        if (regex.test(fileInfo.url)) {
                             exceptionFound = true;
                             break;
                         }
@@ -72026,7 +72060,7 @@ var BABYLON;
                 }
                 if (canUseOfflineSupport) {
                     // Checking if a manifest file has been set for this scene and if offline mode has been requested
-                    database = new BABYLON.Database(rootUrl + sceneFilename, manifestChecked, engine.disableManifestCheck);
+                    database = new BABYLON.Database(fileInfo.url, manifestChecked, engine.disableManifestCheck);
                 }
                 else {
                     manifestChecked();
@@ -72034,19 +72068,39 @@ var BABYLON;
             }
             // Loading file from disk via input file or drag'n'drop
             else {
-                var fileOrString = sceneFilename;
-                if (fileOrString.name) { // File
-                    request = BABYLON.Tools.ReadFile(fileOrString, dataCallback, onProgress, useArrayBuffer);
-                }
-                else if (BABYLON.FilesInput.FilesToLoad[sceneFilename]) {
-                    request = BABYLON.Tools.ReadFile(BABYLON.FilesInput.FilesToLoad[sceneFilename], dataCallback, onProgress, useArrayBuffer);
+                var file = BABYLON.FilesInput.FilesToLoad[fileInfo.name.toLowerCase()];
+                if (file) {
+                    request = BABYLON.Tools.ReadFile(file, dataCallback, onProgress, useArrayBuffer);
                 }
                 else {
-                    onError("Unable to find file named " + sceneFilename);
+                    onError("Unable to find file named " + fileInfo.name);
                 }
             }
             return plugin;
         };
+        SceneLoader._getFileInfo = function (rootUrl, sceneFilename) {
+            var url;
+            var name;
+            if (!sceneFilename) {
+                url = rootUrl;
+                name = BABYLON.Tools.GetFilename(rootUrl);
+                rootUrl = BABYLON.Tools.GetFolderPath(rootUrl);
+            }
+            else {
+                if (sceneFilename.substr(0, 1) === "/") {
+                    BABYLON.Tools.Error("Wrong sceneFilename parameter");
+                    return null;
+                }
+                url = rootUrl + sceneFilename;
+                name = sceneFilename;
+            }
+            ;
+            return {
+                url: url,
+                rootUrl: rootUrl,
+                name: name
+            };
+        };
         // Public functions
         SceneLoader.GetPluginForExtension = function (extension) {
             return SceneLoader._getPluginForExtension(extension).plugin;
@@ -72075,8 +72129,8 @@ var BABYLON;
         /**
          * Import meshes into a scene
          * @param meshNames an array of mesh names, a single mesh name, or empty string for all meshes that filter what meshes are imported
-         * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-         * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
          * @param scene the instance of BABYLON.Scene to append to
          * @param onSuccess a callback with a list of imported meshes, particleSystems, and skeletons when import succeeds
          * @param onProgress a callback with a progress event for each file being loaded
@@ -72095,12 +72149,8 @@ var BABYLON;
                 BABYLON.Tools.Error("No scene available to import mesh to");
                 return null;
             }
-            if (!sceneFilename) {
-                sceneFilename = BABYLON.Tools.GetFilename(rootUrl);
-                rootUrl = BABYLON.Tools.GetFolderPath(rootUrl);
-            }
-            if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
-                BABYLON.Tools.Error("Wrong sceneFilename parameter");
+            var fileInfo = SceneLoader._getFileInfo(rootUrl, sceneFilename);
+            if (!fileInfo) {
                 return null;
             }
             var loadingToken = {};
@@ -72109,7 +72159,7 @@ var BABYLON;
                 scene._removePendingData(loadingToken);
             };
             var errorHandler = function (message, exception) {
-                var errorMessage = "Unable to import meshes from " + rootUrl + sceneFilename + ": " + message;
+                var errorMessage = "Unable to import meshes from " + fileInfo.url + ": " + message;
                 if (onError) {
                     onError(scene, errorMessage, exception);
                 }
@@ -72128,7 +72178,7 @@ var BABYLON;
                 }
             } : undefined;
             var successHandler = function (meshes, particleSystems, skeletons, animationGroups) {
-                scene.importedMeshesFiles.push(rootUrl + sceneFilename);
+                scene.importedMeshesFiles.push(fileInfo.url);
                 if (onSuccess) {
                     try {
                         onSuccess(meshes, particleSystems, skeletons, animationGroups);
@@ -72139,21 +72189,16 @@ var BABYLON;
                 }
                 scene._removePendingData(loadingToken);
             };
-            return SceneLoader._loadData(rootUrl, sceneFilename, scene, function (plugin, data, responseURL) {
+            return SceneLoader._loadData(fileInfo, scene, function (plugin, data, responseURL) {
                 if (plugin.rewriteRootURL) {
-                    rootUrl = plugin.rewriteRootURL(rootUrl, responseURL);
-                }
-                if (sceneFilename === "") {
-                    if (sceneFilename === "") {
-                        rootUrl = BABYLON.Tools.GetFolderPath(rootUrl, true);
-                    }
+                    fileInfo.rootUrl = plugin.rewriteRootURL(fileInfo.rootUrl, responseURL);
                 }
                 if (plugin.importMesh) {
                     var syncedPlugin = plugin;
                     var meshes = new Array();
                     var particleSystems = new Array();
                     var skeletons = new Array();
-                    if (!syncedPlugin.importMesh(meshNames, scene, data, rootUrl, meshes, particleSystems, skeletons, errorHandler)) {
+                    if (!syncedPlugin.importMesh(meshNames, scene, data, fileInfo.rootUrl, meshes, particleSystems, skeletons, errorHandler)) {
                         return;
                     }
                     scene.loadingPluginName = plugin.name;
@@ -72161,7 +72206,7 @@ var BABYLON;
                 }
                 else {
                     var asyncedPlugin = plugin;
-                    asyncedPlugin.importMeshAsync(meshNames, scene, data, rootUrl, progressHandler, rootUrl + sceneFilename).then(function (result) {
+                    asyncedPlugin.importMeshAsync(meshNames, scene, data, fileInfo.rootUrl, progressHandler, fileInfo.name).then(function (result) {
                         scene.loadingPluginName = plugin.name;
                         successHandler(result.meshes, result.particleSystems, result.skeletons, result.animationGroups);
                     }).catch(function (error) {
@@ -72171,15 +72216,15 @@ var BABYLON;
             }, progressHandler, errorHandler, disposeHandler, pluginExtension);
         };
         /**
-        * Import meshes into a scene
-        * @param meshNames an array of mesh names, a single mesh name, or empty string for all meshes that filter what meshes are imported
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param scene the instance of BABYLON.Scene to append to
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The loaded list of imported meshes, particle systems, skeletons, and animation groups
-        */
+         * Import meshes into a scene
+         * @param meshNames an array of mesh names, a single mesh name, or empty string for all meshes that filter what meshes are imported
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param scene the instance of BABYLON.Scene to append to
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The loaded list of imported meshes, particle systems, skeletons, and animation groups
+         */
         SceneLoader.ImportMeshAsync = function (meshNames, rootUrl, sceneFilename, scene, onProgress, pluginExtension) {
             if (sceneFilename === void 0) { sceneFilename = ""; }
             if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
@@ -72199,16 +72244,16 @@ var BABYLON;
             });
         };
         /**
-        * Load a scene
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param engine is the instance of BABYLON.Engine to use to create the scene
-        * @param onSuccess a callback with the scene when import succeeds
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param onError a callback with the scene, a message, and possibly an exception when import fails
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The loaded plugin
-        */
+         * Load a scene
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param engine is the instance of BABYLON.Engine to use to create the scene
+         * @param onSuccess a callback with the scene when import succeeds
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param onError a callback with the scene, a message, and possibly an exception when import fails
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The loaded plugin
+         */
         SceneLoader.Load = function (rootUrl, sceneFilename, engine, onSuccess, onProgress, onError, pluginExtension) {
             if (onSuccess === void 0) { onSuccess = null; }
             if (onProgress === void 0) { onProgress = null; }
@@ -72217,14 +72262,14 @@ var BABYLON;
             return SceneLoader.Append(rootUrl, sceneFilename, new BABYLON.Scene(engine), onSuccess, onProgress, onError, pluginExtension);
         };
         /**
-        * Load a scene
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param engine is the instance of BABYLON.Engine to use to create the scene
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The loaded scene
-        */
+         * Load a scene
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param engine is the instance of BABYLON.Engine to use to create the scene
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The loaded scene
+         */
         SceneLoader.LoadAsync = function (rootUrl, sceneFilename, engine, onProgress, pluginExtension) {
             if (onProgress === void 0) { onProgress = null; }
             if (pluginExtension === void 0) { pluginExtension = null; }
@@ -72237,16 +72282,16 @@ var BABYLON;
             });
         };
         /**
-        * Append a scene
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param scene is the instance of BABYLON.Scene to append to
-        * @param onSuccess a callback with the scene when import succeeds
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param onError a callback with the scene, a message, and possibly an exception when import fails
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The loaded plugin
-        */
+         * Append a scene
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param scene is the instance of BABYLON.Scene to append to
+         * @param onSuccess a callback with the scene when import succeeds
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param onError a callback with the scene, a message, and possibly an exception when import fails
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The loaded plugin
+         */
         SceneLoader.Append = function (rootUrl, sceneFilename, scene, onSuccess, onProgress, onError, pluginExtension) {
             if (sceneFilename === void 0) { sceneFilename = ""; }
             if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
@@ -72258,12 +72303,8 @@ var BABYLON;
                 BABYLON.Tools.Error("No scene available to append to");
                 return null;
             }
-            if (!sceneFilename) {
-                sceneFilename = BABYLON.Tools.GetFilename(rootUrl);
-                rootUrl = BABYLON.Tools.GetFolderPath(rootUrl);
-            }
-            if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
-                BABYLON.Tools.Error("Wrong sceneFilename parameter");
+            var fileInfo = SceneLoader._getFileInfo(rootUrl, sceneFilename);
+            if (!fileInfo) {
                 return null;
             }
             if (SceneLoader.ShowLoadingScreen) {
@@ -72276,7 +72317,7 @@ var BABYLON;
                 scene.getEngine().hideLoadingUI();
             };
             var errorHandler = function (message, exception) {
-                var errorMessage = "Unable to load from " + rootUrl + sceneFilename + (message ? ": " + message : "");
+                var errorMessage = "Unable to load from " + fileInfo.url + (message ? ": " + message : "");
                 if (onError) {
                     onError(scene, errorMessage, exception);
                 }
@@ -72305,13 +72346,10 @@ var BABYLON;
                 }
                 scene._removePendingData(loadingToken);
             };
-            return SceneLoader._loadData(rootUrl, sceneFilename, scene, function (plugin, data, responseURL) {
-                if (sceneFilename === "") {
-                    rootUrl = BABYLON.Tools.GetFolderPath(rootUrl, true);
-                }
+            return SceneLoader._loadData(fileInfo, scene, function (plugin, data, responseURL) {
                 if (plugin.load) {
                     var syncedPlugin = plugin;
-                    if (!syncedPlugin.load(scene, data, rootUrl, errorHandler)) {
+                    if (!syncedPlugin.load(scene, data, fileInfo.rootUrl, errorHandler)) {
                         return;
                     }
                     scene.loadingPluginName = plugin.name;
@@ -72319,7 +72357,7 @@ var BABYLON;
                 }
                 else {
                     var asyncedPlugin = plugin;
-                    asyncedPlugin.loadAsync(scene, data, rootUrl, progressHandler, rootUrl + sceneFilename).then(function () {
+                    asyncedPlugin.loadAsync(scene, data, fileInfo.rootUrl, progressHandler, fileInfo.name).then(function () {
                         scene.loadingPluginName = plugin.name;
                         successHandler();
                     }).catch(function (error) {
@@ -72334,14 +72372,14 @@ var BABYLON;
             }, progressHandler, errorHandler, disposeHandler, pluginExtension);
         };
         /**
-        * Append a scene
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param scene is the instance of BABYLON.Scene to append to
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The given scene
-        */
+         * Append a scene
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param scene is the instance of BABYLON.Scene to append to
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The given scene
+         */
         SceneLoader.AppendAsync = function (rootUrl, sceneFilename, scene, onProgress, pluginExtension) {
             if (sceneFilename === void 0) { sceneFilename = ""; }
             if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
@@ -72356,16 +72394,16 @@ var BABYLON;
             });
         };
         /**
-        * Load a scene into an asset container
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param scene is the instance of BABYLON.Scene to append to (default: last created scene)
-        * @param onSuccess a callback with the scene when import succeeds
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param onError a callback with the scene, a message, and possibly an exception when import fails
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The loaded plugin
-        */
+         * Load a scene into an asset container
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param scene is the instance of BABYLON.Scene to append to (default: last created scene)
+         * @param onSuccess a callback with the scene when import succeeds
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param onError a callback with the scene, a message, and possibly an exception when import fails
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The loaded plugin
+         */
         SceneLoader.LoadAssetContainer = function (rootUrl, sceneFilename, scene, onSuccess, onProgress, onError, pluginExtension) {
             if (sceneFilename === void 0) { sceneFilename = ""; }
             if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
@@ -72377,12 +72415,8 @@ var BABYLON;
                 BABYLON.Tools.Error("No scene available to load asset container to");
                 return null;
             }
-            if (!sceneFilename) {
-                sceneFilename = BABYLON.Tools.GetFilename(rootUrl);
-                rootUrl = BABYLON.Tools.GetFolderPath(rootUrl);
-            }
-            if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
-                BABYLON.Tools.Error("Wrong sceneFilename parameter");
+            var fileInfo = SceneLoader._getFileInfo(rootUrl, sceneFilename);
+            if (!fileInfo) {
                 return null;
             }
             var loadingToken = {};
@@ -72391,7 +72425,7 @@ var BABYLON;
                 scene._removePendingData(loadingToken);
             };
             var errorHandler = function (message, exception) {
-                var errorMessage = "Unable to load assets from " + rootUrl + sceneFilename + (message ? ": " + message : "");
+                var errorMessage = "Unable to load assets from " + fileInfo.url + (message ? ": " + message : "");
                 if (onError) {
                     onError(scene, errorMessage, exception);
                 }
@@ -72420,10 +72454,10 @@ var BABYLON;
                 }
                 scene._removePendingData(loadingToken);
             };
-            return SceneLoader._loadData(rootUrl, sceneFilename, scene, function (plugin, data, responseURL) {
+            return SceneLoader._loadData(fileInfo, scene, function (plugin, data, responseURL) {
                 if (plugin.loadAssetContainer) {
                     var syncedPlugin = plugin;
-                    var assetContainer = syncedPlugin.loadAssetContainer(scene, data, rootUrl, errorHandler);
+                    var assetContainer = syncedPlugin.loadAssetContainer(scene, data, fileInfo.rootUrl, errorHandler);
                     if (!assetContainer) {
                         return;
                     }
@@ -72432,7 +72466,7 @@ var BABYLON;
                 }
                 else if (plugin.loadAssetContainerAsync) {
                     var asyncedPlugin = plugin;
-                    asyncedPlugin.loadAssetContainerAsync(scene, data, rootUrl, progressHandler, rootUrl + sceneFilename).then(function (assetContainer) {
+                    asyncedPlugin.loadAssetContainerAsync(scene, data, fileInfo.rootUrl, progressHandler, fileInfo.name).then(function (assetContainer) {
                         scene.loadingPluginName = plugin.name;
                         successHandler(assetContainer);
                     }).catch(function (error) {
@@ -72450,14 +72484,14 @@ var BABYLON;
             }, progressHandler, errorHandler, disposeHandler, pluginExtension);
         };
         /**
-        * Load a scene into an asset container
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param scene is the instance of BABYLON.Scene to append to
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The loaded asset container
-        */
+         * Load a scene into an asset container
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param scene is the instance of BABYLON.Scene to append to
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The loaded asset container
+         */
         SceneLoader.LoadAssetContainerAsync = function (rootUrl, sceneFilename, scene, onProgress, pluginExtension) {
             if (sceneFilename === void 0) { sceneFilename = ""; }
             if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
@@ -73247,9 +73281,7 @@ var BABYLON;
                     && name.indexOf(".binary.babylon") === -1 && name.indexOf(".incremental.babylon") === -1) {
                     this._sceneFileToLoad = files[i];
                 }
-                else {
-                    FilesInput.FilesToLoad[name] = files[i];
-                }
+                FilesInput.FilesToLoad[name] = files[i];
             }
         };
         FilesInput.prototype.loadFiles = function (event) {
@@ -73334,7 +73366,7 @@ var BABYLON;
                     }
                     this._engine.stopRenderLoop();
                 }
-                BABYLON.SceneLoader.LoadAsync("file:", this._sceneFileToLoad, this._engine, function (progress) {
+                BABYLON.SceneLoader.LoadAsync("file:", this._sceneFileToLoad.name, this._engine, function (progress) {
                     if (_this._progressCallback) {
                         _this._progressCallback(progress);
                     }
@@ -107606,10 +107638,14 @@ var BABYLON;
             this._onBeforeParticlesRenderingObserver = null;
             this.scene.onAfterParticlesRenderingObservable.remove(this._onAfterParticlesRenderingObserver);
             this._onAfterParticlesRenderingObserver = null;
-            this.scene.onBeforeSpritesRenderingObservable.remove(this._onBeforeSpritesRenderingObserver);
-            this._onBeforeSpritesRenderingObserver = null;
-            this.scene.onAfterSpritesRenderingObservable.remove(this._onAfterSpritesRenderingObserver);
-            this._onAfterSpritesRenderingObserver = null;
+            if (this._onBeforeSpritesRenderingObserver) {
+                this.scene.onBeforeSpritesRenderingObservable.remove(this._onBeforeSpritesRenderingObserver);
+                this._onBeforeSpritesRenderingObserver = null;
+            }
+            if (this._onAfterSpritesRenderingObserver) {
+                this.scene.onAfterSpritesRenderingObservable.remove(this._onAfterSpritesRenderingObserver);
+                this._onAfterSpritesRenderingObserver = null;
+            }
             this.scene.onBeforeDrawPhaseObservable.remove(this._onBeforeDrawPhaseObserver);
             this._onBeforeDrawPhaseObserver = null;
             this.scene.onAfterDrawPhaseObservable.remove(this._onAfterDrawPhaseObserver);

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/babylon.worker.js


+ 191 - 155
dist/preview release/es6.js

@@ -33656,12 +33656,14 @@ var BABYLON;
          * Creates a ground mesh from a height map.
          * tuto : http://doc.babylonjs.com/babylon101/height_map
          * Please consider using the same method from the MeshBuilder class instead.
-         * The parameter `url` sets the URL of the height map image resource.
-         * The parameters `width` and `height` (positive floats, default 10) set the ground width and height sizes.
-         * The parameter `subdivisions` (positive integer, default 1) sets the number of subdivision per side.
-         * The parameter `minHeight` (float, default 0) is the minimum altitude on the ground.
-         * The parameter `maxHeight` (float, default 1) is the maximum altitude on the ground.
-         * The parameter `onReady` is a javascript callback function that will be called  once the mesh is just built (the height map download can last some time).
+         * @param url sets the URL of the height map image resource.
+         * @param width (positive float, default 10) set the ground width size.
+         * @param height (positive float, default 10) set the ground height size.
+         * @param subdivisions (positive integer, default 1) sets the number of subdivision per side.
+         * @param minHeight (float, default 0) is the minimum altitude on the ground.
+         * @param maxHeight (float, default 1) is the maximum altitude on the ground.
+         * @param onReady is a javascript callback function that will be called  once the mesh is just built (the height map download can last some time).
+         * @param alphaFilter will filter any data where the alpha channel is below this value, defaults 0 (all data visible).
          * This function is passed the newly built mesh :
          * ```javascript
          * function(mesh) { // do things
@@ -33669,7 +33671,7 @@ var BABYLON;
          * ```
          * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.
          */
-        Mesh.CreateGroundFromHeightMap = function (name, url, width, height, subdivisions, minHeight, maxHeight, scene, updatable, onReady) {
+        Mesh.CreateGroundFromHeightMap = function (name, url, width, height, subdivisions, minHeight, maxHeight, scene, updatable, onReady, alphaFilter) {
             var options = {
                 width: width,
                 height: height,
@@ -33677,7 +33679,8 @@ var BABYLON;
                 minHeight: minHeight,
                 maxHeight: maxHeight,
                 updatable: updatable,
-                onReady: onReady
+                onReady: onReady,
+                alphaFilter: alphaFilter
             };
             return BABYLON.MeshBuilder.CreateGroundFromHeightMap(name, url, options, scene);
         };
@@ -37606,6 +37609,7 @@ var BABYLON;
           * * buffer the array holding the image color data
           * * bufferWidth the width of image
           * * bufferHeight the height of image
+          * * alphaFilter Remove any data where the alpha channel is below this value, defaults 0 (all data visible)
          * @returns the VertexData of the Ground designed from a heightmap
          */
         VertexData.CreateGroundFromHeightMap = function (options) {
@@ -37615,6 +37619,7 @@ var BABYLON;
             var uvs = [];
             var row, col;
             var filter = options.colorFilter || new BABYLON.Color3(0.3, 0.59, 0.11);
+            var alphaFilter = options.alphaFilter || 0.0;
             // Vertices
             for (row = 0; row <= options.subdivisions; row++) {
                 for (col = 0; col <= options.subdivisions; col++) {
@@ -37626,8 +37631,15 @@ var BABYLON;
                     var r = options.buffer[pos] / 255.0;
                     var g = options.buffer[pos + 1] / 255.0;
                     var b = options.buffer[pos + 2] / 255.0;
+                    var a = options.buffer[pos + 3] / 255.0;
                     var gradient = r * filter.r + g * filter.g + b * filter.b;
-                    position.y = options.minHeight + (options.maxHeight - options.minHeight) * gradient;
+                    // If our alpha channel is not within our filter then we will assign a 'special' height 
+                    // Then when building the indices, we will ignore any vertex that is using the special height
+                    if (a >= alphaFilter)
+                        position.y = options.minHeight + (options.maxHeight - options.minHeight) * gradient;
+                    else {
+                        position.y = options.minHeight - BABYLON.Epsilon; // We can't have a height below minHeight, normally.
+                    }
                     // Add  vertex
                     positions.push(position.x, position.y, position.z);
                     normals.push(0, 0, 0);
@@ -37637,12 +37649,28 @@ var BABYLON;
             // Indices
             for (row = 0; row < options.subdivisions; row++) {
                 for (col = 0; col < options.subdivisions; col++) {
-                    indices.push(col + 1 + (row + 1) * (options.subdivisions + 1));
-                    indices.push(col + 1 + row * (options.subdivisions + 1));
-                    indices.push(col + row * (options.subdivisions + 1));
-                    indices.push(col + (row + 1) * (options.subdivisions + 1));
-                    indices.push(col + 1 + (row + 1) * (options.subdivisions + 1));
-                    indices.push(col + row * (options.subdivisions + 1));
+                    // Calculate Indices
+                    var idx1 = (col + 1 + (row + 1) * (options.subdivisions + 1));
+                    var idx2 = (col + 1 + row * (options.subdivisions + 1));
+                    var idx3 = (col + row * (options.subdivisions + 1));
+                    var idx4 = (col + (row + 1) * (options.subdivisions + 1));
+                    // Check that all indices are visible (based on our special height)
+                    // Only display the vertex if all Indices are visible
+                    // Positions are stored x,y,z for each vertex, hence the * 3 and + 1 for height
+                    var isVisibleIdx1 = positions[idx1 * 3 + 1] >= options.minHeight;
+                    var isVisibleIdx2 = positions[idx2 * 3 + 1] >= options.minHeight;
+                    var isVisibleIdx3 = positions[idx3 * 3 + 1] >= options.minHeight;
+                    if (isVisibleIdx1 && isVisibleIdx2 && isVisibleIdx3) {
+                        indices.push(idx1);
+                        indices.push(idx2);
+                        indices.push(idx3);
+                    }
+                    var isVisibleIdx4 = positions[idx4 * 3 + 1] >= options.minHeight;
+                    if (isVisibleIdx4 && isVisibleIdx1 && isVisibleIdx3) {
+                        indices.push(idx4);
+                        indices.push(idx1);
+                        indices.push(idx3);
+                    }
                 }
             }
             // Normals
@@ -56842,9 +56870,6 @@ var BABYLON;
             else {
                 var emitterPosition = subEmitter.particleSystem.emitter;
                 emitterPosition.copyFrom(particle.position);
-                if (subEmitter.inheritDirection) {
-                    BABYLON.Tools.Warn("subEmitter.inheritDirection is not supported with non-mesh emitter type");
-                }
             }
             // Set inheritedVelocityOffset to be used when new particles are created
             particle.direction.scaleToRef(subEmitter.inheritedVelocityAmount / 2, BABYLON.Tmp.Vector3[0]);
@@ -57380,6 +57405,11 @@ var BABYLON;
                     else if (subEmitter instanceof Array) {
                         _this._subEmitters.push(subEmitter);
                     }
+                    _this._subEmitters[_this._subEmitters.length - 1].forEach(function (se) {
+                        if (!(se.particleSystem.emitter instanceof BABYLON.AbstractMesh) && se.inheritDirection) {
+                            BABYLON.Tools.Warn("subEmitter.inheritDirection is not supported with non-mesh emitter type");
+                        }
+                    });
                 });
             }
             this._started = true;
@@ -57977,8 +58007,8 @@ var BABYLON;
                 this._rampGradientsTexture = null;
             }
             this._removeFromRoot();
-            if (this._disposeEmitterOnDispose && !this.emitter.isDisposed) {
-                this.emitter.dispose();
+            if (this._disposeEmitterOnDispose && this.emitter && this.emitter.dispose) {
+                this.emitter.dispose(true);
             }
             // Remove from scene
             var index = this._scene.particleSystems.indexOf(this);
@@ -61816,12 +61846,13 @@ var BABYLON;
             this.scene._beforeEvaluateActiveMeshStage.registerStep(BABYLON.SceneComponentConstants.STEP_BEFOREEVALUATEACTIVEMESH_BOUNDINGBOXRENDERER, this, this.reset);
             this.scene._activeMeshStage.registerStep(BABYLON.SceneComponentConstants.STEP_ACTIVEMESH_BOUNDINGBOXRENDERER, this, this._activeMesh);
             this.scene._evaluateSubMeshStage.registerStep(BABYLON.SceneComponentConstants.STEP_EVALUATESUBMESH_BOUNDINGBOXRENDERER, this, this._evaluateSubMesh);
-            this.scene._afterCameraDrawStage.registerStep(BABYLON.SceneComponentConstants.STEP_AFTERCAMERADRAW_BOUNDINGBOXRENDERER, this, this.render);
+            this.scene._afterRenderingGroupDrawStage.registerStep(BABYLON.SceneComponentConstants.STEP_AFTERCAMERADRAW_BOUNDINGBOXRENDERER, this, this.render);
         };
         BoundingBoxRenderer.prototype._evaluateSubMesh = function (mesh, subMesh) {
             if (mesh.showSubMeshesBoundingBox) {
                 var boundingInfo = subMesh.getBoundingInfo();
                 if (boundingInfo !== null && boundingInfo !== undefined) {
+                    boundingInfo.boundingBox._tag = mesh.renderingGroupId;
                     this.renderList.push(boundingInfo.boundingBox);
                 }
             }
@@ -61829,6 +61860,7 @@ var BABYLON;
         BoundingBoxRenderer.prototype._activeMesh = function (sourceMesh, mesh) {
             if (sourceMesh.showBoundingBox || this.scene.forceShowBoundingBoxes) {
                 var boundingInfo = sourceMesh.getBoundingInfo();
+                boundingInfo.boundingBox._tag = mesh.renderingGroupId;
                 this.renderList.push(boundingInfo.boundingBox);
             }
         };
@@ -61863,7 +61895,7 @@ var BABYLON;
         BoundingBoxRenderer.prototype.reset = function () {
             this.renderList.reset();
         };
-        BoundingBoxRenderer.prototype.render = function () {
+        BoundingBoxRenderer.prototype.render = function (renderingGroupId) {
             if (this.renderList.length === 0) {
                 return;
             }
@@ -61876,6 +61908,9 @@ var BABYLON;
             this._colorShader._preBind();
             for (var boundingBoxIndex = 0; boundingBoxIndex < this.renderList.length; boundingBoxIndex++) {
                 var boundingBox = this.renderList.data[boundingBoxIndex];
+                if (boundingBox._tag !== renderingGroupId) {
+                    continue;
+                }
                 var min = boundingBox.minimum;
                 var max = boundingBox.maximum;
                 var diff = max.subtract(min);
@@ -65283,6 +65318,7 @@ var BABYLON;
          * * The parameter `maxHeight` (float, default 1) is the maximum altitude on the ground.
          * * The parameter `colorFilter` (optional Color3, default (0.3, 0.59, 0.11) ) is the filter to apply to the image pixel colors to compute the height.
          * * The parameter `onReady` is a javascript callback function that will be called  once the mesh is just built (the height map download can last some time).
+         * * The parameter `alphaFilter` will filter any data where the alpha channel is below this value, defaults 0 (all data visible)
          * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.
          * @param name defines the name of the mesh
          * @param url defines the url to the height map
@@ -65299,6 +65335,7 @@ var BABYLON;
             var minHeight = options.minHeight || 0.0;
             var maxHeight = options.maxHeight || 1.0;
             var filter = options.colorFilter || new BABYLON.Color3(0.3, 0.59, 0.11);
+            var alphaFilter = options.alphaFilter || 0.0;
             var updatable = options.updatable;
             var onReady = options.onReady;
             var ground = new BABYLON.GroundMesh(name, scene);
@@ -65333,7 +65370,8 @@ var BABYLON;
                     width: width, height: height,
                     subdivisions: subdivisions,
                     minHeight: minHeight, maxHeight: maxHeight, colorFilter: filter,
-                    buffer: buffer, bufferWidth: bufferWidth, bufferHeight: bufferHeight
+                    buffer: buffer, bufferWidth: bufferWidth, bufferHeight: bufferHeight,
+                    alphaFilter: alphaFilter
                 });
                 vertexData.applyToMesh(ground, updatable);
                 //execute ready callback, if set
@@ -71942,9 +71980,6 @@ var BABYLON;
             return SceneLoader._getDefaultPlugin();
         };
         SceneLoader._getPluginForFilename = function (sceneFilename) {
-            if (sceneFilename.name) {
-                sceneFilename = sceneFilename.name;
-            }
             var queryStringPosition = sceneFilename.indexOf("?");
             if (queryStringPosition !== -1) {
                 sceneFilename = sceneFilename.substring(0, queryStringPosition);
@@ -71955,14 +71990,14 @@ var BABYLON;
         };
         // use babylon file loader directly if sceneFilename is prefixed with "data:"
         SceneLoader._getDirectLoad = function (sceneFilename) {
-            if (sceneFilename.substr && sceneFilename.substr(0, 5) === "data:") {
+            if (sceneFilename.substr(0, 5) === "data:") {
                 return sceneFilename.substr(5);
             }
             return null;
         };
-        SceneLoader._loadData = function (rootUrl, sceneFilename, scene, onSuccess, onProgress, onError, onDispose, pluginExtension) {
-            var directLoad = SceneLoader._getDirectLoad(sceneFilename);
-            var registeredPlugin = pluginExtension ? SceneLoader._getPluginForExtension(pluginExtension) : (directLoad ? SceneLoader._getPluginForDirectLoad(sceneFilename) : SceneLoader._getPluginForFilename(sceneFilename));
+        SceneLoader._loadData = function (fileInfo, scene, onSuccess, onProgress, onError, onDispose, pluginExtension) {
+            var directLoad = SceneLoader._getDirectLoad(fileInfo.name);
+            var registeredPlugin = pluginExtension ? SceneLoader._getPluginForExtension(pluginExtension) : (directLoad ? SceneLoader._getPluginForDirectLoad(fileInfo.name) : SceneLoader._getPluginForFilename(fileInfo.name));
             var plugin;
             if (registeredPlugin.plugin.createPlugin) {
                 plugin = registeredPlugin.plugin.createPlugin();
@@ -71998,8 +72033,7 @@ var BABYLON;
                 if (pluginDisposed) {
                     return;
                 }
-                var url = rootUrl + sceneFilename;
-                request = BABYLON.Tools.LoadFile(url, dataCallback, onProgress ? function (event) {
+                request = BABYLON.Tools.LoadFile(fileInfo.url, dataCallback, onProgress ? function (event) {
                     onProgress(SceneLoaderProgressEvent.FromProgressEvent(event));
                 } : undefined, database, useArrayBuffer, function (request, exception) {
                     onError("Failed to load scene." + (exception ? "" : " " + exception.message), exception);
@@ -72009,7 +72043,7 @@ var BABYLON;
                 dataCallback(directLoad);
                 return plugin;
             }
-            if (rootUrl.indexOf("file:") === -1) {
+            if (fileInfo.rootUrl.indexOf("file:") === -1) {
                 var engine = scene.getEngine();
                 var canUseOfflineSupport = engine.enableOfflineSupport;
                 if (canUseOfflineSupport) {
@@ -72017,7 +72051,7 @@ var BABYLON;
                     var exceptionFound = false;
                     for (var _i = 0, _a = scene.disableOfflineSupportExceptionRules; _i < _a.length; _i++) {
                         var regex = _a[_i];
-                        if (regex.test(rootUrl + sceneFilename)) {
+                        if (regex.test(fileInfo.url)) {
                             exceptionFound = true;
                             break;
                         }
@@ -72026,7 +72060,7 @@ var BABYLON;
                 }
                 if (canUseOfflineSupport) {
                     // Checking if a manifest file has been set for this scene and if offline mode has been requested
-                    database = new BABYLON.Database(rootUrl + sceneFilename, manifestChecked, engine.disableManifestCheck);
+                    database = new BABYLON.Database(fileInfo.url, manifestChecked, engine.disableManifestCheck);
                 }
                 else {
                     manifestChecked();
@@ -72034,19 +72068,39 @@ var BABYLON;
             }
             // Loading file from disk via input file or drag'n'drop
             else {
-                var fileOrString = sceneFilename;
-                if (fileOrString.name) { // File
-                    request = BABYLON.Tools.ReadFile(fileOrString, dataCallback, onProgress, useArrayBuffer);
-                }
-                else if (BABYLON.FilesInput.FilesToLoad[sceneFilename]) {
-                    request = BABYLON.Tools.ReadFile(BABYLON.FilesInput.FilesToLoad[sceneFilename], dataCallback, onProgress, useArrayBuffer);
+                var file = BABYLON.FilesInput.FilesToLoad[fileInfo.name.toLowerCase()];
+                if (file) {
+                    request = BABYLON.Tools.ReadFile(file, dataCallback, onProgress, useArrayBuffer);
                 }
                 else {
-                    onError("Unable to find file named " + sceneFilename);
+                    onError("Unable to find file named " + fileInfo.name);
                 }
             }
             return plugin;
         };
+        SceneLoader._getFileInfo = function (rootUrl, sceneFilename) {
+            var url;
+            var name;
+            if (!sceneFilename) {
+                url = rootUrl;
+                name = BABYLON.Tools.GetFilename(rootUrl);
+                rootUrl = BABYLON.Tools.GetFolderPath(rootUrl);
+            }
+            else {
+                if (sceneFilename.substr(0, 1) === "/") {
+                    BABYLON.Tools.Error("Wrong sceneFilename parameter");
+                    return null;
+                }
+                url = rootUrl + sceneFilename;
+                name = sceneFilename;
+            }
+            ;
+            return {
+                url: url,
+                rootUrl: rootUrl,
+                name: name
+            };
+        };
         // Public functions
         SceneLoader.GetPluginForExtension = function (extension) {
             return SceneLoader._getPluginForExtension(extension).plugin;
@@ -72075,8 +72129,8 @@ var BABYLON;
         /**
          * Import meshes into a scene
          * @param meshNames an array of mesh names, a single mesh name, or empty string for all meshes that filter what meshes are imported
-         * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-         * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
          * @param scene the instance of BABYLON.Scene to append to
          * @param onSuccess a callback with a list of imported meshes, particleSystems, and skeletons when import succeeds
          * @param onProgress a callback with a progress event for each file being loaded
@@ -72095,12 +72149,8 @@ var BABYLON;
                 BABYLON.Tools.Error("No scene available to import mesh to");
                 return null;
             }
-            if (!sceneFilename) {
-                sceneFilename = BABYLON.Tools.GetFilename(rootUrl);
-                rootUrl = BABYLON.Tools.GetFolderPath(rootUrl);
-            }
-            if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
-                BABYLON.Tools.Error("Wrong sceneFilename parameter");
+            var fileInfo = SceneLoader._getFileInfo(rootUrl, sceneFilename);
+            if (!fileInfo) {
                 return null;
             }
             var loadingToken = {};
@@ -72109,7 +72159,7 @@ var BABYLON;
                 scene._removePendingData(loadingToken);
             };
             var errorHandler = function (message, exception) {
-                var errorMessage = "Unable to import meshes from " + rootUrl + sceneFilename + ": " + message;
+                var errorMessage = "Unable to import meshes from " + fileInfo.url + ": " + message;
                 if (onError) {
                     onError(scene, errorMessage, exception);
                 }
@@ -72128,7 +72178,7 @@ var BABYLON;
                 }
             } : undefined;
             var successHandler = function (meshes, particleSystems, skeletons, animationGroups) {
-                scene.importedMeshesFiles.push(rootUrl + sceneFilename);
+                scene.importedMeshesFiles.push(fileInfo.url);
                 if (onSuccess) {
                     try {
                         onSuccess(meshes, particleSystems, skeletons, animationGroups);
@@ -72139,21 +72189,16 @@ var BABYLON;
                 }
                 scene._removePendingData(loadingToken);
             };
-            return SceneLoader._loadData(rootUrl, sceneFilename, scene, function (plugin, data, responseURL) {
+            return SceneLoader._loadData(fileInfo, scene, function (plugin, data, responseURL) {
                 if (plugin.rewriteRootURL) {
-                    rootUrl = plugin.rewriteRootURL(rootUrl, responseURL);
-                }
-                if (sceneFilename === "") {
-                    if (sceneFilename === "") {
-                        rootUrl = BABYLON.Tools.GetFolderPath(rootUrl, true);
-                    }
+                    fileInfo.rootUrl = plugin.rewriteRootURL(fileInfo.rootUrl, responseURL);
                 }
                 if (plugin.importMesh) {
                     var syncedPlugin = plugin;
                     var meshes = new Array();
                     var particleSystems = new Array();
                     var skeletons = new Array();
-                    if (!syncedPlugin.importMesh(meshNames, scene, data, rootUrl, meshes, particleSystems, skeletons, errorHandler)) {
+                    if (!syncedPlugin.importMesh(meshNames, scene, data, fileInfo.rootUrl, meshes, particleSystems, skeletons, errorHandler)) {
                         return;
                     }
                     scene.loadingPluginName = plugin.name;
@@ -72161,7 +72206,7 @@ var BABYLON;
                 }
                 else {
                     var asyncedPlugin = plugin;
-                    asyncedPlugin.importMeshAsync(meshNames, scene, data, rootUrl, progressHandler, rootUrl + sceneFilename).then(function (result) {
+                    asyncedPlugin.importMeshAsync(meshNames, scene, data, fileInfo.rootUrl, progressHandler, fileInfo.name).then(function (result) {
                         scene.loadingPluginName = plugin.name;
                         successHandler(result.meshes, result.particleSystems, result.skeletons, result.animationGroups);
                     }).catch(function (error) {
@@ -72171,15 +72216,15 @@ var BABYLON;
             }, progressHandler, errorHandler, disposeHandler, pluginExtension);
         };
         /**
-        * Import meshes into a scene
-        * @param meshNames an array of mesh names, a single mesh name, or empty string for all meshes that filter what meshes are imported
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param scene the instance of BABYLON.Scene to append to
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The loaded list of imported meshes, particle systems, skeletons, and animation groups
-        */
+         * Import meshes into a scene
+         * @param meshNames an array of mesh names, a single mesh name, or empty string for all meshes that filter what meshes are imported
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param scene the instance of BABYLON.Scene to append to
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The loaded list of imported meshes, particle systems, skeletons, and animation groups
+         */
         SceneLoader.ImportMeshAsync = function (meshNames, rootUrl, sceneFilename, scene, onProgress, pluginExtension) {
             if (sceneFilename === void 0) { sceneFilename = ""; }
             if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
@@ -72199,16 +72244,16 @@ var BABYLON;
             });
         };
         /**
-        * Load a scene
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param engine is the instance of BABYLON.Engine to use to create the scene
-        * @param onSuccess a callback with the scene when import succeeds
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param onError a callback with the scene, a message, and possibly an exception when import fails
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The loaded plugin
-        */
+         * Load a scene
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param engine is the instance of BABYLON.Engine to use to create the scene
+         * @param onSuccess a callback with the scene when import succeeds
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param onError a callback with the scene, a message, and possibly an exception when import fails
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The loaded plugin
+         */
         SceneLoader.Load = function (rootUrl, sceneFilename, engine, onSuccess, onProgress, onError, pluginExtension) {
             if (onSuccess === void 0) { onSuccess = null; }
             if (onProgress === void 0) { onProgress = null; }
@@ -72217,14 +72262,14 @@ var BABYLON;
             return SceneLoader.Append(rootUrl, sceneFilename, new BABYLON.Scene(engine), onSuccess, onProgress, onError, pluginExtension);
         };
         /**
-        * Load a scene
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param engine is the instance of BABYLON.Engine to use to create the scene
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The loaded scene
-        */
+         * Load a scene
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param engine is the instance of BABYLON.Engine to use to create the scene
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The loaded scene
+         */
         SceneLoader.LoadAsync = function (rootUrl, sceneFilename, engine, onProgress, pluginExtension) {
             if (onProgress === void 0) { onProgress = null; }
             if (pluginExtension === void 0) { pluginExtension = null; }
@@ -72237,16 +72282,16 @@ var BABYLON;
             });
         };
         /**
-        * Append a scene
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param scene is the instance of BABYLON.Scene to append to
-        * @param onSuccess a callback with the scene when import succeeds
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param onError a callback with the scene, a message, and possibly an exception when import fails
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The loaded plugin
-        */
+         * Append a scene
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param scene is the instance of BABYLON.Scene to append to
+         * @param onSuccess a callback with the scene when import succeeds
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param onError a callback with the scene, a message, and possibly an exception when import fails
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The loaded plugin
+         */
         SceneLoader.Append = function (rootUrl, sceneFilename, scene, onSuccess, onProgress, onError, pluginExtension) {
             if (sceneFilename === void 0) { sceneFilename = ""; }
             if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
@@ -72258,12 +72303,8 @@ var BABYLON;
                 BABYLON.Tools.Error("No scene available to append to");
                 return null;
             }
-            if (!sceneFilename) {
-                sceneFilename = BABYLON.Tools.GetFilename(rootUrl);
-                rootUrl = BABYLON.Tools.GetFolderPath(rootUrl);
-            }
-            if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
-                BABYLON.Tools.Error("Wrong sceneFilename parameter");
+            var fileInfo = SceneLoader._getFileInfo(rootUrl, sceneFilename);
+            if (!fileInfo) {
                 return null;
             }
             if (SceneLoader.ShowLoadingScreen) {
@@ -72276,7 +72317,7 @@ var BABYLON;
                 scene.getEngine().hideLoadingUI();
             };
             var errorHandler = function (message, exception) {
-                var errorMessage = "Unable to load from " + rootUrl + sceneFilename + (message ? ": " + message : "");
+                var errorMessage = "Unable to load from " + fileInfo.url + (message ? ": " + message : "");
                 if (onError) {
                     onError(scene, errorMessage, exception);
                 }
@@ -72305,13 +72346,10 @@ var BABYLON;
                 }
                 scene._removePendingData(loadingToken);
             };
-            return SceneLoader._loadData(rootUrl, sceneFilename, scene, function (plugin, data, responseURL) {
-                if (sceneFilename === "") {
-                    rootUrl = BABYLON.Tools.GetFolderPath(rootUrl, true);
-                }
+            return SceneLoader._loadData(fileInfo, scene, function (plugin, data, responseURL) {
                 if (plugin.load) {
                     var syncedPlugin = plugin;
-                    if (!syncedPlugin.load(scene, data, rootUrl, errorHandler)) {
+                    if (!syncedPlugin.load(scene, data, fileInfo.rootUrl, errorHandler)) {
                         return;
                     }
                     scene.loadingPluginName = plugin.name;
@@ -72319,7 +72357,7 @@ var BABYLON;
                 }
                 else {
                     var asyncedPlugin = plugin;
-                    asyncedPlugin.loadAsync(scene, data, rootUrl, progressHandler, rootUrl + sceneFilename).then(function () {
+                    asyncedPlugin.loadAsync(scene, data, fileInfo.rootUrl, progressHandler, fileInfo.name).then(function () {
                         scene.loadingPluginName = plugin.name;
                         successHandler();
                     }).catch(function (error) {
@@ -72334,14 +72372,14 @@ var BABYLON;
             }, progressHandler, errorHandler, disposeHandler, pluginExtension);
         };
         /**
-        * Append a scene
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param scene is the instance of BABYLON.Scene to append to
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The given scene
-        */
+         * Append a scene
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param scene is the instance of BABYLON.Scene to append to
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The given scene
+         */
         SceneLoader.AppendAsync = function (rootUrl, sceneFilename, scene, onProgress, pluginExtension) {
             if (sceneFilename === void 0) { sceneFilename = ""; }
             if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
@@ -72356,16 +72394,16 @@ var BABYLON;
             });
         };
         /**
-        * Load a scene into an asset container
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param scene is the instance of BABYLON.Scene to append to (default: last created scene)
-        * @param onSuccess a callback with the scene when import succeeds
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param onError a callback with the scene, a message, and possibly an exception when import fails
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The loaded plugin
-        */
+         * Load a scene into an asset container
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param scene is the instance of BABYLON.Scene to append to (default: last created scene)
+         * @param onSuccess a callback with the scene when import succeeds
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param onError a callback with the scene, a message, and possibly an exception when import fails
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The loaded plugin
+         */
         SceneLoader.LoadAssetContainer = function (rootUrl, sceneFilename, scene, onSuccess, onProgress, onError, pluginExtension) {
             if (sceneFilename === void 0) { sceneFilename = ""; }
             if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
@@ -72377,12 +72415,8 @@ var BABYLON;
                 BABYLON.Tools.Error("No scene available to load asset container to");
                 return null;
             }
-            if (!sceneFilename) {
-                sceneFilename = BABYLON.Tools.GetFilename(rootUrl);
-                rootUrl = BABYLON.Tools.GetFolderPath(rootUrl);
-            }
-            if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
-                BABYLON.Tools.Error("Wrong sceneFilename parameter");
+            var fileInfo = SceneLoader._getFileInfo(rootUrl, sceneFilename);
+            if (!fileInfo) {
                 return null;
             }
             var loadingToken = {};
@@ -72391,7 +72425,7 @@ var BABYLON;
                 scene._removePendingData(loadingToken);
             };
             var errorHandler = function (message, exception) {
-                var errorMessage = "Unable to load assets from " + rootUrl + sceneFilename + (message ? ": " + message : "");
+                var errorMessage = "Unable to load assets from " + fileInfo.url + (message ? ": " + message : "");
                 if (onError) {
                     onError(scene, errorMessage, exception);
                 }
@@ -72420,10 +72454,10 @@ var BABYLON;
                 }
                 scene._removePendingData(loadingToken);
             };
-            return SceneLoader._loadData(rootUrl, sceneFilename, scene, function (plugin, data, responseURL) {
+            return SceneLoader._loadData(fileInfo, scene, function (plugin, data, responseURL) {
                 if (plugin.loadAssetContainer) {
                     var syncedPlugin = plugin;
-                    var assetContainer = syncedPlugin.loadAssetContainer(scene, data, rootUrl, errorHandler);
+                    var assetContainer = syncedPlugin.loadAssetContainer(scene, data, fileInfo.rootUrl, errorHandler);
                     if (!assetContainer) {
                         return;
                     }
@@ -72432,7 +72466,7 @@ var BABYLON;
                 }
                 else if (plugin.loadAssetContainerAsync) {
                     var asyncedPlugin = plugin;
-                    asyncedPlugin.loadAssetContainerAsync(scene, data, rootUrl, progressHandler, rootUrl + sceneFilename).then(function (assetContainer) {
+                    asyncedPlugin.loadAssetContainerAsync(scene, data, fileInfo.rootUrl, progressHandler, fileInfo.name).then(function (assetContainer) {
                         scene.loadingPluginName = plugin.name;
                         successHandler(assetContainer);
                     }).catch(function (error) {
@@ -72450,14 +72484,14 @@ var BABYLON;
             }, progressHandler, errorHandler, disposeHandler, pluginExtension);
         };
         /**
-        * Load a scene into an asset container
-        * @param rootUrl a string that defines the root url for scene and resources OR the concatenation of rootURL and filename (eg. http://example.com/test.glb)
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene (default: empty string)
-        * @param scene is the instance of BABYLON.Scene to append to
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param pluginExtension the extension used to determine the plugin
-        * @returns The loaded asset container
-        */
+         * Load a scene into an asset container
+         * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
+         * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
+         * @param scene is the instance of BABYLON.Scene to append to
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The loaded asset container
+         */
         SceneLoader.LoadAssetContainerAsync = function (rootUrl, sceneFilename, scene, onProgress, pluginExtension) {
             if (sceneFilename === void 0) { sceneFilename = ""; }
             if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
@@ -73247,9 +73281,7 @@ var BABYLON;
                     && name.indexOf(".binary.babylon") === -1 && name.indexOf(".incremental.babylon") === -1) {
                     this._sceneFileToLoad = files[i];
                 }
-                else {
-                    FilesInput.FilesToLoad[name] = files[i];
-                }
+                FilesInput.FilesToLoad[name] = files[i];
             }
         };
         FilesInput.prototype.loadFiles = function (event) {
@@ -73334,7 +73366,7 @@ var BABYLON;
                     }
                     this._engine.stopRenderLoop();
                 }
-                BABYLON.SceneLoader.LoadAsync("file:", this._sceneFileToLoad, this._engine, function (progress) {
+                BABYLON.SceneLoader.LoadAsync("file:", this._sceneFileToLoad.name, this._engine, function (progress) {
                     if (_this._progressCallback) {
                         _this._progressCallback(progress);
                     }
@@ -107606,10 +107638,14 @@ var BABYLON;
             this._onBeforeParticlesRenderingObserver = null;
             this.scene.onAfterParticlesRenderingObservable.remove(this._onAfterParticlesRenderingObserver);
             this._onAfterParticlesRenderingObserver = null;
-            this.scene.onBeforeSpritesRenderingObservable.remove(this._onBeforeSpritesRenderingObserver);
-            this._onBeforeSpritesRenderingObserver = null;
-            this.scene.onAfterSpritesRenderingObservable.remove(this._onAfterSpritesRenderingObserver);
-            this._onAfterSpritesRenderingObserver = null;
+            if (this._onBeforeSpritesRenderingObserver) {
+                this.scene.onBeforeSpritesRenderingObservable.remove(this._onBeforeSpritesRenderingObserver);
+                this._onBeforeSpritesRenderingObserver = null;
+            }
+            if (this._onAfterSpritesRenderingObserver) {
+                this.scene.onAfterSpritesRenderingObservable.remove(this._onAfterSpritesRenderingObserver);
+                this._onAfterSpritesRenderingObserver = null;
+            }
             this.scene.onBeforeDrawPhaseObservable.remove(this._onBeforeDrawPhaseObserver);
             this._onBeforeDrawPhaseObserver = null;
             this.scene.onAfterDrawPhaseObservable.remove(this._onAfterDrawPhaseObserver);

+ 8 - 8
dist/preview release/loaders/babylon.glTF1FileLoader.d.ts

@@ -76,13 +76,13 @@ declare module BABYLON {
     /** @hidden */
     interface IGLTFLoader extends IDisposable {
         readonly state: Nullable<GLTFLoaderState>;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<{
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string) => Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<void>;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string) => Promise<void>;
     }
     /**
      * File loader for loading glTF files into a scene.
@@ -262,10 +262,10 @@ declare module BABYLON {
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
@@ -277,20 +277,20 @@ declare module BABYLON {
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<void>;
         /**
          * 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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns The loaded asset container
          */
-        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<AssetContainer>;
+        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<AssetContainer>;
         /**
          * If the data string can be loaded directly.
          * @param data string contianing the file data

+ 12 - 9
dist/preview release/loaders/babylon.glTF1FileLoader.js

@@ -372,15 +372,16 @@ var BABYLON;
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fullName) {
+        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fileName) {
             var _this = this;
             return Promise.resolve().then(function () {
+                _this._log("Loading " + (fileName || ""));
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onProgress, fullName);
+                return _this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onProgress, fileName);
             });
         };
         /**
@@ -389,15 +390,16 @@ var BABYLON;
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fullName) {
+        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fileName) {
             var _this = this;
             return Promise.resolve().then(function () {
+                _this._log("Loading " + (fileName || ""));
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.loadAsync(scene, loaderData, rootUrl, onProgress, fullName);
+                return _this._loader.loadAsync(scene, loaderData, rootUrl, onProgress, fileName);
             });
         };
         /**
@@ -406,15 +408,16 @@ var BABYLON;
          * @param data The data to import
          * @param rootUrl The root url for scene and resources
          * @param onProgress The callback when the load progresses
-         * @param fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns The loaded asset container
          */
-        GLTFFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress, fullName) {
+        GLTFFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress, fileName) {
             var _this = this;
             return Promise.resolve().then(function () {
+                _this._log("Loading " + (fileName || ""));
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.importMeshAsync(null, scene, loaderData, rootUrl, onProgress, fullName).then(function (result) {
+                return _this._loader.importMeshAsync(null, scene, loaderData, rootUrl, onProgress, fileName).then(function (result) {
                     var container = new BABYLON.AssetContainer(scene);
                     Array.prototype.push.apply(container.meshes, result.meshes);
                     Array.prototype.push.apply(container.particleSystems, result.particleSystems);

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


+ 12 - 11
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -76,13 +76,13 @@ declare module BABYLON {
     /** @hidden */
     interface IGLTFLoader extends IDisposable {
         readonly state: Nullable<GLTFLoaderState>;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<{
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string) => Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<void>;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string) => Promise<void>;
     }
     /**
      * File loader for loading glTF files into a scene.
@@ -262,10 +262,10 @@ declare module BABYLON {
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
@@ -277,20 +277,20 @@ declare module BABYLON {
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<void>;
         /**
          * 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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns The loaded asset container
          */
-        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<AssetContainer>;
+        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<AssetContainer>;
         /**
          * If the data string can be loaded directly.
          * @param data string contianing the file data
@@ -571,7 +571,8 @@ declare module BABYLON.GLTF2 {
         private _state;
         private _extensions;
         private _rootUrl;
-        private _fullName;
+        private _fileName;
+        private _uniqueRootUrl;
         private _rootBabylonMesh;
         private _defaultBabylonMaterialData;
         private _progressCallback?;
@@ -600,14 +601,14 @@ declare module BABYLON.GLTF2 {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
         /** @hidden */
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<void>;
         private _loadAsync;
         private _loadData;
         private _setupData;

+ 19 - 14
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -372,15 +372,16 @@ var BABYLON;
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fullName) {
+        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fileName) {
             var _this = this;
             return Promise.resolve().then(function () {
+                _this._log("Loading " + (fileName || ""));
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onProgress, fullName);
+                return _this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onProgress, fileName);
             });
         };
         /**
@@ -389,15 +390,16 @@ var BABYLON;
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fullName) {
+        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fileName) {
             var _this = this;
             return Promise.resolve().then(function () {
+                _this._log("Loading " + (fileName || ""));
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.loadAsync(scene, loaderData, rootUrl, onProgress, fullName);
+                return _this._loader.loadAsync(scene, loaderData, rootUrl, onProgress, fileName);
             });
         };
         /**
@@ -406,15 +408,16 @@ var BABYLON;
          * @param data The data to import
          * @param rootUrl The root url for scene and resources
          * @param onProgress The callback when the load progresses
-         * @param fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns The loaded asset container
          */
-        GLTFFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress, fullName) {
+        GLTFFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress, fileName) {
             var _this = this;
             return Promise.resolve().then(function () {
+                _this._log("Loading " + (fileName || ""));
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.importMeshAsync(null, scene, loaderData, rootUrl, onProgress, fullName).then(function (result) {
+                return _this._loader.importMeshAsync(null, scene, loaderData, rootUrl, onProgress, fileName).then(function (result) {
                     var container = new BABYLON.AssetContainer(scene);
                     Array.prototype.push.apply(container.meshes, result.meshes);
                     Array.prototype.push.apply(container.particleSystems, result.particleSystems);
@@ -815,12 +818,12 @@ var BABYLON;
                 this._parent._clear();
             };
             /** @hidden */
-            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fullName) {
+            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fileName) {
                 var _this = this;
                 return Promise.resolve().then(function () {
                     _this.babylonScene = scene;
                     _this._rootUrl = rootUrl;
-                    _this._fullName = fullName || "" + Date.now();
+                    _this._fileName = fileName || "scene";
                     _this._progressCallback = onProgress;
                     _this._loadData(data);
                     var nodes = null;
@@ -854,12 +857,12 @@ var BABYLON;
                 });
             };
             /** @hidden */
-            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fullName) {
+            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fileName) {
                 var _this = this;
                 return Promise.resolve().then(function () {
                     _this.babylonScene = scene;
                     _this._rootUrl = rootUrl;
-                    _this._fullName = fullName || "" + Date.now();
+                    _this._fileName = fileName || "scene";
                     _this._progressCallback = onProgress;
                     _this._loadData(data);
                     return _this._loadAsync(null, function () { return undefined; });
@@ -868,6 +871,7 @@ var BABYLON;
             GLTFLoader.prototype._loadAsync = function (nodes, resultFunc) {
                 var _this = this;
                 return Promise.resolve().then(function () {
+                    _this._uniqueRootUrl = (_this._rootUrl.indexOf("file:") === -1 && _this._fileName) ? _this._rootUrl : "" + _this._rootUrl + Date.now() + "/";
                     _this._loadExtensions();
                     _this._checkExtensions();
                     var loadingToReadyCounterName = BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.LOADING] + " => " + BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.READY];
@@ -2118,7 +2122,8 @@ var BABYLON;
                 babylonTexture.wrapV = samplerData.wrapV;
                 var image = ArrayItem.Get(context + "/source", this.gltf.images, texture.source);
                 promises.push(this.loadImageAsync("#/images/" + image.index, image).then(function (data) {
-                    var dataUrl = "data:" + _this._fullName + (image.uri || "image" + image.index);
+                    var name = image.uri || _this._fileName + "#image" + image.index;
+                    var dataUrl = "data:" + _this._uniqueRootUrl + name;
                     babylonTexture.updateURL(dataUrl, new Blob([data], { type: image.mimeType }));
                 }));
                 assign(babylonTexture);

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 12 - 11
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -76,13 +76,13 @@ declare module BABYLON {
     /** @hidden */
     interface IGLTFLoader extends IDisposable {
         readonly state: Nullable<GLTFLoaderState>;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<{
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string) => Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<void>;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string) => Promise<void>;
     }
     /**
      * File loader for loading glTF files into a scene.
@@ -262,10 +262,10 @@ declare module BABYLON {
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
@@ -277,20 +277,20 @@ declare module BABYLON {
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<void>;
         /**
          * 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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns The loaded asset container
          */
-        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<AssetContainer>;
+        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<AssetContainer>;
         /**
          * If the data string can be loaded directly.
          * @param data string contianing the file data
@@ -1133,7 +1133,8 @@ declare module BABYLON.GLTF2 {
         private _state;
         private _extensions;
         private _rootUrl;
-        private _fullName;
+        private _fileName;
+        private _uniqueRootUrl;
         private _rootBabylonMesh;
         private _defaultBabylonMaterialData;
         private _progressCallback?;
@@ -1162,14 +1163,14 @@ declare module BABYLON.GLTF2 {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
         /** @hidden */
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<void>;
         private _loadAsync;
         private _loadData;
         private _setupData;

+ 19 - 14
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -372,15 +372,16 @@ var BABYLON;
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fullName) {
+        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fileName) {
             var _this = this;
             return Promise.resolve().then(function () {
+                _this._log("Loading " + (fileName || ""));
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onProgress, fullName);
+                return _this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onProgress, fileName);
             });
         };
         /**
@@ -389,15 +390,16 @@ var BABYLON;
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fullName) {
+        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fileName) {
             var _this = this;
             return Promise.resolve().then(function () {
+                _this._log("Loading " + (fileName || ""));
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.loadAsync(scene, loaderData, rootUrl, onProgress, fullName);
+                return _this._loader.loadAsync(scene, loaderData, rootUrl, onProgress, fileName);
             });
         };
         /**
@@ -406,15 +408,16 @@ var BABYLON;
          * @param data The data to import
          * @param rootUrl The root url for scene and resources
          * @param onProgress The callback when the load progresses
-         * @param fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns The loaded asset container
          */
-        GLTFFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress, fullName) {
+        GLTFFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress, fileName) {
             var _this = this;
             return Promise.resolve().then(function () {
+                _this._log("Loading " + (fileName || ""));
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.importMeshAsync(null, scene, loaderData, rootUrl, onProgress, fullName).then(function (result) {
+                return _this._loader.importMeshAsync(null, scene, loaderData, rootUrl, onProgress, fileName).then(function (result) {
                     var container = new BABYLON.AssetContainer(scene);
                     Array.prototype.push.apply(container.meshes, result.meshes);
                     Array.prototype.push.apply(container.particleSystems, result.particleSystems);
@@ -3022,12 +3025,12 @@ var BABYLON;
                 this._parent._clear();
             };
             /** @hidden */
-            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fullName) {
+            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fileName) {
                 var _this = this;
                 return Promise.resolve().then(function () {
                     _this.babylonScene = scene;
                     _this._rootUrl = rootUrl;
-                    _this._fullName = fullName || "" + Date.now();
+                    _this._fileName = fileName || "scene";
                     _this._progressCallback = onProgress;
                     _this._loadData(data);
                     var nodes = null;
@@ -3061,12 +3064,12 @@ var BABYLON;
                 });
             };
             /** @hidden */
-            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fullName) {
+            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fileName) {
                 var _this = this;
                 return Promise.resolve().then(function () {
                     _this.babylonScene = scene;
                     _this._rootUrl = rootUrl;
-                    _this._fullName = fullName || "" + Date.now();
+                    _this._fileName = fileName || "scene";
                     _this._progressCallback = onProgress;
                     _this._loadData(data);
                     return _this._loadAsync(null, function () { return undefined; });
@@ -3075,6 +3078,7 @@ var BABYLON;
             GLTFLoader.prototype._loadAsync = function (nodes, resultFunc) {
                 var _this = this;
                 return Promise.resolve().then(function () {
+                    _this._uniqueRootUrl = (_this._rootUrl.indexOf("file:") === -1 && _this._fileName) ? _this._rootUrl : "" + _this._rootUrl + Date.now() + "/";
                     _this._loadExtensions();
                     _this._checkExtensions();
                     var loadingToReadyCounterName = BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.LOADING] + " => " + BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.READY];
@@ -4325,7 +4329,8 @@ var BABYLON;
                 babylonTexture.wrapV = samplerData.wrapV;
                 var image = ArrayItem.Get(context + "/source", this.gltf.images, texture.source);
                 promises.push(this.loadImageAsync("#/images/" + image.index, image).then(function (data) {
-                    var dataUrl = "data:" + _this._fullName + (image.uri || "image" + image.index);
+                    var name = image.uri || _this._fileName + "#image" + image.index;
+                    var dataUrl = "data:" + _this._uniqueRootUrl + name;
                     babylonTexture.updateURL(dataUrl, new Blob([data], { type: image.mimeType }));
                 }));
                 assign(babylonTexture);

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 6 - 6
dist/preview release/loaders/babylon.objFileLoader.d.ts

@@ -65,10 +65,10 @@ declare module BABYLON {
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
@@ -80,20 +80,20 @@ declare module BABYLON {
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        loadAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
+        loadAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<void>;
         /**
          * 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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns The loaded asset container
          */
-        loadAssetContainerAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<AssetContainer>;
+        loadAssetContainerAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<AssetContainer>;
         /**
          * Read the OBJ file and create an Array of meshes.
          * Each mesh contains all information given by the OBJ and the MTL file.

+ 6 - 6
dist/preview release/loaders/babylon.objFileLoader.js

@@ -258,10 +258,10 @@ var BABYLON;
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        OBJFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fullName) {
+        OBJFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fileName) {
             //get the meshes from OBJ file
             return this._parseSolid(meshesNames, scene, data, rootUrl).then(function (meshes) {
                 return {
@@ -278,10 +278,10 @@ var BABYLON;
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        OBJFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fullName) {
+        OBJFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fileName) {
             //Get the 3D model
             return this.importMeshAsync(null, scene, data, rootUrl, onProgress).then(function () {
                 // return void
@@ -293,10 +293,10 @@ var BABYLON;
          * @param data The data to import
          * @param rootUrl The root url for scene and resources
          * @param onProgress The callback when the load progresses
-         * @param fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns The loaded asset container
          */
-        OBJFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress, fullName) {
+        OBJFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress, fileName) {
             return this.importMeshAsync(null, scene, data, rootUrl).then(function (result) {
                 var container = new BABYLON.AssetContainer(scene);
                 result.meshes.forEach(function (mesh) { return container.meshes.push(mesh); });

+ 18 - 17
dist/preview release/loaders/babylonjs.loaders.d.ts

@@ -83,10 +83,10 @@ declare module BABYLON {
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
@@ -98,20 +98,20 @@ declare module BABYLON {
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        loadAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
+        loadAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<void>;
         /**
          * 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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns The loaded asset container
          */
-        loadAssetContainerAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<AssetContainer>;
+        loadAssetContainerAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<AssetContainer>;
         /**
          * Read the OBJ file and create an Array of meshes.
          * Each mesh contains all information given by the OBJ and the MTL file.
@@ -206,13 +206,13 @@ declare module BABYLON {
     /** @hidden */
     interface IGLTFLoader extends IDisposable {
         readonly state: Nullable<GLTFLoaderState>;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<{
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string) => Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<void>;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string) => Promise<void>;
     }
     /**
      * File loader for loading glTF files into a scene.
@@ -392,10 +392,10 @@ declare module BABYLON {
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
@@ -407,20 +407,20 @@ declare module BABYLON {
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<void>;
         /**
          * 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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns The loaded asset container
          */
-        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<AssetContainer>;
+        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<AssetContainer>;
         /**
          * If the data string can be loaded directly.
          * @param data string contianing the file data
@@ -1263,7 +1263,8 @@ declare module BABYLON.GLTF2 {
         private _state;
         private _extensions;
         private _rootUrl;
-        private _fullName;
+        private _fileName;
+        private _uniqueRootUrl;
         private _rootBabylonMesh;
         private _defaultBabylonMaterialData;
         private _progressCallback?;
@@ -1292,14 +1293,14 @@ declare module BABYLON.GLTF2 {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
         /** @hidden */
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<void>;
         private _loadAsync;
         private _loadData;
         private _setupData;

+ 25 - 20
dist/preview release/loaders/babylonjs.loaders.js

@@ -457,10 +457,10 @@ var BABYLON;
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        OBJFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fullName) {
+        OBJFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fileName) {
             //get the meshes from OBJ file
             return this._parseSolid(meshesNames, scene, data, rootUrl).then(function (meshes) {
                 return {
@@ -477,10 +477,10 @@ var BABYLON;
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        OBJFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fullName) {
+        OBJFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fileName) {
             //Get the 3D model
             return this.importMeshAsync(null, scene, data, rootUrl, onProgress).then(function () {
                 // return void
@@ -492,10 +492,10 @@ var BABYLON;
          * @param data The data to import
          * @param rootUrl The root url for scene and resources
          * @param onProgress The callback when the load progresses
-         * @param fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns The loaded asset container
          */
-        OBJFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress, fullName) {
+        OBJFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress, fileName) {
             return this.importMeshAsync(null, scene, data, rootUrl).then(function (result) {
                 var container = new BABYLON.AssetContainer(scene);
                 result.meshes.forEach(function (mesh) { return container.meshes.push(mesh); });
@@ -1455,15 +1455,16 @@ var BABYLON;
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fullName) {
+        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fileName) {
             var _this = this;
             return Promise.resolve().then(function () {
+                _this._log("Loading " + (fileName || ""));
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onProgress, fullName);
+                return _this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onProgress, fileName);
             });
         };
         /**
@@ -1472,15 +1473,16 @@ var BABYLON;
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fullName) {
+        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fileName) {
             var _this = this;
             return Promise.resolve().then(function () {
+                _this._log("Loading " + (fileName || ""));
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.loadAsync(scene, loaderData, rootUrl, onProgress, fullName);
+                return _this._loader.loadAsync(scene, loaderData, rootUrl, onProgress, fileName);
             });
         };
         /**
@@ -1489,15 +1491,16 @@ var BABYLON;
          * @param data The data to import
          * @param rootUrl The root url for scene and resources
          * @param onProgress The callback when the load progresses
-         * @param fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns The loaded asset container
          */
-        GLTFFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress, fullName) {
+        GLTFFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress, fileName) {
             var _this = this;
             return Promise.resolve().then(function () {
+                _this._log("Loading " + (fileName || ""));
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.importMeshAsync(null, scene, loaderData, rootUrl, onProgress, fullName).then(function (result) {
+                return _this._loader.importMeshAsync(null, scene, loaderData, rootUrl, onProgress, fileName).then(function (result) {
                     var container = new BABYLON.AssetContainer(scene);
                     Array.prototype.push.apply(container.meshes, result.meshes);
                     Array.prototype.push.apply(container.particleSystems, result.particleSystems);
@@ -4081,12 +4084,12 @@ var BABYLON;
                 this._parent._clear();
             };
             /** @hidden */
-            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fullName) {
+            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fileName) {
                 var _this = this;
                 return Promise.resolve().then(function () {
                     _this.babylonScene = scene;
                     _this._rootUrl = rootUrl;
-                    _this._fullName = fullName || "" + Date.now();
+                    _this._fileName = fileName || "scene";
                     _this._progressCallback = onProgress;
                     _this._loadData(data);
                     var nodes = null;
@@ -4120,12 +4123,12 @@ var BABYLON;
                 });
             };
             /** @hidden */
-            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fullName) {
+            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fileName) {
                 var _this = this;
                 return Promise.resolve().then(function () {
                     _this.babylonScene = scene;
                     _this._rootUrl = rootUrl;
-                    _this._fullName = fullName || "" + Date.now();
+                    _this._fileName = fileName || "scene";
                     _this._progressCallback = onProgress;
                     _this._loadData(data);
                     return _this._loadAsync(null, function () { return undefined; });
@@ -4134,6 +4137,7 @@ var BABYLON;
             GLTFLoader.prototype._loadAsync = function (nodes, resultFunc) {
                 var _this = this;
                 return Promise.resolve().then(function () {
+                    _this._uniqueRootUrl = (_this._rootUrl.indexOf("file:") === -1 && _this._fileName) ? _this._rootUrl : "" + _this._rootUrl + Date.now() + "/";
                     _this._loadExtensions();
                     _this._checkExtensions();
                     var loadingToReadyCounterName = BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.LOADING] + " => " + BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.READY];
@@ -5384,7 +5388,8 @@ var BABYLON;
                 babylonTexture.wrapV = samplerData.wrapV;
                 var image = ArrayItem.Get(context + "/source", this.gltf.images, texture.source);
                 promises.push(this.loadImageAsync("#/images/" + image.index, image).then(function (data) {
-                    var dataUrl = "data:" + _this._fullName + (image.uri || "image" + image.index);
+                    var name = image.uri || _this._fileName + "#image" + image.index;
+                    var dataUrl = "data:" + _this._uniqueRootUrl + name;
                     babylonTexture.updateURL(dataUrl, new Blob([data], { type: image.mimeType }));
                 }));
                 assign(babylonTexture);

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.min.js


+ 18 - 17
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -90,10 +90,10 @@ declare module BABYLON {
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
@@ -105,20 +105,20 @@ declare module BABYLON {
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        loadAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
+        loadAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<void>;
         /**
          * 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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns The loaded asset container
          */
-        loadAssetContainerAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<AssetContainer>;
+        loadAssetContainerAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<AssetContainer>;
         /**
          * Read the OBJ file and create an Array of meshes.
          * Each mesh contains all information given by the OBJ and the MTL file.
@@ -213,13 +213,13 @@ declare module BABYLON {
     /** @hidden */
     interface IGLTFLoader extends IDisposable {
         readonly state: Nullable<GLTFLoaderState>;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<{
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string) => Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<void>;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string) => Promise<void>;
     }
     /**
      * File loader for loading glTF files into a scene.
@@ -399,10 +399,10 @@ declare module BABYLON {
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
@@ -414,20 +414,20 @@ declare module BABYLON {
          * @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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<void>;
         /**
          * 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 fullName Defines the FQDN of the file to load
+         * @param fileName Defines the name of the file to load
          * @returns The loaded asset container
          */
-        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<AssetContainer>;
+        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<AssetContainer>;
         /**
          * If the data string can be loaded directly.
          * @param data string contianing the file data
@@ -1270,7 +1270,8 @@ declare module BABYLON.GLTF2 {
         private _state;
         private _extensions;
         private _rootUrl;
-        private _fullName;
+        private _fileName;
+        private _uniqueRootUrl;
         private _rootBabylonMesh;
         private _defaultBabylonMaterialData;
         private _progressCallback?;
@@ -1299,14 +1300,14 @@ declare module BABYLON.GLTF2 {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
         /** @hidden */
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fileName?: string): Promise<void>;
         private _loadAsync;
         private _loadData;
         private _setupData;

+ 125 - 15
dist/preview release/serializers/babylon.glTF2Serializer.d.ts

@@ -14,6 +14,10 @@ declare module BABYLON {
          * The sample rate to bake animation curves
          */
         animationSampleRate?: number;
+        /**
+         * Begin serialization without waiting for the scene to be ready
+         */
+        exportWithoutWaitingForScene?: boolean;
     }
     /**
      * Class for generating glTF data from a Babylon scene.
@@ -28,6 +32,8 @@ declare module BABYLON {
          * as keys and their data and paths as values
          */
         static GLTFAsync(scene: Scene, filePrefix: string, options?: IExportOptions): Promise<GLTFData>;
+        private static _PreExportAsync;
+        private static _PostExportAsync;
         /**
          * Exports the geometry of the scene to .glb file format asychronously
          * @param scene Babylon scene with scene hierarchy information
@@ -40,7 +46,7 @@ declare module BABYLON {
 }
 
 
-declare module BABYLON.GLTF2 {
+declare module BABYLON.GLTF2.Exporter {
     /**
      * Converts Babylon Scene into glTF 2.0.
      * @hidden
@@ -49,11 +55,11 @@ declare module BABYLON.GLTF2 {
         /**
          * Stores all generated buffer views, which represents views into the main glTF buffer data
          */
-        private _bufferViews;
+        _bufferViews: IBufferView[];
         /**
          * Stores all the generated accessors, which is used for accessing the data within the buffer views in glTF
          */
-        private _accessors;
+        _accessors: IAccessor[];
         /**
          * Stores all the generated nodes, which contains transform and/or mesh information per node
          */
@@ -131,7 +137,19 @@ declare module BABYLON.GLTF2 {
          */
         private _shouldExportTransformNode;
         private _localEngine;
-        private _glTFMaterialExporter;
+        _glTFMaterialExporter: _GLTFMaterialExporter;
+        private _extensions;
+        private _extensionsUsed;
+        private _extensionsRequired;
+        private static _ExtensionNames;
+        private static _ExtensionFactories;
+        private _applyExtensions;
+        _extensionsPreExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<BaseTexture>>;
+        _extensionsPostExportMeshPrimitiveAsync(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Nullable<Promise<IMeshPrimitive>>;
+        /**
+         * Load glTF serializer extensions
+         */
+        private _loadExtensions;
         /**
          * Creates a glTF Exporter instance, which can accept optional exporter options
          * @param babylonScene Babylon scene object
@@ -139,6 +157,18 @@ declare module BABYLON.GLTF2 {
          */
         constructor(babylonScene: Scene, options?: IExportOptions);
         /**
+         * Registers a glTF exporter extension
+         * @param name Name of the extension to export
+         * @param factory The factory function that creates the exporter extension
+         */
+        static RegisterExtension(name: string, factory: (exporter: _Exporter) => IGLTFExporterExtension): void;
+        /**
+         * Un-registers an exporter extension
+         * @param name The name fo the exporter extension
+         * @returns A boolean indicating whether the extension has been un-registered
+         */
+        static UnregisterExtension(name: string): boolean;
+        /**
          * Lazy load a local engine with premultiplied alpha set to false
          */
         _getLocalEngine(): Engine;
@@ -208,7 +238,7 @@ declare module BABYLON.GLTF2 {
          * @param binaryWriter The buffer to write the binary data to
          * @param indices Used to specify the order of the vertex data
          */
-        private writeAttributeData;
+        writeAttributeData(vertexBufferKind: string, meshAttributeArray: FloatArray, byteStride: number, binaryWriter: _BinaryWriter): void;
         /**
          * Generates glTF json data
          * @param shouldUseGlb Indicates whether the json should be written for a glb file
@@ -279,7 +309,7 @@ declare module BABYLON.GLTF2 {
          * @param babylonTransformNode Babylon mesh to get the primitive attribute data from
          * @param binaryWriter Buffer to write the attribute data to
          */
-        private setPrimitiveAttributes;
+        private setPrimitiveAttributesAsync;
         /**
          * Creates a glTF scene based on the array of meshes
          * Returns the the total byte offset
@@ -295,14 +325,14 @@ declare module BABYLON.GLTF2 {
          * @param binaryWriter Buffer to write binary data to
          * @returns Node mapping of unique id to index
          */
-        private createNodeMapAndAnimations;
+        private createNodeMapAndAnimationsAsync;
         /**
          * Creates a glTF node from a Babylon mesh
          * @param babylonMesh Source Babylon mesh
          * @param binaryWriter Buffer for storing geometry data
          * @returns glTF node
          */
-        private createNode;
+        private createNodeAsync;
     }
     /**
      * @hidden
@@ -396,7 +426,7 @@ declare module BABYLON {
 }
 
 
-declare module BABYLON.GLTF2 {
+declare module BABYLON.GLTF2.Exporter {
     /**
      * Utility methods for working with glTF material conversion properties.  This class should only be used internally
      * @hidden
@@ -600,12 +630,10 @@ declare module BABYLON.GLTF2 {
          * Extracts a texture from a Babylon texture into file data and glTF data
          * @param babylonTexture Babylon texture to extract
          * @param mimeType Mime Type of the babylonTexture
-         * @param images Array of glTF images
-         * @param textures Array of glTF textures
-         * @param imageData map of image file name and data
          * @return glTF texture info, or null if the texture format is not supported
          */
-        private _exportTextureAsync;
+        _exportTextureAsync(babylonTexture: BaseTexture, mimeType: ImageMimeType): Promise<Nullable<ITextureInfo>>;
+        _exportTextureInfoAsync(babylonTexture: BaseTexture, mimeType: ImageMimeType): Promise<Nullable<ITextureInfo>>;
         /**
          * Builds a texture from base64 string
          * @param base64Texture base64 texture string
@@ -621,7 +649,7 @@ declare module BABYLON.GLTF2 {
 }
 
 
-declare module BABYLON.GLTF2 {
+declare module BABYLON.GLTF2.Exporter {
     /**
      * @hidden
      * Interface to store animation data.
@@ -797,7 +825,7 @@ declare module BABYLON.GLTF2 {
 }
 
 
-declare module BABYLON.GLTF2 {
+declare module BABYLON.GLTF2.Exporter {
     /**
      * @hidden
      */
@@ -891,3 +919,85 @@ declare module BABYLON.GLTF2 {
         static _NormalizeTangentFromRef(tangent: Vector4): void;
     }
 }
+
+
+declare module BABYLON.GLTF2.Exporter {
+    /**
+     * Interface for a glTF exporter extension
+     * @hidden
+     */
+    interface IGLTFExporterExtension extends BABYLON.IGLTFExporterExtension, IDisposable {
+        /**
+         * Define this method to modify the default behavior before exporting a texture
+         * @param context The context when loading the asset
+         * @param babylonTexture The glTF texture info property
+         * @param mimeType The mime-type of the generated image
+         * @returns A promise that resolves with the exported glTF texture info when the export is complete, or null if not handled
+         */
+        preExportTextureAsync?(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<Texture>>;
+        /**
+         * Define this method to modify the default behavior when exporting texture info
+         * @param context The context when loading the asset
+         * @param meshPrimitive glTF mesh primitive
+         * @param babylonSubMesh Babylon submesh
+         * @param binaryWriter glTF serializer binary writer instance
+         */
+        postExportMeshPrimitiveAsync?(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Nullable<Promise<IMeshPrimitive>>;
+    }
+}
+/**
+ * Defines the module for the built-in glTF 2.0 exporter extensions.
+ */
+declare module BABYLON.GLTF2.Extensions {
+}
+
+
+declare module BABYLON {
+    /**
+     * Interface for extending the exporter
+     * @hidden
+     */
+    interface IGLTFExporterExtension {
+        /**
+         * The name of this extension
+         */
+        readonly name: string;
+        /**
+         * Defines whether this extension is enabled
+         */
+        enabled: boolean;
+        /**
+         * Defines whether this extension is required
+         */
+        required: boolean;
+    }
+}
+
+
+declare module BABYLON.GLTF2.Exporter.Extensions {
+    /**
+     * @hidden
+     */
+    class KHR_texture_transform implements IGLTFExporterExtension {
+        /** Name of this extension */
+        readonly name: string;
+        /** Defines whether this extension is enabled */
+        enabled: boolean;
+        /** Defines whether this extension is required */
+        required: boolean;
+        /** Reference to the glTF exporter */
+        private _exporter;
+        constructor(exporter: _Exporter);
+        dispose(): void;
+        preExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<Texture>>;
+        /**
+         * Transform the babylon texture by the offset, rotation and scale parameters using a procedural texture
+         * @param babylonTexture
+         * @param offset
+         * @param rotation
+         * @param scale
+         * @param scene
+         */
+        textureTransformTextureAsync(babylonTexture: Texture, offset: Vector2, rotation: number, scale: Vector2, scene: Scene): Promise<BaseTexture>;
+    }
+}

File diff suppressed because it is too large
+ 3086 - 2825
dist/preview release/serializers/babylon.glTF2Serializer.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.min.js


+ 125 - 15
dist/preview release/serializers/babylonjs.serializers.d.ts

@@ -22,6 +22,10 @@ declare module BABYLON {
          * The sample rate to bake animation curves
          */
         animationSampleRate?: number;
+        /**
+         * Begin serialization without waiting for the scene to be ready
+         */
+        exportWithoutWaitingForScene?: boolean;
     }
     /**
      * Class for generating glTF data from a Babylon scene.
@@ -36,6 +40,8 @@ declare module BABYLON {
          * as keys and their data and paths as values
          */
         static GLTFAsync(scene: Scene, filePrefix: string, options?: IExportOptions): Promise<GLTFData>;
+        private static _PreExportAsync;
+        private static _PostExportAsync;
         /**
          * Exports the geometry of the scene to .glb file format asychronously
          * @param scene Babylon scene with scene hierarchy information
@@ -48,7 +54,7 @@ declare module BABYLON {
 }
 
 
-declare module BABYLON.GLTF2 {
+declare module BABYLON.GLTF2.Exporter {
     /**
      * Converts Babylon Scene into glTF 2.0.
      * @hidden
@@ -57,11 +63,11 @@ declare module BABYLON.GLTF2 {
         /**
          * Stores all generated buffer views, which represents views into the main glTF buffer data
          */
-        private _bufferViews;
+        _bufferViews: IBufferView[];
         /**
          * Stores all the generated accessors, which is used for accessing the data within the buffer views in glTF
          */
-        private _accessors;
+        _accessors: IAccessor[];
         /**
          * Stores all the generated nodes, which contains transform and/or mesh information per node
          */
@@ -139,7 +145,19 @@ declare module BABYLON.GLTF2 {
          */
         private _shouldExportTransformNode;
         private _localEngine;
-        private _glTFMaterialExporter;
+        _glTFMaterialExporter: _GLTFMaterialExporter;
+        private _extensions;
+        private _extensionsUsed;
+        private _extensionsRequired;
+        private static _ExtensionNames;
+        private static _ExtensionFactories;
+        private _applyExtensions;
+        _extensionsPreExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<BaseTexture>>;
+        _extensionsPostExportMeshPrimitiveAsync(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Nullable<Promise<IMeshPrimitive>>;
+        /**
+         * Load glTF serializer extensions
+         */
+        private _loadExtensions;
         /**
          * Creates a glTF Exporter instance, which can accept optional exporter options
          * @param babylonScene Babylon scene object
@@ -147,6 +165,18 @@ declare module BABYLON.GLTF2 {
          */
         constructor(babylonScene: Scene, options?: IExportOptions);
         /**
+         * Registers a glTF exporter extension
+         * @param name Name of the extension to export
+         * @param factory The factory function that creates the exporter extension
+         */
+        static RegisterExtension(name: string, factory: (exporter: _Exporter) => IGLTFExporterExtension): void;
+        /**
+         * Un-registers an exporter extension
+         * @param name The name fo the exporter extension
+         * @returns A boolean indicating whether the extension has been un-registered
+         */
+        static UnregisterExtension(name: string): boolean;
+        /**
          * Lazy load a local engine with premultiplied alpha set to false
          */
         _getLocalEngine(): Engine;
@@ -216,7 +246,7 @@ declare module BABYLON.GLTF2 {
          * @param binaryWriter The buffer to write the binary data to
          * @param indices Used to specify the order of the vertex data
          */
-        private writeAttributeData;
+        writeAttributeData(vertexBufferKind: string, meshAttributeArray: FloatArray, byteStride: number, binaryWriter: _BinaryWriter): void;
         /**
          * Generates glTF json data
          * @param shouldUseGlb Indicates whether the json should be written for a glb file
@@ -287,7 +317,7 @@ declare module BABYLON.GLTF2 {
          * @param babylonTransformNode Babylon mesh to get the primitive attribute data from
          * @param binaryWriter Buffer to write the attribute data to
          */
-        private setPrimitiveAttributes;
+        private setPrimitiveAttributesAsync;
         /**
          * Creates a glTF scene based on the array of meshes
          * Returns the the total byte offset
@@ -303,14 +333,14 @@ declare module BABYLON.GLTF2 {
          * @param binaryWriter Buffer to write binary data to
          * @returns Node mapping of unique id to index
          */
-        private createNodeMapAndAnimations;
+        private createNodeMapAndAnimationsAsync;
         /**
          * Creates a glTF node from a Babylon mesh
          * @param babylonMesh Source Babylon mesh
          * @param binaryWriter Buffer for storing geometry data
          * @returns glTF node
          */
-        private createNode;
+        private createNodeAsync;
     }
     /**
      * @hidden
@@ -404,7 +434,7 @@ declare module BABYLON {
 }
 
 
-declare module BABYLON.GLTF2 {
+declare module BABYLON.GLTF2.Exporter {
     /**
      * Utility methods for working with glTF material conversion properties.  This class should only be used internally
      * @hidden
@@ -608,12 +638,10 @@ declare module BABYLON.GLTF2 {
          * Extracts a texture from a Babylon texture into file data and glTF data
          * @param babylonTexture Babylon texture to extract
          * @param mimeType Mime Type of the babylonTexture
-         * @param images Array of glTF images
-         * @param textures Array of glTF textures
-         * @param imageData map of image file name and data
          * @return glTF texture info, or null if the texture format is not supported
          */
-        private _exportTextureAsync;
+        _exportTextureAsync(babylonTexture: BaseTexture, mimeType: ImageMimeType): Promise<Nullable<ITextureInfo>>;
+        _exportTextureInfoAsync(babylonTexture: BaseTexture, mimeType: ImageMimeType): Promise<Nullable<ITextureInfo>>;
         /**
          * Builds a texture from base64 string
          * @param base64Texture base64 texture string
@@ -629,7 +657,7 @@ declare module BABYLON.GLTF2 {
 }
 
 
-declare module BABYLON.GLTF2 {
+declare module BABYLON.GLTF2.Exporter {
     /**
      * @hidden
      * Interface to store animation data.
@@ -805,7 +833,7 @@ declare module BABYLON.GLTF2 {
 }
 
 
-declare module BABYLON.GLTF2 {
+declare module BABYLON.GLTF2.Exporter {
     /**
      * @hidden
      */
@@ -899,3 +927,85 @@ declare module BABYLON.GLTF2 {
         static _NormalizeTangentFromRef(tangent: Vector4): void;
     }
 }
+
+
+declare module BABYLON.GLTF2.Exporter {
+    /**
+     * Interface for a glTF exporter extension
+     * @hidden
+     */
+    interface IGLTFExporterExtension extends BABYLON.IGLTFExporterExtension, IDisposable {
+        /**
+         * Define this method to modify the default behavior before exporting a texture
+         * @param context The context when loading the asset
+         * @param babylonTexture The glTF texture info property
+         * @param mimeType The mime-type of the generated image
+         * @returns A promise that resolves with the exported glTF texture info when the export is complete, or null if not handled
+         */
+        preExportTextureAsync?(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<Texture>>;
+        /**
+         * Define this method to modify the default behavior when exporting texture info
+         * @param context The context when loading the asset
+         * @param meshPrimitive glTF mesh primitive
+         * @param babylonSubMesh Babylon submesh
+         * @param binaryWriter glTF serializer binary writer instance
+         */
+        postExportMeshPrimitiveAsync?(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Nullable<Promise<IMeshPrimitive>>;
+    }
+}
+/**
+ * Defines the module for the built-in glTF 2.0 exporter extensions.
+ */
+declare module BABYLON.GLTF2.Extensions {
+}
+
+
+declare module BABYLON {
+    /**
+     * Interface for extending the exporter
+     * @hidden
+     */
+    interface IGLTFExporterExtension {
+        /**
+         * The name of this extension
+         */
+        readonly name: string;
+        /**
+         * Defines whether this extension is enabled
+         */
+        enabled: boolean;
+        /**
+         * Defines whether this extension is required
+         */
+        required: boolean;
+    }
+}
+
+
+declare module BABYLON.GLTF2.Exporter.Extensions {
+    /**
+     * @hidden
+     */
+    class KHR_texture_transform implements IGLTFExporterExtension {
+        /** Name of this extension */
+        readonly name: string;
+        /** Defines whether this extension is enabled */
+        enabled: boolean;
+        /** Defines whether this extension is required */
+        required: boolean;
+        /** Reference to the glTF exporter */
+        private _exporter;
+        constructor(exporter: _Exporter);
+        dispose(): void;
+        preExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<Texture>>;
+        /**
+         * Transform the babylon texture by the offset, rotation and scale parameters using a procedural texture
+         * @param babylonTexture
+         * @param offset
+         * @param rotation
+         * @param scale
+         * @param scene
+         */
+        textureTransformTextureAsync(babylonTexture: Texture, offset: Vector2, rotation: number, scale: Vector2, scene: Scene): Promise<BaseTexture>;
+    }
+}

File diff suppressed because it is too large
+ 3086 - 2825
dist/preview release/serializers/babylonjs.serializers.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.min.js


+ 125 - 15
dist/preview release/serializers/babylonjs.serializers.module.d.ts

@@ -29,6 +29,10 @@ declare module BABYLON {
          * The sample rate to bake animation curves
          */
         animationSampleRate?: number;
+        /**
+         * Begin serialization without waiting for the scene to be ready
+         */
+        exportWithoutWaitingForScene?: boolean;
     }
     /**
      * Class for generating glTF data from a Babylon scene.
@@ -43,6 +47,8 @@ declare module BABYLON {
          * as keys and their data and paths as values
          */
         static GLTFAsync(scene: Scene, filePrefix: string, options?: IExportOptions): Promise<GLTFData>;
+        private static _PreExportAsync;
+        private static _PostExportAsync;
         /**
          * Exports the geometry of the scene to .glb file format asychronously
          * @param scene Babylon scene with scene hierarchy information
@@ -55,7 +61,7 @@ declare module BABYLON {
 }
 
 
-declare module BABYLON.GLTF2 {
+declare module BABYLON.GLTF2.Exporter {
     /**
      * Converts Babylon Scene into glTF 2.0.
      * @hidden
@@ -64,11 +70,11 @@ declare module BABYLON.GLTF2 {
         /**
          * Stores all generated buffer views, which represents views into the main glTF buffer data
          */
-        private _bufferViews;
+        _bufferViews: IBufferView[];
         /**
          * Stores all the generated accessors, which is used for accessing the data within the buffer views in glTF
          */
-        private _accessors;
+        _accessors: IAccessor[];
         /**
          * Stores all the generated nodes, which contains transform and/or mesh information per node
          */
@@ -146,7 +152,19 @@ declare module BABYLON.GLTF2 {
          */
         private _shouldExportTransformNode;
         private _localEngine;
-        private _glTFMaterialExporter;
+        _glTFMaterialExporter: _GLTFMaterialExporter;
+        private _extensions;
+        private _extensionsUsed;
+        private _extensionsRequired;
+        private static _ExtensionNames;
+        private static _ExtensionFactories;
+        private _applyExtensions;
+        _extensionsPreExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<BaseTexture>>;
+        _extensionsPostExportMeshPrimitiveAsync(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Nullable<Promise<IMeshPrimitive>>;
+        /**
+         * Load glTF serializer extensions
+         */
+        private _loadExtensions;
         /**
          * Creates a glTF Exporter instance, which can accept optional exporter options
          * @param babylonScene Babylon scene object
@@ -154,6 +172,18 @@ declare module BABYLON.GLTF2 {
          */
         constructor(babylonScene: Scene, options?: IExportOptions);
         /**
+         * Registers a glTF exporter extension
+         * @param name Name of the extension to export
+         * @param factory The factory function that creates the exporter extension
+         */
+        static RegisterExtension(name: string, factory: (exporter: _Exporter) => IGLTFExporterExtension): void;
+        /**
+         * Un-registers an exporter extension
+         * @param name The name fo the exporter extension
+         * @returns A boolean indicating whether the extension has been un-registered
+         */
+        static UnregisterExtension(name: string): boolean;
+        /**
          * Lazy load a local engine with premultiplied alpha set to false
          */
         _getLocalEngine(): Engine;
@@ -223,7 +253,7 @@ declare module BABYLON.GLTF2 {
          * @param binaryWriter The buffer to write the binary data to
          * @param indices Used to specify the order of the vertex data
          */
-        private writeAttributeData;
+        writeAttributeData(vertexBufferKind: string, meshAttributeArray: FloatArray, byteStride: number, binaryWriter: _BinaryWriter): void;
         /**
          * Generates glTF json data
          * @param shouldUseGlb Indicates whether the json should be written for a glb file
@@ -294,7 +324,7 @@ declare module BABYLON.GLTF2 {
          * @param babylonTransformNode Babylon mesh to get the primitive attribute data from
          * @param binaryWriter Buffer to write the attribute data to
          */
-        private setPrimitiveAttributes;
+        private setPrimitiveAttributesAsync;
         /**
          * Creates a glTF scene based on the array of meshes
          * Returns the the total byte offset
@@ -310,14 +340,14 @@ declare module BABYLON.GLTF2 {
          * @param binaryWriter Buffer to write binary data to
          * @returns Node mapping of unique id to index
          */
-        private createNodeMapAndAnimations;
+        private createNodeMapAndAnimationsAsync;
         /**
          * Creates a glTF node from a Babylon mesh
          * @param babylonMesh Source Babylon mesh
          * @param binaryWriter Buffer for storing geometry data
          * @returns glTF node
          */
-        private createNode;
+        private createNodeAsync;
     }
     /**
      * @hidden
@@ -411,7 +441,7 @@ declare module BABYLON {
 }
 
 
-declare module BABYLON.GLTF2 {
+declare module BABYLON.GLTF2.Exporter {
     /**
      * Utility methods for working with glTF material conversion properties.  This class should only be used internally
      * @hidden
@@ -615,12 +645,10 @@ declare module BABYLON.GLTF2 {
          * Extracts a texture from a Babylon texture into file data and glTF data
          * @param babylonTexture Babylon texture to extract
          * @param mimeType Mime Type of the babylonTexture
-         * @param images Array of glTF images
-         * @param textures Array of glTF textures
-         * @param imageData map of image file name and data
          * @return glTF texture info, or null if the texture format is not supported
          */
-        private _exportTextureAsync;
+        _exportTextureAsync(babylonTexture: BaseTexture, mimeType: ImageMimeType): Promise<Nullable<ITextureInfo>>;
+        _exportTextureInfoAsync(babylonTexture: BaseTexture, mimeType: ImageMimeType): Promise<Nullable<ITextureInfo>>;
         /**
          * Builds a texture from base64 string
          * @param base64Texture base64 texture string
@@ -636,7 +664,7 @@ declare module BABYLON.GLTF2 {
 }
 
 
-declare module BABYLON.GLTF2 {
+declare module BABYLON.GLTF2.Exporter {
     /**
      * @hidden
      * Interface to store animation data.
@@ -812,7 +840,7 @@ declare module BABYLON.GLTF2 {
 }
 
 
-declare module BABYLON.GLTF2 {
+declare module BABYLON.GLTF2.Exporter {
     /**
      * @hidden
      */
@@ -906,3 +934,85 @@ declare module BABYLON.GLTF2 {
         static _NormalizeTangentFromRef(tangent: Vector4): void;
     }
 }
+
+
+declare module BABYLON.GLTF2.Exporter {
+    /**
+     * Interface for a glTF exporter extension
+     * @hidden
+     */
+    interface IGLTFExporterExtension extends BABYLON.IGLTFExporterExtension, IDisposable {
+        /**
+         * Define this method to modify the default behavior before exporting a texture
+         * @param context The context when loading the asset
+         * @param babylonTexture The glTF texture info property
+         * @param mimeType The mime-type of the generated image
+         * @returns A promise that resolves with the exported glTF texture info when the export is complete, or null if not handled
+         */
+        preExportTextureAsync?(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<Texture>>;
+        /**
+         * Define this method to modify the default behavior when exporting texture info
+         * @param context The context when loading the asset
+         * @param meshPrimitive glTF mesh primitive
+         * @param babylonSubMesh Babylon submesh
+         * @param binaryWriter glTF serializer binary writer instance
+         */
+        postExportMeshPrimitiveAsync?(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Nullable<Promise<IMeshPrimitive>>;
+    }
+}
+/**
+ * Defines the module for the built-in glTF 2.0 exporter extensions.
+ */
+declare module BABYLON.GLTF2.Extensions {
+}
+
+
+declare module BABYLON {
+    /**
+     * Interface for extending the exporter
+     * @hidden
+     */
+    interface IGLTFExporterExtension {
+        /**
+         * The name of this extension
+         */
+        readonly name: string;
+        /**
+         * Defines whether this extension is enabled
+         */
+        enabled: boolean;
+        /**
+         * Defines whether this extension is required
+         */
+        required: boolean;
+    }
+}
+
+
+declare module BABYLON.GLTF2.Exporter.Extensions {
+    /**
+     * @hidden
+     */
+    class KHR_texture_transform implements IGLTFExporterExtension {
+        /** Name of this extension */
+        readonly name: string;
+        /** Defines whether this extension is enabled */
+        enabled: boolean;
+        /** Defines whether this extension is required */
+        required: boolean;
+        /** Reference to the glTF exporter */
+        private _exporter;
+        constructor(exporter: _Exporter);
+        dispose(): void;
+        preExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<Texture>>;
+        /**
+         * Transform the babylon texture by the offset, rotation and scale parameters using a procedural texture
+         * @param babylonTexture
+         * @param offset
+         * @param rotation
+         * @param scale
+         * @param scene
+         */
+        textureTransformTextureAsync(babylonTexture: Texture, offset: Vector2, rotation: number, scale: Vector2, scene: Scene): Promise<BaseTexture>;
+    }
+}

+ 2 - 37
dist/preview release/typedocValidationBaseline.json

@@ -1,7 +1,7 @@
 {
-  "errors": 3874,
+  "errors": 3867,
   "babylon.typedoc.json": {
-    "errors": 3874,
+    "errors": 3867,
     "AnimationGroup": {
       "Constructor": {
         "new AnimationGroup": {
@@ -7826,36 +7826,6 @@
                 "MissingText": true
               }
             },
-            "url": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "width": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "height": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "subdivisions": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "minHeight": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "maxHeight": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
             "scene": {
               "Comments": {
                 "MissingText": true
@@ -7865,11 +7835,6 @@
               "Comments": {
                 "MissingText": true
               }
-            },
-            "onReady": {
-              "Comments": {
-                "MissingText": true
-              }
             }
           }
         },

+ 15 - 1
dist/preview release/viewer/babylon.viewer.d.ts

@@ -924,7 +924,7 @@ declare module BabylonViewer {
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 declare module BabylonViewer {
@@ -1558,6 +1558,20 @@ declare module BabylonViewer {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 declare module BabylonViewer {
+    /**
+        * A custom upgrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedUpgrade(sceneManager: SceneManager): boolean;
+    /**
+        * A custom degrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedDegrade(sceneManager: SceneManager): boolean;
+}
+declare module BabylonViewer {
 }
 declare module BabylonViewer {
     export interface IEnvironmentMapConfiguration {

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/viewer/babylon.viewer.js


File diff suppressed because it is too large
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


+ 18 - 1
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -985,13 +985,14 @@ declare module 'babylonjs-viewer/templating/viewerTemplatePlugin' {
 }
 
 declare module 'babylonjs-viewer/optimizer/custom' {
+    import { extendedUpgrade } from "babylonjs-viewer/optimizer/custom/extended";
     import { SceneManager } from "babylonjs-viewer/managers/sceneManager";
     /**
       *
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 
@@ -1662,6 +1663,22 @@ declare module 'babylonjs-viewer/loader/plugins' {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 
+declare module 'babylonjs-viewer/optimizer/custom/extended' {
+    import { SceneManager } from 'babylonjs-viewer/managers/sceneManager';
+    /**
+        * A custom upgrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedUpgrade(sceneManager: SceneManager): boolean;
+    /**
+        * A custom degrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedDegrade(sceneManager: SceneManager): boolean;
+}
+
 declare module 'babylonjs-viewer/configuration/interfaces' {
     export * from 'babylonjs-viewer/configuration/interfaces/cameraConfiguration';
     export * from 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration';

+ 5 - 0
src/Culling/babylon.boundingBox.ts

@@ -15,6 +15,11 @@
         private _worldMatrix: Matrix;
 
         /**
+         * @hidden
+         */
+        public _tag: number;
+
+        /**
          * Creates a new bounding box
          * @param min defines the minimum vector (in local space)
          * @param max defines the maximum vector (in local space)

+ 8 - 4
src/Rendering/babylon.boundingBoxRenderer.ts

@@ -81,7 +81,7 @@
         public frontColor = new Color3(1, 1, 1);
         public backColor = new Color3(0.1, 0.1, 0.1);
         public showBackLines = true;
-        public renderList = new SmartArray<BoundingBox>(32);
+        public renderList = new SmartArray<BoundingBox>(32);        
 
         private _colorShader: ShaderMaterial;
         private _vertexBuffers: { [key: string]: Nullable<VertexBuffer> } = {};
@@ -102,13 +102,14 @@
 
             this.scene._evaluateSubMeshStage.registerStep(SceneComponentConstants.STEP_EVALUATESUBMESH_BOUNDINGBOXRENDERER, this, this._evaluateSubMesh);
 
-            this.scene._afterCameraDrawStage.registerStep(SceneComponentConstants.STEP_AFTERCAMERADRAW_BOUNDINGBOXRENDERER, this, this.render);
+            this.scene._afterRenderingGroupDrawStage.registerStep(SceneComponentConstants.STEP_AFTERCAMERADRAW_BOUNDINGBOXRENDERER, this, this.render);
         }
 
         private _evaluateSubMesh(mesh: AbstractMesh, subMesh: SubMesh): void {
             if (mesh.showSubMeshesBoundingBox) {
                 const boundingInfo = subMesh.getBoundingInfo();
                 if (boundingInfo !== null && boundingInfo !== undefined) {
+                    boundingInfo.boundingBox._tag = mesh.renderingGroupId;
                     this.renderList.push(boundingInfo.boundingBox);
                 }
             }
@@ -117,7 +118,7 @@
         private _activeMesh(sourceMesh: AbstractMesh, mesh: AbstractMesh): void {
             if (sourceMesh.showBoundingBox || this.scene.forceShowBoundingBoxes) {
                 let boundingInfo = sourceMesh.getBoundingInfo();
-
+                boundingInfo.boundingBox._tag = mesh.renderingGroupId;
                 this.renderList.push(boundingInfo.boundingBox);
             }
         }
@@ -161,7 +162,7 @@
             this.renderList.reset();
         }
 
-        public render(): void {
+        public render(renderingGroupId: number): void {
             if (this.renderList.length === 0) {
                 return;
             }
@@ -177,6 +178,9 @@
             this._colorShader._preBind();
             for (var boundingBoxIndex = 0; boundingBoxIndex < this.renderList.length; boundingBoxIndex++) {
                 var boundingBox = this.renderList.data[boundingBoxIndex];
+                if (boundingBox._tag !== renderingGroupId) {
+                    continue;
+                }
                 var min = boundingBox.minimum;
                 var max = boundingBox.maximum;
                 var diff = max.subtract(min);