David Catuhe 8 年之前
父节点
当前提交
721bca9888
共有 32 个文件被更改,包括 12972 次插入12830 次删除
  1. 1507 1507
      dist/preview release/babylon.d.ts
  2. 39 39
      dist/preview release/babylon.js
  3. 9 3
      dist/preview release/babylon.max.js
  4. 1507 1507
      dist/preview release/babylon.module.d.ts
  5. 40 40
      dist/preview release/babylon.worker.js
  6. 4234 4234
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  7. 42 42
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  8. 243 210
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  9. 4234 4234
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts
  10. 3 3
      dist/preview release/gui/babylon.gui.min.js
  11. 263 263
      dist/preview release/inspector/babylon.inspector.bundle.js
  12. 3 3
      dist/preview release/inspector/babylon.inspector.min.js
  13. 8 4
      dist/preview release/loaders/babylon.glTF1FileLoader.d.ts
  14. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  15. 37 33
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  16. 234 207
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  17. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  18. 37 33
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  19. 234 207
      dist/preview release/loaders/babylon.glTFFileLoader.js
  20. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  21. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  22. 234 207
      dist/preview release/loaders/babylonjs.loaders.js
  23. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  24. 37 33
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  25. 1 1
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  26. 1 1
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js
  27. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.min.js
  28. 3 3
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  29. 1 1
      dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js
  30. 1 1
      dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js
  31. 1 1
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js
  32. 7 1
      src/PostProcess/babylon.volumetricLightScatteringPostProcess.ts

文件差异内容过多而无法显示
+ 1507 - 1507
dist/preview release/babylon.d.ts


文件差异内容过多而无法显示
+ 39 - 39
dist/preview release/babylon.js


+ 9 - 3
dist/preview release/babylon.max.js

@@ -56527,7 +56527,13 @@ var BABYLON;
             this._volumetricLightScatteringRTT.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this._volumetricLightScatteringRTT.renderList = null;
             this._volumetricLightScatteringRTT.renderParticles = false;
-            scene.customRenderTargets.push(this._volumetricLightScatteringRTT);
+            var camera = this.getCamera();
+            if (camera) {
+                camera.customRenderTargets.push(this._volumetricLightScatteringRTT);
+            }
+            else {
+                scene.customRenderTargets.push(this._volumetricLightScatteringRTT);
+            }
             // Custom render function for submeshes
             var renderSubMesh = function (subMesh) {
                 var mesh = subMesh.getRenderingMesh();
@@ -62933,9 +62939,9 @@ var BABYLON;
                         }
                     }
                     currentRotation.multiplyInPlace(mesh.rotationQuaternion);
-                    mesh.getChildMeshes(true).forEach(processMesh.bind(_this, mesh.getAbsolutePosition()));
+                    mesh.getChildMeshes(true).filter(function (m) { return !!m.physicsImpostor; }).forEach(processMesh.bind(_this, mesh.getAbsolutePosition()));
                 };
-                meshChildren.forEach(processMesh.bind(this, mainImpostor.object.getAbsolutePosition()));
+                meshChildren.filter(function (m) { return !!m.physicsImpostor; }).forEach(processMesh.bind(this, mainImpostor.object.getAbsolutePosition()));
             }
         };
         CannonJSPlugin.prototype.removePhysicsBody = function (impostor) {

文件差异内容过多而无法显示
+ 1507 - 1507
dist/preview release/babylon.module.d.ts


文件差异内容过多而无法显示
+ 40 - 40
dist/preview release/babylon.worker.js


文件差异内容过多而无法显示
+ 4234 - 4234
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


文件差异内容过多而无法显示
+ 42 - 42
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


+ 243 - 210
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js

@@ -56527,7 +56527,13 @@ var BABYLON;
             this._volumetricLightScatteringRTT.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this._volumetricLightScatteringRTT.renderList = null;
             this._volumetricLightScatteringRTT.renderParticles = false;
-            scene.customRenderTargets.push(this._volumetricLightScatteringRTT);
+            var camera = this.getCamera();
+            if (camera) {
+                camera.customRenderTargets.push(this._volumetricLightScatteringRTT);
+            }
+            else {
+                scene.customRenderTargets.push(this._volumetricLightScatteringRTT);
+            }
             // Custom render function for submeshes
             var renderSubMesh = function (subMesh) {
                 var mesh = subMesh.getRenderingMesh();
@@ -62933,9 +62939,9 @@ var BABYLON;
                         }
                     }
                     currentRotation.multiplyInPlace(mesh.rotationQuaternion);
-                    mesh.getChildMeshes(true).forEach(processMesh.bind(_this, mesh.getAbsolutePosition()));
+                    mesh.getChildMeshes(true).filter(function (m) { return !!m.physicsImpostor; }).forEach(processMesh.bind(_this, mesh.getAbsolutePosition()));
                 };
-                meshChildren.forEach(processMesh.bind(this, mainImpostor.object.getAbsolutePosition()));
+                meshChildren.filter(function (m) { return !!m.physicsImpostor; }).forEach(processMesh.bind(this, mainImpostor.object.getAbsolutePosition()));
             }
         };
         CannonJSPlugin.prototype.removePhysicsBody = function (impostor) {
@@ -75578,17 +75584,31 @@ var BABYLON;
 (function (BABYLON) {
     var GLTF2;
     (function (GLTF2) {
+        var GLTFLoaderTracker = (function () {
+            function GLTFLoaderTracker(onComplete) {
+                this._pendingCount = 0;
+                this._callback = onComplete;
+            }
+            GLTFLoaderTracker.prototype._addPendingData = function (data) {
+                this._pendingCount++;
+            };
+            GLTFLoaderTracker.prototype._removePendingData = function (data) {
+                if (--this._pendingCount === 0) {
+                    this._callback();
+                }
+            };
+            return GLTFLoaderTracker;
+        }());
         var GLTFLoader = (function () {
             function GLTFLoader(parent) {
                 this._renderReady = false;
                 this._disposed = false;
-                this._blockPendingTracking = false;
-                // Observable with boolean indicating success or error.
                 this._renderReadyObservable = new BABYLON.Observable();
                 // Count of pending work that needs to complete before the asset is rendered.
                 this._renderPendingCount = 0;
-                // Count of pending work that needs to complete before the loader is cleared.
+                // Count of pending work that needs to complete before the loader is disposed.
                 this._loaderPendingCount = 0;
+                this._loaderTrackers = new Array();
                 this._parent = parent;
             }
             GLTFLoader.RegisterExtension = function (extension) {
@@ -75600,28 +75620,6 @@ var BABYLON;
                 // Keep the order of registration so that extensions registered first are called first.
                 GLTF2.GLTFLoaderExtension._Extensions.push(extension);
             };
-            Object.defineProperty(GLTFLoader.prototype, "gltf", {
-                get: function () {
-                    return this._gltf;
-                },
-                enumerable: true,
-                configurable: true
-            });
-            Object.defineProperty(GLTFLoader.prototype, "babylonScene", {
-                get: function () {
-                    return this._babylonScene;
-                },
-                enumerable: true,
-                configurable: true
-            });
-            GLTFLoader.prototype.executeWhenRenderReady = function (func) {
-                if (this._renderReady) {
-                    func();
-                }
-                else {
-                    this._renderReadyObservable.add(func);
-                }
-            };
             GLTFLoader.prototype.dispose = function () {
                 if (this._disposed) {
                     return;
@@ -75662,10 +75660,10 @@ var BABYLON;
                 this._successCallback = onSuccess;
                 this._progressCallback = onProgress;
                 this._errorCallback = onError;
-                this.addPendingData(this);
+                this._addPendingData(this);
                 this._loadScene(nodeNames);
                 this._loadAnimations();
-                this.removePendingData(this);
+                this._removePendingData(this);
             };
             GLTFLoader.prototype._onError = function (message) {
                 if (this._errorCallback) {
@@ -75674,39 +75672,33 @@ var BABYLON;
                 this.dispose();
             };
             GLTFLoader.prototype._onProgress = function (event) {
-                this._progressCallback(event);
+                if (this._progressCallback) {
+                    this._progressCallback(event);
+                }
             };
-            GLTFLoader.prototype._onRenderReady = function () {
-                switch (this._parent.coordinateSystemMode) {
-                    case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO:
-                        if (!this._babylonScene.useRightHandedSystem) {
-                            this._addRightHandToLeftHandRootTransform();
-                        }
-                        break;
-                    case BABYLON.GLTFLoaderCoordinateSystemMode.PASS_THROUGH:
-                        // do nothing
-                        break;
-                    case BABYLON.GLTFLoaderCoordinateSystemMode.FORCE_RIGHT_HANDED:
-                        this._babylonScene.useRightHandedSystem = true;
-                        break;
-                    default:
-                        BABYLON.Tools.Error("Invalid coordinate system mode (" + this._parent.coordinateSystemMode + ")");
-                        break;
+            GLTFLoader.prototype._executeWhenRenderReady = function (func) {
+                if (this._renderReady) {
+                    func();
+                }
+                else {
+                    this._renderReadyObservable.add(func);
                 }
-                this._showMeshes();
+            };
+            GLTFLoader.prototype._onRenderReady = function () {
+                var rootNode = this._gltf.nodes[this._gltf.nodes.length - 1];
+                rootNode.babylonMesh.setEnabled(true);
                 this._startAnimations();
                 this._successCallback();
                 this._renderReadyObservable.notifyObservers(this);
+                if (this._parent.onReady) {
+                    this._parent.onReady();
+                }
             };
-            GLTFLoader.prototype._onLoaderComplete = function () {
+            GLTFLoader.prototype._onComplete = function () {
                 if (this._parent.onComplete) {
                     this._parent.onComplete();
                 }
-            };
-            GLTFLoader.prototype._onLoaderFirstLODComplete = function () {
-                if (this._parent.onFirstLODComplete) {
-                    this._parent.onFirstLODComplete();
-                }
+                this.dispose();
             };
             GLTFLoader.prototype._loadData = function (data) {
                 this._gltf = data.json;
@@ -75727,26 +75719,8 @@ var BABYLON;
                     binaryBuffer.loadedData = data.bin;
                 }
             };
-            GLTFLoader.prototype._addRightHandToLeftHandRootTransform = function () {
-                this._rootMesh = new BABYLON.Mesh("root", this._babylonScene);
-                this._rootMesh.isVisible = false;
-                this._rootMesh.scaling = new BABYLON.Vector3(1, 1, -1);
-                this._rootMesh.rotation.y = Math.PI;
-                var nodes = this._gltf.nodes;
-                if (nodes) {
-                    for (var i = 0; i < nodes.length; i++) {
-                        var mesh = nodes[i].babylonMesh;
-                        if (mesh && !mesh.parent) {
-                            mesh.parent = this._rootMesh;
-                        }
-                    }
-                }
-            };
             GLTFLoader.prototype._getMeshes = function () {
                 var meshes = [];
-                if (this._rootMesh) {
-                    meshes.push(this._rootMesh);
-                }
                 var nodes = this._gltf.nodes;
                 if (nodes) {
                     nodes.forEach(function (node) {
@@ -75779,16 +75753,34 @@ var BABYLON;
                 }
                 return targets;
             };
-            GLTFLoader.prototype._showMeshes = function () {
-                this._getMeshes().forEach(function (mesh) { return mesh.isVisible = true; });
-            };
             GLTFLoader.prototype._startAnimations = function () {
                 var _this = this;
                 this._getAnimationTargets().forEach(function (target) { return _this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true); });
             };
             GLTFLoader.prototype._loadScene = function (nodeNames) {
-                var _this = this;
                 var scene = this._gltf.scenes[this._gltf.scene || 0];
+                var rootNode = { name: "root", children: scene.nodes };
+                switch (this._parent.coordinateSystemMode) {
+                    case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO:
+                        if (!this._babylonScene.useRightHandedSystem) {
+                            rootNode.rotation = [0, 1, 0, 0];
+                            rootNode.scale = [1, 1, -1];
+                        }
+                        break;
+                    case BABYLON.GLTFLoaderCoordinateSystemMode.PASS_THROUGH:
+                        // do nothing
+                        break;
+                    case BABYLON.GLTFLoaderCoordinateSystemMode.FORCE_RIGHT_HANDED:
+                        this._babylonScene.useRightHandedSystem = true;
+                        break;
+                    default:
+                        BABYLON.Tools.Error("Invalid coordinate system mode (" + this._parent.coordinateSystemMode + ")");
+                        break;
+                }
+                // Inject a root node into the scene.
+                this._gltf.nodes = this._gltf.nodes || [];
+                scene.nodes = [this._gltf.nodes.length];
+                this._gltf.nodes.push(rootNode);
                 var nodeIndices = scene.nodes;
                 this._traverseNodes(nodeIndices, function (node, index, parentNode) {
                     node.index = index;
@@ -75805,19 +75797,25 @@ var BABYLON;
                     }
                     var filteredNodeIndices = new Array();
                     this._traverseNodes(nodeIndices, function (node) {
-                        if (nodeNames.indexOf(node.name) === -1) {
-                            return true;
+                        if (nodeNames.indexOf(node.name) !== -1) {
+                            filteredNodeIndices.push(node.index);
+                            return false;
                         }
-                        filteredNodeIndices.push(node.index);
-                        return false;
+                        return true;
                     });
                     nodeIndices = filteredNodeIndices;
                 }
-                this._traverseNodes(nodeIndices, function (node) { return _this._loadNode(node); });
+                for (var i = 0; i < nodeIndices.length; i++) {
+                    this._loadNode(this._gltf.nodes[nodeIndices[i]]);
+                }
+                // Disable the root mesh until the asset is ready to render.
+                rootNode.babylonMesh.setEnabled(false);
             };
             GLTFLoader.prototype._loadNode = function (node) {
+                if (GLTF2.GLTFLoaderExtension.LoadNode(this, node)) {
+                    return;
+                }
                 node.babylonMesh = new BABYLON.Mesh(node.name || "mesh" + node.index, this._babylonScene);
-                node.babylonMesh.isVisible = false;
                 this._loadTransform(node);
                 if (node.mesh !== undefined) {
                     var mesh = this._gltf.meshes[node.mesh];
@@ -75834,7 +75832,11 @@ var BABYLON;
                 if (node.camera !== undefined) {
                     // TODO: handle cameras
                 }
-                return true;
+                if (node.children) {
+                    for (var i = 0; i < node.children.length; i++) {
+                        this._loadNode(this._gltf.nodes[node.children[i]]);
+                    }
+                }
             };
             GLTFLoader.prototype._loadMesh = function (node, mesh) {
                 var _this = this;
@@ -75866,25 +75868,24 @@ var BABYLON;
                             loadMaterial: function () {
                                 if (primitive.material === undefined) {
                                     babylonMultiMaterial.subMaterials[i] = _this._getDefaultMaterial();
+                                    return;
                                 }
-                                else {
-                                    var material = _this._gltf.materials[primitive.material];
-                                    _this.loadMaterial(material, function (babylonMaterial, isNew) {
-                                        if (isNew && _this._parent.onMaterialLoaded) {
-                                            _this._parent.onMaterialLoaded(babylonMaterial);
-                                        }
-                                        if (_this._parent.onBeforeMaterialReadyAsync) {
-                                            _this.addLoaderPendingData(material);
-                                            _this._parent.onBeforeMaterialReadyAsync(babylonMaterial, node.babylonMesh, babylonMultiMaterial.subMaterials[i] != null, function () {
-                                                babylonMultiMaterial.subMaterials[i] = babylonMaterial;
-                                                _this.removeLoaderPendingData(material);
-                                            });
-                                        }
-                                        else {
+                                var material = _this._gltf.materials[primitive.material];
+                                _this._loadMaterial(material, function (babylonMaterial, isNew) {
+                                    if (isNew && _this._parent.onMaterialLoaded) {
+                                        _this._parent.onMaterialLoaded(babylonMaterial);
+                                    }
+                                    if (_this._parent.onBeforeMaterialReadyAsync) {
+                                        _this._addLoaderPendingData(material);
+                                        _this._parent.onBeforeMaterialReadyAsync(babylonMaterial, node.babylonMesh, babylonMultiMaterial.subMaterials[i] != null, function () {
                                             babylonMultiMaterial.subMaterials[i] = babylonMaterial;
-                                        }
-                                    });
-                                }
+                                            _this._removeLoaderPendingData(material);
+                                        });
+                                    }
+                                    else {
+                                        babylonMultiMaterial.subMaterials[i] = babylonMaterial;
+                                    }
+                                });
                             }
                         });
                         vertexData.merge(subVertexData);
@@ -76115,14 +76116,15 @@ var BABYLON;
             };
             GLTFLoader.prototype._traverseNode = function (index, action, parentNode) {
                 if (parentNode === void 0) { parentNode = null; }
+                if (GLTF2.GLTFLoaderExtension.TraverseNode(this, index, action, parentNode)) {
+                    return;
+                }
                 var node = this._gltf.nodes[index];
                 if (!action(node, index, parentNode)) {
                     return;
                 }
                 if (node.children) {
-                    for (var i = 0; i < node.children.length; i++) {
-                        this._traverseNode(node.children[i], action, node);
-                    }
+                    this._traverseNodes(node.children, action, node);
                 }
             };
             GLTFLoader.prototype._loadAnimations = function () {
@@ -76250,11 +76252,11 @@ var BABYLON;
             GLTFLoader.prototype._loadBufferAsync = function (index, onSuccess) {
                 var _this = this;
                 var buffer = this._gltf.buffers[index];
-                this.addPendingData(buffer);
+                this._addPendingData(buffer);
                 if (buffer.loadedData) {
                     setTimeout(function () {
                         onSuccess(buffer.loadedData);
-                        _this.removePendingData(buffer);
+                        _this._removePendingData(buffer);
                     });
                 }
                 else if (GLTF2.GLTFUtils.IsBase64(buffer.uri)) {
@@ -76262,20 +76264,20 @@ var BABYLON;
                     buffer.loadedData = new Uint8Array(data);
                     setTimeout(function () {
                         onSuccess(buffer.loadedData);
-                        _this.removePendingData(buffer);
+                        _this._removePendingData(buffer);
                     });
                 }
                 else if (buffer.loadedObservable) {
                     buffer.loadedObservable.add(function (buffer) {
                         onSuccess(buffer.loadedData);
-                        _this.removePendingData(buffer);
+                        _this._removePendingData(buffer);
                     });
                 }
                 else {
                     buffer.loadedObservable = new BABYLON.Observable();
                     buffer.loadedObservable.add(function (buffer) {
                         onSuccess(buffer.loadedData);
-                        _this.removePendingData(buffer);
+                        _this._removePendingData(buffer);
                     });
                     BABYLON.Tools.LoadFile(this._rootUrl + buffer.uri, function (data) {
                         buffer.loadedData = new Uint8Array(data);
@@ -76288,7 +76290,7 @@ var BABYLON;
                     }, this._babylonScene.database, true, function (request) {
                         if (!_this._disposed) {
                             _this._onError("Failed to load file '" + buffer.uri + "': " + request.status + " " + request.statusText);
-                            _this.removePendingData(buffer);
+                            _this._removePendingData(buffer);
                         }
                     });
                 }
@@ -76417,54 +76419,42 @@ var BABYLON;
                         return 0;
                 }
             };
-            Object.defineProperty(GLTFLoader.prototype, "blockPendingTracking", {
-                set: function (value) {
-                    this._blockPendingTracking = value;
-                },
-                enumerable: true,
-                configurable: true
-            });
-            GLTFLoader.prototype.addPendingData = function (data) {
+            GLTFLoader.prototype._addPendingData = function (data) {
                 if (!this._renderReady) {
                     this._renderPendingCount++;
                 }
-                this.addLoaderPendingData(data);
+                this._addLoaderPendingData(data);
             };
-            GLTFLoader.prototype.removePendingData = function (data) {
+            GLTFLoader.prototype._removePendingData = function (data) {
                 if (!this._renderReady) {
                     if (--this._renderPendingCount === 0) {
                         this._renderReady = true;
                         this._onRenderReady();
                     }
                 }
-                this.removeLoaderPendingData(data);
-            };
-            GLTFLoader.prototype.addLoaderNonBlockingPendingData = function (data) {
-                if (!this._nonBlockingData) {
-                    this._nonBlockingData = new Array();
-                }
-                this._nonBlockingData.push(data);
+                this._removeLoaderPendingData(data);
             };
-            GLTFLoader.prototype.addLoaderPendingData = function (data) {
-                if (this._blockPendingTracking) {
-                    this.addLoaderNonBlockingPendingData(data);
-                    return;
-                }
+            GLTFLoader.prototype._addLoaderPendingData = function (data) {
                 this._loaderPendingCount++;
+                this._loaderTrackers.forEach(function (tracker) { return tracker._addPendingData(data); });
             };
-            GLTFLoader.prototype.removeLoaderPendingData = function (data) {
-                var indexInPending = this._nonBlockingData ? this._nonBlockingData.indexOf(data) : -1;
-                if (indexInPending !== -1) {
-                    this._nonBlockingData.splice(indexInPending, 1);
-                }
-                else if (--this._loaderPendingCount === 0) {
-                    this._onLoaderFirstLODComplete();
-                }
-                if ((!this._nonBlockingData || this._nonBlockingData.length === 0) && this._loaderPendingCount === 0) {
-                    this._onLoaderComplete();
-                    this.dispose();
+            GLTFLoader.prototype._removeLoaderPendingData = function (data) {
+                this._loaderTrackers.forEach(function (tracker) { return tracker._removePendingData(data); });
+                if (--this._loaderPendingCount === 0) {
+                    this._onComplete();
                 }
             };
+            GLTFLoader.prototype._whenAction = function (action, onComplete) {
+                var _this = this;
+                var tracker = new GLTFLoaderTracker(function () {
+                    _this._loaderTrackers.splice(_this._loaderTrackers.indexOf(tracker));
+                    onComplete();
+                });
+                this._loaderTrackers.push(tracker);
+                this._addLoaderPendingData(tracker);
+                action();
+                this._removeLoaderPendingData(tracker);
+            };
             GLTFLoader.prototype._getDefaultMaterial = function () {
                 if (!this._defaultMaterial) {
                     var id = "__gltf_default";
@@ -76492,17 +76482,17 @@ var BABYLON;
                 babylonMaterial.metallic = properties.metallicFactor === undefined ? 1 : properties.metallicFactor;
                 babylonMaterial.roughness = properties.roughnessFactor === undefined ? 1 : properties.roughnessFactor;
                 if (properties.baseColorTexture) {
-                    babylonMaterial.albedoTexture = this.loadTexture(properties.baseColorTexture);
+                    babylonMaterial.albedoTexture = this._loadTexture(properties.baseColorTexture);
                 }
                 if (properties.metallicRoughnessTexture) {
-                    babylonMaterial.metallicTexture = this.loadTexture(properties.metallicRoughnessTexture);
+                    babylonMaterial.metallicTexture = this._loadTexture(properties.metallicRoughnessTexture);
                     babylonMaterial.useMetallnessFromMetallicTextureBlue = true;
                     babylonMaterial.useRoughnessFromMetallicTextureGreen = true;
                     babylonMaterial.useRoughnessFromMetallicTextureAlpha = false;
                 }
-                this.loadMaterialAlphaProperties(material, properties.baseColorFactor);
+                this._loadMaterialAlphaProperties(material, properties.baseColorFactor);
             };
-            GLTFLoader.prototype.loadMaterial = function (material, assign) {
+            GLTFLoader.prototype._loadMaterial = function (material, assign) {
                 if (material.babylonMaterial) {
                     assign(material.babylonMaterial, false);
                     return;
@@ -76510,17 +76500,17 @@ var BABYLON;
                 if (GLTF2.GLTFLoaderExtension.LoadMaterial(this, material, assign)) {
                     return;
                 }
-                this.createPbrMaterial(material);
-                this.loadMaterialBaseProperties(material);
+                this._createPbrMaterial(material);
+                this._loadMaterialBaseProperties(material);
                 this._loadMaterialMetallicRoughnessProperties(material);
                 assign(material.babylonMaterial, true);
             };
-            GLTFLoader.prototype.createPbrMaterial = function (material) {
+            GLTFLoader.prototype._createPbrMaterial = function (material) {
                 var babylonMaterial = new BABYLON.PBRMaterial(material.name || "mat" + material.index, this._babylonScene);
                 babylonMaterial.sideOrientation = BABYLON.Material.CounterClockWiseSideOrientation;
                 material.babylonMaterial = babylonMaterial;
             };
-            GLTFLoader.prototype.loadMaterialBaseProperties = function (material) {
+            GLTFLoader.prototype._loadMaterialBaseProperties = function (material) {
                 var babylonMaterial = material.babylonMaterial;
                 babylonMaterial.emissiveColor = material.emissiveFactor ? BABYLON.Color3.FromArray(material.emissiveFactor) : new BABYLON.Color3(0, 0, 0);
                 if (material.doubleSided) {
@@ -76528,7 +76518,7 @@ var BABYLON;
                     babylonMaterial.twoSidedLighting = true;
                 }
                 if (material.normalTexture) {
-                    babylonMaterial.bumpTexture = this.loadTexture(material.normalTexture);
+                    babylonMaterial.bumpTexture = this._loadTexture(material.normalTexture);
                     babylonMaterial.invertNormalMapX = !this._babylonScene.useRightHandedSystem;
                     babylonMaterial.invertNormalMapY = this._babylonScene.useRightHandedSystem;
                     if (material.normalTexture.scale !== undefined) {
@@ -76536,17 +76526,17 @@ var BABYLON;
                     }
                 }
                 if (material.occlusionTexture) {
-                    babylonMaterial.ambientTexture = this.loadTexture(material.occlusionTexture);
+                    babylonMaterial.ambientTexture = this._loadTexture(material.occlusionTexture);
                     babylonMaterial.useAmbientInGrayScale = true;
                     if (material.occlusionTexture.strength !== undefined) {
                         babylonMaterial.ambientTextureStrength = material.occlusionTexture.strength;
                     }
                 }
                 if (material.emissiveTexture) {
-                    babylonMaterial.emissiveTexture = this.loadTexture(material.emissiveTexture);
+                    babylonMaterial.emissiveTexture = this._loadTexture(material.emissiveTexture);
                 }
             };
-            GLTFLoader.prototype.loadMaterialAlphaProperties = function (material, colorFactor) {
+            GLTFLoader.prototype._loadMaterialAlphaProperties = function (material, colorFactor) {
                 var babylonMaterial = material.babylonMaterial;
                 var alphaMode = material.alphaMode || "OPAQUE";
                 switch (alphaMode) {
@@ -76569,7 +76559,7 @@ var BABYLON;
                 }
                 babylonMaterial.alphaCutOff = material.alphaCutoff === undefined ? 0.5 : material.alphaCutoff;
             };
-            GLTFLoader.prototype.loadTexture = function (textureInfo) {
+            GLTFLoader.prototype._loadTexture = function (textureInfo) {
                 var _this = this;
                 var texture = this._gltf.textures[textureInfo.index];
                 var texCoord = textureInfo.texCoord || 0;
@@ -76580,15 +76570,15 @@ var BABYLON;
                 var sampler = (texture.sampler === undefined ? {} : this._gltf.samplers[texture.sampler]);
                 var noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
                 var samplingMode = GLTF2.GLTFUtils.GetTextureSamplingMode(sampler.magFilter, sampler.minFilter);
-                this.addPendingData(texture);
+                this._addPendingData(texture);
                 var babylonTexture = new BABYLON.Texture(null, this._babylonScene, noMipMaps, false, samplingMode, function () {
                     if (!_this._disposed) {
-                        _this.removePendingData(texture);
+                        _this._removePendingData(texture);
                     }
                 }, function () {
                     if (!_this._disposed) {
                         _this._onError("Failed to load texture '" + source.uri + "'");
-                        _this.removePendingData(texture);
+                        _this._removePendingData(texture);
                     }
                 });
                 if (texture.url) {
@@ -76755,9 +76745,34 @@ var BABYLON;
             function GLTFLoaderExtension() {
                 this.enabled = true;
             }
-            GLTFLoaderExtension.prototype.loadMaterial = function (loader, material, assign) { return false; };
+            GLTFLoaderExtension.prototype._traverseNode = function (loader, index, action, parentNode) { return false; };
+            GLTFLoaderExtension.prototype._loadNode = function (loader, node) { return false; };
+            GLTFLoaderExtension.prototype._loadMaterial = function (loader, material, assign) { return false; };
+            GLTFLoaderExtension.prototype._loadExtension = function (property, action) {
+                var _this = this;
+                if (!property.extensions) {
+                    return false;
+                }
+                var extension = property.extensions[this.name];
+                if (!extension) {
+                    return false;
+                }
+                // Clear out the extension before executing the action to avoid recursing into the same property.
+                property.extensions[this.name] = undefined;
+                action(extension, function () {
+                    // Restore the extension after completing the action.
+                    property.extensions[_this.name] = extension;
+                });
+                return true;
+            };
+            GLTFLoaderExtension.TraverseNode = function (loader, index, action, parentNode) {
+                return this._ApplyExtensions(function (extension) { return extension._traverseNode(loader, index, action, parentNode); });
+            };
+            GLTFLoaderExtension.LoadNode = function (loader, node) {
+                return this._ApplyExtensions(function (extension) { return extension._loadNode(loader, node); });
+            };
             GLTFLoaderExtension.LoadMaterial = function (loader, material, assign) {
-                return this._ApplyExtensions(function (extension) { return extension.loadMaterial(loader, material, assign); });
+                return this._ApplyExtensions(function (extension) { return extension._loadMaterial(loader, material, assign); });
             };
             GLTFLoaderExtension._ApplyExtensions = function (action) {
                 var extensions = GLTFLoaderExtension._Extensions;
@@ -76792,6 +76807,7 @@ var BABYLON;
     (function (GLTF2) {
         var Extensions;
         (function (Extensions) {
+            // See https://github.com/sbtron/glTF/tree/MSFT_lod/extensions/Vendor/MSFT_lod for more information about this extension.
             var MSFTLOD = (function (_super) {
                 __extends(MSFTLOD, _super);
                 function MSFTLOD() {
@@ -76804,49 +76820,71 @@ var BABYLON;
                     enumerable: true,
                     configurable: true
                 });
-                MSFTLOD.prototype.loadMaterial = function (loader, material, assign) {
-                    if (!material.extensions) {
-                        return false;
-                    }
-                    var properties = material.extensions[this.name];
-                    if (!properties) {
-                        return false;
-                    }
-                    // Clear out the extension so that it won't get loaded again.
-                    material.extensions[this.name] = undefined;
-                    // Tell the loader not to clear its state until the highest LOD is loaded.
-                    var materialLODs = [material.index].concat(properties.ids);
-                    loader.addLoaderPendingData(material);
-                    for (var index = 0; index < materialLODs.length; index++) {
-                        loader.addLoaderNonBlockingPendingData(index);
-                    }
-                    // Start with the lowest quality LOD.
-                    this.loadMaterialLOD(loader, material, materialLODs, materialLODs.length - 1, assign);
-                    return true;
+                MSFTLOD.prototype._traverseNode = function (loader, index, action, parentNode) {
+                    var node = loader._gltf.nodes[index];
+                    return this._loadExtension(node, function (extension, onComplete) {
+                        for (var i = extension.ids.length - 1; i >= 0; i--) {
+                            loader._traverseNode(extension.ids[i], action, parentNode);
+                        }
+                        loader._traverseNode(index, action, parentNode);
+                        onComplete();
+                    });
                 };
-                MSFTLOD.prototype.loadMaterialLOD = function (loader, material, materialLODs, lod, assign) {
+                MSFTLOD.prototype._loadNode = function (loader, node) {
                     var _this = this;
-                    var materialLOD = loader.gltf.materials[materialLODs[lod]];
-                    if (lod !== materialLODs.length - 1) {
-                        loader.blockPendingTracking = true;
-                    }
-                    loader.loadMaterial(materialLOD, function (babylonMaterial, isNew) {
-                        assign(babylonMaterial, isNew);
-                        loader.removeLoaderPendingData(lod);
-                        // Loading is considered complete if this is the lowest quality LOD.
-                        if (lod === materialLODs.length - 1) {
-                            loader.removeLoaderPendingData(material);
+                    return this._loadExtension(node, function (extension, onComplete) {
+                        var nodes = [node.index].concat(extension.ids).map(function (index) { return loader._gltf.nodes[index]; });
+                        loader._addLoaderPendingData(node);
+                        _this._loadNodeLOD(loader, nodes, nodes.length - 1, function () {
+                            loader._removeLoaderPendingData(node);
+                            onComplete();
+                        });
+                    });
+                };
+                MSFTLOD.prototype._loadNodeLOD = function (loader, nodes, index, onComplete) {
+                    var _this = this;
+                    loader._whenAction(function () {
+                        loader._loadNode(nodes[index]);
+                    }, function () {
+                        if (index !== nodes.length - 1) {
+                            var previousNode = nodes[index + 1];
+                            previousNode.babylonMesh.setEnabled(false);
                         }
-                        if (lod === 0) {
-                            loader.blockPendingTracking = false;
+                        if (index === 0) {
+                            onComplete();
+                            return;
+                        }
+                        setTimeout(function () {
+                            _this._loadNodeLOD(loader, nodes, index - 1, onComplete);
+                        }, MSFTLOD.MinimalLODDelay);
+                    });
+                };
+                MSFTLOD.prototype._loadMaterial = function (loader, material, assign) {
+                    var _this = this;
+                    return this._loadExtension(material, function (extension, onComplete) {
+                        var materials = [material.index].concat(extension.ids).map(function (index) { return loader._gltf.materials[index]; });
+                        loader._addLoaderPendingData(material);
+                        _this._loadMaterialLOD(loader, materials, materials.length - 1, assign, function () {
+                            material.extensions[_this.name] = extension;
+                            loader._removeLoaderPendingData(material);
+                            onComplete();
+                        });
+                    });
+                };
+                MSFTLOD.prototype._loadMaterialLOD = function (loader, materials, index, assign, onComplete) {
+                    var _this = this;
+                    loader._loadMaterial(materials[index], function (babylonMaterial, isNew) {
+                        assign(babylonMaterial, isNew);
+                        if (index === 0) {
+                            onComplete();
                             return;
                         }
                         // Load the next LOD when the loader is ready to render and
                         // all active material textures of the current LOD are loaded.
-                        loader.executeWhenRenderReady(function () {
+                        loader._executeWhenRenderReady(function () {
                             BABYLON.BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), function () {
                                 setTimeout(function () {
-                                    _this.loadMaterialLOD(loader, material, materialLODs, lod - 1, assign);
+                                    _this._loadMaterialLOD(loader, materials, index - 1, assign, onComplete);
                                 }, MSFTLOD.MinimalLODDelay);
                             });
                         });
@@ -76886,19 +76924,14 @@ var BABYLON;
                     enumerable: true,
                     configurable: true
                 });
-                KHRMaterialsPbrSpecularGlossiness.prototype.loadMaterial = function (loader, material, assign) {
-                    if (!material.extensions) {
-                        return false;
-                    }
-                    var properties = material.extensions[this.name];
-                    if (!properties) {
-                        return false;
-                    }
-                    loader.createPbrMaterial(material);
-                    loader.loadMaterialBaseProperties(material);
-                    this._loadSpecularGlossinessProperties(loader, material, properties);
-                    assign(material.babylonMaterial, true);
-                    return true;
+                KHRMaterialsPbrSpecularGlossiness.prototype._loadMaterial = function (loader, material, assign) {
+                    var _this = this;
+                    return this._loadExtension(material, function (extension, onComplete) {
+                        loader._createPbrMaterial(material);
+                        loader._loadMaterialBaseProperties(material);
+                        _this._loadSpecularGlossinessProperties(loader, material, extension);
+                        assign(material.babylonMaterial, true);
+                    });
                 };
                 KHRMaterialsPbrSpecularGlossiness.prototype._loadSpecularGlossinessProperties = function (loader, material, properties) {
                     var babylonMaterial = material.babylonMaterial;
@@ -76906,14 +76939,14 @@ var BABYLON;
                     babylonMaterial.reflectivityColor = properties.specularFactor ? BABYLON.Color3.FromArray(properties.specularFactor) : new BABYLON.Color3(1, 1, 1);
                     babylonMaterial.microSurface = properties.glossinessFactor === undefined ? 1 : properties.glossinessFactor;
                     if (properties.diffuseTexture) {
-                        babylonMaterial.albedoTexture = loader.loadTexture(properties.diffuseTexture);
+                        babylonMaterial.albedoTexture = loader._loadTexture(properties.diffuseTexture);
                     }
                     if (properties.specularGlossinessTexture) {
-                        babylonMaterial.reflectivityTexture = loader.loadTexture(properties.specularGlossinessTexture);
+                        babylonMaterial.reflectivityTexture = loader._loadTexture(properties.specularGlossinessTexture);
                         babylonMaterial.reflectivityTexture.hasAlpha = true;
                         babylonMaterial.useMicroSurfaceFromReflectivityMapAlpha = true;
                     }
-                    loader.loadMaterialAlphaProperties(material, properties.diffuseFactor);
+                    loader._loadMaterialAlphaProperties(material, properties.diffuseFactor);
                 };
                 return KHRMaterialsPbrSpecularGlossiness;
             }(GLTF2.GLTFLoaderExtension));

文件差异内容过多而无法显示
+ 4234 - 4234
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts


文件差异内容过多而无法显示
+ 3 - 3
dist/preview release/gui/babylon.gui.min.js


文件差异内容过多而无法显示
+ 263 - 263
dist/preview release/inspector/babylon.inspector.bundle.js


文件差异内容过多而无法显示
+ 3 - 3
dist/preview release/inspector/babylon.inspector.min.js


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

@@ -27,13 +27,17 @@ declare module BABYLON {
          */
         onBeforeMaterialReadyAsync: (material: Material, targetMesh: AbstractMesh, isLOD: boolean, callback: () => void) => void;
         /**
-         * Raised when all LODs are complete (or if there is no LOD and model is complete)
+         * Raised when the visible components (geometry, materials, textures, etc.) are first ready to be rendered.
+         * For assets with LODs, raised when the first LOD is complete.
+         * For assets without LODs, raised when the model is complete just before onComplete.
          */
-        onComplete: () => void;
+        onReady: () => void;
         /**
-         * Raised when first LOD complete (or if there is no LOD and model is complete)
+         * Raised when the asset is completely loaded, just before the loader is disposed.
+         * For assets with LODs, raised when all of the LODs are complete.
+         * For assets without LODs, raised when the model is complete just after onReady.
          */
-        onFirstLODComplete: () => void;
+        onComplete: () => void;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;

文件差异内容过多而无法显示
+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


+ 37 - 33
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -27,13 +27,17 @@ declare module BABYLON {
          */
         onBeforeMaterialReadyAsync: (material: Material, targetMesh: AbstractMesh, isLOD: boolean, callback: () => void) => void;
         /**
-         * Raised when all LODs are complete (or if there is no LOD and model is complete)
+         * Raised when the visible components (geometry, materials, textures, etc.) are first ready to be rendered.
+         * For assets with LODs, raised when the first LOD is complete.
+         * For assets without LODs, raised when the model is complete just before onComplete.
          */
-        onComplete: () => void;
+        onReady: () => void;
         /**
-         * Raised when first LOD complete (or if there is no LOD and model is complete)
+         * Raised when the asset is completely loaded, just before the loader is disposed.
+         * For assets with LODs, raised when all of the LODs are complete.
+         * For assets without LODs, raised when the model is complete just after onReady.
          */
-        onFirstLODComplete: () => void;
+        onComplete: () => void;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
@@ -290,9 +294,9 @@ declare module BABYLON.GLTF2 {
 
 declare module BABYLON.GLTF2 {
     class GLTFLoader implements IGLTFLoader, IDisposable {
+        _gltf: IGLTF;
+        _babylonScene: Scene;
         private _parent;
-        private _gltf;
-        private _babylonScene;
         private _rootUrl;
         private _defaultMaterial;
         private _successCallback;
@@ -300,19 +304,14 @@ declare module BABYLON.GLTF2 {
         private _errorCallback;
         private _renderReady;
         private _disposed;
-        private _blockPendingTracking;
-        private _nonBlockingData;
-        private _rootMesh;
         private _renderReadyObservable;
         private _renderPendingCount;
         private _loaderPendingCount;
+        private _loaderTrackers;
         static Extensions: {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
-        readonly gltf: IGLTF;
-        readonly babylonScene: Scene;
-        executeWhenRenderReady(func: () => void): void;
         constructor(parent: GLTFFileLoader);
         dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
@@ -320,18 +319,16 @@ declare module BABYLON.GLTF2 {
         private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess, onProgress, onError);
         private _onError(message);
         private _onProgress(event);
+        _executeWhenRenderReady(func: () => void): void;
         private _onRenderReady();
-        private _onLoaderComplete();
-        private _onLoaderFirstLODComplete();
+        private _onComplete();
         private _loadData(data);
-        private _addRightHandToLeftHandRootTransform();
         private _getMeshes();
         private _getSkeletons();
         private _getAnimationTargets();
-        private _showMeshes();
         private _startAnimations();
         private _loadScene(nodeNames);
-        private _loadNode(node);
+        _loadNode(node: IGLTFNode): void;
         private _loadMesh(node, mesh);
         private _loadVertexDataAsync(primitive, onSuccess);
         private _createMorphTargets(node, mesh, primitive, babylonMesh);
@@ -343,7 +340,7 @@ declare module BABYLON.GLTF2 {
         private _loadBone(node, skin, inverseBindMatrixData, babylonBones);
         private _getNodeMatrix(node);
         private _traverseNodes(indices, action, parentNode?);
-        private _traverseNode(index, action, parentNode?);
+        _traverseNode(index: number, action: (node: IGLTFNode, index: number, parentNode: IGLTFNode) => boolean, parentNode?: IGLTFNode): void;
         private _loadAnimations();
         private _loadAnimationChannel(animation, animationIndex, channelIndex);
         private _loadBufferAsync(index, onSuccess);
@@ -357,19 +354,18 @@ declare module BABYLON.GLTF2 {
         private _loadBufferViewAsync(bufferView, byteOffset, byteLength, bytePerComponent, componentType, onSuccess);
         private _loadAccessorAsync(accessor, onSuccess);
         private _getByteStrideFromType(accessor);
-        blockPendingTracking: boolean;
-        addPendingData(data: any): void;
-        removePendingData(data: any): void;
-        addLoaderNonBlockingPendingData(data: any): void;
-        addLoaderPendingData(data: any): void;
-        removeLoaderPendingData(data: any): void;
+        _addPendingData(data: any): void;
+        _removePendingData(data: any): void;
+        _addLoaderPendingData(data: any): void;
+        _removeLoaderPendingData(data: any): void;
+        _whenAction(action: () => void, onComplete: () => void): void;
         private _getDefaultMaterial();
         private _loadMaterialMetallicRoughnessProperties(material);
-        loadMaterial(material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): void;
-        createPbrMaterial(material: IGLTFMaterial): void;
-        loadMaterialBaseProperties(material: IGLTFMaterial): void;
-        loadMaterialAlphaProperties(material: IGLTFMaterial, colorFactor?: number[]): void;
-        loadTexture(textureInfo: IGLTFTextureInfo): Texture;
+        _loadMaterial(material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): void;
+        _createPbrMaterial(material: IGLTFMaterial): void;
+        _loadMaterialBaseProperties(material: IGLTFMaterial): void;
+        _loadMaterialAlphaProperties(material: IGLTFMaterial, colorFactor?: number[]): void;
+        _loadTexture(textureInfo: IGLTFTextureInfo): Texture;
     }
 }
 
@@ -405,8 +401,13 @@ declare module BABYLON.GLTF2 {
     abstract class GLTFLoaderExtension {
         enabled: boolean;
         readonly abstract name: string;
-        protected loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
+        protected _traverseNode(loader: GLTFLoader, index: number, action: (node: IGLTFNode, index: number, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
+        protected _loadNode(loader: GLTFLoader, node: IGLTFNode): boolean;
+        protected _loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
+        protected _loadExtension<T>(property: IGLTFProperty, action: (extension: T, onComplete: () => void) => void): boolean;
         static _Extensions: GLTFLoaderExtension[];
+        static TraverseNode(loader: GLTFLoader, index: number, action: (node: IGLTFNode, index: number, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
+        static LoadNode(loader: GLTFLoader, node: IGLTFNode): boolean;
         static LoadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         private static _ApplyExtensions(action);
     }
@@ -420,8 +421,11 @@ declare module BABYLON.GLTF2.Extensions {
          */
         static MinimalLODDelay: number;
         readonly name: string;
-        protected loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private loadMaterialLOD(loader, material, materialLODs, lod, assign);
+        protected _traverseNode(loader: GLTFLoader, index: number, action: (node: IGLTFNode, index: number, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
+        protected _loadNode(loader: GLTFLoader, node: IGLTFNode): boolean;
+        private _loadNodeLOD(loader, nodes, index, onComplete);
+        protected _loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
+        private _loadMaterialLOD(loader, materials, index, assign, onComplete);
     }
 }
 
@@ -429,7 +433,7 @@ declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
     class KHRMaterialsPbrSpecularGlossiness extends GLTFLoaderExtension {
         readonly name: string;
-        protected loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
+        protected _loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         private _loadSpecularGlossinessProperties(loader, material, properties);
     }
 }

+ 234 - 207
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -320,17 +320,31 @@ var BABYLON;
 (function (BABYLON) {
     var GLTF2;
     (function (GLTF2) {
+        var GLTFLoaderTracker = (function () {
+            function GLTFLoaderTracker(onComplete) {
+                this._pendingCount = 0;
+                this._callback = onComplete;
+            }
+            GLTFLoaderTracker.prototype._addPendingData = function (data) {
+                this._pendingCount++;
+            };
+            GLTFLoaderTracker.prototype._removePendingData = function (data) {
+                if (--this._pendingCount === 0) {
+                    this._callback();
+                }
+            };
+            return GLTFLoaderTracker;
+        }());
         var GLTFLoader = (function () {
             function GLTFLoader(parent) {
                 this._renderReady = false;
                 this._disposed = false;
-                this._blockPendingTracking = false;
-                // Observable with boolean indicating success or error.
                 this._renderReadyObservable = new BABYLON.Observable();
                 // Count of pending work that needs to complete before the asset is rendered.
                 this._renderPendingCount = 0;
-                // Count of pending work that needs to complete before the loader is cleared.
+                // Count of pending work that needs to complete before the loader is disposed.
                 this._loaderPendingCount = 0;
+                this._loaderTrackers = new Array();
                 this._parent = parent;
             }
             GLTFLoader.RegisterExtension = function (extension) {
@@ -342,28 +356,6 @@ var BABYLON;
                 // Keep the order of registration so that extensions registered first are called first.
                 GLTF2.GLTFLoaderExtension._Extensions.push(extension);
             };
-            Object.defineProperty(GLTFLoader.prototype, "gltf", {
-                get: function () {
-                    return this._gltf;
-                },
-                enumerable: true,
-                configurable: true
-            });
-            Object.defineProperty(GLTFLoader.prototype, "babylonScene", {
-                get: function () {
-                    return this._babylonScene;
-                },
-                enumerable: true,
-                configurable: true
-            });
-            GLTFLoader.prototype.executeWhenRenderReady = function (func) {
-                if (this._renderReady) {
-                    func();
-                }
-                else {
-                    this._renderReadyObservable.add(func);
-                }
-            };
             GLTFLoader.prototype.dispose = function () {
                 if (this._disposed) {
                     return;
@@ -404,10 +396,10 @@ var BABYLON;
                 this._successCallback = onSuccess;
                 this._progressCallback = onProgress;
                 this._errorCallback = onError;
-                this.addPendingData(this);
+                this._addPendingData(this);
                 this._loadScene(nodeNames);
                 this._loadAnimations();
-                this.removePendingData(this);
+                this._removePendingData(this);
             };
             GLTFLoader.prototype._onError = function (message) {
                 if (this._errorCallback) {
@@ -416,39 +408,33 @@ var BABYLON;
                 this.dispose();
             };
             GLTFLoader.prototype._onProgress = function (event) {
-                this._progressCallback(event);
+                if (this._progressCallback) {
+                    this._progressCallback(event);
+                }
             };
-            GLTFLoader.prototype._onRenderReady = function () {
-                switch (this._parent.coordinateSystemMode) {
-                    case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO:
-                        if (!this._babylonScene.useRightHandedSystem) {
-                            this._addRightHandToLeftHandRootTransform();
-                        }
-                        break;
-                    case BABYLON.GLTFLoaderCoordinateSystemMode.PASS_THROUGH:
-                        // do nothing
-                        break;
-                    case BABYLON.GLTFLoaderCoordinateSystemMode.FORCE_RIGHT_HANDED:
-                        this._babylonScene.useRightHandedSystem = true;
-                        break;
-                    default:
-                        BABYLON.Tools.Error("Invalid coordinate system mode (" + this._parent.coordinateSystemMode + ")");
-                        break;
+            GLTFLoader.prototype._executeWhenRenderReady = function (func) {
+                if (this._renderReady) {
+                    func();
                 }
-                this._showMeshes();
+                else {
+                    this._renderReadyObservable.add(func);
+                }
+            };
+            GLTFLoader.prototype._onRenderReady = function () {
+                var rootNode = this._gltf.nodes[this._gltf.nodes.length - 1];
+                rootNode.babylonMesh.setEnabled(true);
                 this._startAnimations();
                 this._successCallback();
                 this._renderReadyObservable.notifyObservers(this);
+                if (this._parent.onReady) {
+                    this._parent.onReady();
+                }
             };
-            GLTFLoader.prototype._onLoaderComplete = function () {
+            GLTFLoader.prototype._onComplete = function () {
                 if (this._parent.onComplete) {
                     this._parent.onComplete();
                 }
-            };
-            GLTFLoader.prototype._onLoaderFirstLODComplete = function () {
-                if (this._parent.onFirstLODComplete) {
-                    this._parent.onFirstLODComplete();
-                }
+                this.dispose();
             };
             GLTFLoader.prototype._loadData = function (data) {
                 this._gltf = data.json;
@@ -469,26 +455,8 @@ var BABYLON;
                     binaryBuffer.loadedData = data.bin;
                 }
             };
-            GLTFLoader.prototype._addRightHandToLeftHandRootTransform = function () {
-                this._rootMesh = new BABYLON.Mesh("root", this._babylonScene);
-                this._rootMesh.isVisible = false;
-                this._rootMesh.scaling = new BABYLON.Vector3(1, 1, -1);
-                this._rootMesh.rotation.y = Math.PI;
-                var nodes = this._gltf.nodes;
-                if (nodes) {
-                    for (var i = 0; i < nodes.length; i++) {
-                        var mesh = nodes[i].babylonMesh;
-                        if (mesh && !mesh.parent) {
-                            mesh.parent = this._rootMesh;
-                        }
-                    }
-                }
-            };
             GLTFLoader.prototype._getMeshes = function () {
                 var meshes = [];
-                if (this._rootMesh) {
-                    meshes.push(this._rootMesh);
-                }
                 var nodes = this._gltf.nodes;
                 if (nodes) {
                     nodes.forEach(function (node) {
@@ -521,16 +489,34 @@ var BABYLON;
                 }
                 return targets;
             };
-            GLTFLoader.prototype._showMeshes = function () {
-                this._getMeshes().forEach(function (mesh) { return mesh.isVisible = true; });
-            };
             GLTFLoader.prototype._startAnimations = function () {
                 var _this = this;
                 this._getAnimationTargets().forEach(function (target) { return _this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true); });
             };
             GLTFLoader.prototype._loadScene = function (nodeNames) {
-                var _this = this;
                 var scene = this._gltf.scenes[this._gltf.scene || 0];
+                var rootNode = { name: "root", children: scene.nodes };
+                switch (this._parent.coordinateSystemMode) {
+                    case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO:
+                        if (!this._babylonScene.useRightHandedSystem) {
+                            rootNode.rotation = [0, 1, 0, 0];
+                            rootNode.scale = [1, 1, -1];
+                        }
+                        break;
+                    case BABYLON.GLTFLoaderCoordinateSystemMode.PASS_THROUGH:
+                        // do nothing
+                        break;
+                    case BABYLON.GLTFLoaderCoordinateSystemMode.FORCE_RIGHT_HANDED:
+                        this._babylonScene.useRightHandedSystem = true;
+                        break;
+                    default:
+                        BABYLON.Tools.Error("Invalid coordinate system mode (" + this._parent.coordinateSystemMode + ")");
+                        break;
+                }
+                // Inject a root node into the scene.
+                this._gltf.nodes = this._gltf.nodes || [];
+                scene.nodes = [this._gltf.nodes.length];
+                this._gltf.nodes.push(rootNode);
                 var nodeIndices = scene.nodes;
                 this._traverseNodes(nodeIndices, function (node, index, parentNode) {
                     node.index = index;
@@ -547,19 +533,25 @@ var BABYLON;
                     }
                     var filteredNodeIndices = new Array();
                     this._traverseNodes(nodeIndices, function (node) {
-                        if (nodeNames.indexOf(node.name) === -1) {
-                            return true;
+                        if (nodeNames.indexOf(node.name) !== -1) {
+                            filteredNodeIndices.push(node.index);
+                            return false;
                         }
-                        filteredNodeIndices.push(node.index);
-                        return false;
+                        return true;
                     });
                     nodeIndices = filteredNodeIndices;
                 }
-                this._traverseNodes(nodeIndices, function (node) { return _this._loadNode(node); });
+                for (var i = 0; i < nodeIndices.length; i++) {
+                    this._loadNode(this._gltf.nodes[nodeIndices[i]]);
+                }
+                // Disable the root mesh until the asset is ready to render.
+                rootNode.babylonMesh.setEnabled(false);
             };
             GLTFLoader.prototype._loadNode = function (node) {
+                if (GLTF2.GLTFLoaderExtension.LoadNode(this, node)) {
+                    return;
+                }
                 node.babylonMesh = new BABYLON.Mesh(node.name || "mesh" + node.index, this._babylonScene);
-                node.babylonMesh.isVisible = false;
                 this._loadTransform(node);
                 if (node.mesh !== undefined) {
                     var mesh = this._gltf.meshes[node.mesh];
@@ -576,7 +568,11 @@ var BABYLON;
                 if (node.camera !== undefined) {
                     // TODO: handle cameras
                 }
-                return true;
+                if (node.children) {
+                    for (var i = 0; i < node.children.length; i++) {
+                        this._loadNode(this._gltf.nodes[node.children[i]]);
+                    }
+                }
             };
             GLTFLoader.prototype._loadMesh = function (node, mesh) {
                 var _this = this;
@@ -608,25 +604,24 @@ var BABYLON;
                             loadMaterial: function () {
                                 if (primitive.material === undefined) {
                                     babylonMultiMaterial.subMaterials[i] = _this._getDefaultMaterial();
+                                    return;
                                 }
-                                else {
-                                    var material = _this._gltf.materials[primitive.material];
-                                    _this.loadMaterial(material, function (babylonMaterial, isNew) {
-                                        if (isNew && _this._parent.onMaterialLoaded) {
-                                            _this._parent.onMaterialLoaded(babylonMaterial);
-                                        }
-                                        if (_this._parent.onBeforeMaterialReadyAsync) {
-                                            _this.addLoaderPendingData(material);
-                                            _this._parent.onBeforeMaterialReadyAsync(babylonMaterial, node.babylonMesh, babylonMultiMaterial.subMaterials[i] != null, function () {
-                                                babylonMultiMaterial.subMaterials[i] = babylonMaterial;
-                                                _this.removeLoaderPendingData(material);
-                                            });
-                                        }
-                                        else {
+                                var material = _this._gltf.materials[primitive.material];
+                                _this._loadMaterial(material, function (babylonMaterial, isNew) {
+                                    if (isNew && _this._parent.onMaterialLoaded) {
+                                        _this._parent.onMaterialLoaded(babylonMaterial);
+                                    }
+                                    if (_this._parent.onBeforeMaterialReadyAsync) {
+                                        _this._addLoaderPendingData(material);
+                                        _this._parent.onBeforeMaterialReadyAsync(babylonMaterial, node.babylonMesh, babylonMultiMaterial.subMaterials[i] != null, function () {
                                             babylonMultiMaterial.subMaterials[i] = babylonMaterial;
-                                        }
-                                    });
-                                }
+                                            _this._removeLoaderPendingData(material);
+                                        });
+                                    }
+                                    else {
+                                        babylonMultiMaterial.subMaterials[i] = babylonMaterial;
+                                    }
+                                });
                             }
                         });
                         vertexData.merge(subVertexData);
@@ -857,14 +852,15 @@ var BABYLON;
             };
             GLTFLoader.prototype._traverseNode = function (index, action, parentNode) {
                 if (parentNode === void 0) { parentNode = null; }
+                if (GLTF2.GLTFLoaderExtension.TraverseNode(this, index, action, parentNode)) {
+                    return;
+                }
                 var node = this._gltf.nodes[index];
                 if (!action(node, index, parentNode)) {
                     return;
                 }
                 if (node.children) {
-                    for (var i = 0; i < node.children.length; i++) {
-                        this._traverseNode(node.children[i], action, node);
-                    }
+                    this._traverseNodes(node.children, action, node);
                 }
             };
             GLTFLoader.prototype._loadAnimations = function () {
@@ -992,11 +988,11 @@ var BABYLON;
             GLTFLoader.prototype._loadBufferAsync = function (index, onSuccess) {
                 var _this = this;
                 var buffer = this._gltf.buffers[index];
-                this.addPendingData(buffer);
+                this._addPendingData(buffer);
                 if (buffer.loadedData) {
                     setTimeout(function () {
                         onSuccess(buffer.loadedData);
-                        _this.removePendingData(buffer);
+                        _this._removePendingData(buffer);
                     });
                 }
                 else if (GLTF2.GLTFUtils.IsBase64(buffer.uri)) {
@@ -1004,20 +1000,20 @@ var BABYLON;
                     buffer.loadedData = new Uint8Array(data);
                     setTimeout(function () {
                         onSuccess(buffer.loadedData);
-                        _this.removePendingData(buffer);
+                        _this._removePendingData(buffer);
                     });
                 }
                 else if (buffer.loadedObservable) {
                     buffer.loadedObservable.add(function (buffer) {
                         onSuccess(buffer.loadedData);
-                        _this.removePendingData(buffer);
+                        _this._removePendingData(buffer);
                     });
                 }
                 else {
                     buffer.loadedObservable = new BABYLON.Observable();
                     buffer.loadedObservable.add(function (buffer) {
                         onSuccess(buffer.loadedData);
-                        _this.removePendingData(buffer);
+                        _this._removePendingData(buffer);
                     });
                     BABYLON.Tools.LoadFile(this._rootUrl + buffer.uri, function (data) {
                         buffer.loadedData = new Uint8Array(data);
@@ -1030,7 +1026,7 @@ var BABYLON;
                     }, this._babylonScene.database, true, function (request) {
                         if (!_this._disposed) {
                             _this._onError("Failed to load file '" + buffer.uri + "': " + request.status + " " + request.statusText);
-                            _this.removePendingData(buffer);
+                            _this._removePendingData(buffer);
                         }
                     });
                 }
@@ -1159,54 +1155,42 @@ var BABYLON;
                         return 0;
                 }
             };
-            Object.defineProperty(GLTFLoader.prototype, "blockPendingTracking", {
-                set: function (value) {
-                    this._blockPendingTracking = value;
-                },
-                enumerable: true,
-                configurable: true
-            });
-            GLTFLoader.prototype.addPendingData = function (data) {
+            GLTFLoader.prototype._addPendingData = function (data) {
                 if (!this._renderReady) {
                     this._renderPendingCount++;
                 }
-                this.addLoaderPendingData(data);
+                this._addLoaderPendingData(data);
             };
-            GLTFLoader.prototype.removePendingData = function (data) {
+            GLTFLoader.prototype._removePendingData = function (data) {
                 if (!this._renderReady) {
                     if (--this._renderPendingCount === 0) {
                         this._renderReady = true;
                         this._onRenderReady();
                     }
                 }
-                this.removeLoaderPendingData(data);
-            };
-            GLTFLoader.prototype.addLoaderNonBlockingPendingData = function (data) {
-                if (!this._nonBlockingData) {
-                    this._nonBlockingData = new Array();
-                }
-                this._nonBlockingData.push(data);
+                this._removeLoaderPendingData(data);
             };
-            GLTFLoader.prototype.addLoaderPendingData = function (data) {
-                if (this._blockPendingTracking) {
-                    this.addLoaderNonBlockingPendingData(data);
-                    return;
-                }
+            GLTFLoader.prototype._addLoaderPendingData = function (data) {
                 this._loaderPendingCount++;
+                this._loaderTrackers.forEach(function (tracker) { return tracker._addPendingData(data); });
             };
-            GLTFLoader.prototype.removeLoaderPendingData = function (data) {
-                var indexInPending = this._nonBlockingData ? this._nonBlockingData.indexOf(data) : -1;
-                if (indexInPending !== -1) {
-                    this._nonBlockingData.splice(indexInPending, 1);
-                }
-                else if (--this._loaderPendingCount === 0) {
-                    this._onLoaderFirstLODComplete();
-                }
-                if ((!this._nonBlockingData || this._nonBlockingData.length === 0) && this._loaderPendingCount === 0) {
-                    this._onLoaderComplete();
-                    this.dispose();
+            GLTFLoader.prototype._removeLoaderPendingData = function (data) {
+                this._loaderTrackers.forEach(function (tracker) { return tracker._removePendingData(data); });
+                if (--this._loaderPendingCount === 0) {
+                    this._onComplete();
                 }
             };
+            GLTFLoader.prototype._whenAction = function (action, onComplete) {
+                var _this = this;
+                var tracker = new GLTFLoaderTracker(function () {
+                    _this._loaderTrackers.splice(_this._loaderTrackers.indexOf(tracker));
+                    onComplete();
+                });
+                this._loaderTrackers.push(tracker);
+                this._addLoaderPendingData(tracker);
+                action();
+                this._removeLoaderPendingData(tracker);
+            };
             GLTFLoader.prototype._getDefaultMaterial = function () {
                 if (!this._defaultMaterial) {
                     var id = "__gltf_default";
@@ -1234,17 +1218,17 @@ var BABYLON;
                 babylonMaterial.metallic = properties.metallicFactor === undefined ? 1 : properties.metallicFactor;
                 babylonMaterial.roughness = properties.roughnessFactor === undefined ? 1 : properties.roughnessFactor;
                 if (properties.baseColorTexture) {
-                    babylonMaterial.albedoTexture = this.loadTexture(properties.baseColorTexture);
+                    babylonMaterial.albedoTexture = this._loadTexture(properties.baseColorTexture);
                 }
                 if (properties.metallicRoughnessTexture) {
-                    babylonMaterial.metallicTexture = this.loadTexture(properties.metallicRoughnessTexture);
+                    babylonMaterial.metallicTexture = this._loadTexture(properties.metallicRoughnessTexture);
                     babylonMaterial.useMetallnessFromMetallicTextureBlue = true;
                     babylonMaterial.useRoughnessFromMetallicTextureGreen = true;
                     babylonMaterial.useRoughnessFromMetallicTextureAlpha = false;
                 }
-                this.loadMaterialAlphaProperties(material, properties.baseColorFactor);
+                this._loadMaterialAlphaProperties(material, properties.baseColorFactor);
             };
-            GLTFLoader.prototype.loadMaterial = function (material, assign) {
+            GLTFLoader.prototype._loadMaterial = function (material, assign) {
                 if (material.babylonMaterial) {
                     assign(material.babylonMaterial, false);
                     return;
@@ -1252,17 +1236,17 @@ var BABYLON;
                 if (GLTF2.GLTFLoaderExtension.LoadMaterial(this, material, assign)) {
                     return;
                 }
-                this.createPbrMaterial(material);
-                this.loadMaterialBaseProperties(material);
+                this._createPbrMaterial(material);
+                this._loadMaterialBaseProperties(material);
                 this._loadMaterialMetallicRoughnessProperties(material);
                 assign(material.babylonMaterial, true);
             };
-            GLTFLoader.prototype.createPbrMaterial = function (material) {
+            GLTFLoader.prototype._createPbrMaterial = function (material) {
                 var babylonMaterial = new BABYLON.PBRMaterial(material.name || "mat" + material.index, this._babylonScene);
                 babylonMaterial.sideOrientation = BABYLON.Material.CounterClockWiseSideOrientation;
                 material.babylonMaterial = babylonMaterial;
             };
-            GLTFLoader.prototype.loadMaterialBaseProperties = function (material) {
+            GLTFLoader.prototype._loadMaterialBaseProperties = function (material) {
                 var babylonMaterial = material.babylonMaterial;
                 babylonMaterial.emissiveColor = material.emissiveFactor ? BABYLON.Color3.FromArray(material.emissiveFactor) : new BABYLON.Color3(0, 0, 0);
                 if (material.doubleSided) {
@@ -1270,7 +1254,7 @@ var BABYLON;
                     babylonMaterial.twoSidedLighting = true;
                 }
                 if (material.normalTexture) {
-                    babylonMaterial.bumpTexture = this.loadTexture(material.normalTexture);
+                    babylonMaterial.bumpTexture = this._loadTexture(material.normalTexture);
                     babylonMaterial.invertNormalMapX = !this._babylonScene.useRightHandedSystem;
                     babylonMaterial.invertNormalMapY = this._babylonScene.useRightHandedSystem;
                     if (material.normalTexture.scale !== undefined) {
@@ -1278,17 +1262,17 @@ var BABYLON;
                     }
                 }
                 if (material.occlusionTexture) {
-                    babylonMaterial.ambientTexture = this.loadTexture(material.occlusionTexture);
+                    babylonMaterial.ambientTexture = this._loadTexture(material.occlusionTexture);
                     babylonMaterial.useAmbientInGrayScale = true;
                     if (material.occlusionTexture.strength !== undefined) {
                         babylonMaterial.ambientTextureStrength = material.occlusionTexture.strength;
                     }
                 }
                 if (material.emissiveTexture) {
-                    babylonMaterial.emissiveTexture = this.loadTexture(material.emissiveTexture);
+                    babylonMaterial.emissiveTexture = this._loadTexture(material.emissiveTexture);
                 }
             };
-            GLTFLoader.prototype.loadMaterialAlphaProperties = function (material, colorFactor) {
+            GLTFLoader.prototype._loadMaterialAlphaProperties = function (material, colorFactor) {
                 var babylonMaterial = material.babylonMaterial;
                 var alphaMode = material.alphaMode || "OPAQUE";
                 switch (alphaMode) {
@@ -1311,7 +1295,7 @@ var BABYLON;
                 }
                 babylonMaterial.alphaCutOff = material.alphaCutoff === undefined ? 0.5 : material.alphaCutoff;
             };
-            GLTFLoader.prototype.loadTexture = function (textureInfo) {
+            GLTFLoader.prototype._loadTexture = function (textureInfo) {
                 var _this = this;
                 var texture = this._gltf.textures[textureInfo.index];
                 var texCoord = textureInfo.texCoord || 0;
@@ -1322,15 +1306,15 @@ var BABYLON;
                 var sampler = (texture.sampler === undefined ? {} : this._gltf.samplers[texture.sampler]);
                 var noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
                 var samplingMode = GLTF2.GLTFUtils.GetTextureSamplingMode(sampler.magFilter, sampler.minFilter);
-                this.addPendingData(texture);
+                this._addPendingData(texture);
                 var babylonTexture = new BABYLON.Texture(null, this._babylonScene, noMipMaps, false, samplingMode, function () {
                     if (!_this._disposed) {
-                        _this.removePendingData(texture);
+                        _this._removePendingData(texture);
                     }
                 }, function () {
                     if (!_this._disposed) {
                         _this._onError("Failed to load texture '" + source.uri + "'");
-                        _this.removePendingData(texture);
+                        _this._removePendingData(texture);
                     }
                 });
                 if (texture.url) {
@@ -1497,9 +1481,34 @@ var BABYLON;
             function GLTFLoaderExtension() {
                 this.enabled = true;
             }
-            GLTFLoaderExtension.prototype.loadMaterial = function (loader, material, assign) { return false; };
+            GLTFLoaderExtension.prototype._traverseNode = function (loader, index, action, parentNode) { return false; };
+            GLTFLoaderExtension.prototype._loadNode = function (loader, node) { return false; };
+            GLTFLoaderExtension.prototype._loadMaterial = function (loader, material, assign) { return false; };
+            GLTFLoaderExtension.prototype._loadExtension = function (property, action) {
+                var _this = this;
+                if (!property.extensions) {
+                    return false;
+                }
+                var extension = property.extensions[this.name];
+                if (!extension) {
+                    return false;
+                }
+                // Clear out the extension before executing the action to avoid recursing into the same property.
+                property.extensions[this.name] = undefined;
+                action(extension, function () {
+                    // Restore the extension after completing the action.
+                    property.extensions[_this.name] = extension;
+                });
+                return true;
+            };
+            GLTFLoaderExtension.TraverseNode = function (loader, index, action, parentNode) {
+                return this._ApplyExtensions(function (extension) { return extension._traverseNode(loader, index, action, parentNode); });
+            };
+            GLTFLoaderExtension.LoadNode = function (loader, node) {
+                return this._ApplyExtensions(function (extension) { return extension._loadNode(loader, node); });
+            };
             GLTFLoaderExtension.LoadMaterial = function (loader, material, assign) {
-                return this._ApplyExtensions(function (extension) { return extension.loadMaterial(loader, material, assign); });
+                return this._ApplyExtensions(function (extension) { return extension._loadMaterial(loader, material, assign); });
             };
             GLTFLoaderExtension._ApplyExtensions = function (action) {
                 var extensions = GLTFLoaderExtension._Extensions;
@@ -1543,6 +1552,7 @@ var BABYLON;
     (function (GLTF2) {
         var Extensions;
         (function (Extensions) {
+            // See https://github.com/sbtron/glTF/tree/MSFT_lod/extensions/Vendor/MSFT_lod for more information about this extension.
             var MSFTLOD = (function (_super) {
                 __extends(MSFTLOD, _super);
                 function MSFTLOD() {
@@ -1555,49 +1565,71 @@ var BABYLON;
                     enumerable: true,
                     configurable: true
                 });
-                MSFTLOD.prototype.loadMaterial = function (loader, material, assign) {
-                    if (!material.extensions) {
-                        return false;
-                    }
-                    var properties = material.extensions[this.name];
-                    if (!properties) {
-                        return false;
-                    }
-                    // Clear out the extension so that it won't get loaded again.
-                    material.extensions[this.name] = undefined;
-                    // Tell the loader not to clear its state until the highest LOD is loaded.
-                    var materialLODs = [material.index].concat(properties.ids);
-                    loader.addLoaderPendingData(material);
-                    for (var index = 0; index < materialLODs.length; index++) {
-                        loader.addLoaderNonBlockingPendingData(index);
-                    }
-                    // Start with the lowest quality LOD.
-                    this.loadMaterialLOD(loader, material, materialLODs, materialLODs.length - 1, assign);
-                    return true;
+                MSFTLOD.prototype._traverseNode = function (loader, index, action, parentNode) {
+                    var node = loader._gltf.nodes[index];
+                    return this._loadExtension(node, function (extension, onComplete) {
+                        for (var i = extension.ids.length - 1; i >= 0; i--) {
+                            loader._traverseNode(extension.ids[i], action, parentNode);
+                        }
+                        loader._traverseNode(index, action, parentNode);
+                        onComplete();
+                    });
                 };
-                MSFTLOD.prototype.loadMaterialLOD = function (loader, material, materialLODs, lod, assign) {
+                MSFTLOD.prototype._loadNode = function (loader, node) {
                     var _this = this;
-                    var materialLOD = loader.gltf.materials[materialLODs[lod]];
-                    if (lod !== materialLODs.length - 1) {
-                        loader.blockPendingTracking = true;
-                    }
-                    loader.loadMaterial(materialLOD, function (babylonMaterial, isNew) {
-                        assign(babylonMaterial, isNew);
-                        loader.removeLoaderPendingData(lod);
-                        // Loading is considered complete if this is the lowest quality LOD.
-                        if (lod === materialLODs.length - 1) {
-                            loader.removeLoaderPendingData(material);
+                    return this._loadExtension(node, function (extension, onComplete) {
+                        var nodes = [node.index].concat(extension.ids).map(function (index) { return loader._gltf.nodes[index]; });
+                        loader._addLoaderPendingData(node);
+                        _this._loadNodeLOD(loader, nodes, nodes.length - 1, function () {
+                            loader._removeLoaderPendingData(node);
+                            onComplete();
+                        });
+                    });
+                };
+                MSFTLOD.prototype._loadNodeLOD = function (loader, nodes, index, onComplete) {
+                    var _this = this;
+                    loader._whenAction(function () {
+                        loader._loadNode(nodes[index]);
+                    }, function () {
+                        if (index !== nodes.length - 1) {
+                            var previousNode = nodes[index + 1];
+                            previousNode.babylonMesh.setEnabled(false);
                         }
-                        if (lod === 0) {
-                            loader.blockPendingTracking = false;
+                        if (index === 0) {
+                            onComplete();
+                            return;
+                        }
+                        setTimeout(function () {
+                            _this._loadNodeLOD(loader, nodes, index - 1, onComplete);
+                        }, MSFTLOD.MinimalLODDelay);
+                    });
+                };
+                MSFTLOD.prototype._loadMaterial = function (loader, material, assign) {
+                    var _this = this;
+                    return this._loadExtension(material, function (extension, onComplete) {
+                        var materials = [material.index].concat(extension.ids).map(function (index) { return loader._gltf.materials[index]; });
+                        loader._addLoaderPendingData(material);
+                        _this._loadMaterialLOD(loader, materials, materials.length - 1, assign, function () {
+                            material.extensions[_this.name] = extension;
+                            loader._removeLoaderPendingData(material);
+                            onComplete();
+                        });
+                    });
+                };
+                MSFTLOD.prototype._loadMaterialLOD = function (loader, materials, index, assign, onComplete) {
+                    var _this = this;
+                    loader._loadMaterial(materials[index], function (babylonMaterial, isNew) {
+                        assign(babylonMaterial, isNew);
+                        if (index === 0) {
+                            onComplete();
                             return;
                         }
                         // Load the next LOD when the loader is ready to render and
                         // all active material textures of the current LOD are loaded.
-                        loader.executeWhenRenderReady(function () {
+                        loader._executeWhenRenderReady(function () {
                             BABYLON.BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), function () {
                                 setTimeout(function () {
-                                    _this.loadMaterialLOD(loader, material, materialLODs, lod - 1, assign);
+                                    _this._loadMaterialLOD(loader, materials, index - 1, assign, onComplete);
                                 }, MSFTLOD.MinimalLODDelay);
                             });
                         });
@@ -1646,19 +1678,14 @@ var BABYLON;
                     enumerable: true,
                     configurable: true
                 });
-                KHRMaterialsPbrSpecularGlossiness.prototype.loadMaterial = function (loader, material, assign) {
-                    if (!material.extensions) {
-                        return false;
-                    }
-                    var properties = material.extensions[this.name];
-                    if (!properties) {
-                        return false;
-                    }
-                    loader.createPbrMaterial(material);
-                    loader.loadMaterialBaseProperties(material);
-                    this._loadSpecularGlossinessProperties(loader, material, properties);
-                    assign(material.babylonMaterial, true);
-                    return true;
+                KHRMaterialsPbrSpecularGlossiness.prototype._loadMaterial = function (loader, material, assign) {
+                    var _this = this;
+                    return this._loadExtension(material, function (extension, onComplete) {
+                        loader._createPbrMaterial(material);
+                        loader._loadMaterialBaseProperties(material);
+                        _this._loadSpecularGlossinessProperties(loader, material, extension);
+                        assign(material.babylonMaterial, true);
+                    });
                 };
                 KHRMaterialsPbrSpecularGlossiness.prototype._loadSpecularGlossinessProperties = function (loader, material, properties) {
                     var babylonMaterial = material.babylonMaterial;
@@ -1666,14 +1693,14 @@ var BABYLON;
                     babylonMaterial.reflectivityColor = properties.specularFactor ? BABYLON.Color3.FromArray(properties.specularFactor) : new BABYLON.Color3(1, 1, 1);
                     babylonMaterial.microSurface = properties.glossinessFactor === undefined ? 1 : properties.glossinessFactor;
                     if (properties.diffuseTexture) {
-                        babylonMaterial.albedoTexture = loader.loadTexture(properties.diffuseTexture);
+                        babylonMaterial.albedoTexture = loader._loadTexture(properties.diffuseTexture);
                     }
                     if (properties.specularGlossinessTexture) {
-                        babylonMaterial.reflectivityTexture = loader.loadTexture(properties.specularGlossinessTexture);
+                        babylonMaterial.reflectivityTexture = loader._loadTexture(properties.specularGlossinessTexture);
                         babylonMaterial.reflectivityTexture.hasAlpha = true;
                         babylonMaterial.useMicroSurfaceFromReflectivityMapAlpha = true;
                     }
-                    loader.loadMaterialAlphaProperties(material, properties.diffuseFactor);
+                    loader._loadMaterialAlphaProperties(material, properties.diffuseFactor);
                 };
                 return KHRMaterialsPbrSpecularGlossiness;
             }(GLTF2.GLTFLoaderExtension));

文件差异内容过多而无法显示
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 37 - 33
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -27,13 +27,17 @@ declare module BABYLON {
          */
         onBeforeMaterialReadyAsync: (material: Material, targetMesh: AbstractMesh, isLOD: boolean, callback: () => void) => void;
         /**
-         * Raised when all LODs are complete (or if there is no LOD and model is complete)
+         * Raised when the visible components (geometry, materials, textures, etc.) are first ready to be rendered.
+         * For assets with LODs, raised when the first LOD is complete.
+         * For assets without LODs, raised when the model is complete just before onComplete.
          */
-        onComplete: () => void;
+        onReady: () => void;
         /**
-         * Raised when first LOD complete (or if there is no LOD and model is complete)
+         * Raised when the asset is completely loaded, just before the loader is disposed.
+         * For assets with LODs, raised when all of the LODs are complete.
+         * For assets without LODs, raised when the model is complete just after onReady.
          */
-        onFirstLODComplete: () => void;
+        onComplete: () => void;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
@@ -786,9 +790,9 @@ declare module BABYLON.GLTF2 {
 
 declare module BABYLON.GLTF2 {
     class GLTFLoader implements IGLTFLoader, IDisposable {
+        _gltf: IGLTF;
+        _babylonScene: Scene;
         private _parent;
-        private _gltf;
-        private _babylonScene;
         private _rootUrl;
         private _defaultMaterial;
         private _successCallback;
@@ -796,19 +800,14 @@ declare module BABYLON.GLTF2 {
         private _errorCallback;
         private _renderReady;
         private _disposed;
-        private _blockPendingTracking;
-        private _nonBlockingData;
-        private _rootMesh;
         private _renderReadyObservable;
         private _renderPendingCount;
         private _loaderPendingCount;
+        private _loaderTrackers;
         static Extensions: {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
-        readonly gltf: IGLTF;
-        readonly babylonScene: Scene;
-        executeWhenRenderReady(func: () => void): void;
         constructor(parent: GLTFFileLoader);
         dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
@@ -816,18 +815,16 @@ declare module BABYLON.GLTF2 {
         private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess, onProgress, onError);
         private _onError(message);
         private _onProgress(event);
+        _executeWhenRenderReady(func: () => void): void;
         private _onRenderReady();
-        private _onLoaderComplete();
-        private _onLoaderFirstLODComplete();
+        private _onComplete();
         private _loadData(data);
-        private _addRightHandToLeftHandRootTransform();
         private _getMeshes();
         private _getSkeletons();
         private _getAnimationTargets();
-        private _showMeshes();
         private _startAnimations();
         private _loadScene(nodeNames);
-        private _loadNode(node);
+        _loadNode(node: IGLTFNode): void;
         private _loadMesh(node, mesh);
         private _loadVertexDataAsync(primitive, onSuccess);
         private _createMorphTargets(node, mesh, primitive, babylonMesh);
@@ -839,7 +836,7 @@ declare module BABYLON.GLTF2 {
         private _loadBone(node, skin, inverseBindMatrixData, babylonBones);
         private _getNodeMatrix(node);
         private _traverseNodes(indices, action, parentNode?);
-        private _traverseNode(index, action, parentNode?);
+        _traverseNode(index: number, action: (node: IGLTFNode, index: number, parentNode: IGLTFNode) => boolean, parentNode?: IGLTFNode): void;
         private _loadAnimations();
         private _loadAnimationChannel(animation, animationIndex, channelIndex);
         private _loadBufferAsync(index, onSuccess);
@@ -853,19 +850,18 @@ declare module BABYLON.GLTF2 {
         private _loadBufferViewAsync(bufferView, byteOffset, byteLength, bytePerComponent, componentType, onSuccess);
         private _loadAccessorAsync(accessor, onSuccess);
         private _getByteStrideFromType(accessor);
-        blockPendingTracking: boolean;
-        addPendingData(data: any): void;
-        removePendingData(data: any): void;
-        addLoaderNonBlockingPendingData(data: any): void;
-        addLoaderPendingData(data: any): void;
-        removeLoaderPendingData(data: any): void;
+        _addPendingData(data: any): void;
+        _removePendingData(data: any): void;
+        _addLoaderPendingData(data: any): void;
+        _removeLoaderPendingData(data: any): void;
+        _whenAction(action: () => void, onComplete: () => void): void;
         private _getDefaultMaterial();
         private _loadMaterialMetallicRoughnessProperties(material);
-        loadMaterial(material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): void;
-        createPbrMaterial(material: IGLTFMaterial): void;
-        loadMaterialBaseProperties(material: IGLTFMaterial): void;
-        loadMaterialAlphaProperties(material: IGLTFMaterial, colorFactor?: number[]): void;
-        loadTexture(textureInfo: IGLTFTextureInfo): Texture;
+        _loadMaterial(material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): void;
+        _createPbrMaterial(material: IGLTFMaterial): void;
+        _loadMaterialBaseProperties(material: IGLTFMaterial): void;
+        _loadMaterialAlphaProperties(material: IGLTFMaterial, colorFactor?: number[]): void;
+        _loadTexture(textureInfo: IGLTFTextureInfo): Texture;
     }
 }
 
@@ -901,8 +897,13 @@ declare module BABYLON.GLTF2 {
     abstract class GLTFLoaderExtension {
         enabled: boolean;
         readonly abstract name: string;
-        protected loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
+        protected _traverseNode(loader: GLTFLoader, index: number, action: (node: IGLTFNode, index: number, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
+        protected _loadNode(loader: GLTFLoader, node: IGLTFNode): boolean;
+        protected _loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
+        protected _loadExtension<T>(property: IGLTFProperty, action: (extension: T, onComplete: () => void) => void): boolean;
         static _Extensions: GLTFLoaderExtension[];
+        static TraverseNode(loader: GLTFLoader, index: number, action: (node: IGLTFNode, index: number, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
+        static LoadNode(loader: GLTFLoader, node: IGLTFNode): boolean;
         static LoadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         private static _ApplyExtensions(action);
     }
@@ -916,8 +917,11 @@ declare module BABYLON.GLTF2.Extensions {
          */
         static MinimalLODDelay: number;
         readonly name: string;
-        protected loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private loadMaterialLOD(loader, material, materialLODs, lod, assign);
+        protected _traverseNode(loader: GLTFLoader, index: number, action: (node: IGLTFNode, index: number, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
+        protected _loadNode(loader: GLTFLoader, node: IGLTFNode): boolean;
+        private _loadNodeLOD(loader, nodes, index, onComplete);
+        protected _loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
+        private _loadMaterialLOD(loader, materials, index, assign, onComplete);
     }
 }
 
@@ -925,7 +929,7 @@ declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
     class KHRMaterialsPbrSpecularGlossiness extends GLTFLoaderExtension {
         readonly name: string;
-        protected loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
+        protected _loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         private _loadSpecularGlossinessProperties(loader, material, properties);
     }
 }

+ 234 - 207
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -2478,17 +2478,31 @@ var BABYLON;
 (function (BABYLON) {
     var GLTF2;
     (function (GLTF2) {
+        var GLTFLoaderTracker = (function () {
+            function GLTFLoaderTracker(onComplete) {
+                this._pendingCount = 0;
+                this._callback = onComplete;
+            }
+            GLTFLoaderTracker.prototype._addPendingData = function (data) {
+                this._pendingCount++;
+            };
+            GLTFLoaderTracker.prototype._removePendingData = function (data) {
+                if (--this._pendingCount === 0) {
+                    this._callback();
+                }
+            };
+            return GLTFLoaderTracker;
+        }());
         var GLTFLoader = (function () {
             function GLTFLoader(parent) {
                 this._renderReady = false;
                 this._disposed = false;
-                this._blockPendingTracking = false;
-                // Observable with boolean indicating success or error.
                 this._renderReadyObservable = new BABYLON.Observable();
                 // Count of pending work that needs to complete before the asset is rendered.
                 this._renderPendingCount = 0;
-                // Count of pending work that needs to complete before the loader is cleared.
+                // Count of pending work that needs to complete before the loader is disposed.
                 this._loaderPendingCount = 0;
+                this._loaderTrackers = new Array();
                 this._parent = parent;
             }
             GLTFLoader.RegisterExtension = function (extension) {
@@ -2500,28 +2514,6 @@ var BABYLON;
                 // Keep the order of registration so that extensions registered first are called first.
                 GLTF2.GLTFLoaderExtension._Extensions.push(extension);
             };
-            Object.defineProperty(GLTFLoader.prototype, "gltf", {
-                get: function () {
-                    return this._gltf;
-                },
-                enumerable: true,
-                configurable: true
-            });
-            Object.defineProperty(GLTFLoader.prototype, "babylonScene", {
-                get: function () {
-                    return this._babylonScene;
-                },
-                enumerable: true,
-                configurable: true
-            });
-            GLTFLoader.prototype.executeWhenRenderReady = function (func) {
-                if (this._renderReady) {
-                    func();
-                }
-                else {
-                    this._renderReadyObservable.add(func);
-                }
-            };
             GLTFLoader.prototype.dispose = function () {
                 if (this._disposed) {
                     return;
@@ -2562,10 +2554,10 @@ var BABYLON;
                 this._successCallback = onSuccess;
                 this._progressCallback = onProgress;
                 this._errorCallback = onError;
-                this.addPendingData(this);
+                this._addPendingData(this);
                 this._loadScene(nodeNames);
                 this._loadAnimations();
-                this.removePendingData(this);
+                this._removePendingData(this);
             };
             GLTFLoader.prototype._onError = function (message) {
                 if (this._errorCallback) {
@@ -2574,39 +2566,33 @@ var BABYLON;
                 this.dispose();
             };
             GLTFLoader.prototype._onProgress = function (event) {
-                this._progressCallback(event);
+                if (this._progressCallback) {
+                    this._progressCallback(event);
+                }
             };
-            GLTFLoader.prototype._onRenderReady = function () {
-                switch (this._parent.coordinateSystemMode) {
-                    case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO:
-                        if (!this._babylonScene.useRightHandedSystem) {
-                            this._addRightHandToLeftHandRootTransform();
-                        }
-                        break;
-                    case BABYLON.GLTFLoaderCoordinateSystemMode.PASS_THROUGH:
-                        // do nothing
-                        break;
-                    case BABYLON.GLTFLoaderCoordinateSystemMode.FORCE_RIGHT_HANDED:
-                        this._babylonScene.useRightHandedSystem = true;
-                        break;
-                    default:
-                        BABYLON.Tools.Error("Invalid coordinate system mode (" + this._parent.coordinateSystemMode + ")");
-                        break;
+            GLTFLoader.prototype._executeWhenRenderReady = function (func) {
+                if (this._renderReady) {
+                    func();
                 }
-                this._showMeshes();
+                else {
+                    this._renderReadyObservable.add(func);
+                }
+            };
+            GLTFLoader.prototype._onRenderReady = function () {
+                var rootNode = this._gltf.nodes[this._gltf.nodes.length - 1];
+                rootNode.babylonMesh.setEnabled(true);
                 this._startAnimations();
                 this._successCallback();
                 this._renderReadyObservable.notifyObservers(this);
+                if (this._parent.onReady) {
+                    this._parent.onReady();
+                }
             };
-            GLTFLoader.prototype._onLoaderComplete = function () {
+            GLTFLoader.prototype._onComplete = function () {
                 if (this._parent.onComplete) {
                     this._parent.onComplete();
                 }
-            };
-            GLTFLoader.prototype._onLoaderFirstLODComplete = function () {
-                if (this._parent.onFirstLODComplete) {
-                    this._parent.onFirstLODComplete();
-                }
+                this.dispose();
             };
             GLTFLoader.prototype._loadData = function (data) {
                 this._gltf = data.json;
@@ -2627,26 +2613,8 @@ var BABYLON;
                     binaryBuffer.loadedData = data.bin;
                 }
             };
-            GLTFLoader.prototype._addRightHandToLeftHandRootTransform = function () {
-                this._rootMesh = new BABYLON.Mesh("root", this._babylonScene);
-                this._rootMesh.isVisible = false;
-                this._rootMesh.scaling = new BABYLON.Vector3(1, 1, -1);
-                this._rootMesh.rotation.y = Math.PI;
-                var nodes = this._gltf.nodes;
-                if (nodes) {
-                    for (var i = 0; i < nodes.length; i++) {
-                        var mesh = nodes[i].babylonMesh;
-                        if (mesh && !mesh.parent) {
-                            mesh.parent = this._rootMesh;
-                        }
-                    }
-                }
-            };
             GLTFLoader.prototype._getMeshes = function () {
                 var meshes = [];
-                if (this._rootMesh) {
-                    meshes.push(this._rootMesh);
-                }
                 var nodes = this._gltf.nodes;
                 if (nodes) {
                     nodes.forEach(function (node) {
@@ -2679,16 +2647,34 @@ var BABYLON;
                 }
                 return targets;
             };
-            GLTFLoader.prototype._showMeshes = function () {
-                this._getMeshes().forEach(function (mesh) { return mesh.isVisible = true; });
-            };
             GLTFLoader.prototype._startAnimations = function () {
                 var _this = this;
                 this._getAnimationTargets().forEach(function (target) { return _this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true); });
             };
             GLTFLoader.prototype._loadScene = function (nodeNames) {
-                var _this = this;
                 var scene = this._gltf.scenes[this._gltf.scene || 0];
+                var rootNode = { name: "root", children: scene.nodes };
+                switch (this._parent.coordinateSystemMode) {
+                    case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO:
+                        if (!this._babylonScene.useRightHandedSystem) {
+                            rootNode.rotation = [0, 1, 0, 0];
+                            rootNode.scale = [1, 1, -1];
+                        }
+                        break;
+                    case BABYLON.GLTFLoaderCoordinateSystemMode.PASS_THROUGH:
+                        // do nothing
+                        break;
+                    case BABYLON.GLTFLoaderCoordinateSystemMode.FORCE_RIGHT_HANDED:
+                        this._babylonScene.useRightHandedSystem = true;
+                        break;
+                    default:
+                        BABYLON.Tools.Error("Invalid coordinate system mode (" + this._parent.coordinateSystemMode + ")");
+                        break;
+                }
+                // Inject a root node into the scene.
+                this._gltf.nodes = this._gltf.nodes || [];
+                scene.nodes = [this._gltf.nodes.length];
+                this._gltf.nodes.push(rootNode);
                 var nodeIndices = scene.nodes;
                 this._traverseNodes(nodeIndices, function (node, index, parentNode) {
                     node.index = index;
@@ -2705,19 +2691,25 @@ var BABYLON;
                     }
                     var filteredNodeIndices = new Array();
                     this._traverseNodes(nodeIndices, function (node) {
-                        if (nodeNames.indexOf(node.name) === -1) {
-                            return true;
+                        if (nodeNames.indexOf(node.name) !== -1) {
+                            filteredNodeIndices.push(node.index);
+                            return false;
                         }
-                        filteredNodeIndices.push(node.index);
-                        return false;
+                        return true;
                     });
                     nodeIndices = filteredNodeIndices;
                 }
-                this._traverseNodes(nodeIndices, function (node) { return _this._loadNode(node); });
+                for (var i = 0; i < nodeIndices.length; i++) {
+                    this._loadNode(this._gltf.nodes[nodeIndices[i]]);
+                }
+                // Disable the root mesh until the asset is ready to render.
+                rootNode.babylonMesh.setEnabled(false);
             };
             GLTFLoader.prototype._loadNode = function (node) {
+                if (GLTF2.GLTFLoaderExtension.LoadNode(this, node)) {
+                    return;
+                }
                 node.babylonMesh = new BABYLON.Mesh(node.name || "mesh" + node.index, this._babylonScene);
-                node.babylonMesh.isVisible = false;
                 this._loadTransform(node);
                 if (node.mesh !== undefined) {
                     var mesh = this._gltf.meshes[node.mesh];
@@ -2734,7 +2726,11 @@ var BABYLON;
                 if (node.camera !== undefined) {
                     // TODO: handle cameras
                 }
-                return true;
+                if (node.children) {
+                    for (var i = 0; i < node.children.length; i++) {
+                        this._loadNode(this._gltf.nodes[node.children[i]]);
+                    }
+                }
             };
             GLTFLoader.prototype._loadMesh = function (node, mesh) {
                 var _this = this;
@@ -2766,25 +2762,24 @@ var BABYLON;
                             loadMaterial: function () {
                                 if (primitive.material === undefined) {
                                     babylonMultiMaterial.subMaterials[i] = _this._getDefaultMaterial();
+                                    return;
                                 }
-                                else {
-                                    var material = _this._gltf.materials[primitive.material];
-                                    _this.loadMaterial(material, function (babylonMaterial, isNew) {
-                                        if (isNew && _this._parent.onMaterialLoaded) {
-                                            _this._parent.onMaterialLoaded(babylonMaterial);
-                                        }
-                                        if (_this._parent.onBeforeMaterialReadyAsync) {
-                                            _this.addLoaderPendingData(material);
-                                            _this._parent.onBeforeMaterialReadyAsync(babylonMaterial, node.babylonMesh, babylonMultiMaterial.subMaterials[i] != null, function () {
-                                                babylonMultiMaterial.subMaterials[i] = babylonMaterial;
-                                                _this.removeLoaderPendingData(material);
-                                            });
-                                        }
-                                        else {
+                                var material = _this._gltf.materials[primitive.material];
+                                _this._loadMaterial(material, function (babylonMaterial, isNew) {
+                                    if (isNew && _this._parent.onMaterialLoaded) {
+                                        _this._parent.onMaterialLoaded(babylonMaterial);
+                                    }
+                                    if (_this._parent.onBeforeMaterialReadyAsync) {
+                                        _this._addLoaderPendingData(material);
+                                        _this._parent.onBeforeMaterialReadyAsync(babylonMaterial, node.babylonMesh, babylonMultiMaterial.subMaterials[i] != null, function () {
                                             babylonMultiMaterial.subMaterials[i] = babylonMaterial;
-                                        }
-                                    });
-                                }
+                                            _this._removeLoaderPendingData(material);
+                                        });
+                                    }
+                                    else {
+                                        babylonMultiMaterial.subMaterials[i] = babylonMaterial;
+                                    }
+                                });
                             }
                         });
                         vertexData.merge(subVertexData);
@@ -3015,14 +3010,15 @@ var BABYLON;
             };
             GLTFLoader.prototype._traverseNode = function (index, action, parentNode) {
                 if (parentNode === void 0) { parentNode = null; }
+                if (GLTF2.GLTFLoaderExtension.TraverseNode(this, index, action, parentNode)) {
+                    return;
+                }
                 var node = this._gltf.nodes[index];
                 if (!action(node, index, parentNode)) {
                     return;
                 }
                 if (node.children) {
-                    for (var i = 0; i < node.children.length; i++) {
-                        this._traverseNode(node.children[i], action, node);
-                    }
+                    this._traverseNodes(node.children, action, node);
                 }
             };
             GLTFLoader.prototype._loadAnimations = function () {
@@ -3150,11 +3146,11 @@ var BABYLON;
             GLTFLoader.prototype._loadBufferAsync = function (index, onSuccess) {
                 var _this = this;
                 var buffer = this._gltf.buffers[index];
-                this.addPendingData(buffer);
+                this._addPendingData(buffer);
                 if (buffer.loadedData) {
                     setTimeout(function () {
                         onSuccess(buffer.loadedData);
-                        _this.removePendingData(buffer);
+                        _this._removePendingData(buffer);
                     });
                 }
                 else if (GLTF2.GLTFUtils.IsBase64(buffer.uri)) {
@@ -3162,20 +3158,20 @@ var BABYLON;
                     buffer.loadedData = new Uint8Array(data);
                     setTimeout(function () {
                         onSuccess(buffer.loadedData);
-                        _this.removePendingData(buffer);
+                        _this._removePendingData(buffer);
                     });
                 }
                 else if (buffer.loadedObservable) {
                     buffer.loadedObservable.add(function (buffer) {
                         onSuccess(buffer.loadedData);
-                        _this.removePendingData(buffer);
+                        _this._removePendingData(buffer);
                     });
                 }
                 else {
                     buffer.loadedObservable = new BABYLON.Observable();
                     buffer.loadedObservable.add(function (buffer) {
                         onSuccess(buffer.loadedData);
-                        _this.removePendingData(buffer);
+                        _this._removePendingData(buffer);
                     });
                     BABYLON.Tools.LoadFile(this._rootUrl + buffer.uri, function (data) {
                         buffer.loadedData = new Uint8Array(data);
@@ -3188,7 +3184,7 @@ var BABYLON;
                     }, this._babylonScene.database, true, function (request) {
                         if (!_this._disposed) {
                             _this._onError("Failed to load file '" + buffer.uri + "': " + request.status + " " + request.statusText);
-                            _this.removePendingData(buffer);
+                            _this._removePendingData(buffer);
                         }
                     });
                 }
@@ -3317,54 +3313,42 @@ var BABYLON;
                         return 0;
                 }
             };
-            Object.defineProperty(GLTFLoader.prototype, "blockPendingTracking", {
-                set: function (value) {
-                    this._blockPendingTracking = value;
-                },
-                enumerable: true,
-                configurable: true
-            });
-            GLTFLoader.prototype.addPendingData = function (data) {
+            GLTFLoader.prototype._addPendingData = function (data) {
                 if (!this._renderReady) {
                     this._renderPendingCount++;
                 }
-                this.addLoaderPendingData(data);
+                this._addLoaderPendingData(data);
             };
-            GLTFLoader.prototype.removePendingData = function (data) {
+            GLTFLoader.prototype._removePendingData = function (data) {
                 if (!this._renderReady) {
                     if (--this._renderPendingCount === 0) {
                         this._renderReady = true;
                         this._onRenderReady();
                     }
                 }
-                this.removeLoaderPendingData(data);
-            };
-            GLTFLoader.prototype.addLoaderNonBlockingPendingData = function (data) {
-                if (!this._nonBlockingData) {
-                    this._nonBlockingData = new Array();
-                }
-                this._nonBlockingData.push(data);
+                this._removeLoaderPendingData(data);
             };
-            GLTFLoader.prototype.addLoaderPendingData = function (data) {
-                if (this._blockPendingTracking) {
-                    this.addLoaderNonBlockingPendingData(data);
-                    return;
-                }
+            GLTFLoader.prototype._addLoaderPendingData = function (data) {
                 this._loaderPendingCount++;
+                this._loaderTrackers.forEach(function (tracker) { return tracker._addPendingData(data); });
             };
-            GLTFLoader.prototype.removeLoaderPendingData = function (data) {
-                var indexInPending = this._nonBlockingData ? this._nonBlockingData.indexOf(data) : -1;
-                if (indexInPending !== -1) {
-                    this._nonBlockingData.splice(indexInPending, 1);
-                }
-                else if (--this._loaderPendingCount === 0) {
-                    this._onLoaderFirstLODComplete();
-                }
-                if ((!this._nonBlockingData || this._nonBlockingData.length === 0) && this._loaderPendingCount === 0) {
-                    this._onLoaderComplete();
-                    this.dispose();
+            GLTFLoader.prototype._removeLoaderPendingData = function (data) {
+                this._loaderTrackers.forEach(function (tracker) { return tracker._removePendingData(data); });
+                if (--this._loaderPendingCount === 0) {
+                    this._onComplete();
                 }
             };
+            GLTFLoader.prototype._whenAction = function (action, onComplete) {
+                var _this = this;
+                var tracker = new GLTFLoaderTracker(function () {
+                    _this._loaderTrackers.splice(_this._loaderTrackers.indexOf(tracker));
+                    onComplete();
+                });
+                this._loaderTrackers.push(tracker);
+                this._addLoaderPendingData(tracker);
+                action();
+                this._removeLoaderPendingData(tracker);
+            };
             GLTFLoader.prototype._getDefaultMaterial = function () {
                 if (!this._defaultMaterial) {
                     var id = "__gltf_default";
@@ -3392,17 +3376,17 @@ var BABYLON;
                 babylonMaterial.metallic = properties.metallicFactor === undefined ? 1 : properties.metallicFactor;
                 babylonMaterial.roughness = properties.roughnessFactor === undefined ? 1 : properties.roughnessFactor;
                 if (properties.baseColorTexture) {
-                    babylonMaterial.albedoTexture = this.loadTexture(properties.baseColorTexture);
+                    babylonMaterial.albedoTexture = this._loadTexture(properties.baseColorTexture);
                 }
                 if (properties.metallicRoughnessTexture) {
-                    babylonMaterial.metallicTexture = this.loadTexture(properties.metallicRoughnessTexture);
+                    babylonMaterial.metallicTexture = this._loadTexture(properties.metallicRoughnessTexture);
                     babylonMaterial.useMetallnessFromMetallicTextureBlue = true;
                     babylonMaterial.useRoughnessFromMetallicTextureGreen = true;
                     babylonMaterial.useRoughnessFromMetallicTextureAlpha = false;
                 }
-                this.loadMaterialAlphaProperties(material, properties.baseColorFactor);
+                this._loadMaterialAlphaProperties(material, properties.baseColorFactor);
             };
-            GLTFLoader.prototype.loadMaterial = function (material, assign) {
+            GLTFLoader.prototype._loadMaterial = function (material, assign) {
                 if (material.babylonMaterial) {
                     assign(material.babylonMaterial, false);
                     return;
@@ -3410,17 +3394,17 @@ var BABYLON;
                 if (GLTF2.GLTFLoaderExtension.LoadMaterial(this, material, assign)) {
                     return;
                 }
-                this.createPbrMaterial(material);
-                this.loadMaterialBaseProperties(material);
+                this._createPbrMaterial(material);
+                this._loadMaterialBaseProperties(material);
                 this._loadMaterialMetallicRoughnessProperties(material);
                 assign(material.babylonMaterial, true);
             };
-            GLTFLoader.prototype.createPbrMaterial = function (material) {
+            GLTFLoader.prototype._createPbrMaterial = function (material) {
                 var babylonMaterial = new BABYLON.PBRMaterial(material.name || "mat" + material.index, this._babylonScene);
                 babylonMaterial.sideOrientation = BABYLON.Material.CounterClockWiseSideOrientation;
                 material.babylonMaterial = babylonMaterial;
             };
-            GLTFLoader.prototype.loadMaterialBaseProperties = function (material) {
+            GLTFLoader.prototype._loadMaterialBaseProperties = function (material) {
                 var babylonMaterial = material.babylonMaterial;
                 babylonMaterial.emissiveColor = material.emissiveFactor ? BABYLON.Color3.FromArray(material.emissiveFactor) : new BABYLON.Color3(0, 0, 0);
                 if (material.doubleSided) {
@@ -3428,7 +3412,7 @@ var BABYLON;
                     babylonMaterial.twoSidedLighting = true;
                 }
                 if (material.normalTexture) {
-                    babylonMaterial.bumpTexture = this.loadTexture(material.normalTexture);
+                    babylonMaterial.bumpTexture = this._loadTexture(material.normalTexture);
                     babylonMaterial.invertNormalMapX = !this._babylonScene.useRightHandedSystem;
                     babylonMaterial.invertNormalMapY = this._babylonScene.useRightHandedSystem;
                     if (material.normalTexture.scale !== undefined) {
@@ -3436,17 +3420,17 @@ var BABYLON;
                     }
                 }
                 if (material.occlusionTexture) {
-                    babylonMaterial.ambientTexture = this.loadTexture(material.occlusionTexture);
+                    babylonMaterial.ambientTexture = this._loadTexture(material.occlusionTexture);
                     babylonMaterial.useAmbientInGrayScale = true;
                     if (material.occlusionTexture.strength !== undefined) {
                         babylonMaterial.ambientTextureStrength = material.occlusionTexture.strength;
                     }
                 }
                 if (material.emissiveTexture) {
-                    babylonMaterial.emissiveTexture = this.loadTexture(material.emissiveTexture);
+                    babylonMaterial.emissiveTexture = this._loadTexture(material.emissiveTexture);
                 }
             };
-            GLTFLoader.prototype.loadMaterialAlphaProperties = function (material, colorFactor) {
+            GLTFLoader.prototype._loadMaterialAlphaProperties = function (material, colorFactor) {
                 var babylonMaterial = material.babylonMaterial;
                 var alphaMode = material.alphaMode || "OPAQUE";
                 switch (alphaMode) {
@@ -3469,7 +3453,7 @@ var BABYLON;
                 }
                 babylonMaterial.alphaCutOff = material.alphaCutoff === undefined ? 0.5 : material.alphaCutoff;
             };
-            GLTFLoader.prototype.loadTexture = function (textureInfo) {
+            GLTFLoader.prototype._loadTexture = function (textureInfo) {
                 var _this = this;
                 var texture = this._gltf.textures[textureInfo.index];
                 var texCoord = textureInfo.texCoord || 0;
@@ -3480,15 +3464,15 @@ var BABYLON;
                 var sampler = (texture.sampler === undefined ? {} : this._gltf.samplers[texture.sampler]);
                 var noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
                 var samplingMode = GLTF2.GLTFUtils.GetTextureSamplingMode(sampler.magFilter, sampler.minFilter);
-                this.addPendingData(texture);
+                this._addPendingData(texture);
                 var babylonTexture = new BABYLON.Texture(null, this._babylonScene, noMipMaps, false, samplingMode, function () {
                     if (!_this._disposed) {
-                        _this.removePendingData(texture);
+                        _this._removePendingData(texture);
                     }
                 }, function () {
                     if (!_this._disposed) {
                         _this._onError("Failed to load texture '" + source.uri + "'");
-                        _this.removePendingData(texture);
+                        _this._removePendingData(texture);
                     }
                 });
                 if (texture.url) {
@@ -3655,9 +3639,34 @@ var BABYLON;
             function GLTFLoaderExtension() {
                 this.enabled = true;
             }
-            GLTFLoaderExtension.prototype.loadMaterial = function (loader, material, assign) { return false; };
+            GLTFLoaderExtension.prototype._traverseNode = function (loader, index, action, parentNode) { return false; };
+            GLTFLoaderExtension.prototype._loadNode = function (loader, node) { return false; };
+            GLTFLoaderExtension.prototype._loadMaterial = function (loader, material, assign) { return false; };
+            GLTFLoaderExtension.prototype._loadExtension = function (property, action) {
+                var _this = this;
+                if (!property.extensions) {
+                    return false;
+                }
+                var extension = property.extensions[this.name];
+                if (!extension) {
+                    return false;
+                }
+                // Clear out the extension before executing the action to avoid recursing into the same property.
+                property.extensions[this.name] = undefined;
+                action(extension, function () {
+                    // Restore the extension after completing the action.
+                    property.extensions[_this.name] = extension;
+                });
+                return true;
+            };
+            GLTFLoaderExtension.TraverseNode = function (loader, index, action, parentNode) {
+                return this._ApplyExtensions(function (extension) { return extension._traverseNode(loader, index, action, parentNode); });
+            };
+            GLTFLoaderExtension.LoadNode = function (loader, node) {
+                return this._ApplyExtensions(function (extension) { return extension._loadNode(loader, node); });
+            };
             GLTFLoaderExtension.LoadMaterial = function (loader, material, assign) {
-                return this._ApplyExtensions(function (extension) { return extension.loadMaterial(loader, material, assign); });
+                return this._ApplyExtensions(function (extension) { return extension._loadMaterial(loader, material, assign); });
             };
             GLTFLoaderExtension._ApplyExtensions = function (action) {
                 var extensions = GLTFLoaderExtension._Extensions;
@@ -3701,6 +3710,7 @@ var BABYLON;
     (function (GLTF2) {
         var Extensions;
         (function (Extensions) {
+            // See https://github.com/sbtron/glTF/tree/MSFT_lod/extensions/Vendor/MSFT_lod for more information about this extension.
             var MSFTLOD = (function (_super) {
                 __extends(MSFTLOD, _super);
                 function MSFTLOD() {
@@ -3713,49 +3723,71 @@ var BABYLON;
                     enumerable: true,
                     configurable: true
                 });
-                MSFTLOD.prototype.loadMaterial = function (loader, material, assign) {
-                    if (!material.extensions) {
-                        return false;
-                    }
-                    var properties = material.extensions[this.name];
-                    if (!properties) {
-                        return false;
-                    }
-                    // Clear out the extension so that it won't get loaded again.
-                    material.extensions[this.name] = undefined;
-                    // Tell the loader not to clear its state until the highest LOD is loaded.
-                    var materialLODs = [material.index].concat(properties.ids);
-                    loader.addLoaderPendingData(material);
-                    for (var index = 0; index < materialLODs.length; index++) {
-                        loader.addLoaderNonBlockingPendingData(index);
-                    }
-                    // Start with the lowest quality LOD.
-                    this.loadMaterialLOD(loader, material, materialLODs, materialLODs.length - 1, assign);
-                    return true;
+                MSFTLOD.prototype._traverseNode = function (loader, index, action, parentNode) {
+                    var node = loader._gltf.nodes[index];
+                    return this._loadExtension(node, function (extension, onComplete) {
+                        for (var i = extension.ids.length - 1; i >= 0; i--) {
+                            loader._traverseNode(extension.ids[i], action, parentNode);
+                        }
+                        loader._traverseNode(index, action, parentNode);
+                        onComplete();
+                    });
                 };
-                MSFTLOD.prototype.loadMaterialLOD = function (loader, material, materialLODs, lod, assign) {
+                MSFTLOD.prototype._loadNode = function (loader, node) {
                     var _this = this;
-                    var materialLOD = loader.gltf.materials[materialLODs[lod]];
-                    if (lod !== materialLODs.length - 1) {
-                        loader.blockPendingTracking = true;
-                    }
-                    loader.loadMaterial(materialLOD, function (babylonMaterial, isNew) {
-                        assign(babylonMaterial, isNew);
-                        loader.removeLoaderPendingData(lod);
-                        // Loading is considered complete if this is the lowest quality LOD.
-                        if (lod === materialLODs.length - 1) {
-                            loader.removeLoaderPendingData(material);
+                    return this._loadExtension(node, function (extension, onComplete) {
+                        var nodes = [node.index].concat(extension.ids).map(function (index) { return loader._gltf.nodes[index]; });
+                        loader._addLoaderPendingData(node);
+                        _this._loadNodeLOD(loader, nodes, nodes.length - 1, function () {
+                            loader._removeLoaderPendingData(node);
+                            onComplete();
+                        });
+                    });
+                };
+                MSFTLOD.prototype._loadNodeLOD = function (loader, nodes, index, onComplete) {
+                    var _this = this;
+                    loader._whenAction(function () {
+                        loader._loadNode(nodes[index]);
+                    }, function () {
+                        if (index !== nodes.length - 1) {
+                            var previousNode = nodes[index + 1];
+                            previousNode.babylonMesh.setEnabled(false);
                         }
-                        if (lod === 0) {
-                            loader.blockPendingTracking = false;
+                        if (index === 0) {
+                            onComplete();
+                            return;
+                        }
+                        setTimeout(function () {
+                            _this._loadNodeLOD(loader, nodes, index - 1, onComplete);
+                        }, MSFTLOD.MinimalLODDelay);
+                    });
+                };
+                MSFTLOD.prototype._loadMaterial = function (loader, material, assign) {
+                    var _this = this;
+                    return this._loadExtension(material, function (extension, onComplete) {
+                        var materials = [material.index].concat(extension.ids).map(function (index) { return loader._gltf.materials[index]; });
+                        loader._addLoaderPendingData(material);
+                        _this._loadMaterialLOD(loader, materials, materials.length - 1, assign, function () {
+                            material.extensions[_this.name] = extension;
+                            loader._removeLoaderPendingData(material);
+                            onComplete();
+                        });
+                    });
+                };
+                MSFTLOD.prototype._loadMaterialLOD = function (loader, materials, index, assign, onComplete) {
+                    var _this = this;
+                    loader._loadMaterial(materials[index], function (babylonMaterial, isNew) {
+                        assign(babylonMaterial, isNew);
+                        if (index === 0) {
+                            onComplete();
                             return;
                         }
                         // Load the next LOD when the loader is ready to render and
                         // all active material textures of the current LOD are loaded.
-                        loader.executeWhenRenderReady(function () {
+                        loader._executeWhenRenderReady(function () {
                             BABYLON.BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), function () {
                                 setTimeout(function () {
-                                    _this.loadMaterialLOD(loader, material, materialLODs, lod - 1, assign);
+                                    _this._loadMaterialLOD(loader, materials, index - 1, assign, onComplete);
                                 }, MSFTLOD.MinimalLODDelay);
                             });
                         });
@@ -3804,19 +3836,14 @@ var BABYLON;
                     enumerable: true,
                     configurable: true
                 });
-                KHRMaterialsPbrSpecularGlossiness.prototype.loadMaterial = function (loader, material, assign) {
-                    if (!material.extensions) {
-                        return false;
-                    }
-                    var properties = material.extensions[this.name];
-                    if (!properties) {
-                        return false;
-                    }
-                    loader.createPbrMaterial(material);
-                    loader.loadMaterialBaseProperties(material);
-                    this._loadSpecularGlossinessProperties(loader, material, properties);
-                    assign(material.babylonMaterial, true);
-                    return true;
+                KHRMaterialsPbrSpecularGlossiness.prototype._loadMaterial = function (loader, material, assign) {
+                    var _this = this;
+                    return this._loadExtension(material, function (extension, onComplete) {
+                        loader._createPbrMaterial(material);
+                        loader._loadMaterialBaseProperties(material);
+                        _this._loadSpecularGlossinessProperties(loader, material, extension);
+                        assign(material.babylonMaterial, true);
+                    });
                 };
                 KHRMaterialsPbrSpecularGlossiness.prototype._loadSpecularGlossinessProperties = function (loader, material, properties) {
                     var babylonMaterial = material.babylonMaterial;
@@ -3824,14 +3851,14 @@ var BABYLON;
                     babylonMaterial.reflectivityColor = properties.specularFactor ? BABYLON.Color3.FromArray(properties.specularFactor) : new BABYLON.Color3(1, 1, 1);
                     babylonMaterial.microSurface = properties.glossinessFactor === undefined ? 1 : properties.glossinessFactor;
                     if (properties.diffuseTexture) {
-                        babylonMaterial.albedoTexture = loader.loadTexture(properties.diffuseTexture);
+                        babylonMaterial.albedoTexture = loader._loadTexture(properties.diffuseTexture);
                     }
                     if (properties.specularGlossinessTexture) {
-                        babylonMaterial.reflectivityTexture = loader.loadTexture(properties.specularGlossinessTexture);
+                        babylonMaterial.reflectivityTexture = loader._loadTexture(properties.specularGlossinessTexture);
                         babylonMaterial.reflectivityTexture.hasAlpha = true;
                         babylonMaterial.useMicroSurfaceFromReflectivityMapAlpha = true;
                     }
-                    loader.loadMaterialAlphaProperties(material, properties.diffuseFactor);
+                    loader._loadMaterialAlphaProperties(material, properties.diffuseFactor);
                 };
                 return KHRMaterialsPbrSpecularGlossiness;
             }(GLTF2.GLTFLoaderExtension));

文件差异内容过多而无法显示
+ 3 - 3
dist/preview release/loaders/babylon.glTFFileLoader.min.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.min.js


+ 234 - 207
dist/preview release/loaders/babylonjs.loaders.js

@@ -3430,17 +3430,31 @@ var BABYLON;
 (function (BABYLON) {
     var GLTF2;
     (function (GLTF2) {
+        var GLTFLoaderTracker = (function () {
+            function GLTFLoaderTracker(onComplete) {
+                this._pendingCount = 0;
+                this._callback = onComplete;
+            }
+            GLTFLoaderTracker.prototype._addPendingData = function (data) {
+                this._pendingCount++;
+            };
+            GLTFLoaderTracker.prototype._removePendingData = function (data) {
+                if (--this._pendingCount === 0) {
+                    this._callback();
+                }
+            };
+            return GLTFLoaderTracker;
+        }());
         var GLTFLoader = (function () {
             function GLTFLoader(parent) {
                 this._renderReady = false;
                 this._disposed = false;
-                this._blockPendingTracking = false;
-                // Observable with boolean indicating success or error.
                 this._renderReadyObservable = new BABYLON.Observable();
                 // Count of pending work that needs to complete before the asset is rendered.
                 this._renderPendingCount = 0;
-                // Count of pending work that needs to complete before the loader is cleared.
+                // Count of pending work that needs to complete before the loader is disposed.
                 this._loaderPendingCount = 0;
+                this._loaderTrackers = new Array();
                 this._parent = parent;
             }
             GLTFLoader.RegisterExtension = function (extension) {
@@ -3452,28 +3466,6 @@ var BABYLON;
                 // Keep the order of registration so that extensions registered first are called first.
                 GLTF2.GLTFLoaderExtension._Extensions.push(extension);
             };
-            Object.defineProperty(GLTFLoader.prototype, "gltf", {
-                get: function () {
-                    return this._gltf;
-                },
-                enumerable: true,
-                configurable: true
-            });
-            Object.defineProperty(GLTFLoader.prototype, "babylonScene", {
-                get: function () {
-                    return this._babylonScene;
-                },
-                enumerable: true,
-                configurable: true
-            });
-            GLTFLoader.prototype.executeWhenRenderReady = function (func) {
-                if (this._renderReady) {
-                    func();
-                }
-                else {
-                    this._renderReadyObservable.add(func);
-                }
-            };
             GLTFLoader.prototype.dispose = function () {
                 if (this._disposed) {
                     return;
@@ -3514,10 +3506,10 @@ var BABYLON;
                 this._successCallback = onSuccess;
                 this._progressCallback = onProgress;
                 this._errorCallback = onError;
-                this.addPendingData(this);
+                this._addPendingData(this);
                 this._loadScene(nodeNames);
                 this._loadAnimations();
-                this.removePendingData(this);
+                this._removePendingData(this);
             };
             GLTFLoader.prototype._onError = function (message) {
                 if (this._errorCallback) {
@@ -3526,39 +3518,33 @@ var BABYLON;
                 this.dispose();
             };
             GLTFLoader.prototype._onProgress = function (event) {
-                this._progressCallback(event);
+                if (this._progressCallback) {
+                    this._progressCallback(event);
+                }
             };
-            GLTFLoader.prototype._onRenderReady = function () {
-                switch (this._parent.coordinateSystemMode) {
-                    case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO:
-                        if (!this._babylonScene.useRightHandedSystem) {
-                            this._addRightHandToLeftHandRootTransform();
-                        }
-                        break;
-                    case BABYLON.GLTFLoaderCoordinateSystemMode.PASS_THROUGH:
-                        // do nothing
-                        break;
-                    case BABYLON.GLTFLoaderCoordinateSystemMode.FORCE_RIGHT_HANDED:
-                        this._babylonScene.useRightHandedSystem = true;
-                        break;
-                    default:
-                        BABYLON.Tools.Error("Invalid coordinate system mode (" + this._parent.coordinateSystemMode + ")");
-                        break;
+            GLTFLoader.prototype._executeWhenRenderReady = function (func) {
+                if (this._renderReady) {
+                    func();
                 }
-                this._showMeshes();
+                else {
+                    this._renderReadyObservable.add(func);
+                }
+            };
+            GLTFLoader.prototype._onRenderReady = function () {
+                var rootNode = this._gltf.nodes[this._gltf.nodes.length - 1];
+                rootNode.babylonMesh.setEnabled(true);
                 this._startAnimations();
                 this._successCallback();
                 this._renderReadyObservable.notifyObservers(this);
+                if (this._parent.onReady) {
+                    this._parent.onReady();
+                }
             };
-            GLTFLoader.prototype._onLoaderComplete = function () {
+            GLTFLoader.prototype._onComplete = function () {
                 if (this._parent.onComplete) {
                     this._parent.onComplete();
                 }
-            };
-            GLTFLoader.prototype._onLoaderFirstLODComplete = function () {
-                if (this._parent.onFirstLODComplete) {
-                    this._parent.onFirstLODComplete();
-                }
+                this.dispose();
             };
             GLTFLoader.prototype._loadData = function (data) {
                 this._gltf = data.json;
@@ -3579,26 +3565,8 @@ var BABYLON;
                     binaryBuffer.loadedData = data.bin;
                 }
             };
-            GLTFLoader.prototype._addRightHandToLeftHandRootTransform = function () {
-                this._rootMesh = new BABYLON.Mesh("root", this._babylonScene);
-                this._rootMesh.isVisible = false;
-                this._rootMesh.scaling = new BABYLON.Vector3(1, 1, -1);
-                this._rootMesh.rotation.y = Math.PI;
-                var nodes = this._gltf.nodes;
-                if (nodes) {
-                    for (var i = 0; i < nodes.length; i++) {
-                        var mesh = nodes[i].babylonMesh;
-                        if (mesh && !mesh.parent) {
-                            mesh.parent = this._rootMesh;
-                        }
-                    }
-                }
-            };
             GLTFLoader.prototype._getMeshes = function () {
                 var meshes = [];
-                if (this._rootMesh) {
-                    meshes.push(this._rootMesh);
-                }
                 var nodes = this._gltf.nodes;
                 if (nodes) {
                     nodes.forEach(function (node) {
@@ -3631,16 +3599,34 @@ var BABYLON;
                 }
                 return targets;
             };
-            GLTFLoader.prototype._showMeshes = function () {
-                this._getMeshes().forEach(function (mesh) { return mesh.isVisible = true; });
-            };
             GLTFLoader.prototype._startAnimations = function () {
                 var _this = this;
                 this._getAnimationTargets().forEach(function (target) { return _this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true); });
             };
             GLTFLoader.prototype._loadScene = function (nodeNames) {
-                var _this = this;
                 var scene = this._gltf.scenes[this._gltf.scene || 0];
+                var rootNode = { name: "root", children: scene.nodes };
+                switch (this._parent.coordinateSystemMode) {
+                    case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO:
+                        if (!this._babylonScene.useRightHandedSystem) {
+                            rootNode.rotation = [0, 1, 0, 0];
+                            rootNode.scale = [1, 1, -1];
+                        }
+                        break;
+                    case BABYLON.GLTFLoaderCoordinateSystemMode.PASS_THROUGH:
+                        // do nothing
+                        break;
+                    case BABYLON.GLTFLoaderCoordinateSystemMode.FORCE_RIGHT_HANDED:
+                        this._babylonScene.useRightHandedSystem = true;
+                        break;
+                    default:
+                        BABYLON.Tools.Error("Invalid coordinate system mode (" + this._parent.coordinateSystemMode + ")");
+                        break;
+                }
+                // Inject a root node into the scene.
+                this._gltf.nodes = this._gltf.nodes || [];
+                scene.nodes = [this._gltf.nodes.length];
+                this._gltf.nodes.push(rootNode);
                 var nodeIndices = scene.nodes;
                 this._traverseNodes(nodeIndices, function (node, index, parentNode) {
                     node.index = index;
@@ -3657,19 +3643,25 @@ var BABYLON;
                     }
                     var filteredNodeIndices = new Array();
                     this._traverseNodes(nodeIndices, function (node) {
-                        if (nodeNames.indexOf(node.name) === -1) {
-                            return true;
+                        if (nodeNames.indexOf(node.name) !== -1) {
+                            filteredNodeIndices.push(node.index);
+                            return false;
                         }
-                        filteredNodeIndices.push(node.index);
-                        return false;
+                        return true;
                     });
                     nodeIndices = filteredNodeIndices;
                 }
-                this._traverseNodes(nodeIndices, function (node) { return _this._loadNode(node); });
+                for (var i = 0; i < nodeIndices.length; i++) {
+                    this._loadNode(this._gltf.nodes[nodeIndices[i]]);
+                }
+                // Disable the root mesh until the asset is ready to render.
+                rootNode.babylonMesh.setEnabled(false);
             };
             GLTFLoader.prototype._loadNode = function (node) {
+                if (GLTF2.GLTFLoaderExtension.LoadNode(this, node)) {
+                    return;
+                }
                 node.babylonMesh = new BABYLON.Mesh(node.name || "mesh" + node.index, this._babylonScene);
-                node.babylonMesh.isVisible = false;
                 this._loadTransform(node);
                 if (node.mesh !== undefined) {
                     var mesh = this._gltf.meshes[node.mesh];
@@ -3686,7 +3678,11 @@ var BABYLON;
                 if (node.camera !== undefined) {
                     // TODO: handle cameras
                 }
-                return true;
+                if (node.children) {
+                    for (var i = 0; i < node.children.length; i++) {
+                        this._loadNode(this._gltf.nodes[node.children[i]]);
+                    }
+                }
             };
             GLTFLoader.prototype._loadMesh = function (node, mesh) {
                 var _this = this;
@@ -3718,25 +3714,24 @@ var BABYLON;
                             loadMaterial: function () {
                                 if (primitive.material === undefined) {
                                     babylonMultiMaterial.subMaterials[i] = _this._getDefaultMaterial();
+                                    return;
                                 }
-                                else {
-                                    var material = _this._gltf.materials[primitive.material];
-                                    _this.loadMaterial(material, function (babylonMaterial, isNew) {
-                                        if (isNew && _this._parent.onMaterialLoaded) {
-                                            _this._parent.onMaterialLoaded(babylonMaterial);
-                                        }
-                                        if (_this._parent.onBeforeMaterialReadyAsync) {
-                                            _this.addLoaderPendingData(material);
-                                            _this._parent.onBeforeMaterialReadyAsync(babylonMaterial, node.babylonMesh, babylonMultiMaterial.subMaterials[i] != null, function () {
-                                                babylonMultiMaterial.subMaterials[i] = babylonMaterial;
-                                                _this.removeLoaderPendingData(material);
-                                            });
-                                        }
-                                        else {
+                                var material = _this._gltf.materials[primitive.material];
+                                _this._loadMaterial(material, function (babylonMaterial, isNew) {
+                                    if (isNew && _this._parent.onMaterialLoaded) {
+                                        _this._parent.onMaterialLoaded(babylonMaterial);
+                                    }
+                                    if (_this._parent.onBeforeMaterialReadyAsync) {
+                                        _this._addLoaderPendingData(material);
+                                        _this._parent.onBeforeMaterialReadyAsync(babylonMaterial, node.babylonMesh, babylonMultiMaterial.subMaterials[i] != null, function () {
                                             babylonMultiMaterial.subMaterials[i] = babylonMaterial;
-                                        }
-                                    });
-                                }
+                                            _this._removeLoaderPendingData(material);
+                                        });
+                                    }
+                                    else {
+                                        babylonMultiMaterial.subMaterials[i] = babylonMaterial;
+                                    }
+                                });
                             }
                         });
                         vertexData.merge(subVertexData);
@@ -3967,14 +3962,15 @@ var BABYLON;
             };
             GLTFLoader.prototype._traverseNode = function (index, action, parentNode) {
                 if (parentNode === void 0) { parentNode = null; }
+                if (GLTF2.GLTFLoaderExtension.TraverseNode(this, index, action, parentNode)) {
+                    return;
+                }
                 var node = this._gltf.nodes[index];
                 if (!action(node, index, parentNode)) {
                     return;
                 }
                 if (node.children) {
-                    for (var i = 0; i < node.children.length; i++) {
-                        this._traverseNode(node.children[i], action, node);
-                    }
+                    this._traverseNodes(node.children, action, node);
                 }
             };
             GLTFLoader.prototype._loadAnimations = function () {
@@ -4102,11 +4098,11 @@ var BABYLON;
             GLTFLoader.prototype._loadBufferAsync = function (index, onSuccess) {
                 var _this = this;
                 var buffer = this._gltf.buffers[index];
-                this.addPendingData(buffer);
+                this._addPendingData(buffer);
                 if (buffer.loadedData) {
                     setTimeout(function () {
                         onSuccess(buffer.loadedData);
-                        _this.removePendingData(buffer);
+                        _this._removePendingData(buffer);
                     });
                 }
                 else if (GLTF2.GLTFUtils.IsBase64(buffer.uri)) {
@@ -4114,20 +4110,20 @@ var BABYLON;
                     buffer.loadedData = new Uint8Array(data);
                     setTimeout(function () {
                         onSuccess(buffer.loadedData);
-                        _this.removePendingData(buffer);
+                        _this._removePendingData(buffer);
                     });
                 }
                 else if (buffer.loadedObservable) {
                     buffer.loadedObservable.add(function (buffer) {
                         onSuccess(buffer.loadedData);
-                        _this.removePendingData(buffer);
+                        _this._removePendingData(buffer);
                     });
                 }
                 else {
                     buffer.loadedObservable = new BABYLON.Observable();
                     buffer.loadedObservable.add(function (buffer) {
                         onSuccess(buffer.loadedData);
-                        _this.removePendingData(buffer);
+                        _this._removePendingData(buffer);
                     });
                     BABYLON.Tools.LoadFile(this._rootUrl + buffer.uri, function (data) {
                         buffer.loadedData = new Uint8Array(data);
@@ -4140,7 +4136,7 @@ var BABYLON;
                     }, this._babylonScene.database, true, function (request) {
                         if (!_this._disposed) {
                             _this._onError("Failed to load file '" + buffer.uri + "': " + request.status + " " + request.statusText);
-                            _this.removePendingData(buffer);
+                            _this._removePendingData(buffer);
                         }
                     });
                 }
@@ -4269,54 +4265,42 @@ var BABYLON;
                         return 0;
                 }
             };
-            Object.defineProperty(GLTFLoader.prototype, "blockPendingTracking", {
-                set: function (value) {
-                    this._blockPendingTracking = value;
-                },
-                enumerable: true,
-                configurable: true
-            });
-            GLTFLoader.prototype.addPendingData = function (data) {
+            GLTFLoader.prototype._addPendingData = function (data) {
                 if (!this._renderReady) {
                     this._renderPendingCount++;
                 }
-                this.addLoaderPendingData(data);
+                this._addLoaderPendingData(data);
             };
-            GLTFLoader.prototype.removePendingData = function (data) {
+            GLTFLoader.prototype._removePendingData = function (data) {
                 if (!this._renderReady) {
                     if (--this._renderPendingCount === 0) {
                         this._renderReady = true;
                         this._onRenderReady();
                     }
                 }
-                this.removeLoaderPendingData(data);
-            };
-            GLTFLoader.prototype.addLoaderNonBlockingPendingData = function (data) {
-                if (!this._nonBlockingData) {
-                    this._nonBlockingData = new Array();
-                }
-                this._nonBlockingData.push(data);
+                this._removeLoaderPendingData(data);
             };
-            GLTFLoader.prototype.addLoaderPendingData = function (data) {
-                if (this._blockPendingTracking) {
-                    this.addLoaderNonBlockingPendingData(data);
-                    return;
-                }
+            GLTFLoader.prototype._addLoaderPendingData = function (data) {
                 this._loaderPendingCount++;
+                this._loaderTrackers.forEach(function (tracker) { return tracker._addPendingData(data); });
             };
-            GLTFLoader.prototype.removeLoaderPendingData = function (data) {
-                var indexInPending = this._nonBlockingData ? this._nonBlockingData.indexOf(data) : -1;
-                if (indexInPending !== -1) {
-                    this._nonBlockingData.splice(indexInPending, 1);
-                }
-                else if (--this._loaderPendingCount === 0) {
-                    this._onLoaderFirstLODComplete();
-                }
-                if ((!this._nonBlockingData || this._nonBlockingData.length === 0) && this._loaderPendingCount === 0) {
-                    this._onLoaderComplete();
-                    this.dispose();
+            GLTFLoader.prototype._removeLoaderPendingData = function (data) {
+                this._loaderTrackers.forEach(function (tracker) { return tracker._removePendingData(data); });
+                if (--this._loaderPendingCount === 0) {
+                    this._onComplete();
                 }
             };
+            GLTFLoader.prototype._whenAction = function (action, onComplete) {
+                var _this = this;
+                var tracker = new GLTFLoaderTracker(function () {
+                    _this._loaderTrackers.splice(_this._loaderTrackers.indexOf(tracker));
+                    onComplete();
+                });
+                this._loaderTrackers.push(tracker);
+                this._addLoaderPendingData(tracker);
+                action();
+                this._removeLoaderPendingData(tracker);
+            };
             GLTFLoader.prototype._getDefaultMaterial = function () {
                 if (!this._defaultMaterial) {
                     var id = "__gltf_default";
@@ -4344,17 +4328,17 @@ var BABYLON;
                 babylonMaterial.metallic = properties.metallicFactor === undefined ? 1 : properties.metallicFactor;
                 babylonMaterial.roughness = properties.roughnessFactor === undefined ? 1 : properties.roughnessFactor;
                 if (properties.baseColorTexture) {
-                    babylonMaterial.albedoTexture = this.loadTexture(properties.baseColorTexture);
+                    babylonMaterial.albedoTexture = this._loadTexture(properties.baseColorTexture);
                 }
                 if (properties.metallicRoughnessTexture) {
-                    babylonMaterial.metallicTexture = this.loadTexture(properties.metallicRoughnessTexture);
+                    babylonMaterial.metallicTexture = this._loadTexture(properties.metallicRoughnessTexture);
                     babylonMaterial.useMetallnessFromMetallicTextureBlue = true;
                     babylonMaterial.useRoughnessFromMetallicTextureGreen = true;
                     babylonMaterial.useRoughnessFromMetallicTextureAlpha = false;
                 }
-                this.loadMaterialAlphaProperties(material, properties.baseColorFactor);
+                this._loadMaterialAlphaProperties(material, properties.baseColorFactor);
             };
-            GLTFLoader.prototype.loadMaterial = function (material, assign) {
+            GLTFLoader.prototype._loadMaterial = function (material, assign) {
                 if (material.babylonMaterial) {
                     assign(material.babylonMaterial, false);
                     return;
@@ -4362,17 +4346,17 @@ var BABYLON;
                 if (GLTF2.GLTFLoaderExtension.LoadMaterial(this, material, assign)) {
                     return;
                 }
-                this.createPbrMaterial(material);
-                this.loadMaterialBaseProperties(material);
+                this._createPbrMaterial(material);
+                this._loadMaterialBaseProperties(material);
                 this._loadMaterialMetallicRoughnessProperties(material);
                 assign(material.babylonMaterial, true);
             };
-            GLTFLoader.prototype.createPbrMaterial = function (material) {
+            GLTFLoader.prototype._createPbrMaterial = function (material) {
                 var babylonMaterial = new BABYLON.PBRMaterial(material.name || "mat" + material.index, this._babylonScene);
                 babylonMaterial.sideOrientation = BABYLON.Material.CounterClockWiseSideOrientation;
                 material.babylonMaterial = babylonMaterial;
             };
-            GLTFLoader.prototype.loadMaterialBaseProperties = function (material) {
+            GLTFLoader.prototype._loadMaterialBaseProperties = function (material) {
                 var babylonMaterial = material.babylonMaterial;
                 babylonMaterial.emissiveColor = material.emissiveFactor ? BABYLON.Color3.FromArray(material.emissiveFactor) : new BABYLON.Color3(0, 0, 0);
                 if (material.doubleSided) {
@@ -4380,7 +4364,7 @@ var BABYLON;
                     babylonMaterial.twoSidedLighting = true;
                 }
                 if (material.normalTexture) {
-                    babylonMaterial.bumpTexture = this.loadTexture(material.normalTexture);
+                    babylonMaterial.bumpTexture = this._loadTexture(material.normalTexture);
                     babylonMaterial.invertNormalMapX = !this._babylonScene.useRightHandedSystem;
                     babylonMaterial.invertNormalMapY = this._babylonScene.useRightHandedSystem;
                     if (material.normalTexture.scale !== undefined) {
@@ -4388,17 +4372,17 @@ var BABYLON;
                     }
                 }
                 if (material.occlusionTexture) {
-                    babylonMaterial.ambientTexture = this.loadTexture(material.occlusionTexture);
+                    babylonMaterial.ambientTexture = this._loadTexture(material.occlusionTexture);
                     babylonMaterial.useAmbientInGrayScale = true;
                     if (material.occlusionTexture.strength !== undefined) {
                         babylonMaterial.ambientTextureStrength = material.occlusionTexture.strength;
                     }
                 }
                 if (material.emissiveTexture) {
-                    babylonMaterial.emissiveTexture = this.loadTexture(material.emissiveTexture);
+                    babylonMaterial.emissiveTexture = this._loadTexture(material.emissiveTexture);
                 }
             };
-            GLTFLoader.prototype.loadMaterialAlphaProperties = function (material, colorFactor) {
+            GLTFLoader.prototype._loadMaterialAlphaProperties = function (material, colorFactor) {
                 var babylonMaterial = material.babylonMaterial;
                 var alphaMode = material.alphaMode || "OPAQUE";
                 switch (alphaMode) {
@@ -4421,7 +4405,7 @@ var BABYLON;
                 }
                 babylonMaterial.alphaCutOff = material.alphaCutoff === undefined ? 0.5 : material.alphaCutoff;
             };
-            GLTFLoader.prototype.loadTexture = function (textureInfo) {
+            GLTFLoader.prototype._loadTexture = function (textureInfo) {
                 var _this = this;
                 var texture = this._gltf.textures[textureInfo.index];
                 var texCoord = textureInfo.texCoord || 0;
@@ -4432,15 +4416,15 @@ var BABYLON;
                 var sampler = (texture.sampler === undefined ? {} : this._gltf.samplers[texture.sampler]);
                 var noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
                 var samplingMode = GLTF2.GLTFUtils.GetTextureSamplingMode(sampler.magFilter, sampler.minFilter);
-                this.addPendingData(texture);
+                this._addPendingData(texture);
                 var babylonTexture = new BABYLON.Texture(null, this._babylonScene, noMipMaps, false, samplingMode, function () {
                     if (!_this._disposed) {
-                        _this.removePendingData(texture);
+                        _this._removePendingData(texture);
                     }
                 }, function () {
                     if (!_this._disposed) {
                         _this._onError("Failed to load texture '" + source.uri + "'");
-                        _this.removePendingData(texture);
+                        _this._removePendingData(texture);
                     }
                 });
                 if (texture.url) {
@@ -4607,9 +4591,34 @@ var BABYLON;
             function GLTFLoaderExtension() {
                 this.enabled = true;
             }
-            GLTFLoaderExtension.prototype.loadMaterial = function (loader, material, assign) { return false; };
+            GLTFLoaderExtension.prototype._traverseNode = function (loader, index, action, parentNode) { return false; };
+            GLTFLoaderExtension.prototype._loadNode = function (loader, node) { return false; };
+            GLTFLoaderExtension.prototype._loadMaterial = function (loader, material, assign) { return false; };
+            GLTFLoaderExtension.prototype._loadExtension = function (property, action) {
+                var _this = this;
+                if (!property.extensions) {
+                    return false;
+                }
+                var extension = property.extensions[this.name];
+                if (!extension) {
+                    return false;
+                }
+                // Clear out the extension before executing the action to avoid recursing into the same property.
+                property.extensions[this.name] = undefined;
+                action(extension, function () {
+                    // Restore the extension after completing the action.
+                    property.extensions[_this.name] = extension;
+                });
+                return true;
+            };
+            GLTFLoaderExtension.TraverseNode = function (loader, index, action, parentNode) {
+                return this._ApplyExtensions(function (extension) { return extension._traverseNode(loader, index, action, parentNode); });
+            };
+            GLTFLoaderExtension.LoadNode = function (loader, node) {
+                return this._ApplyExtensions(function (extension) { return extension._loadNode(loader, node); });
+            };
             GLTFLoaderExtension.LoadMaterial = function (loader, material, assign) {
-                return this._ApplyExtensions(function (extension) { return extension.loadMaterial(loader, material, assign); });
+                return this._ApplyExtensions(function (extension) { return extension._loadMaterial(loader, material, assign); });
             };
             GLTFLoaderExtension._ApplyExtensions = function (action) {
                 var extensions = GLTFLoaderExtension._Extensions;
@@ -4644,6 +4653,7 @@ var BABYLON;
     (function (GLTF2) {
         var Extensions;
         (function (Extensions) {
+            // See https://github.com/sbtron/glTF/tree/MSFT_lod/extensions/Vendor/MSFT_lod for more information about this extension.
             var MSFTLOD = (function (_super) {
                 __extends(MSFTLOD, _super);
                 function MSFTLOD() {
@@ -4656,49 +4666,71 @@ var BABYLON;
                     enumerable: true,
                     configurable: true
                 });
-                MSFTLOD.prototype.loadMaterial = function (loader, material, assign) {
-                    if (!material.extensions) {
-                        return false;
-                    }
-                    var properties = material.extensions[this.name];
-                    if (!properties) {
-                        return false;
-                    }
-                    // Clear out the extension so that it won't get loaded again.
-                    material.extensions[this.name] = undefined;
-                    // Tell the loader not to clear its state until the highest LOD is loaded.
-                    var materialLODs = [material.index].concat(properties.ids);
-                    loader.addLoaderPendingData(material);
-                    for (var index = 0; index < materialLODs.length; index++) {
-                        loader.addLoaderNonBlockingPendingData(index);
-                    }
-                    // Start with the lowest quality LOD.
-                    this.loadMaterialLOD(loader, material, materialLODs, materialLODs.length - 1, assign);
-                    return true;
+                MSFTLOD.prototype._traverseNode = function (loader, index, action, parentNode) {
+                    var node = loader._gltf.nodes[index];
+                    return this._loadExtension(node, function (extension, onComplete) {
+                        for (var i = extension.ids.length - 1; i >= 0; i--) {
+                            loader._traverseNode(extension.ids[i], action, parentNode);
+                        }
+                        loader._traverseNode(index, action, parentNode);
+                        onComplete();
+                    });
                 };
-                MSFTLOD.prototype.loadMaterialLOD = function (loader, material, materialLODs, lod, assign) {
+                MSFTLOD.prototype._loadNode = function (loader, node) {
                     var _this = this;
-                    var materialLOD = loader.gltf.materials[materialLODs[lod]];
-                    if (lod !== materialLODs.length - 1) {
-                        loader.blockPendingTracking = true;
-                    }
-                    loader.loadMaterial(materialLOD, function (babylonMaterial, isNew) {
-                        assign(babylonMaterial, isNew);
-                        loader.removeLoaderPendingData(lod);
-                        // Loading is considered complete if this is the lowest quality LOD.
-                        if (lod === materialLODs.length - 1) {
-                            loader.removeLoaderPendingData(material);
+                    return this._loadExtension(node, function (extension, onComplete) {
+                        var nodes = [node.index].concat(extension.ids).map(function (index) { return loader._gltf.nodes[index]; });
+                        loader._addLoaderPendingData(node);
+                        _this._loadNodeLOD(loader, nodes, nodes.length - 1, function () {
+                            loader._removeLoaderPendingData(node);
+                            onComplete();
+                        });
+                    });
+                };
+                MSFTLOD.prototype._loadNodeLOD = function (loader, nodes, index, onComplete) {
+                    var _this = this;
+                    loader._whenAction(function () {
+                        loader._loadNode(nodes[index]);
+                    }, function () {
+                        if (index !== nodes.length - 1) {
+                            var previousNode = nodes[index + 1];
+                            previousNode.babylonMesh.setEnabled(false);
+                        }
+                        if (index === 0) {
+                            onComplete();
+                            return;
                         }
-                        if (lod === 0) {
-                            loader.blockPendingTracking = false;
+                        setTimeout(function () {
+                            _this._loadNodeLOD(loader, nodes, index - 1, onComplete);
+                        }, MSFTLOD.MinimalLODDelay);
+                    });
+                };
+                MSFTLOD.prototype._loadMaterial = function (loader, material, assign) {
+                    var _this = this;
+                    return this._loadExtension(material, function (extension, onComplete) {
+                        var materials = [material.index].concat(extension.ids).map(function (index) { return loader._gltf.materials[index]; });
+                        loader._addLoaderPendingData(material);
+                        _this._loadMaterialLOD(loader, materials, materials.length - 1, assign, function () {
+                            material.extensions[_this.name] = extension;
+                            loader._removeLoaderPendingData(material);
+                            onComplete();
+                        });
+                    });
+                };
+                MSFTLOD.prototype._loadMaterialLOD = function (loader, materials, index, assign, onComplete) {
+                    var _this = this;
+                    loader._loadMaterial(materials[index], function (babylonMaterial, isNew) {
+                        assign(babylonMaterial, isNew);
+                        if (index === 0) {
+                            onComplete();
                             return;
                         }
                         // Load the next LOD when the loader is ready to render and
                         // all active material textures of the current LOD are loaded.
-                        loader.executeWhenRenderReady(function () {
+                        loader._executeWhenRenderReady(function () {
                             BABYLON.BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), function () {
                                 setTimeout(function () {
-                                    _this.loadMaterialLOD(loader, material, materialLODs, lod - 1, assign);
+                                    _this._loadMaterialLOD(loader, materials, index - 1, assign, onComplete);
                                 }, MSFTLOD.MinimalLODDelay);
                             });
                         });
@@ -4738,19 +4770,14 @@ var BABYLON;
                     enumerable: true,
                     configurable: true
                 });
-                KHRMaterialsPbrSpecularGlossiness.prototype.loadMaterial = function (loader, material, assign) {
-                    if (!material.extensions) {
-                        return false;
-                    }
-                    var properties = material.extensions[this.name];
-                    if (!properties) {
-                        return false;
-                    }
-                    loader.createPbrMaterial(material);
-                    loader.loadMaterialBaseProperties(material);
-                    this._loadSpecularGlossinessProperties(loader, material, properties);
-                    assign(material.babylonMaterial, true);
-                    return true;
+                KHRMaterialsPbrSpecularGlossiness.prototype._loadMaterial = function (loader, material, assign) {
+                    var _this = this;
+                    return this._loadExtension(material, function (extension, onComplete) {
+                        loader._createPbrMaterial(material);
+                        loader._loadMaterialBaseProperties(material);
+                        _this._loadSpecularGlossinessProperties(loader, material, extension);
+                        assign(material.babylonMaterial, true);
+                    });
                 };
                 KHRMaterialsPbrSpecularGlossiness.prototype._loadSpecularGlossinessProperties = function (loader, material, properties) {
                     var babylonMaterial = material.babylonMaterial;
@@ -4758,14 +4785,14 @@ var BABYLON;
                     babylonMaterial.reflectivityColor = properties.specularFactor ? BABYLON.Color3.FromArray(properties.specularFactor) : new BABYLON.Color3(1, 1, 1);
                     babylonMaterial.microSurface = properties.glossinessFactor === undefined ? 1 : properties.glossinessFactor;
                     if (properties.diffuseTexture) {
-                        babylonMaterial.albedoTexture = loader.loadTexture(properties.diffuseTexture);
+                        babylonMaterial.albedoTexture = loader._loadTexture(properties.diffuseTexture);
                     }
                     if (properties.specularGlossinessTexture) {
-                        babylonMaterial.reflectivityTexture = loader.loadTexture(properties.specularGlossinessTexture);
+                        babylonMaterial.reflectivityTexture = loader._loadTexture(properties.specularGlossinessTexture);
                         babylonMaterial.reflectivityTexture.hasAlpha = true;
                         babylonMaterial.useMicroSurfaceFromReflectivityMapAlpha = true;
                     }
-                    loader.loadMaterialAlphaProperties(material, properties.diffuseFactor);
+                    loader._loadMaterialAlphaProperties(material, properties.diffuseFactor);
                 };
                 return KHRMaterialsPbrSpecularGlossiness;
             }(GLTF2.GLTFLoaderExtension));

文件差异内容过多而无法显示
+ 3 - 3
dist/preview release/loaders/babylonjs.loaders.min.js


+ 37 - 33
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -125,13 +125,17 @@ declare module BABYLON {
          */
         onBeforeMaterialReadyAsync: (material: Material, targetMesh: AbstractMesh, isLOD: boolean, callback: () => void) => void;
         /**
-         * Raised when all LODs are complete (or if there is no LOD and model is complete)
+         * Raised when the visible components (geometry, materials, textures, etc.) are first ready to be rendered.
+         * For assets with LODs, raised when the first LOD is complete.
+         * For assets without LODs, raised when the model is complete just before onComplete.
          */
-        onComplete: () => void;
+        onReady: () => void;
         /**
-         * Raised when first LOD complete (or if there is no LOD and model is complete)
+         * Raised when the asset is completely loaded, just before the loader is disposed.
+         * For assets with LODs, raised when all of the LODs are complete.
+         * For assets without LODs, raised when the model is complete just after onReady.
          */
-        onFirstLODComplete: () => void;
+        onComplete: () => void;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
@@ -884,9 +888,9 @@ declare module BABYLON.GLTF2 {
 
 declare module BABYLON.GLTF2 {
     class GLTFLoader implements IGLTFLoader, IDisposable {
+        _gltf: IGLTF;
+        _babylonScene: Scene;
         private _parent;
-        private _gltf;
-        private _babylonScene;
         private _rootUrl;
         private _defaultMaterial;
         private _successCallback;
@@ -894,19 +898,14 @@ declare module BABYLON.GLTF2 {
         private _errorCallback;
         private _renderReady;
         private _disposed;
-        private _blockPendingTracking;
-        private _nonBlockingData;
-        private _rootMesh;
         private _renderReadyObservable;
         private _renderPendingCount;
         private _loaderPendingCount;
+        private _loaderTrackers;
         static Extensions: {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
-        readonly gltf: IGLTF;
-        readonly babylonScene: Scene;
-        executeWhenRenderReady(func: () => void): void;
         constructor(parent: GLTFFileLoader);
         dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
@@ -914,18 +913,16 @@ declare module BABYLON.GLTF2 {
         private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess, onProgress, onError);
         private _onError(message);
         private _onProgress(event);
+        _executeWhenRenderReady(func: () => void): void;
         private _onRenderReady();
-        private _onLoaderComplete();
-        private _onLoaderFirstLODComplete();
+        private _onComplete();
         private _loadData(data);
-        private _addRightHandToLeftHandRootTransform();
         private _getMeshes();
         private _getSkeletons();
         private _getAnimationTargets();
-        private _showMeshes();
         private _startAnimations();
         private _loadScene(nodeNames);
-        private _loadNode(node);
+        _loadNode(node: IGLTFNode): void;
         private _loadMesh(node, mesh);
         private _loadVertexDataAsync(primitive, onSuccess);
         private _createMorphTargets(node, mesh, primitive, babylonMesh);
@@ -937,7 +934,7 @@ declare module BABYLON.GLTF2 {
         private _loadBone(node, skin, inverseBindMatrixData, babylonBones);
         private _getNodeMatrix(node);
         private _traverseNodes(indices, action, parentNode?);
-        private _traverseNode(index, action, parentNode?);
+        _traverseNode(index: number, action: (node: IGLTFNode, index: number, parentNode: IGLTFNode) => boolean, parentNode?: IGLTFNode): void;
         private _loadAnimations();
         private _loadAnimationChannel(animation, animationIndex, channelIndex);
         private _loadBufferAsync(index, onSuccess);
@@ -951,19 +948,18 @@ declare module BABYLON.GLTF2 {
         private _loadBufferViewAsync(bufferView, byteOffset, byteLength, bytePerComponent, componentType, onSuccess);
         private _loadAccessorAsync(accessor, onSuccess);
         private _getByteStrideFromType(accessor);
-        blockPendingTracking: boolean;
-        addPendingData(data: any): void;
-        removePendingData(data: any): void;
-        addLoaderNonBlockingPendingData(data: any): void;
-        addLoaderPendingData(data: any): void;
-        removeLoaderPendingData(data: any): void;
+        _addPendingData(data: any): void;
+        _removePendingData(data: any): void;
+        _addLoaderPendingData(data: any): void;
+        _removeLoaderPendingData(data: any): void;
+        _whenAction(action: () => void, onComplete: () => void): void;
         private _getDefaultMaterial();
         private _loadMaterialMetallicRoughnessProperties(material);
-        loadMaterial(material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): void;
-        createPbrMaterial(material: IGLTFMaterial): void;
-        loadMaterialBaseProperties(material: IGLTFMaterial): void;
-        loadMaterialAlphaProperties(material: IGLTFMaterial, colorFactor?: number[]): void;
-        loadTexture(textureInfo: IGLTFTextureInfo): Texture;
+        _loadMaterial(material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): void;
+        _createPbrMaterial(material: IGLTFMaterial): void;
+        _loadMaterialBaseProperties(material: IGLTFMaterial): void;
+        _loadMaterialAlphaProperties(material: IGLTFMaterial, colorFactor?: number[]): void;
+        _loadTexture(textureInfo: IGLTFTextureInfo): Texture;
     }
 }
 
@@ -999,8 +995,13 @@ declare module BABYLON.GLTF2 {
     abstract class GLTFLoaderExtension {
         enabled: boolean;
         readonly abstract name: string;
-        protected loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
+        protected _traverseNode(loader: GLTFLoader, index: number, action: (node: IGLTFNode, index: number, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
+        protected _loadNode(loader: GLTFLoader, node: IGLTFNode): boolean;
+        protected _loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
+        protected _loadExtension<T>(property: IGLTFProperty, action: (extension: T, onComplete: () => void) => void): boolean;
         static _Extensions: GLTFLoaderExtension[];
+        static TraverseNode(loader: GLTFLoader, index: number, action: (node: IGLTFNode, index: number, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
+        static LoadNode(loader: GLTFLoader, node: IGLTFNode): boolean;
         static LoadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         private static _ApplyExtensions(action);
     }
@@ -1014,8 +1015,11 @@ declare module BABYLON.GLTF2.Extensions {
          */
         static MinimalLODDelay: number;
         readonly name: string;
-        protected loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private loadMaterialLOD(loader, material, materialLODs, lod, assign);
+        protected _traverseNode(loader: GLTFLoader, index: number, action: (node: IGLTFNode, index: number, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
+        protected _loadNode(loader: GLTFLoader, node: IGLTFNode): boolean;
+        private _loadNodeLOD(loader, nodes, index, onComplete);
+        protected _loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
+        private _loadMaterialLOD(loader, materials, index, assign, onComplete);
     }
 }
 
@@ -1023,7 +1027,7 @@ declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
     class KHRMaterialsPbrSpecularGlossiness extends GLTFLoaderExtension {
         readonly name: string;
-        protected loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
+        protected _loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         private _loadSpecularGlossinessProperties(loader, material, properties);
     }
 }

文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/materialsLibrary/babylon.customMaterial.min.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.min.js


文件差异内容过多而无法显示
+ 3 - 3
dist/preview release/materialsLibrary/babylonjs.materials.min.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js


+ 7 - 1
src/PostProcess/babylon.volumetricLightScatteringPostProcess.ts

@@ -252,7 +252,13 @@
             this._volumetricLightScatteringRTT.wrapV = Texture.CLAMP_ADDRESSMODE;
             this._volumetricLightScatteringRTT.renderList = null;
             this._volumetricLightScatteringRTT.renderParticles = false;
-            scene.customRenderTargets.push(this._volumetricLightScatteringRTT);
+
+            var camera = this.getCamera();
+            if (camera) {
+                camera.customRenderTargets.push(this._volumetricLightScatteringRTT);
+            } else {
+                scene.customRenderTargets.push(this._volumetricLightScatteringRTT);
+            }
 
             // Custom render function for submeshes
             var renderSubMesh = (subMesh: SubMesh): void => {