浏览代码

Merge branch 'master' into MSFT_audio_emitter.only

Jamie Marconi 7 年之前
父节点
当前提交
3bb9787dc8
共有 100 个文件被更改,包括 35179 次插入28314 次删除
  1. 11702 11416
      Playground/babylon.d.txt
  2. 5 4
      Playground/ts.html
  3. 7 4
      Tools/Gulp/config.json
  4. 70 78
      Tools/Gulp/gulpfile.js
  5. 7 0
      Tools/Gulp/processViewerDeclaration.js
  6. 2 1
      Tools/Publisher/index.js
  7. 3 3
      Viewer/assets/templates/default/navbar.html
  8. 25 0
      Viewer/dist/printExample.html
  9. 2 2
      Viewer/src/configuration/configurationCompatibility.ts
  10. 2 2
      Viewer/src/configuration/types/default.ts
  11. 3 3
      Viewer/src/templating/plugins/printButton.ts
  12. 23 11
      Viewer/src/viewer/defaultViewer.ts
  13. 48 30
      Viewer/src/viewer/viewer.ts
  14. 15652 15403
      dist/preview release/babylon.d.ts
  15. 63 62
      dist/preview release/babylon.js
  16. 533 70
      dist/preview release/babylon.max.js
  17. 533 70
      dist/preview release/babylon.no-module.max.js
  18. 64 63
      dist/preview release/babylon.worker.js
  19. 535 72
      dist/preview release/es6.js
  20. 1 1
      dist/preview release/glTF2Interface/package.json
  21. 1 1
      dist/preview release/gui/babylon.gui.d.ts
  22. 1 1
      dist/preview release/gui/babylon.gui.min.js
  23. 1 1
      dist/preview release/gui/babylon.gui.min.js.map
  24. 2329 1
      dist/preview release/gui/babylon.gui.module.d.ts
  25. 1 1
      dist/preview release/gui/package.json
  26. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js
  27. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js.map
  28. 7 5
      dist/preview release/inspector/babylon.inspector.d.ts
  29. 1049 6
      dist/preview release/inspector/babylon.inspector.module.d.ts
  30. 1 1
      dist/preview release/inspector/package.json
  31. 11 0
      dist/preview release/loaders/babylon.glTF1FileLoader.d.ts
  32. 23 1
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  33. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  34. 38 8
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  35. 146 94
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  36. 3 3
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  37. 38 8
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  38. 146 94
      dist/preview release/loaders/babylon.glTFFileLoader.js
  39. 4 4
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  40. 38 8
      dist/preview release/loaders/babylonjs.loaders.d.ts
  41. 146 94
      dist/preview release/loaders/babylonjs.loaders.js
  42. 4 4
      dist/preview release/loaders/babylonjs.loaders.min.js
  43. 38 8
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  44. 2 2
      dist/preview release/loaders/package.json
  45. 1 1
      dist/preview release/materialsLibrary/package.json
  46. 1 1
      dist/preview release/postProcessesLibrary/package.json
  47. 1 1
      dist/preview release/proceduralTexturesLibrary/package.json
  48. 7 0
      dist/preview release/serializers/babylon.glTF2Serializer.d.ts
  49. 113 91
      dist/preview release/serializers/babylon.glTF2Serializer.js
  50. 2 2
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  51. 7 0
      dist/preview release/serializers/babylonjs.serializers.d.ts
  52. 113 91
      dist/preview release/serializers/babylonjs.serializers.js
  53. 2 2
      dist/preview release/serializers/babylonjs.serializers.min.js
  54. 7 0
      dist/preview release/serializers/babylonjs.serializers.module.d.ts
  55. 2 2
      dist/preview release/serializers/package.json
  56. 2 7
      dist/preview release/typedocValidationBaseline.json
  57. 5 4
      dist/preview release/viewer/babylon.viewer.d.ts
  58. 3 3
      dist/preview release/viewer/babylon.viewer.js
  59. 894 33
      dist/preview release/viewer/babylon.viewer.max.js
  60. 5 3
      dist/preview release/viewer/babylon.viewer.module.d.ts
  61. 4 0
      dist/preview release/what's new.md
  62. 2 0
      gui/src/2D/advancedDynamicTexture.ts
  63. 3 3
      gui/src/2D/controls/control.ts
  64. 15 0
      gui/src/legacy.ts
  65. 1 1
      gui/webpack.config.js
  66. 26 15
      inspector/src/Inspector.ts
  67. 3 4
      inspector/src/adapters/GUIAdapter.ts
  68. 15 0
      inspector/src/legacy.ts
  69. 117 108
      inspector/src/properties_gui.ts
  70. 2 0
      inspector/src/tabs/ConsoleTab.ts
  71. 2 0
      inspector/src/tabs/GLTFTab.ts
  72. 7 6
      inspector/src/tabs/GUITab.ts
  73. 2 0
      inspector/src/tabs/PropertyTab.ts
  74. 2 0
      inspector/src/tabs/SceneTab.ts
  75. 1 2
      inspector/src/tabs/TabBar.ts
  76. 1 0
      inspector/src/tabs/TextureTab.ts
  77. 24 26
      inspector/src/tools/LabelTool.ts
  78. 1 1
      inspector/tsconfig.json
  79. 2 2
      inspector/webpack.config.js
  80. 10 10
      loaders/src/glTF/2.0/Extensions/EXT_lights_imageBased.ts
  81. 10 10
      loaders/src/glTF/2.0/Extensions/KHR_lights.ts
  82. 42 42
      loaders/src/glTF/2.0/Extensions/MSFT_lod.ts
  83. 14 12
      loaders/src/glTF/2.0/Extensions/MSFT_sRGBFactors.ts
  84. 37 25
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  85. 26 0
      loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts
  86. 23 1
      loaders/src/glTF/babylon.glTFFileLoader.ts
  87. 1 1
      package.json
  88. 129 108
      serializers/src/glTF/2.0/babylon.glTFMaterialExporter.ts
  89. 3 1
      src/Cameras/VR/babylon.vrExperienceHelper.ts
  90. 6 2
      src/Cameras/babylon.camera.ts
  91. 6 2
      src/Cameras/babylon.targetCamera.ts
  92. 6 3
      src/Engine/babylon.engine.ts
  93. 3 1
      src/Engine/babylon.nullEngine.ts
  94. 3 1
      src/Gizmos/babylon.gizmo.ts
  95. 14 1
      src/Lights/babylon.light.ts
  96. 12 3
      src/Lights/babylon.pointLight.ts
  97. 42 1
      src/Lights/babylon.spotLight.ts
  98. 33 6
      src/Materials/PBR/babylon.pbrBaseMaterial.ts
  99. 53 31
      src/Materials/PBR/babylon.pbrMaterial.ts
  100. 0 0
      src/Materials/Textures/babylon.dynamicTexture.ts

文件差异内容过多而无法显示
+ 11702 - 11416
Playground/babylon.d.txt


+ 5 - 4
Playground/ts.html

@@ -37,17 +37,18 @@
         <script src="https://preview.babylonjs.com/cannon.js"></script>
         <script src="https://preview.babylonjs.com/Oimo.js"></script>
         <script src="https://preview.babylonjs.com/earcut.min.js"></script>
-        <!-- Monaco -->
-        <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
         <!-- Babylon.js -->
         <script src="https://preview.babylonjs.com/babylon.js"></script>
+        <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
         <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
         <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
         <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
         <script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
         <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.js"></script>
         <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
-        <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
+
+        <!-- Monaco -->
+        <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
 
         <!-- Extensions -->
         <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js" async></script>
@@ -488,4 +489,4 @@
         </script>        
     </body>
 
-</html>
+</html>

+ 7 - 4
Tools/Gulp/config.json

@@ -294,6 +294,8 @@
                 "../../src/Particles/EmitterTypes/babylon.boxParticleEmitter.js",
                 "../../src/Particles/EmitterTypes/babylon.coneParticleEmitter.js",
                 "../../src/Particles/EmitterTypes/babylon.sphereParticleEmitter.js",
+                "../../src/Particles/EmitterTypes/babylon.hemisphericParticleEmitter.js",
+                "../../src/Particles/EmitterTypes/babylon.pointParticleEmitter.js",
                 "../../src/Particles/babylon.particleSystemComponent.js"
             ],
             "dependUpon": [
@@ -1956,7 +1958,7 @@
             },
             "outputs": [
                 {
-                    "destination": [
+                    "destinations": [
                         {
                             "filename": "viewer.js",
                             "outputDirectory": "/../../Viewer/dist/"
@@ -1970,10 +1972,11 @@
                                 "glTF2Interface/babylon.glTF2Interface.d.ts"
                             ]
                         }
-                    ]
+                    ],
+                    "minified": true
                 },
                 {
-                    "destination": [
+                    "destinations": [
                         {
                             "filename": "viewer.max.js",
                             "outputDirectory": "/../../Viewer/dist/"
@@ -2014,7 +2017,7 @@
             },
             "outputs": [
                 {
-                    "destination": [
+                    "destinations": [
                         {
                             "filename": "babylon.viewer.assets.js",
                             "outputDirectory": "/../../Viewer/build/assets/"

+ 70 - 78
Tools/Gulp/gulpfile.js

@@ -447,100 +447,90 @@ var buildExternalLibrary = function (library, settings, watch) {
 
         if (library.webpack) {
             let sequence = [waitAll];
-            let wpBuild = webpackStream(require(library.webpack), webpack);
-            if (settings.build.outputs) {
-                //shoud dtsBundle create the declaration?
-                if (settings.build.dtsBundle) {
-                    let event = wpBuild
-                        .pipe(through.obj(function (file, enc, cb) {
-                            // only declaration files
-                            const isdts = /\.d\.ts$/.test(file.path);
-                            if (isdts) this.push(file);
-                            cb();
-                        }))
-                        .pipe(gulp.dest(outputDirectory));
-                    // dts-bundle does NOT support (gulp) streams, so files have to be saved and reloaded, 
-                    // until I fix it
-                    event.on("end", function () {
-                        // create the file
-                        dtsBundle.bundle(settings.build.dtsBundle);
-                        // prepend the needed reference
-                        let fileLocation = path.join(path.dirname(settings.build.dtsBundle.main), settings.build.dtsBundle.out);
-                        fs.readFile(fileLocation, function (err, data) {
-                            if (err) throw err;
-                            data = (settings.build.dtsBundle.prependText || "") + '\n' + data.toString();
-                            fs.writeFile(fileLocation, data);
-                            if (settings.build.processDeclaration) {
-                                var newData = processDeclaration(data, settings.build.processDeclaration);
-                                fs.writeFile(fileLocation.replace('.module', ''), newData);
-                            }
-                        });
-                    });
-                }
 
-                let build = wpBuild
-                    .pipe(through.obj(function (file, enc, cb) {
-                        // only pipe js files
-                        const isJs = /\.js$/.test(file.path);
-                        if (isJs) this.push(file);
-                        cb();
-                    }))
-                    .pipe(addModuleExports(library.moduleDeclaration, { subModule: false, extendsRoot: false, externalUsingBabylon: true, noBabylonInit: library.babylonIncluded }));
+            if (settings.build.outputs) {
 
-                let unminifiedOutpus = [];
-                let minifiedOutputs = [];
                 settings.build.outputs.forEach(out => {
-                    if (out.minified) {
-                        out.destination.forEach(dest => {
-                            minifiedOutputs.push(dest);
-                        });
-                    } else {
-                        out.destination.forEach(dest => {
-                            unminifiedOutpus.push(dest);
-                        });
+                    let wpConfig = require(library.webpack);
+                    if (!out.minified) {
+                        wpConfig.mode = "development";
                     }
-                });
+                    let wpBuild = webpackStream(wpConfig, webpack);
 
-                function processDestination(dest) {
-                    var outputDirectory = config.build.outputDirectory + dest.outputDirectory;
-                    build = build
-                        .pipe(rename(dest.filename.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
-                        .pipe(gulp.dest(outputDirectory));
+                    //shoud dtsBundle create the declaration?
+                    if (settings.build.dtsBundle) {
+                        let event = wpBuild
+                            .pipe(through.obj(function (file, enc, cb) {
+                                // only declaration files
+                                const isdts = /\.d\.ts$/.test(file.path);
+                                if (isdts) this.push(file);
+                                cb();
+                            }))
+                            .pipe(gulp.dest(outputDirectory));
+                        // dts-bundle does NOT support (gulp) streams, so files have to be saved and reloaded, 
+                        // until I fix it
+                        event.on("end", function () {
+                            // create the file
+                            dtsBundle.bundle(settings.build.dtsBundle);
+                            // prepend the needed reference
+                            let fileLocation = path.join(path.dirname(settings.build.dtsBundle.main), settings.build.dtsBundle.out);
+                            fs.readFile(fileLocation, function (err, data) {
+                                if (err) throw err;
+                                data = (settings.build.dtsBundle.prependText || "") + '\n' + data.toString();
+                                fs.writeFile(fileLocation, data);
+                                if (settings.build.processDeclaration) {
+                                    var newData = processDeclaration(data, settings.build.processDeclaration);
+                                    fs.writeFile(fileLocation.replace('.module', ''), newData);
+                                }
+                            });
+                        });
+                    }
 
-                    if (library.babylonIncluded && dest.addBabylonDeclaration) {
-                        // include the babylon declaration
-                        if (dest.addBabylonDeclaration === true) {
-                            dest.addBabylonDeclaration = [config.build.declarationFilename];
+                    let build = wpBuild
+                        .pipe(through.obj(function (file, enc, cb) {
+                            // only pipe js files
+                            const isJs = /\.js$/.test(file.path);
+                            if (isJs) this.push(file);
+                            cb();
+                        }))
+                        .pipe(addModuleExports(library.moduleDeclaration, { subModule: false, extendsRoot: false, externalUsingBabylon: true, noBabylonInit: library.babylonIncluded }));
+
+                    function processDestination(dest) {
+                        var outputDirectory = config.build.outputDirectory + dest.outputDirectory;
+                        build = build
+                            .pipe(rename(dest.filename.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
+                            .pipe(gulp.dest(outputDirectory));
+
+                        if (library.babylonIncluded && dest.addBabylonDeclaration) {
+                            // include the babylon declaration
+                            if (dest.addBabylonDeclaration === true) {
+                                dest.addBabylonDeclaration = [config.build.declarationFilename];
+                            }
+                            var decsToAdd = dest.addBabylonDeclaration.map(function (dec) {
+                                return config.build.outputDirectory + '/' + dec;
+                            });
+                            sequence.unshift(gulp.src(decsToAdd)
+                                .pipe(rename(function (path) {
+                                    path.dirname = '';
+                                }))
+                                .pipe(gulp.dest(outputDirectory)))
                         }
-                        var decsToAdd = dest.addBabylonDeclaration.map(function (dec) {
-                            return config.build.outputDirectory + '/' + dec;
-                        });
-                        sequence.unshift(gulp.src(decsToAdd)
-                            .pipe(rename(function (path) {
-                                path.dirname = '';
-                            }))
-                            .pipe(gulp.dest(outputDirectory)))
                     }
-                }
 
-                unminifiedOutpus.forEach(dest => {
-                    processDestination(dest);
-                });
+                    out.destinations.forEach(dest => {
+                        processDestination(dest);
+                    });
 
-                if (minifiedOutputs.length) {
-                    build = build
-                        .pipe(uglify())
-                        .pipe(optimisejs())
-                }
+                    sequence.push(build);
 
-                minifiedOutputs.forEach(dest => {
-                    processDestination(dest);
                 });
 
-                sequence.push(build);
+
 
             } else {
 
+                let wpBuild = webpackStream(require(library.webpack), webpack);
+
                 let buildEvent = wpBuild
                     .pipe(gulp.dest(outputDirectory))
                     //back-compat
@@ -567,6 +557,8 @@ var buildExternalLibrary = function (library, settings, watch) {
                                 if (err) throw err;
                                 var newData = processDeclaration(data, settings.build.processDeclaration);
                                 fs.writeFile(fileLocation.replace('.module', ''), newData);
+                                //legacy module support
+                                fs.writeFile(fileLocation, data + "\n" + newData);
                             });
                         }
                     });

+ 7 - 0
Tools/Gulp/processViewerDeclaration.js

@@ -59,7 +59,14 @@ module.exports = function (data, options) {
 
     str = str.replace(/export {(.*)};/g, '');
 
+    str = str.replace(/import (.*);/g, "");
+
     str = str.split("\n").filter(line => line.trim()).filter(line => line.indexOf("export * from") === -1).join("\n");
 
+    //empty declare regex
+    let emptyDeclareRegexp = new RegExp("declare module " + options.moduleName + " {\n}", "g");
+
+    str = str.replace(emptyDeclareRegexp, "");
+
     return str;
 }

+ 2 - 1
Tools/Publisher/index.js

@@ -51,7 +51,8 @@ let packages = [
         required: [
             basePath + '/viewer/readme.md',
             basePath + '/viewer/package.json',
-            basePath + '/viewer/babylon.viewer.js'
+            basePath + '/viewer/babylon.viewer.js',
+            basePath + '/viewer/babylon.viewer.max.js'
         ]
     },
     {

+ 3 - 3
Viewer/assets/templates/default/navbar.html

@@ -494,15 +494,15 @@
     {{/unless}}
     <div class="default-control">
         {{#unless hideVr}}
-        <button class="vr vr-button" title="{{text.vrButton}}">
+        <button class="vr vr-button" title="{{text.vrButton}} ">
             <span class="icon vr-icon"></span>
         </button>
         {{/unless}}{{#unless hideHelp}}
-        <button class="help help-button" title="{{text.helpButton}}">
+        <button class="help help-button" title="{{text.helpButton}} ">
             <span class="icon help-icon"></span>
         </button>
         {{/unless}} {{#unless hideFullscreen}}
-        <button class="fullscreen fullscreen-button" title="{{text.fullscreenButton}}">
+        <button class="fullscreen fullscreen-button" title="{{text.fullscreenButton}} ">
             <span class="icon fullscreen-icon"></span>
         </button>
         {{/unless}}

+ 25 - 0
Viewer/dist/printExample.html

@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html lang="en">
+
+    <head>
+        <meta charset="UTF-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1.0">
+        <meta http-equiv="X-UA-Compatible" content="ie=edge">
+        <title>BabylonJS Viewer - 3D Print usage</title>
+        <style>
+            babylon {
+                width: 800px;
+                height: 500px;
+            }
+        </style>
+    </head>
+
+    <body>
+        <babylon templates.nav-bar.params.hide-print="false">
+            <model url="https://playground.babylonjs.com/scenes/BoomBox.glb">
+            </model>
+        </babylon>
+        <script src="viewer.js"></script>
+    </body>
+
+</html>

+ 2 - 2
Viewer/src/configuration/configurationCompatibility.ts

@@ -43,7 +43,7 @@ export function processConfigurationCompatibility(configuration: ViewerConfigura
 
     if (configuration.lab) {
         if (configuration.lab.assetsRootURL) {
-            setKeyInObject(configuration, "scene.assetsRootURL", configuration.lab.assetsRootURL);
+            setKeyInObject(configuration, "scene.assetsRootURL", configuration.lab.assetsRootURL, true);
         }
         if (configuration.lab.environmentMap) {
             setKeyInObject(configuration, "environmentMap", configuration.lab.environmentMap, true);
@@ -63,4 +63,4 @@ function setKeyInObject(object: any, keys: string, value: any, shouldOverwrite?:
     });
     if (curObj[lastKey] !== undefined && !shouldOverwrite) return;
     curObj[lastKey] = value;
-}
+}

+ 2 - 2
Viewer/src/configuration/types/default.ts

@@ -55,10 +55,10 @@ export let defaultConfiguration: ViewerConfiguration = {
                 disableOnFullscreen: false,
                 text: {
                     hdButton: "Toggle HD",
-                    fullscreenButton: "Fullscreen",
+                    fullscreenButton: "Toggle Fullscreen",
                     helpButton: "Help",
                     vrButton: "Toggle VR",
-                    printButton: "Print model in 3D"
+                    printButton: "3D Print Object"
                 }
             },
             events: {

+ 3 - 3
Viewer/src/templating/plugins/printButton.ts

@@ -34,8 +34,8 @@ export class PrintButtonPlugin extends AbstractViewerNavbarButton {
 
     onEvent(event: EventCallback): void {
         if (this._currentModelUrl) {
-            let printUrl = this._currentModelUrl.replace(/https?:\/\//, "com.microsoft.print3d://");
-            window.open(printUrl);
+            let printUrl = this._currentModelUrl.replace(/https?:\/\//, "com.microsoft.builder3d://");
+            window.open(printUrl, "_self");
         }
     }
 
@@ -59,4 +59,4 @@ export class PrintButtonPlugin extends AbstractViewerNavbarButton {
  </button>
  {{/unless}}
 `;
-}
+}

+ 23 - 11
Viewer/src/viewer/defaultViewer.ts

@@ -328,19 +328,31 @@ export class DefaultViewer extends AbstractViewer {
         this._updateAnimationSpeed("1.0", paramsObject);
     }
 
-    public toggleVR() {
-        super.toggleVR();
-
-        let viewerTemplate = this.templateManager.getTemplate('viewer');
-        let viewerElement = viewerTemplate && viewerTemplate.parent;
-
-        if (viewerElement) {
-            if (this._vrToggled) {
-                viewerElement.classList.add("in-vr");
-            } else {
-                viewerElement.classList.remove("in-vr");
+    protected _initVR() {
+        this.engine.onVRDisplayChangedObservable.add(() => {
+            let viewerTemplate = this.templateManager.getTemplate('viewer');
+            let viewerElement = viewerTemplate && viewerTemplate.parent;
+
+            if (viewerElement) {
+                if (this.sceneManager.vrHelper!.isInVRMode) {
+                    viewerElement.classList.add("in-vr");
+                } else {
+                    viewerElement.classList.remove("in-vr");
+                }
             }
+        });
+        if (this.sceneManager.vrHelper) {
+            // due to the way the experience helper is exisintg VR, this must be added.
+            this.sceneManager.vrHelper.onExitingVR.add(() => {
+                let viewerTemplate = this.templateManager.getTemplate('viewer');
+                let viewerElement = viewerTemplate && viewerTemplate.parent;
+
+                if (viewerElement) {
+                    viewerElement.classList.remove("in-vr");
+                }
+            });
         }
+        super._initVR();
     }
 
     /**

+ 48 - 30
Viewer/src/viewer/viewer.ts

@@ -262,10 +262,14 @@ export abstract class AbstractViewer {
     private _vrModelRepositioning: number = 0;
     protected _vrScale: number = 1;
 
+    protected _vrInit: boolean = false;
+
     public toggleVR() {
-        this._vrToggled = !this._vrToggled;
+        if (!this._vrInit) {
+            this._initVR();
+        }
 
-        if (this._vrToggled && this.sceneManager.vrHelper) {
+        if (this.sceneManager.vrHelper && !this.sceneManager.vrHelper.isInVRMode) {
             // make sure the floor is set
             if (this.sceneManager.environmentHelper && this.sceneManager.environmentHelper.ground) {
                 this.sceneManager.vrHelper.addFloorMesh(this.sceneManager.environmentHelper.ground);
@@ -274,7 +278,7 @@ export abstract class AbstractViewer {
             this.sceneManager.vrHelper.enterVR();
 
             // position the vr camera to be in front of the object or wherever the user has configured it to be
-            if (this.sceneManager.vrHelper.currentVRCamera) {
+            if (this.sceneManager.vrHelper.currentVRCamera && this.sceneManager.vrHelper.currentVRCamera !== this.sceneManager.camera) {
                 if (this.configuration.vr && this.configuration.vr.cameraPosition !== undefined) {
                     this.sceneManager.vrHelper.currentVRCamera.position.copyFrom(this.configuration.vr.cameraPosition as Vector3);
                 } else {
@@ -291,42 +295,49 @@ export abstract class AbstractViewer {
                         this._vrModelRepositioning = 0;
                     }
                 }
-            } else {
-                this._vrModelRepositioning = 0;
-            }
 
-            // scale the model
-            if (this.sceneManager.models.length) {
-                let boundingVectors = this.sceneManager.models[0].rootMesh.getHierarchyBoundingVectors();
-                let sizeVec = boundingVectors.max.subtract(boundingVectors.min);
-                let maxDimension = Math.max(sizeVec.x, sizeVec.y, sizeVec.z);
-                this._vrScale = (1 / maxDimension);
-                if (this.configuration.vr && this.configuration.vr.objectScaleFactor) {
-                    this._vrScale *= this.configuration.vr.objectScaleFactor;
-                }
+                // scale the model
+                if (this.sceneManager.models.length) {
+                    let boundingVectors = this.sceneManager.models[0].rootMesh.getHierarchyBoundingVectors();
+                    let sizeVec = boundingVectors.max.subtract(boundingVectors.min);
+                    let maxDimension = Math.max(sizeVec.x, sizeVec.y, sizeVec.z);
+                    this._vrScale = (1 / maxDimension);
+                    if (this.configuration.vr && this.configuration.vr.objectScaleFactor) {
+                        this._vrScale *= this.configuration.vr.objectScaleFactor;
+                    }
 
-                this.sceneManager.models[0].rootMesh.scaling.scaleInPlace(this._vrScale);
+                    this.sceneManager.models[0].rootMesh.scaling.scaleInPlace(this._vrScale);
 
-                // reposition the object to "float" in front of the user
-                this.sceneManager.models[0].rootMesh.position.y += this._vrModelRepositioning;
-                this.sceneManager.models[0].rootMesh.rotationQuaternion = null;
-            }
+                    // reposition the object to "float" in front of the user
+                    this.sceneManager.models[0].rootMesh.position.y += this._vrModelRepositioning;
+                    this.sceneManager.models[0].rootMesh.rotationQuaternion = null;
+                }
 
-            // scale the environment to match the model
-            if (this.sceneManager.environmentHelper) {
-                this.sceneManager.environmentHelper.ground && this.sceneManager.environmentHelper.ground.scaling.scaleInPlace(this._vrScale);
-                this.sceneManager.environmentHelper.skybox && this.sceneManager.environmentHelper.skybox.scaling.scaleInPlace(this._vrScale);
-            }
+                // scale the environment to match the model
+                if (this.sceneManager.environmentHelper) {
+                    this.sceneManager.environmentHelper.ground && this.sceneManager.environmentHelper.ground.scaling.scaleInPlace(this._vrScale);
+                    this.sceneManager.environmentHelper.skybox && this.sceneManager.environmentHelper.skybox.scaling.scaleInPlace(this._vrScale);
+                }
 
-            // post processing
-            if (this.sceneManager.defaultRenderingPipelineEnabled && this.sceneManager.defaultRenderingPipeline) {
-                this.sceneManager.defaultRenderingPipeline.imageProcessingEnabled = false;
-                this.sceneManager.defaultRenderingPipeline.prepare();
+                // post processing
+                if (this.sceneManager.defaultRenderingPipelineEnabled && this.sceneManager.defaultRenderingPipeline) {
+                    this.sceneManager.defaultRenderingPipeline.imageProcessingEnabled = false;
+                    this.sceneManager.defaultRenderingPipeline.prepare();
+                }
+            } else {
+                this._vrModelRepositioning = 0;
             }
         } else {
             if (this.sceneManager.vrHelper) {
                 this.sceneManager.vrHelper.exitVR();
+            }
+        }
+    }
+
+    protected _initVR() {
 
+        if (this.sceneManager.vrHelper) {
+            this.sceneManager.vrHelper.onExitingVR.add(() => {
                 // undo the scaling of the model
                 if (this.sceneManager.models.length) {
                     this.sceneManager.models[0].rootMesh.scaling.scaleInPlace(1 / this._vrScale);
@@ -344,8 +355,15 @@ export abstract class AbstractViewer {
                     this.sceneManager.defaultRenderingPipeline.imageProcessingEnabled = true;
                     this.sceneManager.defaultRenderingPipeline.prepare();
                 }
-            }
+
+                // clear set height and eidth
+                this.canvas.removeAttribute("height");
+                this.canvas.removeAttribute("width");
+                this.engine.resize();
+            })
         }
+
+        this._vrInit = true;
     }
 
     /**

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


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


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


文件差异内容过多而无法显示
+ 533 - 70
dist/preview release/babylon.no-module.max.js


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


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


+ 1 - 1
dist/preview release/glTF2Interface/package.json

@@ -1,7 +1,7 @@
 {
     "name": "babylonjs-gltf2interface",
     "description": "A typescript declaration of babylon's gltf2 inteface.",
-    "version": "3.3.0-alpha.12",
+    "version": "3.3.0-alpha.13",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/gui/babylon.gui.d.ts

@@ -1,6 +1,6 @@
 /*BabylonJS GUI*/
 // Dependencies for this module:
-//   ../../../../tools/Gulp/babylonjs
+//   ../../../../Tools/Gulp/babylonjs
 declare module BABYLON.GUI {
 }
 declare module BABYLON.GUI {

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


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


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


+ 1 - 1
dist/preview release/gui/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-gui",
     "description": "The Babylon.js GUI library is an extension you can use to generate interactive user interface. It is build on top of the DynamicTexture.",
-    "version": "3.3.0-alpha.12",
+    "version": "3.3.0-alpha.13",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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


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


+ 7 - 5
dist/preview release/inspector/babylon.inspector.d.ts

@@ -1,7 +1,6 @@
 /*BabylonJS Inspector*/
 // Dependencies for this module:
-//   ../../../../tools/Gulp/babylonjs
-//   ../../../../tools/Gulp/babylonjs-gui
+//   ../../../../Tools/Gulp/babylonjs
 declare module INSPECTOR {
 }
 declare module INSPECTOR {
@@ -23,12 +22,13 @@ declare module INSPECTOR {
 declare module INSPECTOR {
 }
 declare module INSPECTOR {
-    import "../sass/main.scss";
     export class Inspector {
             /** The HTML document relative to this inspector (the window or the popup depending on its mode) */
             static DOCUMENT: HTMLDocument;
             /** The HTML window. In popup mode, it's the popup itself. Otherwise, it's the current tab */
             static WINDOW: Window;
+            onGUILoaded: BABYLON.Observable<typeof import("babylonjs-gui")>;
+            static GUIObject: typeof import("babylonjs-gui");
             /** The inspector is created with the given engine.
                 * If the parameter 'popup' is false, the inspector is created as a right panel on the main window.
                 * If the parameter 'popup' is true, the inspector is created in another popup.
@@ -239,10 +239,12 @@ declare module INSPECTOR {
     };
 }
 declare module INSPECTOR {
+    export type GUITyping = typeof import("babylonjs-gui");
+    export let guiLoaded: boolean;
     /**
        * Function that add gui objects properties to the variable PROPERTIES
        */
-    export function loadGUIProperties(): void;
+    export function loadGUIProperties(GUI: GUITyping): void;
 }
 declare module INSPECTOR {
     export abstract class Adapter {
@@ -282,7 +284,7 @@ declare module INSPECTOR {
 }
 declare module INSPECTOR {
     export class GUIAdapter extends Adapter implements IToolVisible {
-        constructor(obj: BABYLON.GUI.Control);
+        constructor(obj: import("babylonjs-gui").Control);
         /** Returns the name displayed in the tree */
         id(): string;
         /** Returns the type of this object - displayed in the tree */

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


+ 1 - 1
dist/preview release/inspector/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-inspector",
     "description": "The Babylon.js inspector.",
-    "version": "3.3.0-alpha.12",
+    "version": "3.3.0-alpha.13",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -191,9 +191,20 @@ declare module BABYLON {
         private _onCompleteObserver;
         /**
          * Callback raised when the asset is completely loaded, immediately 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, immediately after the loader resolves the returned promise.
          */
         onComplete: () => void;
         /**
+         * Observable raised when an error occurs.
+         */
+        readonly onErrorObservable: Observable<any>;
+        private _onErrorObserver;
+        /**
+         * Callback raised when an error occurs.
+         */
+        onError: (reason: any) => void;
+        /**
          * Observable raised after the loader is disposed.
          */
         readonly onDisposeObservable: Observable<void>;

+ 23 - 1
dist/preview release/loaders/babylon.glTF1FileLoader.js

@@ -118,6 +118,10 @@ var BABYLON;
              */
             this.onCompleteObservable = new BABYLON.Observable();
             /**
+             * Observable raised when an error occurs.
+             */
+            this.onErrorObservable = new BABYLON.Observable();
+            /**
              * Observable raised after the loader is disposed.
              */
             this.onDisposeObservable = new BABYLON.Observable();
@@ -217,6 +221,8 @@ var BABYLON;
         Object.defineProperty(GLTFFileLoader.prototype, "onComplete", {
             /**
              * Callback raised when the asset is completely loaded, immediately 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, immediately after the loader resolves the returned promise.
              */
             set: function (callback) {
                 if (this._onCompleteObserver) {
@@ -227,6 +233,19 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(GLTFFileLoader.prototype, "onError", {
+            /**
+             * Callback raised when an error occurs.
+             */
+            set: function (callback) {
+                if (this._onErrorObserver) {
+                    this.onErrorObservable.remove(this._onErrorObserver);
+                }
+                this._onErrorObserver = this.onErrorObservable.add(callback);
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(GLTFFileLoader.prototype, "onDispose", {
             /**
              * Callback raised after the loader is disposed.
@@ -259,10 +278,13 @@ var BABYLON;
          */
         GLTFFileLoader.prototype.whenCompleteAsync = function () {
             var _this = this;
-            return new Promise(function (resolve) {
+            return new Promise(function (resolve, reject) {
                 _this.onCompleteObservable.addOnce(function () {
                     resolve();
                 });
+                _this.onErrorObservable.addOnce(function (reason) {
+                    reject(reason);
+                });
             });
         };
         Object.defineProperty(GLTFFileLoader.prototype, "loaderState", {

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


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

@@ -191,9 +191,20 @@ declare module BABYLON {
         private _onCompleteObserver;
         /**
          * Callback raised when the asset is completely loaded, immediately 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, immediately after the loader resolves the returned promise.
          */
         onComplete: () => void;
         /**
+         * Observable raised when an error occurs.
+         */
+        readonly onErrorObservable: Observable<any>;
+        private _onErrorObserver;
+        /**
+         * Callback raised when an error occurs.
+         */
+        onError: (reason: any) => void;
+        /**
          * Observable raised after the loader is disposed.
          */
         readonly onDisposeObservable: Observable<void>;
@@ -449,7 +460,6 @@ declare module BABYLON.GLTF2 {
         _parent: GLTFFileLoader;
         _gltf: _ILoaderGLTF;
         _babylonScene: Scene;
-        _readyPromise: Promise<void>;
         _completePromises: Promise<void>[];
         private _disposed;
         private _state;
@@ -463,9 +473,6 @@ declare module BABYLON.GLTF2 {
         private static _ExtensionNames;
         private static _ExtensionFactories;
         static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
-        /**
-         * Loader state or null if the loader is not active.
-         */
         readonly state: Nullable<GLTFLoaderState>;
         constructor(parent: GLTFFileLoader);
         dispose(): void;
@@ -481,6 +488,7 @@ declare module BABYLON.GLTF2 {
         private _setupData();
         private _loadExtensions();
         private _checkExtensions();
+        private _setState(state);
         private _createRootNode();
         _loadSceneAsync(context: string, scene: _ILoaderScene): Promise<void>;
         private _forEachPrimitive(node, callback);
@@ -536,6 +544,7 @@ declare module BABYLON.GLTF2 {
         private _compileMaterialsAsync();
         private _compileShadowGeneratorsAsync();
         _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>): Nullable<Promise<T>>;
+        _forEachExtensions(action: (extension: GLTFLoaderExtension) => void): void;
     }
 }
 
@@ -564,6 +573,14 @@ declare module BABYLON.GLTF2 {
          */
         dispose(): void;
         /**
+         * Override this method to do work after the state changes to LOADING.
+         */
+        protected _onLoading(): void;
+        /**
+         * Override this method to do work after the state changes to READY.
+         */
+        protected _onReady(): void;
+        /**
          * Override this method to modify the default behavior for loading scenes.
          * @hidden
          */
@@ -614,6 +631,16 @@ declare module BABYLON.GLTF2 {
          */
         protected _loadExtrasValueAsync<TProperty, TResult = void>(context: string, property: IProperty, actionAsync: (extensionContext: string, value: TProperty) => Nullable<Promise<TResult>>): Nullable<Promise<TResult>>;
         /**
+         * Helper method called by the loader after the state changes to LOADING.
+         * @hidden
+         */
+        static _OnLoading(loader: GLTFLoader): void;
+        /**
+         * Helper method called by the loader after the state changes to READY.
+         * @hidden
+         */
+        static _OnReady(loader: GLTFLoader): void;
+        /**
          * Helper method called by the loader to allow extensions to override loading scenes.
          * @hidden
          */
@@ -690,8 +717,8 @@ declare module BABYLON.GLTF2.Extensions {
         private _materialIndexLOD;
         private _materialSignalLODs;
         private _materialPromiseLODs;
-        constructor(loader: GLTFLoader);
         dispose(): void;
+        protected _onReady(): void;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
@@ -717,7 +744,8 @@ declare module BABYLON.GLTF2.Extensions {
     /** @hidden */
     class MSFT_sRGBFactors extends GLTFLoaderExtension {
         readonly name: string;
-        protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
+        protected _loadMaterialPropertiesAsync(context: string, material: _ILoaderMaterial, babylonMaterial: Material): Nullable<Promise<void>>;
+        private _convertColorsToLinear(babylonMaterial);
     }
 }
 
@@ -766,9 +794,10 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class KHR_lights extends GLTFLoaderExtension {
         readonly name: string;
+        private _lights?;
+        protected _onLoading(): void;
         protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
-        private readonly _lights;
     }
 }
 
@@ -790,8 +819,9 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class EXT_lights_imageBased extends GLTFLoaderExtension {
         readonly name: string;
+        private _lights?;
+        protected _onLoading(): void;
         protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
         private _loadLightAsync(context, light);
-        private readonly _lights;
     }
 }

+ 146 - 94
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -118,6 +118,10 @@ var BABYLON;
              */
             this.onCompleteObservable = new BABYLON.Observable();
             /**
+             * Observable raised when an error occurs.
+             */
+            this.onErrorObservable = new BABYLON.Observable();
+            /**
              * Observable raised after the loader is disposed.
              */
             this.onDisposeObservable = new BABYLON.Observable();
@@ -217,6 +221,8 @@ var BABYLON;
         Object.defineProperty(GLTFFileLoader.prototype, "onComplete", {
             /**
              * Callback raised when the asset is completely loaded, immediately 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, immediately after the loader resolves the returned promise.
              */
             set: function (callback) {
                 if (this._onCompleteObserver) {
@@ -227,6 +233,19 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(GLTFFileLoader.prototype, "onError", {
+            /**
+             * Callback raised when an error occurs.
+             */
+            set: function (callback) {
+                if (this._onErrorObserver) {
+                    this.onErrorObservable.remove(this._onErrorObserver);
+                }
+                this._onErrorObserver = this.onErrorObservable.add(callback);
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(GLTFFileLoader.prototype, "onDispose", {
             /**
              * Callback raised after the loader is disposed.
@@ -259,10 +278,13 @@ var BABYLON;
          */
         GLTFFileLoader.prototype.whenCompleteAsync = function () {
             var _this = this;
-            return new Promise(function (resolve) {
+            return new Promise(function (resolve, reject) {
                 _this.onCompleteObservable.addOnce(function () {
                     resolve();
                 });
+                _this.onErrorObservable.addOnce(function (reason) {
+                    reject(reason);
+                });
             });
         };
         Object.defineProperty(GLTFFileLoader.prototype, "loaderState", {
@@ -713,9 +735,6 @@ var BABYLON;
                 GLTFLoader._ExtensionNames.push(name);
             };
             Object.defineProperty(GLTFLoader.prototype, "state", {
-                /**
-                 * Loader state or null if the loader is not active.
-                 */
                 get: function () {
                     return this._state;
                 },
@@ -734,7 +753,6 @@ var BABYLON;
                 this._requests.length = 0;
                 delete this._gltf;
                 delete this._babylonScene;
-                delete this._readyPromise;
                 this._completePromises.length = 0;
                 for (var name_1 in this._extensions) {
                     this._extensions[name_1].dispose();
@@ -794,14 +812,14 @@ var BABYLON;
             GLTFLoader.prototype._loadAsync = function (nodes) {
                 var _this = this;
                 return Promise.resolve().then(function () {
-                    _this._parent._startPerformanceCounter("Loading => Ready");
-                    _this._parent._startPerformanceCounter("Loading => Complete");
-                    _this._state = BABYLON.GLTFLoaderState.LOADING;
-                    _this._parent._log("Loading");
-                    var readyDeferred = new BABYLON.Deferred();
-                    _this._readyPromise = readyDeferred.promise;
                     _this._loadExtensions();
                     _this._checkExtensions();
+                    var loadingToReadyCounterName = BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.LOADING] + " => " + BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.READY];
+                    var loadingToCompleteCounterName = BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.LOADING] + " => " + BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.COMPLETE];
+                    _this._parent._startPerformanceCounter(loadingToReadyCounterName);
+                    _this._parent._startPerformanceCounter(loadingToCompleteCounterName);
+                    _this._setState(BABYLON.GLTFLoaderState.LOADING);
+                    GLTF2.GLTFLoaderExtension._OnLoading(_this);
                     var promises = new Array();
                     if (nodes) {
                         promises.push(_this._loadSceneAsync("#/nodes", { nodes: nodes, _index: -1 }));
@@ -817,33 +835,33 @@ var BABYLON;
                         promises.push(_this._compileShadowGeneratorsAsync());
                     }
                     var resultPromise = Promise.all(promises).then(function () {
-                        _this._state = BABYLON.GLTFLoaderState.READY;
-                        _this._parent._log("Ready");
-                        readyDeferred.resolve();
+                        _this._setState(BABYLON.GLTFLoaderState.READY);
+                        GLTF2.GLTFLoaderExtension._OnReady(_this);
                         _this._startAnimations();
                     });
                     resultPromise.then(function () {
-                        _this._parent._endPerformanceCounter("Loading => Ready");
+                        _this._parent._endPerformanceCounter(loadingToReadyCounterName);
                         BABYLON.Tools.SetImmediate(function () {
                             if (!_this._disposed) {
                                 Promise.all(_this._completePromises).then(function () {
-                                    _this._parent._endPerformanceCounter("Loading => Complete");
-                                    _this._state = BABYLON.GLTFLoaderState.COMPLETE;
-                                    _this._parent._log("Complete");
+                                    _this._parent._endPerformanceCounter(loadingToCompleteCounterName);
+                                    _this._setState(BABYLON.GLTFLoaderState.COMPLETE);
                                     _this._parent.onCompleteObservable.notifyObservers(undefined);
                                     _this._parent.onCompleteObservable.clear();
                                     _this.dispose();
-                                }).catch(function (error) {
-                                    BABYLON.Tools.Error("glTF Loader: " + error.message);
+                                }, function (error) {
+                                    _this._parent.onErrorObservable.notifyObservers(error);
+                                    _this._parent.onErrorObservable.clear();
                                     _this.dispose();
                                 });
                             }
                         });
                     });
                     return resultPromise;
-                }).catch(function (error) {
+                }, function (error) {
                     if (!_this._disposed) {
-                        BABYLON.Tools.Error("glTF Loader: " + error.message);
+                        _this._parent.onErrorObservable.notifyObservers(error);
+                        _this._parent.onErrorObservable.clear();
                         _this.dispose();
                         throw error;
                     }
@@ -919,6 +937,10 @@ var BABYLON;
                     }
                 }
             };
+            GLTFLoader.prototype._setState = function (state) {
+                this._state = state;
+                this._parent._log(BABYLON.GLTFLoaderState[this._state]);
+            };
             GLTFLoader.prototype._createRootNode = function () {
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this._babylonScene);
                 var rootNode = { _babylonMesh: this._rootBabylonMesh };
@@ -2173,6 +2195,15 @@ var BABYLON;
                 }
                 return null;
             };
+            GLTFLoader.prototype._forEachExtensions = function (action) {
+                for (var _i = 0, _a = GLTFLoader._ExtensionNames; _i < _a.length; _i++) {
+                    var name_6 = _a[_i];
+                    var extension = this._extensions[name_6];
+                    if (extension.enabled) {
+                        action(extension);
+                    }
+                }
+            };
             GLTFLoader._ExtensionNames = new Array();
             GLTFLoader._ExtensionFactories = {};
             return GLTFLoader;
@@ -2212,6 +2243,14 @@ var BABYLON;
             };
             // #region Overridable Methods
             /**
+             * Override this method to do work after the state changes to LOADING.
+             */
+            GLTFLoaderExtension.prototype._onLoading = function () { };
+            /**
+             * Override this method to do work after the state changes to READY.
+             */
+            GLTFLoaderExtension.prototype._onReady = function () { };
+            /**
              * Override this method to modify the default behavior for loading scenes.
              * @hidden
              */
@@ -2299,6 +2338,20 @@ var BABYLON;
                 }
             };
             /**
+             * Helper method called by the loader after the state changes to LOADING.
+             * @hidden
+             */
+            GLTFLoaderExtension._OnLoading = function (loader) {
+                loader._forEachExtensions(function (extension) { return extension._onLoading(); });
+            };
+            /**
+             * Helper method called by the loader after the state changes to READY.
+             * @hidden
+             */
+            GLTFLoaderExtension._OnReady = function (loader) {
+                loader._forEachExtensions(function (extension) { return extension._onReady(); });
+            };
+            /**
              * Helper method called by the loader to allow extensions to override loading scenes.
              * @hidden
              */
@@ -2385,8 +2438,8 @@ var BABYLON;
              */
             var MSFT_lod = /** @class */ (function (_super) {
                 __extends(MSFT_lod, _super);
-                function MSFT_lod(loader) {
-                    var _this = _super.call(this, loader) || this;
+                function MSFT_lod() {
+                    var _this = _super !== null && _super.apply(this, arguments) || this;
                     _this.name = NAME;
                     /**
                      * Maximum number of LODs to load, starting from the lowest LOD.
@@ -2410,42 +2463,6 @@ var BABYLON;
                     _this._materialIndexLOD = null;
                     _this._materialSignalLODs = new Array();
                     _this._materialPromiseLODs = new Array();
-                    _this._loader._readyPromise.then(function () {
-                        var _loop_1 = function (indexLOD) {
-                            var promise = Promise.all(_this._nodePromiseLODs[indexLOD]).then(function () {
-                                if (indexLOD !== 0) {
-                                    _this._loader._parent._endPerformanceCounter("Node LOD " + indexLOD);
-                                }
-                                _this._loader._parent._log("Loaded node LOD " + indexLOD);
-                                _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
-                                if (indexLOD !== _this._nodePromiseLODs.length - 1) {
-                                    _this._loader._parent._startPerformanceCounter("Node LOD " + (indexLOD + 1));
-                                    _this._nodeSignalLODs[indexLOD].resolve();
-                                }
-                            });
-                            _this._loader._completePromises.push(promise);
-                        };
-                        for (var indexLOD = 0; indexLOD < _this._nodePromiseLODs.length; indexLOD++) {
-                            _loop_1(indexLOD);
-                        }
-                        var _loop_2 = function (indexLOD) {
-                            var promise = Promise.all(_this._materialPromiseLODs[indexLOD]).then(function () {
-                                if (indexLOD !== 0) {
-                                    _this._loader._parent._endPerformanceCounter("Material LOD " + indexLOD);
-                                }
-                                _this._loader._parent._log("Loaded material LOD " + indexLOD);
-                                _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
-                                if (indexLOD !== _this._materialPromiseLODs.length - 1) {
-                                    _this._loader._parent._startPerformanceCounter("Material LOD " + (indexLOD + 1));
-                                    _this._materialSignalLODs[indexLOD].resolve();
-                                }
-                            });
-                            _this._loader._completePromises.push(promise);
-                        };
-                        for (var indexLOD = 0; indexLOD < _this._materialPromiseLODs.length; indexLOD++) {
-                            _loop_2(indexLOD);
-                        }
-                    });
                     return _this;
                 }
                 MSFT_lod.prototype.dispose = function () {
@@ -2459,6 +2476,49 @@ var BABYLON;
                     this.onMaterialLODsLoadedObservable.clear();
                     this.onNodeLODsLoadedObservable.clear();
                 };
+                MSFT_lod.prototype._onReady = function () {
+                    var _this = this;
+                    var _loop_1 = function (indexLOD) {
+                        var promise = Promise.all(this_1._nodePromiseLODs[indexLOD]).then(function () {
+                            if (indexLOD !== 0) {
+                                _this._loader._parent._endPerformanceCounter("Node LOD " + indexLOD);
+                            }
+                            _this._loader._parent._log("Loaded node LOD " + indexLOD);
+                            _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
+                            if (indexLOD !== _this._nodePromiseLODs.length - 1) {
+                                _this._loader._parent._startPerformanceCounter("Node LOD " + (indexLOD + 1));
+                                if (_this._nodeSignalLODs[indexLOD]) {
+                                    _this._nodeSignalLODs[indexLOD].resolve();
+                                }
+                            }
+                        });
+                        this_1._loader._completePromises.push(promise);
+                    };
+                    var this_1 = this;
+                    for (var indexLOD = 0; indexLOD < this._nodePromiseLODs.length; indexLOD++) {
+                        _loop_1(indexLOD);
+                    }
+                    var _loop_2 = function (indexLOD) {
+                        var promise = Promise.all(this_2._materialPromiseLODs[indexLOD]).then(function () {
+                            if (indexLOD !== 0) {
+                                _this._loader._parent._endPerformanceCounter("Material LOD " + indexLOD);
+                            }
+                            _this._loader._parent._log("Loaded material LOD " + indexLOD);
+                            _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
+                            if (indexLOD !== _this._materialPromiseLODs.length - 1) {
+                                _this._loader._parent._startPerformanceCounter("Material LOD " + (indexLOD + 1));
+                                if (_this._materialSignalLODs[indexLOD]) {
+                                    _this._materialSignalLODs[indexLOD].resolve();
+                                }
+                            }
+                        });
+                        this_2._loader._completePromises.push(promise);
+                    };
+                    var this_2 = this;
+                    for (var indexLOD = 0; indexLOD < this._materialPromiseLODs.length; indexLOD++) {
+                        _loop_2(indexLOD);
+                    }
+                };
                 MSFT_lod.prototype._loadNodeAsync = function (context, node) {
                     var _this = this;
                     return this._loadExtensionAsync(context, node, function (extensionContext, extension) {
@@ -2683,23 +2743,25 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
-                MSFT_sRGBFactors.prototype._loadMaterialAsync = function (context, material, mesh, babylonMesh, babylonDrawMode, assign) {
+                MSFT_sRGBFactors.prototype._loadMaterialPropertiesAsync = function (context, material, babylonMaterial) {
                     var _this = this;
                     return this._loadExtrasValueAsync(context, material, function (extensionContext, value) {
                         if (value) {
-                            return _this._loader._loadMaterialAsync(context, material, mesh, babylonMesh, babylonDrawMode, function (babylonMaterial) {
-                                if (!babylonMaterial.albedoTexture) {
-                                    babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor);
-                                }
-                                if (!babylonMaterial.reflectivityTexture) {
-                                    babylonMaterial.reflectivityColor.toLinearSpaceToRef(babylonMaterial.reflectivityColor);
-                                }
-                                assign(babylonMaterial);
-                            });
+                            var promise = _this._loader._loadMaterialPropertiesAsync(context, material, babylonMaterial);
+                            _this._convertColorsToLinear(babylonMaterial);
+                            return promise;
                         }
                         return null;
                     });
                 };
+                MSFT_sRGBFactors.prototype._convertColorsToLinear = function (babylonMaterial) {
+                    if (!babylonMaterial.albedoTexture) {
+                        babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor);
+                    }
+                    if (!babylonMaterial.reflectivityTexture) {
+                        babylonMaterial.reflectivityColor.toLinearSpaceToRef(babylonMaterial.reflectivityColor);
+                    }
+                };
                 return MSFT_sRGBFactors;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.MSFT_sRGBFactors = MSFT_sRGBFactors;
@@ -2990,6 +3052,13 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
+                KHR_lights.prototype._onLoading = function () {
+                    var extensions = this._loader._gltf.extensions;
+                    if (extensions && extensions[this.name]) {
+                        var extension = extensions[this.name];
+                        this._lights = extension.lights;
+                    }
+                };
                 KHR_lights.prototype._loadSceneAsync = function (context, scene) {
                     var _this = this;
                     return this._loadExtensionAsync(context, scene, function (extensionContext, extension) {
@@ -3038,18 +3107,6 @@ var BABYLON;
                         return promise;
                     });
                 };
-                Object.defineProperty(KHR_lights.prototype, "_lights", {
-                    get: function () {
-                        var extensions = this._loader._gltf.extensions;
-                        if (!extensions || !extensions[this.name]) {
-                            throw new Error("#/extensions: '" + this.name + "' not found");
-                        }
-                        var extension = extensions[this.name];
-                        return extension.lights;
-                    },
-                    enumerable: true,
-                    configurable: true
-                });
                 return KHR_lights;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.KHR_lights = KHR_lights;
@@ -3151,6 +3208,13 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
+                EXT_lights_imageBased.prototype._onLoading = function () {
+                    var extensions = this._loader._gltf.extensions;
+                    if (extensions && extensions[this.name]) {
+                        var extension = extensions[this.name];
+                        this._lights = extension.lights;
+                    }
+                };
                 EXT_lights_imageBased.prototype._loadSceneAsync = function (context, scene) {
                     var _this = this;
                     return this._loadExtensionAsync(context, scene, function (extensionContext, extension) {
@@ -3220,18 +3284,6 @@ var BABYLON;
                         return light._babylonTexture;
                     });
                 };
-                Object.defineProperty(EXT_lights_imageBased.prototype, "_lights", {
-                    get: function () {
-                        var extensions = this._loader._gltf.extensions;
-                        if (!extensions || !extensions[this.name]) {
-                            throw new Error("#/extensions: '" + this.name + "' not found");
-                        }
-                        var extension = extensions[this.name];
-                        return extension.lights;
-                    },
-                    enumerable: true,
-                    configurable: true
-                });
                 return EXT_lights_imageBased;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.EXT_lights_imageBased = EXT_lights_imageBased;

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


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

@@ -191,9 +191,20 @@ declare module BABYLON {
         private _onCompleteObserver;
         /**
          * Callback raised when the asset is completely loaded, immediately 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, immediately after the loader resolves the returned promise.
          */
         onComplete: () => void;
         /**
+         * Observable raised when an error occurs.
+         */
+        readonly onErrorObservable: Observable<any>;
+        private _onErrorObserver;
+        /**
+         * Callback raised when an error occurs.
+         */
+        onError: (reason: any) => void;
+        /**
          * Observable raised after the loader is disposed.
          */
         readonly onDisposeObservable: Observable<void>;
@@ -1011,7 +1022,6 @@ declare module BABYLON.GLTF2 {
         _parent: GLTFFileLoader;
         _gltf: _ILoaderGLTF;
         _babylonScene: Scene;
-        _readyPromise: Promise<void>;
         _completePromises: Promise<void>[];
         private _disposed;
         private _state;
@@ -1025,9 +1035,6 @@ declare module BABYLON.GLTF2 {
         private static _ExtensionNames;
         private static _ExtensionFactories;
         static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
-        /**
-         * Loader state or null if the loader is not active.
-         */
         readonly state: Nullable<GLTFLoaderState>;
         constructor(parent: GLTFFileLoader);
         dispose(): void;
@@ -1043,6 +1050,7 @@ declare module BABYLON.GLTF2 {
         private _setupData();
         private _loadExtensions();
         private _checkExtensions();
+        private _setState(state);
         private _createRootNode();
         _loadSceneAsync(context: string, scene: _ILoaderScene): Promise<void>;
         private _forEachPrimitive(node, callback);
@@ -1098,6 +1106,7 @@ declare module BABYLON.GLTF2 {
         private _compileMaterialsAsync();
         private _compileShadowGeneratorsAsync();
         _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>): Nullable<Promise<T>>;
+        _forEachExtensions(action: (extension: GLTFLoaderExtension) => void): void;
     }
 }
 
@@ -1126,6 +1135,14 @@ declare module BABYLON.GLTF2 {
          */
         dispose(): void;
         /**
+         * Override this method to do work after the state changes to LOADING.
+         */
+        protected _onLoading(): void;
+        /**
+         * Override this method to do work after the state changes to READY.
+         */
+        protected _onReady(): void;
+        /**
          * Override this method to modify the default behavior for loading scenes.
          * @hidden
          */
@@ -1176,6 +1193,16 @@ declare module BABYLON.GLTF2 {
          */
         protected _loadExtrasValueAsync<TProperty, TResult = void>(context: string, property: IProperty, actionAsync: (extensionContext: string, value: TProperty) => Nullable<Promise<TResult>>): Nullable<Promise<TResult>>;
         /**
+         * Helper method called by the loader after the state changes to LOADING.
+         * @hidden
+         */
+        static _OnLoading(loader: GLTFLoader): void;
+        /**
+         * Helper method called by the loader after the state changes to READY.
+         * @hidden
+         */
+        static _OnReady(loader: GLTFLoader): void;
+        /**
          * Helper method called by the loader to allow extensions to override loading scenes.
          * @hidden
          */
@@ -1252,8 +1279,8 @@ declare module BABYLON.GLTF2.Extensions {
         private _materialIndexLOD;
         private _materialSignalLODs;
         private _materialPromiseLODs;
-        constructor(loader: GLTFLoader);
         dispose(): void;
+        protected _onReady(): void;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
@@ -1279,7 +1306,8 @@ declare module BABYLON.GLTF2.Extensions {
     /** @hidden */
     class MSFT_sRGBFactors extends GLTFLoaderExtension {
         readonly name: string;
-        protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
+        protected _loadMaterialPropertiesAsync(context: string, material: _ILoaderMaterial, babylonMaterial: Material): Nullable<Promise<void>>;
+        private _convertColorsToLinear(babylonMaterial);
     }
 }
 
@@ -1328,9 +1356,10 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class KHR_lights extends GLTFLoaderExtension {
         readonly name: string;
+        private _lights?;
+        protected _onLoading(): void;
         protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
-        private readonly _lights;
     }
 }
 
@@ -1352,8 +1381,9 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class EXT_lights_imageBased extends GLTFLoaderExtension {
         readonly name: string;
+        private _lights?;
+        protected _onLoading(): void;
         protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
         private _loadLightAsync(context, light);
-        private readonly _lights;
     }
 }

+ 146 - 94
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -118,6 +118,10 @@ var BABYLON;
              */
             this.onCompleteObservable = new BABYLON.Observable();
             /**
+             * Observable raised when an error occurs.
+             */
+            this.onErrorObservable = new BABYLON.Observable();
+            /**
              * Observable raised after the loader is disposed.
              */
             this.onDisposeObservable = new BABYLON.Observable();
@@ -217,6 +221,8 @@ var BABYLON;
         Object.defineProperty(GLTFFileLoader.prototype, "onComplete", {
             /**
              * Callback raised when the asset is completely loaded, immediately 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, immediately after the loader resolves the returned promise.
              */
             set: function (callback) {
                 if (this._onCompleteObserver) {
@@ -227,6 +233,19 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(GLTFFileLoader.prototype, "onError", {
+            /**
+             * Callback raised when an error occurs.
+             */
+            set: function (callback) {
+                if (this._onErrorObserver) {
+                    this.onErrorObservable.remove(this._onErrorObserver);
+                }
+                this._onErrorObserver = this.onErrorObservable.add(callback);
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(GLTFFileLoader.prototype, "onDispose", {
             /**
              * Callback raised after the loader is disposed.
@@ -259,10 +278,13 @@ var BABYLON;
          */
         GLTFFileLoader.prototype.whenCompleteAsync = function () {
             var _this = this;
-            return new Promise(function (resolve) {
+            return new Promise(function (resolve, reject) {
                 _this.onCompleteObservable.addOnce(function () {
                     resolve();
                 });
+                _this.onErrorObservable.addOnce(function (reason) {
+                    reject(reason);
+                });
             });
         };
         Object.defineProperty(GLTFFileLoader.prototype, "loaderState", {
@@ -2914,9 +2936,6 @@ var BABYLON;
                 GLTFLoader._ExtensionNames.push(name);
             };
             Object.defineProperty(GLTFLoader.prototype, "state", {
-                /**
-                 * Loader state or null if the loader is not active.
-                 */
                 get: function () {
                     return this._state;
                 },
@@ -2935,7 +2954,6 @@ var BABYLON;
                 this._requests.length = 0;
                 delete this._gltf;
                 delete this._babylonScene;
-                delete this._readyPromise;
                 this._completePromises.length = 0;
                 for (var name_1 in this._extensions) {
                     this._extensions[name_1].dispose();
@@ -2995,14 +3013,14 @@ var BABYLON;
             GLTFLoader.prototype._loadAsync = function (nodes) {
                 var _this = this;
                 return Promise.resolve().then(function () {
-                    _this._parent._startPerformanceCounter("Loading => Ready");
-                    _this._parent._startPerformanceCounter("Loading => Complete");
-                    _this._state = BABYLON.GLTFLoaderState.LOADING;
-                    _this._parent._log("Loading");
-                    var readyDeferred = new BABYLON.Deferred();
-                    _this._readyPromise = readyDeferred.promise;
                     _this._loadExtensions();
                     _this._checkExtensions();
+                    var loadingToReadyCounterName = BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.LOADING] + " => " + BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.READY];
+                    var loadingToCompleteCounterName = BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.LOADING] + " => " + BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.COMPLETE];
+                    _this._parent._startPerformanceCounter(loadingToReadyCounterName);
+                    _this._parent._startPerformanceCounter(loadingToCompleteCounterName);
+                    _this._setState(BABYLON.GLTFLoaderState.LOADING);
+                    GLTF2.GLTFLoaderExtension._OnLoading(_this);
                     var promises = new Array();
                     if (nodes) {
                         promises.push(_this._loadSceneAsync("#/nodes", { nodes: nodes, _index: -1 }));
@@ -3018,33 +3036,33 @@ var BABYLON;
                         promises.push(_this._compileShadowGeneratorsAsync());
                     }
                     var resultPromise = Promise.all(promises).then(function () {
-                        _this._state = BABYLON.GLTFLoaderState.READY;
-                        _this._parent._log("Ready");
-                        readyDeferred.resolve();
+                        _this._setState(BABYLON.GLTFLoaderState.READY);
+                        GLTF2.GLTFLoaderExtension._OnReady(_this);
                         _this._startAnimations();
                     });
                     resultPromise.then(function () {
-                        _this._parent._endPerformanceCounter("Loading => Ready");
+                        _this._parent._endPerformanceCounter(loadingToReadyCounterName);
                         BABYLON.Tools.SetImmediate(function () {
                             if (!_this._disposed) {
                                 Promise.all(_this._completePromises).then(function () {
-                                    _this._parent._endPerformanceCounter("Loading => Complete");
-                                    _this._state = BABYLON.GLTFLoaderState.COMPLETE;
-                                    _this._parent._log("Complete");
+                                    _this._parent._endPerformanceCounter(loadingToCompleteCounterName);
+                                    _this._setState(BABYLON.GLTFLoaderState.COMPLETE);
                                     _this._parent.onCompleteObservable.notifyObservers(undefined);
                                     _this._parent.onCompleteObservable.clear();
                                     _this.dispose();
-                                }).catch(function (error) {
-                                    BABYLON.Tools.Error("glTF Loader: " + error.message);
+                                }, function (error) {
+                                    _this._parent.onErrorObservable.notifyObservers(error);
+                                    _this._parent.onErrorObservable.clear();
                                     _this.dispose();
                                 });
                             }
                         });
                     });
                     return resultPromise;
-                }).catch(function (error) {
+                }, function (error) {
                     if (!_this._disposed) {
-                        BABYLON.Tools.Error("glTF Loader: " + error.message);
+                        _this._parent.onErrorObservable.notifyObservers(error);
+                        _this._parent.onErrorObservable.clear();
                         _this.dispose();
                         throw error;
                     }
@@ -3120,6 +3138,10 @@ var BABYLON;
                     }
                 }
             };
+            GLTFLoader.prototype._setState = function (state) {
+                this._state = state;
+                this._parent._log(BABYLON.GLTFLoaderState[this._state]);
+            };
             GLTFLoader.prototype._createRootNode = function () {
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this._babylonScene);
                 var rootNode = { _babylonMesh: this._rootBabylonMesh };
@@ -4374,6 +4396,15 @@ var BABYLON;
                 }
                 return null;
             };
+            GLTFLoader.prototype._forEachExtensions = function (action) {
+                for (var _i = 0, _a = GLTFLoader._ExtensionNames; _i < _a.length; _i++) {
+                    var name_6 = _a[_i];
+                    var extension = this._extensions[name_6];
+                    if (extension.enabled) {
+                        action(extension);
+                    }
+                }
+            };
             GLTFLoader._ExtensionNames = new Array();
             GLTFLoader._ExtensionFactories = {};
             return GLTFLoader;
@@ -4413,6 +4444,14 @@ var BABYLON;
             };
             // #region Overridable Methods
             /**
+             * Override this method to do work after the state changes to LOADING.
+             */
+            GLTFLoaderExtension.prototype._onLoading = function () { };
+            /**
+             * Override this method to do work after the state changes to READY.
+             */
+            GLTFLoaderExtension.prototype._onReady = function () { };
+            /**
              * Override this method to modify the default behavior for loading scenes.
              * @hidden
              */
@@ -4500,6 +4539,20 @@ var BABYLON;
                 }
             };
             /**
+             * Helper method called by the loader after the state changes to LOADING.
+             * @hidden
+             */
+            GLTFLoaderExtension._OnLoading = function (loader) {
+                loader._forEachExtensions(function (extension) { return extension._onLoading(); });
+            };
+            /**
+             * Helper method called by the loader after the state changes to READY.
+             * @hidden
+             */
+            GLTFLoaderExtension._OnReady = function (loader) {
+                loader._forEachExtensions(function (extension) { return extension._onReady(); });
+            };
+            /**
              * Helper method called by the loader to allow extensions to override loading scenes.
              * @hidden
              */
@@ -4586,8 +4639,8 @@ var BABYLON;
              */
             var MSFT_lod = /** @class */ (function (_super) {
                 __extends(MSFT_lod, _super);
-                function MSFT_lod(loader) {
-                    var _this = _super.call(this, loader) || this;
+                function MSFT_lod() {
+                    var _this = _super !== null && _super.apply(this, arguments) || this;
                     _this.name = NAME;
                     /**
                      * Maximum number of LODs to load, starting from the lowest LOD.
@@ -4611,42 +4664,6 @@ var BABYLON;
                     _this._materialIndexLOD = null;
                     _this._materialSignalLODs = new Array();
                     _this._materialPromiseLODs = new Array();
-                    _this._loader._readyPromise.then(function () {
-                        var _loop_1 = function (indexLOD) {
-                            var promise = Promise.all(_this._nodePromiseLODs[indexLOD]).then(function () {
-                                if (indexLOD !== 0) {
-                                    _this._loader._parent._endPerformanceCounter("Node LOD " + indexLOD);
-                                }
-                                _this._loader._parent._log("Loaded node LOD " + indexLOD);
-                                _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
-                                if (indexLOD !== _this._nodePromiseLODs.length - 1) {
-                                    _this._loader._parent._startPerformanceCounter("Node LOD " + (indexLOD + 1));
-                                    _this._nodeSignalLODs[indexLOD].resolve();
-                                }
-                            });
-                            _this._loader._completePromises.push(promise);
-                        };
-                        for (var indexLOD = 0; indexLOD < _this._nodePromiseLODs.length; indexLOD++) {
-                            _loop_1(indexLOD);
-                        }
-                        var _loop_2 = function (indexLOD) {
-                            var promise = Promise.all(_this._materialPromiseLODs[indexLOD]).then(function () {
-                                if (indexLOD !== 0) {
-                                    _this._loader._parent._endPerformanceCounter("Material LOD " + indexLOD);
-                                }
-                                _this._loader._parent._log("Loaded material LOD " + indexLOD);
-                                _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
-                                if (indexLOD !== _this._materialPromiseLODs.length - 1) {
-                                    _this._loader._parent._startPerformanceCounter("Material LOD " + (indexLOD + 1));
-                                    _this._materialSignalLODs[indexLOD].resolve();
-                                }
-                            });
-                            _this._loader._completePromises.push(promise);
-                        };
-                        for (var indexLOD = 0; indexLOD < _this._materialPromiseLODs.length; indexLOD++) {
-                            _loop_2(indexLOD);
-                        }
-                    });
                     return _this;
                 }
                 MSFT_lod.prototype.dispose = function () {
@@ -4660,6 +4677,49 @@ var BABYLON;
                     this.onMaterialLODsLoadedObservable.clear();
                     this.onNodeLODsLoadedObservable.clear();
                 };
+                MSFT_lod.prototype._onReady = function () {
+                    var _this = this;
+                    var _loop_1 = function (indexLOD) {
+                        var promise = Promise.all(this_1._nodePromiseLODs[indexLOD]).then(function () {
+                            if (indexLOD !== 0) {
+                                _this._loader._parent._endPerformanceCounter("Node LOD " + indexLOD);
+                            }
+                            _this._loader._parent._log("Loaded node LOD " + indexLOD);
+                            _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
+                            if (indexLOD !== _this._nodePromiseLODs.length - 1) {
+                                _this._loader._parent._startPerformanceCounter("Node LOD " + (indexLOD + 1));
+                                if (_this._nodeSignalLODs[indexLOD]) {
+                                    _this._nodeSignalLODs[indexLOD].resolve();
+                                }
+                            }
+                        });
+                        this_1._loader._completePromises.push(promise);
+                    };
+                    var this_1 = this;
+                    for (var indexLOD = 0; indexLOD < this._nodePromiseLODs.length; indexLOD++) {
+                        _loop_1(indexLOD);
+                    }
+                    var _loop_2 = function (indexLOD) {
+                        var promise = Promise.all(this_2._materialPromiseLODs[indexLOD]).then(function () {
+                            if (indexLOD !== 0) {
+                                _this._loader._parent._endPerformanceCounter("Material LOD " + indexLOD);
+                            }
+                            _this._loader._parent._log("Loaded material LOD " + indexLOD);
+                            _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
+                            if (indexLOD !== _this._materialPromiseLODs.length - 1) {
+                                _this._loader._parent._startPerformanceCounter("Material LOD " + (indexLOD + 1));
+                                if (_this._materialSignalLODs[indexLOD]) {
+                                    _this._materialSignalLODs[indexLOD].resolve();
+                                }
+                            }
+                        });
+                        this_2._loader._completePromises.push(promise);
+                    };
+                    var this_2 = this;
+                    for (var indexLOD = 0; indexLOD < this._materialPromiseLODs.length; indexLOD++) {
+                        _loop_2(indexLOD);
+                    }
+                };
                 MSFT_lod.prototype._loadNodeAsync = function (context, node) {
                     var _this = this;
                     return this._loadExtensionAsync(context, node, function (extensionContext, extension) {
@@ -4884,23 +4944,25 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
-                MSFT_sRGBFactors.prototype._loadMaterialAsync = function (context, material, mesh, babylonMesh, babylonDrawMode, assign) {
+                MSFT_sRGBFactors.prototype._loadMaterialPropertiesAsync = function (context, material, babylonMaterial) {
                     var _this = this;
                     return this._loadExtrasValueAsync(context, material, function (extensionContext, value) {
                         if (value) {
-                            return _this._loader._loadMaterialAsync(context, material, mesh, babylonMesh, babylonDrawMode, function (babylonMaterial) {
-                                if (!babylonMaterial.albedoTexture) {
-                                    babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor);
-                                }
-                                if (!babylonMaterial.reflectivityTexture) {
-                                    babylonMaterial.reflectivityColor.toLinearSpaceToRef(babylonMaterial.reflectivityColor);
-                                }
-                                assign(babylonMaterial);
-                            });
+                            var promise = _this._loader._loadMaterialPropertiesAsync(context, material, babylonMaterial);
+                            _this._convertColorsToLinear(babylonMaterial);
+                            return promise;
                         }
                         return null;
                     });
                 };
+                MSFT_sRGBFactors.prototype._convertColorsToLinear = function (babylonMaterial) {
+                    if (!babylonMaterial.albedoTexture) {
+                        babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor);
+                    }
+                    if (!babylonMaterial.reflectivityTexture) {
+                        babylonMaterial.reflectivityColor.toLinearSpaceToRef(babylonMaterial.reflectivityColor);
+                    }
+                };
                 return MSFT_sRGBFactors;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.MSFT_sRGBFactors = MSFT_sRGBFactors;
@@ -5191,6 +5253,13 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
+                KHR_lights.prototype._onLoading = function () {
+                    var extensions = this._loader._gltf.extensions;
+                    if (extensions && extensions[this.name]) {
+                        var extension = extensions[this.name];
+                        this._lights = extension.lights;
+                    }
+                };
                 KHR_lights.prototype._loadSceneAsync = function (context, scene) {
                     var _this = this;
                     return this._loadExtensionAsync(context, scene, function (extensionContext, extension) {
@@ -5239,18 +5308,6 @@ var BABYLON;
                         return promise;
                     });
                 };
-                Object.defineProperty(KHR_lights.prototype, "_lights", {
-                    get: function () {
-                        var extensions = this._loader._gltf.extensions;
-                        if (!extensions || !extensions[this.name]) {
-                            throw new Error("#/extensions: '" + this.name + "' not found");
-                        }
-                        var extension = extensions[this.name];
-                        return extension.lights;
-                    },
-                    enumerable: true,
-                    configurable: true
-                });
                 return KHR_lights;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.KHR_lights = KHR_lights;
@@ -5348,6 +5405,13 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
+                EXT_lights_imageBased.prototype._onLoading = function () {
+                    var extensions = this._loader._gltf.extensions;
+                    if (extensions && extensions[this.name]) {
+                        var extension = extensions[this.name];
+                        this._lights = extension.lights;
+                    }
+                };
                 EXT_lights_imageBased.prototype._loadSceneAsync = function (context, scene) {
                     var _this = this;
                     return this._loadExtensionAsync(context, scene, function (extensionContext, extension) {
@@ -5417,18 +5481,6 @@ var BABYLON;
                         return light._babylonTexture;
                     });
                 };
-                Object.defineProperty(EXT_lights_imageBased.prototype, "_lights", {
-                    get: function () {
-                        var extensions = this._loader._gltf.extensions;
-                        if (!extensions || !extensions[this.name]) {
-                            throw new Error("#/extensions: '" + this.name + "' not found");
-                        }
-                        var extension = extensions[this.name];
-                        return extension.lights;
-                    },
-                    enumerable: true,
-                    configurable: true
-                });
                 return EXT_lights_imageBased;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.EXT_lights_imageBased = EXT_lights_imageBased;

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


+ 38 - 8
dist/preview release/loaders/babylonjs.loaders.d.ts

@@ -293,9 +293,20 @@ declare module BABYLON {
         private _onCompleteObserver;
         /**
          * Callback raised when the asset is completely loaded, immediately 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, immediately after the loader resolves the returned promise.
          */
         onComplete: () => void;
         /**
+         * Observable raised when an error occurs.
+         */
+        readonly onErrorObservable: Observable<any>;
+        private _onErrorObserver;
+        /**
+         * Callback raised when an error occurs.
+         */
+        onError: (reason: any) => void;
+        /**
          * Observable raised after the loader is disposed.
          */
         readonly onDisposeObservable: Observable<void>;
@@ -1113,7 +1124,6 @@ declare module BABYLON.GLTF2 {
         _parent: GLTFFileLoader;
         _gltf: _ILoaderGLTF;
         _babylonScene: Scene;
-        _readyPromise: Promise<void>;
         _completePromises: Promise<void>[];
         private _disposed;
         private _state;
@@ -1127,9 +1137,6 @@ declare module BABYLON.GLTF2 {
         private static _ExtensionNames;
         private static _ExtensionFactories;
         static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
-        /**
-         * Loader state or null if the loader is not active.
-         */
         readonly state: Nullable<GLTFLoaderState>;
         constructor(parent: GLTFFileLoader);
         dispose(): void;
@@ -1145,6 +1152,7 @@ declare module BABYLON.GLTF2 {
         private _setupData();
         private _loadExtensions();
         private _checkExtensions();
+        private _setState(state);
         private _createRootNode();
         _loadSceneAsync(context: string, scene: _ILoaderScene): Promise<void>;
         private _forEachPrimitive(node, callback);
@@ -1200,6 +1208,7 @@ declare module BABYLON.GLTF2 {
         private _compileMaterialsAsync();
         private _compileShadowGeneratorsAsync();
         _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>): Nullable<Promise<T>>;
+        _forEachExtensions(action: (extension: GLTFLoaderExtension) => void): void;
     }
 }
 
@@ -1228,6 +1237,14 @@ declare module BABYLON.GLTF2 {
          */
         dispose(): void;
         /**
+         * Override this method to do work after the state changes to LOADING.
+         */
+        protected _onLoading(): void;
+        /**
+         * Override this method to do work after the state changes to READY.
+         */
+        protected _onReady(): void;
+        /**
          * Override this method to modify the default behavior for loading scenes.
          * @hidden
          */
@@ -1278,6 +1295,16 @@ declare module BABYLON.GLTF2 {
          */
         protected _loadExtrasValueAsync<TProperty, TResult = void>(context: string, property: IProperty, actionAsync: (extensionContext: string, value: TProperty) => Nullable<Promise<TResult>>): Nullable<Promise<TResult>>;
         /**
+         * Helper method called by the loader after the state changes to LOADING.
+         * @hidden
+         */
+        static _OnLoading(loader: GLTFLoader): void;
+        /**
+         * Helper method called by the loader after the state changes to READY.
+         * @hidden
+         */
+        static _OnReady(loader: GLTFLoader): void;
+        /**
          * Helper method called by the loader to allow extensions to override loading scenes.
          * @hidden
          */
@@ -1354,8 +1381,8 @@ declare module BABYLON.GLTF2.Extensions {
         private _materialIndexLOD;
         private _materialSignalLODs;
         private _materialPromiseLODs;
-        constructor(loader: GLTFLoader);
         dispose(): void;
+        protected _onReady(): void;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
@@ -1381,7 +1408,8 @@ declare module BABYLON.GLTF2.Extensions {
     /** @hidden */
     class MSFT_sRGBFactors extends GLTFLoaderExtension {
         readonly name: string;
-        protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
+        protected _loadMaterialPropertiesAsync(context: string, material: _ILoaderMaterial, babylonMaterial: Material): Nullable<Promise<void>>;
+        private _convertColorsToLinear(babylonMaterial);
     }
 }
 
@@ -1430,9 +1458,10 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class KHR_lights extends GLTFLoaderExtension {
         readonly name: string;
+        private _lights?;
+        protected _onLoading(): void;
         protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
-        private readonly _lights;
     }
 }
 
@@ -1454,8 +1483,9 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class EXT_lights_imageBased extends GLTFLoaderExtension {
         readonly name: string;
+        private _lights?;
+        protected _onLoading(): void;
         protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
         private _loadLightAsync(context, light);
-        private readonly _lights;
     }
 }

+ 146 - 94
dist/preview release/loaders/babylonjs.loaders.js

@@ -1173,6 +1173,10 @@ var BABYLON;
              */
             this.onCompleteObservable = new BABYLON.Observable();
             /**
+             * Observable raised when an error occurs.
+             */
+            this.onErrorObservable = new BABYLON.Observable();
+            /**
              * Observable raised after the loader is disposed.
              */
             this.onDisposeObservable = new BABYLON.Observable();
@@ -1272,6 +1276,8 @@ var BABYLON;
         Object.defineProperty(GLTFFileLoader.prototype, "onComplete", {
             /**
              * Callback raised when the asset is completely loaded, immediately 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, immediately after the loader resolves the returned promise.
              */
             set: function (callback) {
                 if (this._onCompleteObserver) {
@@ -1282,6 +1288,19 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(GLTFFileLoader.prototype, "onError", {
+            /**
+             * Callback raised when an error occurs.
+             */
+            set: function (callback) {
+                if (this._onErrorObserver) {
+                    this.onErrorObservable.remove(this._onErrorObserver);
+                }
+                this._onErrorObserver = this.onErrorObservable.add(callback);
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(GLTFFileLoader.prototype, "onDispose", {
             /**
              * Callback raised after the loader is disposed.
@@ -1314,10 +1333,13 @@ var BABYLON;
          */
         GLTFFileLoader.prototype.whenCompleteAsync = function () {
             var _this = this;
-            return new Promise(function (resolve) {
+            return new Promise(function (resolve, reject) {
                 _this.onCompleteObservable.addOnce(function () {
                     resolve();
                 });
+                _this.onErrorObservable.addOnce(function (reason) {
+                    reject(reason);
+                });
             });
         };
         Object.defineProperty(GLTFFileLoader.prototype, "loaderState", {
@@ -3951,9 +3973,6 @@ var BABYLON;
                 GLTFLoader._ExtensionNames.push(name);
             };
             Object.defineProperty(GLTFLoader.prototype, "state", {
-                /**
-                 * Loader state or null if the loader is not active.
-                 */
                 get: function () {
                     return this._state;
                 },
@@ -3972,7 +3991,6 @@ var BABYLON;
                 this._requests.length = 0;
                 delete this._gltf;
                 delete this._babylonScene;
-                delete this._readyPromise;
                 this._completePromises.length = 0;
                 for (var name_1 in this._extensions) {
                     this._extensions[name_1].dispose();
@@ -4032,14 +4050,14 @@ var BABYLON;
             GLTFLoader.prototype._loadAsync = function (nodes) {
                 var _this = this;
                 return Promise.resolve().then(function () {
-                    _this._parent._startPerformanceCounter("Loading => Ready");
-                    _this._parent._startPerformanceCounter("Loading => Complete");
-                    _this._state = BABYLON.GLTFLoaderState.LOADING;
-                    _this._parent._log("Loading");
-                    var readyDeferred = new BABYLON.Deferred();
-                    _this._readyPromise = readyDeferred.promise;
                     _this._loadExtensions();
                     _this._checkExtensions();
+                    var loadingToReadyCounterName = BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.LOADING] + " => " + BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.READY];
+                    var loadingToCompleteCounterName = BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.LOADING] + " => " + BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.COMPLETE];
+                    _this._parent._startPerformanceCounter(loadingToReadyCounterName);
+                    _this._parent._startPerformanceCounter(loadingToCompleteCounterName);
+                    _this._setState(BABYLON.GLTFLoaderState.LOADING);
+                    GLTF2.GLTFLoaderExtension._OnLoading(_this);
                     var promises = new Array();
                     if (nodes) {
                         promises.push(_this._loadSceneAsync("#/nodes", { nodes: nodes, _index: -1 }));
@@ -4055,33 +4073,33 @@ var BABYLON;
                         promises.push(_this._compileShadowGeneratorsAsync());
                     }
                     var resultPromise = Promise.all(promises).then(function () {
-                        _this._state = BABYLON.GLTFLoaderState.READY;
-                        _this._parent._log("Ready");
-                        readyDeferred.resolve();
+                        _this._setState(BABYLON.GLTFLoaderState.READY);
+                        GLTF2.GLTFLoaderExtension._OnReady(_this);
                         _this._startAnimations();
                     });
                     resultPromise.then(function () {
-                        _this._parent._endPerformanceCounter("Loading => Ready");
+                        _this._parent._endPerformanceCounter(loadingToReadyCounterName);
                         BABYLON.Tools.SetImmediate(function () {
                             if (!_this._disposed) {
                                 Promise.all(_this._completePromises).then(function () {
-                                    _this._parent._endPerformanceCounter("Loading => Complete");
-                                    _this._state = BABYLON.GLTFLoaderState.COMPLETE;
-                                    _this._parent._log("Complete");
+                                    _this._parent._endPerformanceCounter(loadingToCompleteCounterName);
+                                    _this._setState(BABYLON.GLTFLoaderState.COMPLETE);
                                     _this._parent.onCompleteObservable.notifyObservers(undefined);
                                     _this._parent.onCompleteObservable.clear();
                                     _this.dispose();
-                                }).catch(function (error) {
-                                    BABYLON.Tools.Error("glTF Loader: " + error.message);
+                                }, function (error) {
+                                    _this._parent.onErrorObservable.notifyObservers(error);
+                                    _this._parent.onErrorObservable.clear();
                                     _this.dispose();
                                 });
                             }
                         });
                     });
                     return resultPromise;
-                }).catch(function (error) {
+                }, function (error) {
                     if (!_this._disposed) {
-                        BABYLON.Tools.Error("glTF Loader: " + error.message);
+                        _this._parent.onErrorObservable.notifyObservers(error);
+                        _this._parent.onErrorObservable.clear();
                         _this.dispose();
                         throw error;
                     }
@@ -4157,6 +4175,10 @@ var BABYLON;
                     }
                 }
             };
+            GLTFLoader.prototype._setState = function (state) {
+                this._state = state;
+                this._parent._log(BABYLON.GLTFLoaderState[this._state]);
+            };
             GLTFLoader.prototype._createRootNode = function () {
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this._babylonScene);
                 var rootNode = { _babylonMesh: this._rootBabylonMesh };
@@ -5411,6 +5433,15 @@ var BABYLON;
                 }
                 return null;
             };
+            GLTFLoader.prototype._forEachExtensions = function (action) {
+                for (var _i = 0, _a = GLTFLoader._ExtensionNames; _i < _a.length; _i++) {
+                    var name_6 = _a[_i];
+                    var extension = this._extensions[name_6];
+                    if (extension.enabled) {
+                        action(extension);
+                    }
+                }
+            };
             GLTFLoader._ExtensionNames = new Array();
             GLTFLoader._ExtensionFactories = {};
             return GLTFLoader;
@@ -5450,6 +5481,14 @@ var BABYLON;
             };
             // #region Overridable Methods
             /**
+             * Override this method to do work after the state changes to LOADING.
+             */
+            GLTFLoaderExtension.prototype._onLoading = function () { };
+            /**
+             * Override this method to do work after the state changes to READY.
+             */
+            GLTFLoaderExtension.prototype._onReady = function () { };
+            /**
              * Override this method to modify the default behavior for loading scenes.
              * @hidden
              */
@@ -5537,6 +5576,20 @@ var BABYLON;
                 }
             };
             /**
+             * Helper method called by the loader after the state changes to LOADING.
+             * @hidden
+             */
+            GLTFLoaderExtension._OnLoading = function (loader) {
+                loader._forEachExtensions(function (extension) { return extension._onLoading(); });
+            };
+            /**
+             * Helper method called by the loader after the state changes to READY.
+             * @hidden
+             */
+            GLTFLoaderExtension._OnReady = function (loader) {
+                loader._forEachExtensions(function (extension) { return extension._onReady(); });
+            };
+            /**
              * Helper method called by the loader to allow extensions to override loading scenes.
              * @hidden
              */
@@ -5614,8 +5667,8 @@ var BABYLON;
              */
             var MSFT_lod = /** @class */ (function (_super) {
                 __extends(MSFT_lod, _super);
-                function MSFT_lod(loader) {
-                    var _this = _super.call(this, loader) || this;
+                function MSFT_lod() {
+                    var _this = _super !== null && _super.apply(this, arguments) || this;
                     _this.name = NAME;
                     /**
                      * Maximum number of LODs to load, starting from the lowest LOD.
@@ -5639,42 +5692,6 @@ var BABYLON;
                     _this._materialIndexLOD = null;
                     _this._materialSignalLODs = new Array();
                     _this._materialPromiseLODs = new Array();
-                    _this._loader._readyPromise.then(function () {
-                        var _loop_1 = function (indexLOD) {
-                            var promise = Promise.all(_this._nodePromiseLODs[indexLOD]).then(function () {
-                                if (indexLOD !== 0) {
-                                    _this._loader._parent._endPerformanceCounter("Node LOD " + indexLOD);
-                                }
-                                _this._loader._parent._log("Loaded node LOD " + indexLOD);
-                                _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
-                                if (indexLOD !== _this._nodePromiseLODs.length - 1) {
-                                    _this._loader._parent._startPerformanceCounter("Node LOD " + (indexLOD + 1));
-                                    _this._nodeSignalLODs[indexLOD].resolve();
-                                }
-                            });
-                            _this._loader._completePromises.push(promise);
-                        };
-                        for (var indexLOD = 0; indexLOD < _this._nodePromiseLODs.length; indexLOD++) {
-                            _loop_1(indexLOD);
-                        }
-                        var _loop_2 = function (indexLOD) {
-                            var promise = Promise.all(_this._materialPromiseLODs[indexLOD]).then(function () {
-                                if (indexLOD !== 0) {
-                                    _this._loader._parent._endPerformanceCounter("Material LOD " + indexLOD);
-                                }
-                                _this._loader._parent._log("Loaded material LOD " + indexLOD);
-                                _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
-                                if (indexLOD !== _this._materialPromiseLODs.length - 1) {
-                                    _this._loader._parent._startPerformanceCounter("Material LOD " + (indexLOD + 1));
-                                    _this._materialSignalLODs[indexLOD].resolve();
-                                }
-                            });
-                            _this._loader._completePromises.push(promise);
-                        };
-                        for (var indexLOD = 0; indexLOD < _this._materialPromiseLODs.length; indexLOD++) {
-                            _loop_2(indexLOD);
-                        }
-                    });
                     return _this;
                 }
                 MSFT_lod.prototype.dispose = function () {
@@ -5688,6 +5705,49 @@ var BABYLON;
                     this.onMaterialLODsLoadedObservable.clear();
                     this.onNodeLODsLoadedObservable.clear();
                 };
+                MSFT_lod.prototype._onReady = function () {
+                    var _this = this;
+                    var _loop_1 = function (indexLOD) {
+                        var promise = Promise.all(this_1._nodePromiseLODs[indexLOD]).then(function () {
+                            if (indexLOD !== 0) {
+                                _this._loader._parent._endPerformanceCounter("Node LOD " + indexLOD);
+                            }
+                            _this._loader._parent._log("Loaded node LOD " + indexLOD);
+                            _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
+                            if (indexLOD !== _this._nodePromiseLODs.length - 1) {
+                                _this._loader._parent._startPerformanceCounter("Node LOD " + (indexLOD + 1));
+                                if (_this._nodeSignalLODs[indexLOD]) {
+                                    _this._nodeSignalLODs[indexLOD].resolve();
+                                }
+                            }
+                        });
+                        this_1._loader._completePromises.push(promise);
+                    };
+                    var this_1 = this;
+                    for (var indexLOD = 0; indexLOD < this._nodePromiseLODs.length; indexLOD++) {
+                        _loop_1(indexLOD);
+                    }
+                    var _loop_2 = function (indexLOD) {
+                        var promise = Promise.all(this_2._materialPromiseLODs[indexLOD]).then(function () {
+                            if (indexLOD !== 0) {
+                                _this._loader._parent._endPerformanceCounter("Material LOD " + indexLOD);
+                            }
+                            _this._loader._parent._log("Loaded material LOD " + indexLOD);
+                            _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
+                            if (indexLOD !== _this._materialPromiseLODs.length - 1) {
+                                _this._loader._parent._startPerformanceCounter("Material LOD " + (indexLOD + 1));
+                                if (_this._materialSignalLODs[indexLOD]) {
+                                    _this._materialSignalLODs[indexLOD].resolve();
+                                }
+                            }
+                        });
+                        this_2._loader._completePromises.push(promise);
+                    };
+                    var this_2 = this;
+                    for (var indexLOD = 0; indexLOD < this._materialPromiseLODs.length; indexLOD++) {
+                        _loop_2(indexLOD);
+                    }
+                };
                 MSFT_lod.prototype._loadNodeAsync = function (context, node) {
                     var _this = this;
                     return this._loadExtensionAsync(context, node, function (extensionContext, extension) {
@@ -5894,23 +5954,25 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
-                MSFT_sRGBFactors.prototype._loadMaterialAsync = function (context, material, mesh, babylonMesh, babylonDrawMode, assign) {
+                MSFT_sRGBFactors.prototype._loadMaterialPropertiesAsync = function (context, material, babylonMaterial) {
                     var _this = this;
                     return this._loadExtrasValueAsync(context, material, function (extensionContext, value) {
                         if (value) {
-                            return _this._loader._loadMaterialAsync(context, material, mesh, babylonMesh, babylonDrawMode, function (babylonMaterial) {
-                                if (!babylonMaterial.albedoTexture) {
-                                    babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor);
-                                }
-                                if (!babylonMaterial.reflectivityTexture) {
-                                    babylonMaterial.reflectivityColor.toLinearSpaceToRef(babylonMaterial.reflectivityColor);
-                                }
-                                assign(babylonMaterial);
-                            });
+                            var promise = _this._loader._loadMaterialPropertiesAsync(context, material, babylonMaterial);
+                            _this._convertColorsToLinear(babylonMaterial);
+                            return promise;
                         }
                         return null;
                     });
                 };
+                MSFT_sRGBFactors.prototype._convertColorsToLinear = function (babylonMaterial) {
+                    if (!babylonMaterial.albedoTexture) {
+                        babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor);
+                    }
+                    if (!babylonMaterial.reflectivityTexture) {
+                        babylonMaterial.reflectivityColor.toLinearSpaceToRef(babylonMaterial.reflectivityColor);
+                    }
+                };
                 return MSFT_sRGBFactors;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.MSFT_sRGBFactors = MSFT_sRGBFactors;
@@ -6165,6 +6227,13 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
+                KHR_lights.prototype._onLoading = function () {
+                    var extensions = this._loader._gltf.extensions;
+                    if (extensions && extensions[this.name]) {
+                        var extension = extensions[this.name];
+                        this._lights = extension.lights;
+                    }
+                };
                 KHR_lights.prototype._loadSceneAsync = function (context, scene) {
                     var _this = this;
                     return this._loadExtensionAsync(context, scene, function (extensionContext, extension) {
@@ -6213,18 +6282,6 @@ var BABYLON;
                         return promise;
                     });
                 };
-                Object.defineProperty(KHR_lights.prototype, "_lights", {
-                    get: function () {
-                        var extensions = this._loader._gltf.extensions;
-                        if (!extensions || !extensions[this.name]) {
-                            throw new Error("#/extensions: '" + this.name + "' not found");
-                        }
-                        var extension = extensions[this.name];
-                        return extension.lights;
-                    },
-                    enumerable: true,
-                    configurable: true
-                });
                 return KHR_lights;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.KHR_lights = KHR_lights;
@@ -6304,6 +6361,13 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
+                EXT_lights_imageBased.prototype._onLoading = function () {
+                    var extensions = this._loader._gltf.extensions;
+                    if (extensions && extensions[this.name]) {
+                        var extension = extensions[this.name];
+                        this._lights = extension.lights;
+                    }
+                };
                 EXT_lights_imageBased.prototype._loadSceneAsync = function (context, scene) {
                     var _this = this;
                     return this._loadExtensionAsync(context, scene, function (extensionContext, extension) {
@@ -6373,18 +6437,6 @@ var BABYLON;
                         return light._babylonTexture;
                     });
                 };
-                Object.defineProperty(EXT_lights_imageBased.prototype, "_lights", {
-                    get: function () {
-                        var extensions = this._loader._gltf.extensions;
-                        if (!extensions || !extensions[this.name]) {
-                            throw new Error("#/extensions: '" + this.name + "' not found");
-                        }
-                        var extension = extensions[this.name];
-                        return extension.lights;
-                    },
-                    enumerable: true,
-                    configurable: true
-                });
                 return EXT_lights_imageBased;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.EXT_lights_imageBased = EXT_lights_imageBased;

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


+ 38 - 8
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -300,9 +300,20 @@ declare module BABYLON {
         private _onCompleteObserver;
         /**
          * Callback raised when the asset is completely loaded, immediately 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, immediately after the loader resolves the returned promise.
          */
         onComplete: () => void;
         /**
+         * Observable raised when an error occurs.
+         */
+        readonly onErrorObservable: Observable<any>;
+        private _onErrorObserver;
+        /**
+         * Callback raised when an error occurs.
+         */
+        onError: (reason: any) => void;
+        /**
          * Observable raised after the loader is disposed.
          */
         readonly onDisposeObservable: Observable<void>;
@@ -1120,7 +1131,6 @@ declare module BABYLON.GLTF2 {
         _parent: GLTFFileLoader;
         _gltf: _ILoaderGLTF;
         _babylonScene: Scene;
-        _readyPromise: Promise<void>;
         _completePromises: Promise<void>[];
         private _disposed;
         private _state;
@@ -1134,9 +1144,6 @@ declare module BABYLON.GLTF2 {
         private static _ExtensionNames;
         private static _ExtensionFactories;
         static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
-        /**
-         * Loader state or null if the loader is not active.
-         */
         readonly state: Nullable<GLTFLoaderState>;
         constructor(parent: GLTFFileLoader);
         dispose(): void;
@@ -1152,6 +1159,7 @@ declare module BABYLON.GLTF2 {
         private _setupData();
         private _loadExtensions();
         private _checkExtensions();
+        private _setState(state);
         private _createRootNode();
         _loadSceneAsync(context: string, scene: _ILoaderScene): Promise<void>;
         private _forEachPrimitive(node, callback);
@@ -1207,6 +1215,7 @@ declare module BABYLON.GLTF2 {
         private _compileMaterialsAsync();
         private _compileShadowGeneratorsAsync();
         _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>): Nullable<Promise<T>>;
+        _forEachExtensions(action: (extension: GLTFLoaderExtension) => void): void;
     }
 }
 
@@ -1235,6 +1244,14 @@ declare module BABYLON.GLTF2 {
          */
         dispose(): void;
         /**
+         * Override this method to do work after the state changes to LOADING.
+         */
+        protected _onLoading(): void;
+        /**
+         * Override this method to do work after the state changes to READY.
+         */
+        protected _onReady(): void;
+        /**
          * Override this method to modify the default behavior for loading scenes.
          * @hidden
          */
@@ -1285,6 +1302,16 @@ declare module BABYLON.GLTF2 {
          */
         protected _loadExtrasValueAsync<TProperty, TResult = void>(context: string, property: IProperty, actionAsync: (extensionContext: string, value: TProperty) => Nullable<Promise<TResult>>): Nullable<Promise<TResult>>;
         /**
+         * Helper method called by the loader after the state changes to LOADING.
+         * @hidden
+         */
+        static _OnLoading(loader: GLTFLoader): void;
+        /**
+         * Helper method called by the loader after the state changes to READY.
+         * @hidden
+         */
+        static _OnReady(loader: GLTFLoader): void;
+        /**
          * Helper method called by the loader to allow extensions to override loading scenes.
          * @hidden
          */
@@ -1361,8 +1388,8 @@ declare module BABYLON.GLTF2.Extensions {
         private _materialIndexLOD;
         private _materialSignalLODs;
         private _materialPromiseLODs;
-        constructor(loader: GLTFLoader);
         dispose(): void;
+        protected _onReady(): void;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
@@ -1388,7 +1415,8 @@ declare module BABYLON.GLTF2.Extensions {
     /** @hidden */
     class MSFT_sRGBFactors extends GLTFLoaderExtension {
         readonly name: string;
-        protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
+        protected _loadMaterialPropertiesAsync(context: string, material: _ILoaderMaterial, babylonMaterial: Material): Nullable<Promise<void>>;
+        private _convertColorsToLinear(babylonMaterial);
     }
 }
 
@@ -1437,9 +1465,10 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class KHR_lights extends GLTFLoaderExtension {
         readonly name: string;
+        private _lights?;
+        protected _onLoading(): void;
         protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
-        private readonly _lights;
     }
 }
 
@@ -1461,8 +1490,9 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class EXT_lights_imageBased extends GLTFLoaderExtension {
         readonly name: string;
+        private _lights?;
+        protected _onLoading(): void;
         protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
         private _loadLightAsync(context, light);
-        private readonly _lights;
     }
 }

+ 2 - 2
dist/preview release/loaders/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-loaders",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
-    "version": "3.3.0-alpha.12",
+    "version": "3.3.0-alpha.13",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "3.3.0-alpha.12"
+        "babylonjs-gltf2interface": "3.3.0-alpha.13"
     },
     "peerDependencies": {
         "babylonjs": ">=3.2.0-alpha"

+ 1 - 1
dist/preview release/materialsLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-materials",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.3.0-alpha.12",
+    "version": "3.3.0-alpha.13",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/postProcessesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-post-process",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.3.0-alpha.12",
+    "version": "3.3.0-alpha.13",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/proceduralTexturesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-procedural-textures",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.3.0-alpha.12",
+    "version": "3.3.0-alpha.13",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 7 - 0
dist/preview release/serializers/babylon.glTF2Serializer.d.ts

@@ -521,6 +521,13 @@ declare module BABYLON.GLTF2 {
          */
         private _resizeTexturesToSameDimensions(texture1, texture2, scene);
         /**
+         * Converts an array of pixels to a Float32Array
+         * Throws an error if the pixel format is not supported
+         * @param pixels - array buffer containing pixel values
+         * @returns Float32 of pixels
+         */
+        private _convertPixelArrayToFloat32(pixels);
+        /**
          * Convert Specular Glossiness Textures to Metallic Roughness
          * See link below for info on the material conversions from PBR Metallic/Roughness and Specular/Glossiness
          * @link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/examples/convert-between-workflows-bjs/js/babylon.pbrUtilities.js

+ 113 - 91
dist/preview release/serializers/babylon.glTF2Serializer.js

@@ -1821,6 +1821,28 @@ var BABYLON;
                 };
             };
             /**
+             * Converts an array of pixels to a Float32Array
+             * Throws an error if the pixel format is not supported
+             * @param pixels - array buffer containing pixel values
+             * @returns Float32 of pixels
+             */
+            _GLTFMaterialExporter.prototype._convertPixelArrayToFloat32 = function (pixels) {
+                if (pixels instanceof Uint8Array) {
+                    var length_1 = pixels.length;
+                    var buffer = new Float32Array(pixels.length);
+                    for (var i = 0; i < length_1; ++i) {
+                        buffer[i] = pixels[i] / 255;
+                    }
+                    return buffer;
+                }
+                else if (pixels instanceof Float32Array) {
+                    return pixels;
+                }
+                else {
+                    throw new Error('Unsupported pixel format!');
+                }
+            };
+            /**
              * Convert Specular Glossiness Textures to Metallic Roughness
              * See link below for info on the material conversions from PBR Metallic/Roughness and Specular/Glossiness
              * @link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/examples/convert-between-workflows-bjs/js/babylon.pbrUtilities.js
@@ -1843,99 +1865,99 @@ var BABYLON;
                     var specularGlossinessBuffer = void 0;
                     var width = diffuseSize.width;
                     var height = diffuseSize.height;
-                    var pixels = (resizedTextures.texture1.readPixels());
-                    if (pixels instanceof Uint8Array) {
-                        diffuseBuffer = (resizedTextures.texture1.readPixels());
-                        pixels = resizedTextures.texture2.readPixels();
-                        if (pixels instanceof Uint8Array) {
-                            specularGlossinessBuffer = (resizedTextures.texture2.readPixels());
-                            var byteLength = specularGlossinessBuffer.byteLength;
-                            var metallicRoughnessBuffer = new Uint8Array(byteLength);
-                            var baseColorBuffer = new Uint8Array(byteLength);
-                            var strideSize = 4;
-                            var maxBaseColor = BABYLON.Color3.Black();
-                            var maxMetallic = 0;
-                            var maxRoughness = 0;
-                            for (var h = 0; h < height; ++h) {
-                                for (var w = 0; w < width; ++w) {
-                                    var offset = (width * h + w) * strideSize;
-                                    var diffuseColor = BABYLON.Color3.FromInts(diffuseBuffer[offset], diffuseBuffer[offset + 1], diffuseBuffer[offset + 2]).toLinearSpace().multiply(factors.diffuseColor);
-                                    var specularColor = BABYLON.Color3.FromInts(specularGlossinessBuffer[offset], specularGlossinessBuffer[offset + 1], specularGlossinessBuffer[offset + 2]).toLinearSpace().multiply(factors.specularColor);
-                                    var glossiness = (specularGlossinessBuffer[offset + 3] / 255) * factors.glossiness;
-                                    var specularGlossiness = {
-                                        diffuseColor: diffuseColor,
-                                        specularColor: specularColor,
-                                        glossiness: glossiness
-                                    };
-                                    var metallicRoughness = this._convertSpecularGlossinessToMetallicRoughness(specularGlossiness);
-                                    maxBaseColor.r = Math.max(maxBaseColor.r, metallicRoughness.baseColor.r);
-                                    maxBaseColor.g = Math.max(maxBaseColor.g, metallicRoughness.baseColor.g);
-                                    maxBaseColor.b = Math.max(maxBaseColor.b, metallicRoughness.baseColor.b);
-                                    maxMetallic = Math.max(maxMetallic, metallicRoughness.metallic);
-                                    maxRoughness = Math.max(maxRoughness, metallicRoughness.roughness);
-                                    baseColorBuffer[offset] = metallicRoughness.baseColor.r * 255;
-                                    baseColorBuffer[offset + 1] = metallicRoughness.baseColor.g * 255;
-                                    baseColorBuffer[offset + 2] = metallicRoughness.baseColor.b * 255;
-                                    baseColorBuffer[offset + 3] = resizedTextures.texture1.hasAlpha ? diffuseBuffer[offset + 3] : 255;
-                                    metallicRoughnessBuffer[offset] = 0;
-                                    metallicRoughnessBuffer[offset + 1] = metallicRoughness.roughness * 255;
-                                    metallicRoughnessBuffer[offset + 2] = metallicRoughness.metallic * 255;
-                                    metallicRoughnessBuffer[offset + 3] = 255;
-                                }
-                            }
-                            // Retrieves the metallic roughness factors from the maximum texture values.
-                            var metallicRoughnessFactors_1 = {
-                                baseColor: maxBaseColor,
-                                metallic: maxMetallic,
-                                roughness: maxRoughness
-                            };
-                            var writeOutMetallicRoughnessTexture = false;
-                            var writeOutBaseColorTexture = false;
-                            for (var h = 0; h < height; ++h) {
-                                for (var w = 0; w < width; ++w) {
-                                    var destinationOffset = (width * h + w) * strideSize;
-                                    baseColorBuffer[destinationOffset] /= metallicRoughnessFactors_1.baseColor.r > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.r : 1;
-                                    baseColorBuffer[destinationOffset + 1] /= metallicRoughnessFactors_1.baseColor.g > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.g : 1;
-                                    baseColorBuffer[destinationOffset + 2] /= metallicRoughnessFactors_1.baseColor.b > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.b : 1;
-                                    var linearBaseColorPixel = BABYLON.Color3.FromInts(baseColorBuffer[destinationOffset], baseColorBuffer[destinationOffset + 1], baseColorBuffer[destinationOffset + 2]);
-                                    var sRGBBaseColorPixel = linearBaseColorPixel.toGammaSpace();
-                                    baseColorBuffer[destinationOffset] = sRGBBaseColorPixel.r * 255;
-                                    baseColorBuffer[destinationOffset + 1] = sRGBBaseColorPixel.g * 255;
-                                    baseColorBuffer[destinationOffset + 2] = sRGBBaseColorPixel.b * 255;
-                                    if (!_GLTFMaterialExporter.FuzzyEquals(sRGBBaseColorPixel, BABYLON.Color3.White(), _GLTFMaterialExporter._Epsilon)) {
-                                        writeOutBaseColorTexture = true;
-                                    }
-                                    metallicRoughnessBuffer[destinationOffset + 1] /= metallicRoughnessFactors_1.roughness > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.roughness : 1;
-                                    metallicRoughnessBuffer[destinationOffset + 2] /= metallicRoughnessFactors_1.metallic > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.metallic : 1;
-                                    var metallicRoughnessPixel = BABYLON.Color3.FromInts(255, metallicRoughnessBuffer[destinationOffset + 1], metallicRoughnessBuffer[destinationOffset + 2]);
-                                    if (!_GLTFMaterialExporter.FuzzyEquals(metallicRoughnessPixel, BABYLON.Color3.White(), _GLTFMaterialExporter._Epsilon)) {
-                                        writeOutMetallicRoughnessTexture = true;
-                                    }
-                                }
-                            }
-                            if (writeOutMetallicRoughnessTexture) {
-                                var promise = this._createBase64FromCanvasAsync(metallicRoughnessBuffer, width, height, mimeType).then(function (metallicRoughnessBase64) {
-                                    metallicRoughnessFactors_1.metallicRoughnessTextureBase64 = metallicRoughnessBase64;
-                                });
-                                promises.push(promise);
-                            }
-                            if (writeOutBaseColorTexture) {
-                                var promise = this._createBase64FromCanvasAsync(baseColorBuffer, width, height, mimeType).then(function (baseColorBase64) {
-                                    metallicRoughnessFactors_1.baseColorTextureBase64 = baseColorBase64;
-                                });
-                                promises.push(promise);
-                            }
-                            return Promise.all(promises).then(function () {
-                                return metallicRoughnessFactors_1;
-                            });
-                        }
-                        else {
-                            return Promise.reject("_ConvertSpecularGlossinessTexturesToMetallicRoughness: Pixel array buffer type not supported for texture: " + resizedTextures.texture2.name);
-                        }
+                    var diffusePixels = resizedTextures.texture1.readPixels();
+                    var specularPixels = resizedTextures.texture2.readPixels();
+                    if (diffusePixels) {
+                        diffuseBuffer = this._convertPixelArrayToFloat32(diffusePixels);
                     }
                     else {
-                        return Promise.reject("_ConvertSpecularGlossinessTexturesToMetallicRoughness: Pixel array buffer type not supported for texture: " + resizedTextures.texture1.name);
+                        return Promise.reject("Failed to retrieve pixels from diffuse texture!");
                     }
+                    if (specularPixels) {
+                        specularGlossinessBuffer = this._convertPixelArrayToFloat32(specularPixels);
+                    }
+                    else {
+                        return Promise.reject("Failed to retrieve pixels from specular glossiness texture!");
+                    }
+                    var byteLength = specularGlossinessBuffer.byteLength;
+                    var metallicRoughnessBuffer = new Uint8Array(byteLength);
+                    var baseColorBuffer = new Uint8Array(byteLength);
+                    var strideSize = 4;
+                    var maxBaseColor = BABYLON.Color3.Black();
+                    var maxMetallic = 0;
+                    var maxRoughness = 0;
+                    for (var h = 0; h < height; ++h) {
+                        for (var w = 0; w < width; ++w) {
+                            var offset = (width * h + w) * strideSize;
+                            var diffuseColor = new BABYLON.Color3(diffuseBuffer[offset], diffuseBuffer[offset + 1], diffuseBuffer[offset + 2]).toLinearSpace().multiply(factors.diffuseColor);
+                            var specularColor = new BABYLON.Color3(specularGlossinessBuffer[offset], specularGlossinessBuffer[offset + 1], specularGlossinessBuffer[offset + 2]).toLinearSpace().multiply(factors.specularColor);
+                            var glossiness = (specularGlossinessBuffer[offset + 3]) * factors.glossiness;
+                            var specularGlossiness = {
+                                diffuseColor: diffuseColor,
+                                specularColor: specularColor,
+                                glossiness: glossiness
+                            };
+                            var metallicRoughness = this._convertSpecularGlossinessToMetallicRoughness(specularGlossiness);
+                            maxBaseColor.r = Math.max(maxBaseColor.r, metallicRoughness.baseColor.r);
+                            maxBaseColor.g = Math.max(maxBaseColor.g, metallicRoughness.baseColor.g);
+                            maxBaseColor.b = Math.max(maxBaseColor.b, metallicRoughness.baseColor.b);
+                            maxMetallic = Math.max(maxMetallic, metallicRoughness.metallic);
+                            maxRoughness = Math.max(maxRoughness, metallicRoughness.roughness);
+                            baseColorBuffer[offset] = metallicRoughness.baseColor.r * 255;
+                            baseColorBuffer[offset + 1] = metallicRoughness.baseColor.g * 255;
+                            baseColorBuffer[offset + 2] = metallicRoughness.baseColor.b * 255;
+                            baseColorBuffer[offset + 3] = resizedTextures.texture1.hasAlpha ? diffuseBuffer[offset + 3] * 255 : 255;
+                            metallicRoughnessBuffer[offset] = 0;
+                            metallicRoughnessBuffer[offset + 1] = metallicRoughness.roughness * 255;
+                            metallicRoughnessBuffer[offset + 2] = metallicRoughness.metallic * 255;
+                            metallicRoughnessBuffer[offset + 3] = 255;
+                        }
+                    }
+                    // Retrieves the metallic roughness factors from the maximum texture values.
+                    var metallicRoughnessFactors_1 = {
+                        baseColor: maxBaseColor,
+                        metallic: maxMetallic,
+                        roughness: maxRoughness
+                    };
+                    var writeOutMetallicRoughnessTexture = false;
+                    var writeOutBaseColorTexture = false;
+                    for (var h = 0; h < height; ++h) {
+                        for (var w = 0; w < width; ++w) {
+                            var destinationOffset = (width * h + w) * strideSize;
+                            baseColorBuffer[destinationOffset] /= metallicRoughnessFactors_1.baseColor.r > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.r : 1;
+                            baseColorBuffer[destinationOffset + 1] /= metallicRoughnessFactors_1.baseColor.g > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.g : 1;
+                            baseColorBuffer[destinationOffset + 2] /= metallicRoughnessFactors_1.baseColor.b > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.b : 1;
+                            var linearBaseColorPixel = BABYLON.Color3.FromInts(baseColorBuffer[destinationOffset], baseColorBuffer[destinationOffset + 1], baseColorBuffer[destinationOffset + 2]);
+                            var sRGBBaseColorPixel = linearBaseColorPixel.toGammaSpace();
+                            baseColorBuffer[destinationOffset] = sRGBBaseColorPixel.r * 255;
+                            baseColorBuffer[destinationOffset + 1] = sRGBBaseColorPixel.g * 255;
+                            baseColorBuffer[destinationOffset + 2] = sRGBBaseColorPixel.b * 255;
+                            if (!_GLTFMaterialExporter.FuzzyEquals(sRGBBaseColorPixel, BABYLON.Color3.White(), _GLTFMaterialExporter._Epsilon)) {
+                                writeOutBaseColorTexture = true;
+                            }
+                            metallicRoughnessBuffer[destinationOffset + 1] /= metallicRoughnessFactors_1.roughness > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.roughness : 1;
+                            metallicRoughnessBuffer[destinationOffset + 2] /= metallicRoughnessFactors_1.metallic > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.metallic : 1;
+                            var metallicRoughnessPixel = BABYLON.Color3.FromInts(255, metallicRoughnessBuffer[destinationOffset + 1], metallicRoughnessBuffer[destinationOffset + 2]);
+                            if (!_GLTFMaterialExporter.FuzzyEquals(metallicRoughnessPixel, BABYLON.Color3.White(), _GLTFMaterialExporter._Epsilon)) {
+                                writeOutMetallicRoughnessTexture = true;
+                            }
+                        }
+                    }
+                    if (writeOutMetallicRoughnessTexture) {
+                        var promise = this._createBase64FromCanvasAsync(metallicRoughnessBuffer, width, height, mimeType).then(function (metallicRoughnessBase64) {
+                            metallicRoughnessFactors_1.metallicRoughnessTextureBase64 = metallicRoughnessBase64;
+                        });
+                        promises.push(promise);
+                    }
+                    if (writeOutBaseColorTexture) {
+                        var promise = this._createBase64FromCanvasAsync(baseColorBuffer, width, height, mimeType).then(function (baseColorBase64) {
+                            metallicRoughnessFactors_1.baseColorTextureBase64 = baseColorBase64;
+                        });
+                        promises.push(promise);
+                    }
+                    return Promise.all(promises).then(function () {
+                        return metallicRoughnessFactors_1;
+                    });
                 }
                 else {
                     return Promise.reject("_ConvertSpecularGlossinessTexturesToMetallicRoughness: Scene from textures is missing!");
@@ -2363,7 +2385,7 @@ var BABYLON;
                 var binStr = atob(base64Texture.split(',')[1]);
                 var arrBuff = new ArrayBuffer(binStr.length);
                 var arr = new Uint8Array(arrBuff);
-                for (var i = 0, length_1 = binStr.length; i < length_1; ++i) {
+                for (var i = 0, length_2 = binStr.length; i < length_2; ++i) {
                     arr[i] = binStr.charCodeAt(i);
                 }
                 var imageValues = { data: arr, mimeType: mimeType };

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


+ 7 - 0
dist/preview release/serializers/babylonjs.serializers.d.ts

@@ -529,6 +529,13 @@ declare module BABYLON.GLTF2 {
          */
         private _resizeTexturesToSameDimensions(texture1, texture2, scene);
         /**
+         * Converts an array of pixels to a Float32Array
+         * Throws an error if the pixel format is not supported
+         * @param pixels - array buffer containing pixel values
+         * @returns Float32 of pixels
+         */
+        private _convertPixelArrayToFloat32(pixels);
+        /**
          * Convert Specular Glossiness Textures to Metallic Roughness
          * See link below for info on the material conversions from PBR Metallic/Roughness and Specular/Glossiness
          * @link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/examples/convert-between-workflows-bjs/js/babylon.pbrUtilities.js

+ 113 - 91
dist/preview release/serializers/babylonjs.serializers.js

@@ -1982,6 +1982,28 @@ var BABYLON;
                 };
             };
             /**
+             * Converts an array of pixels to a Float32Array
+             * Throws an error if the pixel format is not supported
+             * @param pixels - array buffer containing pixel values
+             * @returns Float32 of pixels
+             */
+            _GLTFMaterialExporter.prototype._convertPixelArrayToFloat32 = function (pixels) {
+                if (pixels instanceof Uint8Array) {
+                    var length_1 = pixels.length;
+                    var buffer = new Float32Array(pixels.length);
+                    for (var i = 0; i < length_1; ++i) {
+                        buffer[i] = pixels[i] / 255;
+                    }
+                    return buffer;
+                }
+                else if (pixels instanceof Float32Array) {
+                    return pixels;
+                }
+                else {
+                    throw new Error('Unsupported pixel format!');
+                }
+            };
+            /**
              * Convert Specular Glossiness Textures to Metallic Roughness
              * See link below for info on the material conversions from PBR Metallic/Roughness and Specular/Glossiness
              * @link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/examples/convert-between-workflows-bjs/js/babylon.pbrUtilities.js
@@ -2004,99 +2026,99 @@ var BABYLON;
                     var specularGlossinessBuffer = void 0;
                     var width = diffuseSize.width;
                     var height = diffuseSize.height;
-                    var pixels = (resizedTextures.texture1.readPixels());
-                    if (pixels instanceof Uint8Array) {
-                        diffuseBuffer = (resizedTextures.texture1.readPixels());
-                        pixels = resizedTextures.texture2.readPixels();
-                        if (pixels instanceof Uint8Array) {
-                            specularGlossinessBuffer = (resizedTextures.texture2.readPixels());
-                            var byteLength = specularGlossinessBuffer.byteLength;
-                            var metallicRoughnessBuffer = new Uint8Array(byteLength);
-                            var baseColorBuffer = new Uint8Array(byteLength);
-                            var strideSize = 4;
-                            var maxBaseColor = BABYLON.Color3.Black();
-                            var maxMetallic = 0;
-                            var maxRoughness = 0;
-                            for (var h = 0; h < height; ++h) {
-                                for (var w = 0; w < width; ++w) {
-                                    var offset = (width * h + w) * strideSize;
-                                    var diffuseColor = BABYLON.Color3.FromInts(diffuseBuffer[offset], diffuseBuffer[offset + 1], diffuseBuffer[offset + 2]).toLinearSpace().multiply(factors.diffuseColor);
-                                    var specularColor = BABYLON.Color3.FromInts(specularGlossinessBuffer[offset], specularGlossinessBuffer[offset + 1], specularGlossinessBuffer[offset + 2]).toLinearSpace().multiply(factors.specularColor);
-                                    var glossiness = (specularGlossinessBuffer[offset + 3] / 255) * factors.glossiness;
-                                    var specularGlossiness = {
-                                        diffuseColor: diffuseColor,
-                                        specularColor: specularColor,
-                                        glossiness: glossiness
-                                    };
-                                    var metallicRoughness = this._convertSpecularGlossinessToMetallicRoughness(specularGlossiness);
-                                    maxBaseColor.r = Math.max(maxBaseColor.r, metallicRoughness.baseColor.r);
-                                    maxBaseColor.g = Math.max(maxBaseColor.g, metallicRoughness.baseColor.g);
-                                    maxBaseColor.b = Math.max(maxBaseColor.b, metallicRoughness.baseColor.b);
-                                    maxMetallic = Math.max(maxMetallic, metallicRoughness.metallic);
-                                    maxRoughness = Math.max(maxRoughness, metallicRoughness.roughness);
-                                    baseColorBuffer[offset] = metallicRoughness.baseColor.r * 255;
-                                    baseColorBuffer[offset + 1] = metallicRoughness.baseColor.g * 255;
-                                    baseColorBuffer[offset + 2] = metallicRoughness.baseColor.b * 255;
-                                    baseColorBuffer[offset + 3] = resizedTextures.texture1.hasAlpha ? diffuseBuffer[offset + 3] : 255;
-                                    metallicRoughnessBuffer[offset] = 0;
-                                    metallicRoughnessBuffer[offset + 1] = metallicRoughness.roughness * 255;
-                                    metallicRoughnessBuffer[offset + 2] = metallicRoughness.metallic * 255;
-                                    metallicRoughnessBuffer[offset + 3] = 255;
-                                }
-                            }
-                            // Retrieves the metallic roughness factors from the maximum texture values.
-                            var metallicRoughnessFactors_1 = {
-                                baseColor: maxBaseColor,
-                                metallic: maxMetallic,
-                                roughness: maxRoughness
-                            };
-                            var writeOutMetallicRoughnessTexture = false;
-                            var writeOutBaseColorTexture = false;
-                            for (var h = 0; h < height; ++h) {
-                                for (var w = 0; w < width; ++w) {
-                                    var destinationOffset = (width * h + w) * strideSize;
-                                    baseColorBuffer[destinationOffset] /= metallicRoughnessFactors_1.baseColor.r > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.r : 1;
-                                    baseColorBuffer[destinationOffset + 1] /= metallicRoughnessFactors_1.baseColor.g > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.g : 1;
-                                    baseColorBuffer[destinationOffset + 2] /= metallicRoughnessFactors_1.baseColor.b > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.b : 1;
-                                    var linearBaseColorPixel = BABYLON.Color3.FromInts(baseColorBuffer[destinationOffset], baseColorBuffer[destinationOffset + 1], baseColorBuffer[destinationOffset + 2]);
-                                    var sRGBBaseColorPixel = linearBaseColorPixel.toGammaSpace();
-                                    baseColorBuffer[destinationOffset] = sRGBBaseColorPixel.r * 255;
-                                    baseColorBuffer[destinationOffset + 1] = sRGBBaseColorPixel.g * 255;
-                                    baseColorBuffer[destinationOffset + 2] = sRGBBaseColorPixel.b * 255;
-                                    if (!_GLTFMaterialExporter.FuzzyEquals(sRGBBaseColorPixel, BABYLON.Color3.White(), _GLTFMaterialExporter._Epsilon)) {
-                                        writeOutBaseColorTexture = true;
-                                    }
-                                    metallicRoughnessBuffer[destinationOffset + 1] /= metallicRoughnessFactors_1.roughness > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.roughness : 1;
-                                    metallicRoughnessBuffer[destinationOffset + 2] /= metallicRoughnessFactors_1.metallic > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.metallic : 1;
-                                    var metallicRoughnessPixel = BABYLON.Color3.FromInts(255, metallicRoughnessBuffer[destinationOffset + 1], metallicRoughnessBuffer[destinationOffset + 2]);
-                                    if (!_GLTFMaterialExporter.FuzzyEquals(metallicRoughnessPixel, BABYLON.Color3.White(), _GLTFMaterialExporter._Epsilon)) {
-                                        writeOutMetallicRoughnessTexture = true;
-                                    }
-                                }
-                            }
-                            if (writeOutMetallicRoughnessTexture) {
-                                var promise = this._createBase64FromCanvasAsync(metallicRoughnessBuffer, width, height, mimeType).then(function (metallicRoughnessBase64) {
-                                    metallicRoughnessFactors_1.metallicRoughnessTextureBase64 = metallicRoughnessBase64;
-                                });
-                                promises.push(promise);
-                            }
-                            if (writeOutBaseColorTexture) {
-                                var promise = this._createBase64FromCanvasAsync(baseColorBuffer, width, height, mimeType).then(function (baseColorBase64) {
-                                    metallicRoughnessFactors_1.baseColorTextureBase64 = baseColorBase64;
-                                });
-                                promises.push(promise);
-                            }
-                            return Promise.all(promises).then(function () {
-                                return metallicRoughnessFactors_1;
-                            });
-                        }
-                        else {
-                            return Promise.reject("_ConvertSpecularGlossinessTexturesToMetallicRoughness: Pixel array buffer type not supported for texture: " + resizedTextures.texture2.name);
-                        }
+                    var diffusePixels = resizedTextures.texture1.readPixels();
+                    var specularPixels = resizedTextures.texture2.readPixels();
+                    if (diffusePixels) {
+                        diffuseBuffer = this._convertPixelArrayToFloat32(diffusePixels);
                     }
                     else {
-                        return Promise.reject("_ConvertSpecularGlossinessTexturesToMetallicRoughness: Pixel array buffer type not supported for texture: " + resizedTextures.texture1.name);
+                        return Promise.reject("Failed to retrieve pixels from diffuse texture!");
                     }
+                    if (specularPixels) {
+                        specularGlossinessBuffer = this._convertPixelArrayToFloat32(specularPixels);
+                    }
+                    else {
+                        return Promise.reject("Failed to retrieve pixels from specular glossiness texture!");
+                    }
+                    var byteLength = specularGlossinessBuffer.byteLength;
+                    var metallicRoughnessBuffer = new Uint8Array(byteLength);
+                    var baseColorBuffer = new Uint8Array(byteLength);
+                    var strideSize = 4;
+                    var maxBaseColor = BABYLON.Color3.Black();
+                    var maxMetallic = 0;
+                    var maxRoughness = 0;
+                    for (var h = 0; h < height; ++h) {
+                        for (var w = 0; w < width; ++w) {
+                            var offset = (width * h + w) * strideSize;
+                            var diffuseColor = new BABYLON.Color3(diffuseBuffer[offset], diffuseBuffer[offset + 1], diffuseBuffer[offset + 2]).toLinearSpace().multiply(factors.diffuseColor);
+                            var specularColor = new BABYLON.Color3(specularGlossinessBuffer[offset], specularGlossinessBuffer[offset + 1], specularGlossinessBuffer[offset + 2]).toLinearSpace().multiply(factors.specularColor);
+                            var glossiness = (specularGlossinessBuffer[offset + 3]) * factors.glossiness;
+                            var specularGlossiness = {
+                                diffuseColor: diffuseColor,
+                                specularColor: specularColor,
+                                glossiness: glossiness
+                            };
+                            var metallicRoughness = this._convertSpecularGlossinessToMetallicRoughness(specularGlossiness);
+                            maxBaseColor.r = Math.max(maxBaseColor.r, metallicRoughness.baseColor.r);
+                            maxBaseColor.g = Math.max(maxBaseColor.g, metallicRoughness.baseColor.g);
+                            maxBaseColor.b = Math.max(maxBaseColor.b, metallicRoughness.baseColor.b);
+                            maxMetallic = Math.max(maxMetallic, metallicRoughness.metallic);
+                            maxRoughness = Math.max(maxRoughness, metallicRoughness.roughness);
+                            baseColorBuffer[offset] = metallicRoughness.baseColor.r * 255;
+                            baseColorBuffer[offset + 1] = metallicRoughness.baseColor.g * 255;
+                            baseColorBuffer[offset + 2] = metallicRoughness.baseColor.b * 255;
+                            baseColorBuffer[offset + 3] = resizedTextures.texture1.hasAlpha ? diffuseBuffer[offset + 3] * 255 : 255;
+                            metallicRoughnessBuffer[offset] = 0;
+                            metallicRoughnessBuffer[offset + 1] = metallicRoughness.roughness * 255;
+                            metallicRoughnessBuffer[offset + 2] = metallicRoughness.metallic * 255;
+                            metallicRoughnessBuffer[offset + 3] = 255;
+                        }
+                    }
+                    // Retrieves the metallic roughness factors from the maximum texture values.
+                    var metallicRoughnessFactors_1 = {
+                        baseColor: maxBaseColor,
+                        metallic: maxMetallic,
+                        roughness: maxRoughness
+                    };
+                    var writeOutMetallicRoughnessTexture = false;
+                    var writeOutBaseColorTexture = false;
+                    for (var h = 0; h < height; ++h) {
+                        for (var w = 0; w < width; ++w) {
+                            var destinationOffset = (width * h + w) * strideSize;
+                            baseColorBuffer[destinationOffset] /= metallicRoughnessFactors_1.baseColor.r > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.r : 1;
+                            baseColorBuffer[destinationOffset + 1] /= metallicRoughnessFactors_1.baseColor.g > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.g : 1;
+                            baseColorBuffer[destinationOffset + 2] /= metallicRoughnessFactors_1.baseColor.b > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.b : 1;
+                            var linearBaseColorPixel = BABYLON.Color3.FromInts(baseColorBuffer[destinationOffset], baseColorBuffer[destinationOffset + 1], baseColorBuffer[destinationOffset + 2]);
+                            var sRGBBaseColorPixel = linearBaseColorPixel.toGammaSpace();
+                            baseColorBuffer[destinationOffset] = sRGBBaseColorPixel.r * 255;
+                            baseColorBuffer[destinationOffset + 1] = sRGBBaseColorPixel.g * 255;
+                            baseColorBuffer[destinationOffset + 2] = sRGBBaseColorPixel.b * 255;
+                            if (!_GLTFMaterialExporter.FuzzyEquals(sRGBBaseColorPixel, BABYLON.Color3.White(), _GLTFMaterialExporter._Epsilon)) {
+                                writeOutBaseColorTexture = true;
+                            }
+                            metallicRoughnessBuffer[destinationOffset + 1] /= metallicRoughnessFactors_1.roughness > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.roughness : 1;
+                            metallicRoughnessBuffer[destinationOffset + 2] /= metallicRoughnessFactors_1.metallic > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.metallic : 1;
+                            var metallicRoughnessPixel = BABYLON.Color3.FromInts(255, metallicRoughnessBuffer[destinationOffset + 1], metallicRoughnessBuffer[destinationOffset + 2]);
+                            if (!_GLTFMaterialExporter.FuzzyEquals(metallicRoughnessPixel, BABYLON.Color3.White(), _GLTFMaterialExporter._Epsilon)) {
+                                writeOutMetallicRoughnessTexture = true;
+                            }
+                        }
+                    }
+                    if (writeOutMetallicRoughnessTexture) {
+                        var promise = this._createBase64FromCanvasAsync(metallicRoughnessBuffer, width, height, mimeType).then(function (metallicRoughnessBase64) {
+                            metallicRoughnessFactors_1.metallicRoughnessTextureBase64 = metallicRoughnessBase64;
+                        });
+                        promises.push(promise);
+                    }
+                    if (writeOutBaseColorTexture) {
+                        var promise = this._createBase64FromCanvasAsync(baseColorBuffer, width, height, mimeType).then(function (baseColorBase64) {
+                            metallicRoughnessFactors_1.baseColorTextureBase64 = baseColorBase64;
+                        });
+                        promises.push(promise);
+                    }
+                    return Promise.all(promises).then(function () {
+                        return metallicRoughnessFactors_1;
+                    });
                 }
                 else {
                     return Promise.reject("_ConvertSpecularGlossinessTexturesToMetallicRoughness: Scene from textures is missing!");
@@ -2524,7 +2546,7 @@ var BABYLON;
                 var binStr = atob(base64Texture.split(',')[1]);
                 var arrBuff = new ArrayBuffer(binStr.length);
                 var arr = new Uint8Array(arrBuff);
-                for (var i = 0, length_1 = binStr.length; i < length_1; ++i) {
+                for (var i = 0, length_2 = binStr.length; i < length_2; ++i) {
                     arr[i] = binStr.charCodeAt(i);
                 }
                 var imageValues = { data: arr, mimeType: mimeType };

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


+ 7 - 0
dist/preview release/serializers/babylonjs.serializers.module.d.ts

@@ -536,6 +536,13 @@ declare module BABYLON.GLTF2 {
          */
         private _resizeTexturesToSameDimensions(texture1, texture2, scene);
         /**
+         * Converts an array of pixels to a Float32Array
+         * Throws an error if the pixel format is not supported
+         * @param pixels - array buffer containing pixel values
+         * @returns Float32 of pixels
+         */
+        private _convertPixelArrayToFloat32(pixels);
+        /**
          * Convert Specular Glossiness Textures to Metallic Roughness
          * See link below for info on the material conversions from PBR Metallic/Roughness and Specular/Glossiness
          * @link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/examples/convert-between-workflows-bjs/js/babylon.pbrUtilities.js

+ 2 - 2
dist/preview release/serializers/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-serializers",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
-    "version": "3.3.0-alpha.12",
+    "version": "3.3.0-alpha.13",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "3.3.0-alpha.12"
+        "babylonjs-gltf2interface": "3.3.0-alpha.13"
     },
     "peerDependencies": {
         "babylonjs": ">=3.2.0-alpha"

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

@@ -1,7 +1,7 @@
 {
-  "errors": 4239,
+  "errors": 4238,
   "babylon.typedoc.json": {
-    "errors": 4239,
+    "errors": 4238,
     "AbstractMesh": {
       "Property": {
         "showBoundingBox": {
@@ -2930,11 +2930,6 @@
             "MissingText": true
           }
         },
-        "getTranformationMatrix": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "getViewMatrix": {
           "Comments": {
             "MissingText": true

+ 5 - 4
dist/preview release/viewer/babylon.viewer.d.ts

@@ -4,15 +4,14 @@
 declare module "babylonjs-loaders"{ export=BABYLON;}
 // Generated by dts-bundle v0.7.3
 // Dependencies for this module:
-//   ../../../../../tools/Gulp/babylonjs
-//   ../../../../../tools/Gulp/babylonjs-loaders
+//   ../../../../../Tools/Gulp/babylonjs
+//   ../../../../../Tools/Gulp/babylonjs-loaders
 declare module BabylonViewer {
     /**
         * BabylonJS Viewer
         *
         * An HTML-Based viewer for 3D models, based on BabylonJS and its extensions.
         */
-    import 'pepjs';
     let disableInit: boolean;
     /**
         * Dispose all viewers currently registered
@@ -142,7 +141,7 @@ declare module BabylonViewer {
                 * This will be executed when the templates initialize.
                 */
             protected _onTemplatesLoaded(): Promise<AbstractViewer>;
-            toggleVR(): void;
+            protected _initVR(): void;
             /**
                 * Toggle fullscreen of the entire viewer
                 */
@@ -335,7 +334,9 @@ declare module BabylonViewer {
             toggleHD(): void;
             protected _vrToggled: boolean;
             protected _vrScale: number;
+            protected _vrInit: boolean;
             toggleVR(): void;
+            protected _initVR(): void;
             /**
                 * The resize function that will be registered with the window object
                 */

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


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


+ 5 - 3
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -5,8 +5,8 @@ declare module "babylonjs-loaders"{ export=BABYLON;}
 
 // Generated by dts-bundle v0.7.3
 // Dependencies for this module:
-//   ../../../../../tools/Gulp/babylonjs
-//   ../../../../../tools/Gulp/babylonjs-loaders
+//   ../../../../../Tools/Gulp/babylonjs
+//   ../../../../../Tools/Gulp/babylonjs-loaders
 
 declare module 'babylonjs-viewer' {
     import { mapperManager } from 'babylonjs-viewer/configuration/mappers';
@@ -173,7 +173,7 @@ declare module 'babylonjs-viewer/viewer/defaultViewer' {
                 * This will be executed when the templates initialize.
                 */
             protected _onTemplatesLoaded(): Promise<AbstractViewer>;
-            toggleVR(): void;
+            protected _initVR(): void;
             /**
                 * Toggle fullscreen of the entire viewer
                 */
@@ -376,7 +376,9 @@ declare module 'babylonjs-viewer/viewer/viewer' {
             toggleHD(): void;
             protected _vrToggled: boolean;
             protected _vrScale: number;
+            protected _vrInit: boolean;
             toggleVR(): void;
+            protected _initVR(): void;
             /**
                 * The resize function that will be registered with the window object
                 */

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

@@ -17,6 +17,8 @@
   - Added support for `minScaleX`, `minScaleY`, `maxScaleX`, `maxScaleY`. [Doc](https://doc.babylonjs.com/babylon101/particles#size)
   - Added support for `radiusRange` for sphere emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#sphere-emitter)
   - Added support for `radiusRange` and `heightRange` for cone emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#cone-emitter)
+  - Added new point emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#point-emitter)
+  - Added new hemispheric emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#hemispheric-emitter)
   - Added support for `ParticleSystem.BLENDMODE_ADD` alpha mode. [Doc](https://doc.babylonjs.com/babylon101/particles#particle-blending)
   - Added support for color gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#particle-colors)
   - Added support for pre-warming. [Doc](https://doc.babylonjs.com/babylon101/particles#pre-warming)
@@ -78,6 +80,7 @@
 - Added attachToBoxBehavior to attach UI to a bounding box ([TrevorDev](https://github.com/TrevorDev))
 - Gizmo manager's internal gizmos are now public ([TrevorDev](https://github.com/TrevorDev))
 - Ability to customize meshes on gizmos ([TrevorDev](https://github.com/TrevorDev))
+- Added gltf light falloff [Issue 4148](https://github.com/BabylonJS/Babylon.js/issues/4148) ([sebavan](http://www.github.com/sebavan))
 - Added WeightedSound; selects one from many Sounds with random weight for playback. ([najadojo](https://github.com/najadojo))
 
 ### glTF Loader
@@ -157,6 +160,7 @@
 - Template location was ignored if html was defined ([RaananW](https://github.com/RaananW))
 - Drag and Drop only worked if a model was already loaded before ([RaananW](https://github.com/RaananW))
 - It was not possible to add new custom optimizers, only use existing ones ([RaananW](https://github.com/RaananW))
+- Button texts were truncated incorrectly ([RaananW](https://github.com/RaananW))
 
 ### Loaders
 

+ 2 - 0
gui/src/2D/advancedDynamicTexture.ts

@@ -282,6 +282,8 @@ export class AdvancedDynamicTexture extends DynamicTexture {
             container = this._rootContainer;
         }
 
+        func(container);
+
         for (var child of container.children) {
             if ((<any>child).children) {
                 this.executeOnAllControls(func, (<Container>child));

+ 3 - 3
gui/src/2D/controls/control.ts

@@ -915,7 +915,7 @@ export class Control {
         }
 
         if (this._alphaSet) {
-            context.globalAlpha = this._alpha;
+            context.globalAlpha = this.parent ? this.parent.alpha * this._alpha : this._alpha;
         }
     }
 
@@ -1283,9 +1283,9 @@ export class Control {
         }
 
         if (this._style) {
-            this._font = (this._style.fontWeight ? this._style.fontWeight : this._style.fontStyle) + " " + this.fontSizeInPixels + "px " + this._style.fontFamily;
+            this._font = this._style.fontStyle + " " + this._style.fontWeight + " " + this.fontSizeInPixels + "px " + this._style.fontFamily;
         } else {
-            this._font = (this._fontWeight ? this._fontWeight : this._fontStyle) + " " + this.fontSizeInPixels + "px " + this._fontFamily;
+            this._font = this._fontStyle + " " + this._fontWeight + " " + this.fontSizeInPixels + "px " + this._fontFamily;
         }
 
         this._fontOffset = Control._GetFontOffset(this._font);

+ 15 - 0
gui/src/legacy.ts

@@ -0,0 +1,15 @@
+import * as GUI from "./index";
+
+/**
+ * Legacy support, defining window.BABYLON.GUI (global variable).
+ * 
+ * This is the entry point for the UMD module. 
+ * The entry point for a future ESM package should be index.ts
+ */
+var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : undefined);
+if (typeof globalObject !== "undefined") {
+    (<any>globalObject).BABYLON = (<any>globalObject).BABYLON || {};
+    (<any>globalObject).BABYLON.GUI = GUI;
+}
+
+export * from "./index";

+ 1 - 1
gui/webpack.config.js

@@ -6,7 +6,7 @@ const CleanWebpackPlugin = require('clean-webpack-plugin');
 module.exports = {
     context: __dirname,
     entry: {
-        'babylonjs-gui': path.resolve(__dirname, './src/index.ts'),
+        'babylonjs-gui': path.resolve(__dirname, './src/legacy.ts'),
     },
     output: {
         path: path.resolve(__dirname, '../dist/preview release/gui'),

+ 26 - 15
inspector/src/Inspector.ts

@@ -1,11 +1,11 @@
-import { AbstractMesh, Nullable, Scene, Tools } from "babylonjs";
-import * as GUI from "babylonjs-gui";
+import { AbstractMesh, Nullable, Scene, Tools, Observable } from "babylonjs";
 import "../sass/main.scss";
 import { Helpers } from "./helpers/Helpers";
 import { loadGUIProperties } from "./properties_gui";
 import { Scheduler } from "./scheduler/Scheduler";
 import { TabBar } from "./tabs/TabBar";
 
+import * as Split from "Split";
 
 export class Inspector {
 
@@ -32,6 +32,10 @@ export class Inspector {
 
     private _parentElement: Nullable<HTMLElement>;
 
+    public onGUILoaded: Observable<typeof import("babylonjs-gui")>;
+
+    public static GUIObject: typeof import("babylonjs-gui"); // should be typeof "babylonjs-gui";
+
     /** The inspector is created with the given engine.
      * If the parameter 'popup' is false, the inspector is created as a right panel on the main window.
      * If the parameter 'popup' is true, the inspector is created in another popup.
@@ -46,20 +50,27 @@ export class Inspector {
         colorBot?: string
     }) {
 
-        // Load GUI library if not already done
-        if (!GUI) {
-            Tools.LoadScript("https://preview.babylonjs.com/gui/babylon.gui.min.js", () => {
+        this.onGUILoaded = new Observable();
+
+        import("babylonjs-gui").then(GUI => {
+            // Load GUI library if not already done
+            if (!GUI || (typeof GUI !== "undefined" && Object.keys(GUI).indexOf("default") !== -1)) {
+                Tools.LoadScript("https://preview.babylonjs.com/gui/babylon.gui.min.js", () => {
+                    Inspector.GUIObject = (<any>BABYLON).GUI;
+                    this.onGUILoaded.notifyObservers(Inspector.GUIObject);
+                    //Load properties of GUI objects now as GUI has to be declared before 
+                    loadGUIProperties(Inspector.GUIObject);
+                }, () => {
+                    console.warn('Error : loading "babylon.gui.min.js". Please add script https://preview.babylonjs.com/gui/babylon.min.gui.js to the HTML file.');
+                });
+            }
+            else {
+                Inspector.GUIObject = GUI;
+                this.onGUILoaded.notifyObservers(Inspector.GUIObject);
                 //Load properties of GUI objects now as GUI has to be declared before 
-                loadGUIProperties();
-            }, () => {
-                console.warn('Error : loading "babylon.gui.min.js". Please add script https://preview.babylonjs.com/gui/babylon.min.gui.js to the HTML file.');
-            });
-        }
-        else {
-            //Load properties of GUI objects now as GUI has to be declared before 
-            loadGUIProperties();
-        }
-
+                loadGUIProperties(Inspector.GUIObject);
+            }
+        })
         //get Tabbar initialTab
         this._initialTab = initialTab;
 

+ 3 - 4
inspector/src/adapters/GUIAdapter.ts

@@ -4,14 +4,13 @@ import { Helpers } from "../helpers/Helpers";
 import { AbstractTreeTool } from "../treetools/AbstractTreeTool";
 import { Checkbox, IToolVisible } from "../treetools/Checkbox";
 import { Adapter } from "./Adapter";
-import { Control } from "babylonjs-gui";
 
 
 export class GUIAdapter
     extends Adapter
     implements IToolVisible {
 
-    constructor(obj: Control) {
+    constructor(obj: import("babylonjs-gui").Control) {
         super(obj);
     }
 
@@ -41,10 +40,10 @@ export class GUIAdapter
     }
 
     public setVisible(b: boolean) {
-        (this._obj as Control).isVisible = b;
+        (this._obj).isVisible = b;
     }
 
     public isVisible(): boolean {
-        return (this._obj as Control).isVisible;
+        return (this._obj).isVisible;
     }
 }

+ 15 - 0
inspector/src/legacy.ts

@@ -0,0 +1,15 @@
+import * as INSPECTOR from "./index";
+
+/**
+ * Legacy support, defining window.INSPECTOR (global variable).
+ * 
+ * This is the entry point for the UMD module. 
+ * The entry point for a future ESM package should be index.ts
+ */
+
+var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : undefined);
+if (typeof globalObject !== "undefined") {
+    (<any>globalObject).INSPECTOR = INSPECTOR;
+}
+
+export * from "./index";

+ 117 - 108
inspector/src/properties_gui.ts

@@ -1,116 +1,125 @@
-import * as GUI from "babylonjs-gui";
+
 import { PROPERTIES } from "./properties";
 
+export type GUITyping = typeof import("babylonjs-gui");
+
+export let guiLoaded: boolean = false;
 /**
   * Function that add gui objects properties to the variable PROPERTIES
   */
-export function loadGUIProperties() {
-    let PROPERTIES_GUI = {
-        'ValueAndUnit': {
-            type: GUI.ValueAndUnit,
-            properties: ['_value', 'unit'],
-            format: (valueAndUnit: GUI.ValueAndUnit) => { return valueAndUnit }
-        },
-        'Control': {
-            type: GUI.Control,
-            properties: [
-                '_alpha',
-                '_fontFamily',
-                '_color',
-                '_scaleX',
-                '_scaleY',
-                '_rotation',
-                '_currentMeasure',
-                '_width',
-                '_height',
-                '_left',
-                '_top',
-                '_linkedMesh',
-                'isHitTestVisible',
-                'isPointerBlocker',
-            ],
-            format: (control: GUI.Control) => { return control.name }
-        },
-        'Button': {
-            type: GUI.Button,
-            properties: new Array(),
-            format: (button: GUI.Button) => { return button.name }
-        },
-        'ColorPicker': {
-            type: GUI.ColorPicker,
-            properties: ['_value'],
-            format: (colorPicker: GUI.ColorPicker) => { return colorPicker.name }
-        },
-        'Checkbox': {
-            type: GUI.Checkbox,
-            properties: ['_isChecked', '_background'],
-            format: (checkbox: GUI.Checkbox) => { return checkbox.name }
-        },
-        'Ellipse': {
-            type: GUI.Ellipse,
-            properties: ['_thickness'],
-            format: (ellipse: GUI.Ellipse) => { return ellipse.name }
-        },
-        'Image': {
-            type: GUI.Image,
-            properties: [
-                '_imageWidth',
-                '_imageHeight',
-                '_loaded',
-                '_source',
-            ],
-            format: (image: GUI.Image) => { return image.name }
-        },
-        'Line': {
-            type: GUI.Line,
-            properties: ['_lineWidth',
-                '_background',
-                '_x1',
-                '_y1',
-                '_x2',
-                '_y2',
-            ],
-            format: (line: GUI.Line) => { return line.name }
-        },
-        'RadioButton': {
-            type: GUI.RadioButton,
-            properties: ['_isChecked', '_background'],
-            format: (radioButton: GUI.RadioButton) => { return radioButton.name }
-        },
-        'Rectangle': {
-            type: GUI.Rectangle,
-            properties: ['_thickness', '_cornerRadius'],
-            format: (rectangle: GUI.Rectangle) => { return rectangle.name }
-        },
-        'Slider': {
-            type: GUI.Slider,
-            properties: [
-                '_minimum',
-                '_maximum',
-                '_value',
-                '_background',
-                '_borderColor',
-            ],
-            format: (slider: GUI.Slider) => { return slider.name }
-        },
-        'StackPanel': {
-            type: GUI.StackPanel,
-            properties: ['_isVertical'],
-            format: (stackPanel: GUI.StackPanel) => { return stackPanel.name }
-        },
-        'TextBlock': {
-            type: GUI.TextBlock,
-            properties: ['_text', '_textWrapping'],
-            format: (textBlock: GUI.TextBlock) => { return textBlock.name }
-        },
-        'Container': {
-            type: GUI.Container,
-            properties: ['_background'],
-            format: (container: GUI.Container) => { return container.name }
-        },
-    }
+export function loadGUIProperties(GUI: GUITyping) {
+
+    guiLoaded = !!GUI;
+
+    if (guiLoaded) {
+
+        let PROPERTIES_GUI = {
+            'ValueAndUnit': {
+                type: GUI.ValueAndUnit,
+                properties: ['_value', 'unit'],
+                format: (valueAndUnit: import("babylonjs-gui").ValueAndUnit) => { return valueAndUnit }
+            },
+            'Control': {
+                type: GUI.Control,
+                properties: [
+                    '_alpha',
+                    '_fontFamily',
+                    '_color',
+                    '_scaleX',
+                    '_scaleY',
+                    '_rotation',
+                    '_currentMeasure',
+                    '_width',
+                    '_height',
+                    '_left',
+                    '_top',
+                    '_linkedMesh',
+                    'isHitTestVisible',
+                    'isPointerBlocker',
+                ],
+                format: (control: import("babylonjs-gui").Control) => { return control.name }
+            },
+            'Button': {
+                type: GUI.Button,
+                properties: new Array(),
+                format: (button: import("babylonjs-gui").Button) => { return button.name }
+            },
+            'ColorPicker': {
+                type: GUI.ColorPicker,
+                properties: ['_value'],
+                format: (colorPicker: import("babylonjs-gui").ColorPicker) => { return colorPicker.name }
+            },
+            'Checkbox': {
+                type: GUI.Checkbox,
+                properties: ['_isChecked', '_background'],
+                format: (checkbox: import("babylonjs-gui").Checkbox) => { return checkbox.name }
+            },
+            'Ellipse': {
+                type: GUI.Ellipse,
+                properties: ['_thickness'],
+                format: (ellipse: import("babylonjs-gui").Ellipse) => { return ellipse.name }
+            },
+            'Image': {
+                type: GUI.Image,
+                properties: [
+                    '_imageWidth',
+                    '_imageHeight',
+                    '_loaded',
+                    '_source',
+                ],
+                format: (image: import("babylonjs-gui").Image) => { return image.name }
+            },
+            'Line': {
+                type: GUI.Line,
+                properties: ['_lineWidth',
+                    '_background',
+                    '_x1',
+                    '_y1',
+                    '_x2',
+                    '_y2',
+                ],
+                format: (line: import("babylonjs-gui").Line) => { return line.name }
+            },
+            'RadioButton': {
+                type: GUI.RadioButton,
+                properties: ['_isChecked', '_background'],
+                format: (radioButton: import("babylonjs-gui").RadioButton) => { return radioButton.name }
+            },
+            'Rectangle': {
+                type: GUI.Rectangle,
+                properties: ['_thickness', '_cornerRadius'],
+                format: (rectangle: import("babylonjs-gui").Rectangle) => { return rectangle.name }
+            },
+            'Slider': {
+                type: GUI.Slider,
+                properties: [
+                    '_minimum',
+                    '_maximum',
+                    '_value',
+                    '_background',
+                    '_borderColor',
+                ],
+                format: (slider: import("babylonjs-gui").Slider) => { return slider.name }
+            },
+            'StackPanel': {
+                type: GUI.StackPanel,
+                properties: ['_isVertical'],
+                format: (stackPanel: import("babylonjs-gui").StackPanel) => { return stackPanel.name }
+            },
+            'TextBlock': {
+                type: GUI.TextBlock,
+                properties: ['_text', '_textWrapping'],
+                format: (textBlock: import("babylonjs-gui").TextBlock) => { return textBlock.name }
+            },
+            'Container': {
+                type: GUI.Container,
+                properties: ['_background'],
+                format: (container: import("babylonjs-gui").Container) => { return container.name }
+            },
+        }
 
-    for (let prop in PROPERTIES_GUI) {
-        (<any>PROPERTIES)[prop] = (<any>PROPERTIES_GUI)[prop];
+        for (let prop in PROPERTIES_GUI) {
+            (<any>PROPERTIES)[prop] = (<any>PROPERTIES_GUI)[prop];
+        }
     }
 } 

+ 2 - 0
inspector/src/tabs/ConsoleTab.ts

@@ -4,6 +4,8 @@ import { Inspector } from "../Inspector";
 import { Tab } from "./Tab";
 import { TabBar } from "./TabBar";
 
+import * as Split from "Split";
+
 /** 
  * The console tab will have two features : 
  * - hook all console.log call and display them in this panel (and in the browser console as well)

+ 2 - 0
inspector/src/tabs/GLTFTab.ts

@@ -9,6 +9,8 @@ import { Inspector } from "../Inspector";
 import { Tab } from "./Tab";
 import { TabBar } from "./TabBar";
 
+import * as Split from "Split";
+
 interface ILoaderDefaults {
     [extensionName: string]: {
         [key: string]: any

+ 7 - 6
inspector/src/tabs/GUITab.ts

@@ -1,4 +1,3 @@
-import { AdvancedDynamicTexture, Container, Control } from "babylonjs-gui";
 import { GUIAdapter } from "../adapters/GUIAdapter";
 import { Inspector } from "../Inspector";
 import { TreeItem } from "../tree/TreeItem";
@@ -13,11 +12,13 @@ export class GUITab extends PropertyTab {
 
     /* Overrides super */
     protected _getTree(): Array<TreeItem> {
-        let arr = [];
+        let arr: Array<TreeItem> = [];
+
+        if (!Inspector.GUIObject) return arr;
 
         // Recursive method building the tree panel
-        let createNode = (obj: Control) => {
-            let descendants = (obj as Container).children;
+        let createNode = (obj: import("babylonjs-gui").Control) => {
+            let descendants = (obj as import("babylonjs-gui").Container).children;
 
             if (descendants && descendants.length > 0) {
                 let node = new TreeItem(this, new GUIAdapter(obj));
@@ -36,8 +37,8 @@ export class GUITab extends PropertyTab {
         let instances = this._inspector.scene;
         for (let tex of instances.textures) {
             //only get GUI's textures
-            if (tex instanceof AdvancedDynamicTexture) {
-                let node = createNode(tex._rootContainer);
+            if (tex instanceof Inspector.GUIObject.AdvancedDynamicTexture) {
+                let node = createNode((<import("babylonjs-gui").AdvancedDynamicTexture>tex)._rootContainer);
                 arr.push(node);
             }
         }

+ 2 - 0
inspector/src/tabs/PropertyTab.ts

@@ -7,6 +7,8 @@ import { TreeItem } from "../tree/TreeItem";
 import { Tab } from "./Tab";
 import { TabBar } from "./TabBar";
 
+import * as Split from "Split";
+
 /**
  * A Property tab can creates two panels: 
  * a tree panel and a detail panel, 

+ 2 - 0
inspector/src/tabs/SceneTab.ts

@@ -7,6 +7,8 @@ import { Inspector } from "../Inspector";
 import { Tab } from "./Tab";
 import { TabBar } from "./TabBar";
 
+import * as Split from "Split";
+
 export class SceneTab extends Tab {
 
     private _inspector: Inspector;

+ 1 - 2
inspector/src/tabs/TabBar.ts

@@ -1,5 +1,4 @@
 import { AbstractMesh, Nullable } from "babylonjs";
-import * as GUI from "babylonjs-gui";
 import { BasicElement } from "../gui/BasicElement";
 import { Helpers } from "../helpers/Helpers";
 import { Inspector } from "../Inspector";
@@ -56,7 +55,7 @@ export class TabBar extends BasicElement {
         if (GLTFTab.IsSupported) {
             this._tabs.push(new GLTFTab(this, this._inspector));
         }
-        if (GUI) {
+        if (Inspector.GUIObject) {
             this._tabs.push(new GUITab(this, this._inspector));
         }
         this._tabs.push(new PhysicsTab(this, this._inspector));

+ 1 - 0
inspector/src/tabs/TextureTab.ts

@@ -6,6 +6,7 @@ import { TreeItem } from "../tree/TreeItem";
 import { Tab } from "./Tab";
 import { TabBar } from "./TabBar";
 
+import * as Split from "Split";
 
 export class TextureTab extends Tab {
 

+ 24 - 26
inspector/src/tools/LabelTool.ts

@@ -1,18 +1,16 @@
 import { AbstractMesh, Nullable, Scene } from "babylonjs";
-import * as GUI from "babylonjs-gui";
 import { Helpers } from "../helpers/Helpers";
 import { Inspector } from "../Inspector";
 import { AbstractTool } from "./AbstractTool";
-
+import { guiLoaded } from "../properties_gui";
 
 export class LabelTool extends AbstractTool {
 
     /** True if label are displayed, false otherwise */
     private _isDisplayed: boolean = false;
-    private _advancedTexture: Nullable<GUI.AdvancedDynamicTexture> = null;
+    private _advancedTexture: Nullable<any/*AdvancedDynamicTexture*/> = null;
     private _labelInitialized: boolean = false;
     private _scene: Nullable<Scene> = null;
-    private _guiLoaded: boolean = false;
 
     constructor(parent: HTMLElement, inspector: Inspector) {
         super('fa', 'fa-tags', parent, inspector, 'Display mesh names on the canvas');
@@ -28,48 +26,45 @@ export class LabelTool extends AbstractTool {
     }
 
     private _checkGUILoaded(): boolean {
-        if (this._guiLoaded === true) {
-            return true;
-        }
-        if (GUI) {
-            this._guiLoaded = true;
-        }
-        return this._guiLoaded;
+        return guiLoaded;
     }
 
     private _initializeLabels() {
-        // Check if the label are already initialized and quit if it's the case
-        if (this._labelInitialized || !this._scene) {
-            return;
-        }
 
         // Can't initialize them if the GUI lib is not loaded yet
         if (!this._checkGUILoaded()) {
             return;
         }
 
+
+        // Check if the label are already initialized and quit if it's the case
+        if (this._labelInitialized || !this._scene) {
+            return false;
+        }
         // Create the canvas that will be used to display the labels
-        this._advancedTexture = GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI");
+        this._advancedTexture = Inspector.GUIObject.AdvancedDynamicTexture.CreateFullscreenUI("UI");
 
         // Create label for all the Meshes, Lights and Cameras
         // Those that will be created/removed after this method is called will be taken care by the event handlers added below
 
         for (let m of this._scene.meshes) {
-            this._createLabel(m);
+            this._createLabel(m, Inspector.GUIObject);
         }
 
-        this._scene.onNewMeshAddedObservable.add((m, s) => {
-            this._createLabel(m);
+        this._scene.onNewMeshAddedObservable.add((m) => {
+            this._createLabel(m, Inspector.GUIObject);
         });
 
-        this._scene.onMeshRemovedObservable.add((m, s) => {
+        this._scene.onMeshRemovedObservable.add((m) => {
             this._removeLabel(m);
         });
 
         this._labelInitialized = true;
+
+        return true;
     }
 
-    private _createLabel(mesh: AbstractMesh) {
+    private _createLabel(mesh: AbstractMesh, GUI: typeof import("babylonjs-gui")) {
         // Don't create label for "system nodes" (starting and ending with ###)
         let name = mesh.name;
 
@@ -78,14 +73,14 @@ export class LabelTool extends AbstractTool {
         }
 
         if (mesh && this._advancedTexture) {
-            let rect1 = new GUI.Rectangle();
+            let rect1: import("babylonjs-gui").Rectangle = new GUI.Rectangle();
             rect1.width = 4 + 10 * name.length + "px";
             rect1.height = "22px";
             rect1.background = "rgba(0,0,0,0.6)";
             rect1.color = "black";
             this._advancedTexture.addControl(rect1);
 
-            let label = new GUI.TextBlock();
+            let label: import("babylonjs-gui").TextBlock = new GUI.TextBlock();
             label.text = name;
             label.fontSize = 12;
             rect1.addControl(label);
@@ -110,7 +105,7 @@ export class LabelTool extends AbstractTool {
     // Action : Display/hide mesh names on the canvas
     public action() {
         // Don't toggle if the script is not loaded
-        if (!this._checkGUILoaded() || !this._advancedTexture) {
+        if (!this._checkGUILoaded()) {
             return;
         }
 
@@ -120,12 +115,15 @@ export class LabelTool extends AbstractTool {
         // Check if we have to display the labels
         if (this._isDisplayed) {
             this._initializeLabels();
-            this._advancedTexture._rootContainer.isVisible = true;
+            if (this._advancedTexture)
+                this._advancedTexture._rootContainer.isVisible = true;
+
         }
 
         // Or to hide them
         else {
-            this._advancedTexture._rootContainer.isVisible = false;
+            if (this._advancedTexture)
+                this._advancedTexture._rootContainer.isVisible = false;
         }
     }
 }

+ 1 - 1
inspector/tsconfig.json

@@ -1,7 +1,7 @@
 {
     "compilerOptions": {
         "experimentalDecorators": true,
-        "module": "commonjs",
+        "module": "esnext",
         "target": "es5",
         "noImplicitAny": true,
         "noImplicitReturns": true,

+ 2 - 2
inspector/webpack.config.js

@@ -7,7 +7,7 @@ const CleanWebpackPlugin = require('clean-webpack-plugin');
 module.exports = {
     context: __dirname,
     entry: {
-        'babylonjs-inspector': path.resolve(__dirname, './src/index.ts'),
+        'babylonjs-inspector': path.resolve(__dirname, './src/legacy.ts'),
     },
     output: {
         path: path.resolve(__dirname, '../dist/preview release/inspector'),
@@ -103,4 +103,4 @@ module.exports = {
     watchOptions: {
         ignored: [path.resolve(__dirname, './dist/**/*.*'), 'node_modules']
     }
-}
+}

+ 10 - 10
loaders/src/glTF/2.0/Extensions/EXT_lights_imageBased.ts

@@ -28,6 +28,16 @@ module BABYLON.GLTF2.Extensions {
     export class EXT_lights_imageBased extends GLTFLoaderExtension {
         public readonly name = NAME;
 
+        private _lights?: ILight[];
+
+        protected _onLoading(): void {
+            const extensions = this._loader._gltf.extensions;
+            if (extensions && extensions[this.name]) {
+                const extension = extensions[this.name] as ILights;
+                this._lights = extension.lights;
+            }
+        }
+
         protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>> { 
             return this._loadExtensionAsync<ILightReference>(context, scene, (extensionContext, extension) => {
                 const promises = new Array<Promise<void>>();
@@ -108,16 +118,6 @@ module BABYLON.GLTF2.Extensions {
                 return light._babylonTexture!;
             });
         }
-
-        private get _lights(): Array<ILight> {
-            const extensions = this._loader._gltf.extensions;
-            if (!extensions || !extensions[this.name]) {
-                throw new Error(`#/extensions: '${this.name}' not found`);
-            }
-
-            const extension = extensions[this.name] as ILights;
-            return extension.lights;
-        }
     }
 
     GLTFLoader._Register(NAME, loader => new EXT_lights_imageBased(loader));

+ 10 - 10
loaders/src/glTF/2.0/Extensions/KHR_lights.ts

@@ -34,6 +34,16 @@ module BABYLON.GLTF2.Extensions {
     export class KHR_lights extends GLTFLoaderExtension {
         public readonly name = NAME;
 
+        private _lights?: ILight[];
+
+        protected _onLoading(): void {
+            const extensions = this._loader._gltf.extensions;
+            if (extensions && extensions[this.name]) {
+                const extension = extensions[this.name] as ILights;
+                this._lights = extension.lights;
+            }
+        }
+
         protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>> { 
             return this._loadExtensionAsync<ILightReference>(context, scene, (extensionContext, extension) => {
                 const promise = this._loader._loadSceneAsync(extensionContext, scene);
@@ -88,16 +98,6 @@ module BABYLON.GLTF2.Extensions {
                 return promise;
             });
         }
-
-        private get _lights(): Array<ILight> {
-            const extensions = this._loader._gltf.extensions;
-            if (!extensions || !extensions[this.name]) {
-                throw new Error(`#/extensions: '${this.name}' not found`);
-            }
-
-            const extension = extensions[this.name] as ILights;
-            return extension.lights;
-        }
     }
 
     GLTFLoader._Register(NAME, loader => new KHR_lights(loader));

+ 42 - 42
loaders/src/glTF/2.0/Extensions/MSFT_lod.ts

@@ -40,48 +40,6 @@ module BABYLON.GLTF2.Extensions {
         private _materialSignalLODs = new Array<Deferred<void>>();
         private _materialPromiseLODs = new Array<Array<Promise<void>>>();
 
-        constructor(loader: GLTFLoader) {
-            super(loader);
-
-            this._loader._readyPromise.then(() => {
-                for (let indexLOD = 0; indexLOD < this._nodePromiseLODs.length; indexLOD++) {
-                    const promise = Promise.all(this._nodePromiseLODs[indexLOD]).then(() => {
-                        if (indexLOD !== 0) {
-                            this._loader._parent._endPerformanceCounter(`Node LOD ${indexLOD}`);
-                        }
-
-                        this._loader._parent._log(`Loaded node LOD ${indexLOD}`);
-                        this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
-
-                        if (indexLOD !== this._nodePromiseLODs.length - 1) {
-                            this._loader._parent._startPerformanceCounter(`Node LOD ${indexLOD + 1}`);
-                            this._nodeSignalLODs[indexLOD].resolve();
-                        }
-                    });
-
-                    this._loader._completePromises.push(promise);
-                }
-
-                for (let indexLOD = 0; indexLOD < this._materialPromiseLODs.length; indexLOD++) {
-                    const promise = Promise.all(this._materialPromiseLODs[indexLOD]).then(() => {
-                        if (indexLOD !== 0) {
-                            this._loader._parent._endPerformanceCounter(`Material LOD ${indexLOD}`);
-                        }
-
-                        this._loader._parent._log(`Loaded material LOD ${indexLOD}`);
-                        this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
-
-                        if (indexLOD !== this._materialPromiseLODs.length - 1) {
-                            this._loader._parent._startPerformanceCounter(`Material LOD ${indexLOD + 1}`);
-                            this._materialSignalLODs[indexLOD].resolve();
-                        }
-                    });
-
-                    this._loader._completePromises.push(promise);
-                }
-            });
-        }
-
         public dispose() {
             super.dispose();
 
@@ -97,6 +55,48 @@ module BABYLON.GLTF2.Extensions {
             this.onNodeLODsLoadedObservable.clear();
         }
 
+        protected _onReady(): void {
+            for (let indexLOD = 0; indexLOD < this._nodePromiseLODs.length; indexLOD++) {
+                const promise = Promise.all(this._nodePromiseLODs[indexLOD]).then(() => {
+                    if (indexLOD !== 0) {
+                        this._loader._parent._endPerformanceCounter(`Node LOD ${indexLOD}`);
+                    }
+
+                    this._loader._parent._log(`Loaded node LOD ${indexLOD}`);
+                    this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
+
+                    if (indexLOD !== this._nodePromiseLODs.length - 1) {
+                        this._loader._parent._startPerformanceCounter(`Node LOD ${indexLOD + 1}`);
+                        if (this._nodeSignalLODs[indexLOD]) {
+                            this._nodeSignalLODs[indexLOD].resolve();
+                        }
+                    }
+                });
+
+                this._loader._completePromises.push(promise);
+            }
+
+            for (let indexLOD = 0; indexLOD < this._materialPromiseLODs.length; indexLOD++) {
+                const promise = Promise.all(this._materialPromiseLODs[indexLOD]).then(() => {
+                    if (indexLOD !== 0) {
+                        this._loader._parent._endPerformanceCounter(`Material LOD ${indexLOD}`);
+                    }
+
+                    this._loader._parent._log(`Loaded material LOD ${indexLOD}`);
+                    this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
+
+                    if (indexLOD !== this._materialPromiseLODs.length - 1) {
+                        this._loader._parent._startPerformanceCounter(`Material LOD ${indexLOD + 1}`);
+                        if (this._materialSignalLODs[indexLOD]) {
+                            this._materialSignalLODs[indexLOD].resolve();
+                        }
+                    }
+                });
+
+                this._loader._completePromises.push(promise);
+            }
+        }
+
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>> {
             return this._loadExtensionAsync<IMSFTLOD>(context, node, (extensionContext, extension) => {
                 let firstPromise: Promise<void>;

+ 14 - 12
loaders/src/glTF/2.0/Extensions/MSFT_sRGBFactors.ts

@@ -7,25 +7,27 @@ module BABYLON.GLTF2.Extensions {
     export class MSFT_sRGBFactors extends GLTFLoaderExtension {
         public readonly name = NAME;
 
-        protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>> {
+        protected _loadMaterialPropertiesAsync(context: string, material: _ILoaderMaterial, babylonMaterial: Material): Nullable<Promise<void>> {
             return this._loadExtrasValueAsync<boolean>(context, material, (extensionContext, value) => {
                 if (value) {
-                    return this._loader._loadMaterialAsync(context, material, mesh, babylonMesh, babylonDrawMode, (babylonMaterial: PBRMaterial) => {
-                        if (!babylonMaterial.albedoTexture) {
-                            babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor);
-                        }
-
-                        if (!babylonMaterial.reflectivityTexture) {
-                            babylonMaterial.reflectivityColor.toLinearSpaceToRef(babylonMaterial.reflectivityColor);
-                        }
-
-                        assign(babylonMaterial);
-                    });
+                    const promise = this._loader._loadMaterialPropertiesAsync(context, material, babylonMaterial);
+                    this._convertColorsToLinear(babylonMaterial as PBRMaterial);
+                    return promise;
                 }
 
                 return null;
             });
         }
+
+        private _convertColorsToLinear(babylonMaterial: PBRMaterial): void {
+            if (!babylonMaterial.albedoTexture) {
+                babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor);
+            }
+
+            if (!babylonMaterial.reflectivityTexture) {
+                babylonMaterial.reflectivityColor.toLinearSpaceToRef(babylonMaterial.reflectivityColor);
+            }
+        }
     }
 
     GLTFLoader._Register(NAME, loader => new MSFT_sRGBFactors(loader));

+ 37 - 25
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -26,7 +26,6 @@ module BABYLON.GLTF2 {
         public _parent: GLTFFileLoader;
         public _gltf: _ILoaderGLTF;
         public _babylonScene: Scene;
-        public _readyPromise: Promise<void>;
         public _completePromises = new Array<Promise<void>>();
 
         private _disposed = false;
@@ -54,9 +53,6 @@ module BABYLON.GLTF2 {
             GLTFLoader._ExtensionNames.push(name);
         }
 
-        /**
-         * Loader state or null if the loader is not active.
-         */
         public get state(): Nullable<GLTFLoaderState> {
             return this._state;
         }
@@ -80,7 +76,6 @@ module BABYLON.GLTF2 {
 
             delete this._gltf;
             delete this._babylonScene;
-            delete this._readyPromise;
             this._completePromises.length = 0;
 
             for (const name in this._extensions) {
@@ -148,17 +143,17 @@ module BABYLON.GLTF2 {
 
         private _loadAsync(nodes: Nullable<Array<number>>): Promise<void> {
             return Promise.resolve().then(() => {
-                this._parent._startPerformanceCounter("Loading => Ready");
-                this._parent._startPerformanceCounter("Loading => Complete");
+                this._loadExtensions();
+                this._checkExtensions();
 
-                this._state = GLTFLoaderState.LOADING;
-                this._parent._log("Loading");
+                const loadingToReadyCounterName = `${GLTFLoaderState[GLTFLoaderState.LOADING]} => ${GLTFLoaderState[GLTFLoaderState.READY]}`;
+                const loadingToCompleteCounterName = `${GLTFLoaderState[GLTFLoaderState.LOADING]} => ${GLTFLoaderState[GLTFLoaderState.COMPLETE]}`;
 
-                const readyDeferred = new Deferred<void>();
-                this._readyPromise = readyDeferred.promise;
+                this._parent._startPerformanceCounter(loadingToReadyCounterName);
+                this._parent._startPerformanceCounter(loadingToCompleteCounterName);
 
-                this._loadExtensions();
-                this._checkExtensions();
+                this._setState(GLTFLoaderState.LOADING);
+                GLTFLoaderExtension._OnLoading(this);
 
                 const promises = new Array<Promise<void>>();
 
@@ -179,30 +174,30 @@ module BABYLON.GLTF2 {
                 }
 
                 const resultPromise = Promise.all(promises).then(() => {
-                    this._state = GLTFLoaderState.READY;
-                    this._parent._log("Ready");
-
-                    readyDeferred.resolve();
+                    this._setState(GLTFLoaderState.READY);
+                    GLTFLoaderExtension._OnReady(this);
 
                     this._startAnimations();
                 });
 
                 resultPromise.then(() => {
-                    this._parent._endPerformanceCounter("Loading => Ready");
+                    this._parent._endPerformanceCounter(loadingToReadyCounterName);
 
                     Tools.SetImmediate(() => {
                         if (!this._disposed) {
                             Promise.all(this._completePromises).then(() => {
-                                this._parent._endPerformanceCounter("Loading => Complete");
+                                this._parent._endPerformanceCounter(loadingToCompleteCounterName);
 
-                                this._state = GLTFLoaderState.COMPLETE;
-                                this._parent._log("Complete");
+                                this._setState(GLTFLoaderState.COMPLETE);
 
                                 this._parent.onCompleteObservable.notifyObservers(undefined);
                                 this._parent.onCompleteObservable.clear();
+
                                 this.dispose();
-                            }).catch(error => {
-                                Tools.Error(`glTF Loader: ${error.message}`);
+                            }, error => {
+                                this._parent.onErrorObservable.notifyObservers(error);
+                                this._parent.onErrorObservable.clear();
+
                                 this.dispose();
                             });
                         }
@@ -210,10 +205,13 @@ module BABYLON.GLTF2 {
                 });
 
                 return resultPromise;
-            }).catch(error => {
+            }, error => {
                 if (!this._disposed) {
-                    Tools.Error(`glTF Loader: ${error.message}`);
+                    this._parent.onErrorObservable.notifyObservers(error);
+                    this._parent.onErrorObservable.clear();
+
                     this.dispose();
+
                     throw error;
                 }
             });
@@ -294,6 +292,11 @@ module BABYLON.GLTF2 {
             }
         }
 
+        private _setState(state: GLTFLoaderState): void {
+            this._state = state;
+            this._parent._log(GLTFLoaderState[this._state]);
+        }
+
         private _createRootNode(): _ILoaderNode {
             this._rootBabylonMesh = new Mesh("__root__", this._babylonScene);
 
@@ -1758,6 +1761,15 @@ module BABYLON.GLTF2 {
 
             return null;
         }
+
+        public _forEachExtensions(action: (extension: GLTFLoaderExtension) => void): void {
+            for (const name of GLTFLoader._ExtensionNames) {
+                const extension = this._extensions[name];
+                if (extension.enabled) {
+                    action(extension);
+                }
+            }
+        }
     }
 
     GLTFFileLoader._CreateGLTFLoaderV2 = parent => new GLTFLoader(parent);

+ 26 - 0
loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts

@@ -35,6 +35,16 @@ module BABYLON.GLTF2 {
         // #region Overridable Methods
 
         /**
+         * Override this method to do work after the state changes to LOADING.
+         */
+        protected _onLoading(): void {}
+
+        /**
+         * Override this method to do work after the state changes to READY.
+         */
+        protected _onReady(): void {}
+
+        /**
          * Override this method to modify the default behavior for loading scenes.
          * @hidden
          */
@@ -144,6 +154,22 @@ module BABYLON.GLTF2 {
         }
 
         /**
+         * Helper method called by the loader after the state changes to LOADING.
+         * @hidden
+         */
+        public static _OnLoading(loader: GLTFLoader): void {
+            loader._forEachExtensions(extension => extension._onLoading());
+        }
+
+        /**
+         * Helper method called by the loader after the state changes to READY.
+         * @hidden
+         */
+        public static _OnReady(loader: GLTFLoader): void {
+            loader._forEachExtensions(extension => extension._onReady());
+        }
+
+        /**
          * Helper method called by the loader to allow extensions to override loading scenes.
          * @hidden
          */

+ 23 - 1
loaders/src/glTF/babylon.glTFFileLoader.ts

@@ -264,6 +264,8 @@ module BABYLON {
 
         /**
          * Callback raised when the asset is completely loaded, immediately 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, immediately after the loader resolves the returned promise.
          */
         public set onComplete(callback: () => void) {
             if (this._onCompleteObserver) {
@@ -273,6 +275,23 @@ module BABYLON {
         }
 
         /**
+         * Observable raised when an error occurs.
+         */
+        public readonly onErrorObservable = new Observable<any>();
+
+        private _onErrorObserver: Nullable<Observer<any>>;
+
+        /**
+         * Callback raised when an error occurs.
+         */
+        public set onError(callback: (reason: any) => void) {
+            if (this._onErrorObserver) {
+                this.onErrorObservable.remove(this._onErrorObserver);
+            }
+            this._onErrorObserver = this.onErrorObservable.add(callback);
+        }
+
+        /**
          * Observable raised after the loader is disposed.
          */
         public readonly onDisposeObservable = new Observable<void>();
@@ -312,10 +331,13 @@ module BABYLON {
          * @returns a promise that resolves when the asset is completely loaded.
          */
         public whenCompleteAsync(): Promise<void> {
-            return new Promise(resolve => {
+            return new Promise((resolve, reject) => {
                 this.onCompleteObservable.addOnce(() => {
                     resolve();
                 });
+                this.onErrorObservable.addOnce(reason => {
+                    reject(reason);
+                });
             });
         }
 

+ 1 - 1
package.json

@@ -9,7 +9,7 @@
     ],
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "3.3.0-alpha.12",
+    "version": "3.3.0-alpha.13",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 129 - 108
serializers/src/glTF/2.0/babylon.glTFMaterialExporter.ts

@@ -585,6 +585,29 @@ module BABYLON.GLTF2 {
         }
 
         /**
+         * Converts an array of pixels to a Float32Array
+         * Throws an error if the pixel format is not supported
+         * @param pixels - array buffer containing pixel values
+         * @returns Float32 of pixels
+         */
+        private _convertPixelArrayToFloat32(pixels: ArrayBufferView): Float32Array {
+            if (pixels instanceof Uint8Array) {
+                const length = pixels.length;
+                const buffer = new Float32Array(pixels.length);
+                for (let i = 0; i < length; ++i) {
+                    buffer[i] = pixels[i] / 255;
+                }
+                return buffer;
+            }
+            else if (pixels instanceof Float32Array) {
+                return pixels;
+            }
+            else {
+                throw new Error('Unsupported pixel format!');
+            }
+        }
+
+        /**
          * Convert Specular Glossiness Textures to Metallic Roughness
          * See link below for info on the material conversions from PBR Metallic/Roughness and Specular/Glossiness
          * @link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/examples/convert-between-workflows-bjs/js/babylon.pbrUtilities.js
@@ -606,128 +629,126 @@ module BABYLON.GLTF2 {
 
                 let diffuseSize = resizedTextures.texture1.getSize();
 
-                let diffuseBuffer: Uint8Array;
-                let specularGlossinessBuffer: Uint8Array;
+                let diffuseBuffer: Float32Array;
+                let specularGlossinessBuffer: Float32Array;
 
                 const width = diffuseSize.width;
                 const height = diffuseSize.height;
 
-                let pixels = (resizedTextures.texture1.readPixels());
-                if (pixels instanceof Uint8Array) {
-                    diffuseBuffer = (resizedTextures.texture1.readPixels()) as Uint8Array;
-
-                    pixels = resizedTextures.texture2.readPixels();
-
-                    if (pixels instanceof Uint8Array) {
-                        specularGlossinessBuffer = (resizedTextures.texture2.readPixels()) as Uint8Array;
-
-                        const byteLength = specularGlossinessBuffer.byteLength;
-
-                        const metallicRoughnessBuffer = new Uint8Array(byteLength);
-                        const baseColorBuffer = new Uint8Array(byteLength);
+                let diffusePixels = resizedTextures.texture1.readPixels();
+                let specularPixels = resizedTextures.texture2.readPixels();
 
-                        const strideSize = 4;
-                        const maxBaseColor = Color3.Black();
-                        let maxMetallic = 0;
-                        let maxRoughness = 0;
-
-                        for (let h = 0; h < height; ++h) {
-                            for (let w = 0; w < width; ++w) {
-                                const offset = (width * h + w) * strideSize;
-
-                                const diffuseColor = Color3.FromInts(diffuseBuffer[offset], diffuseBuffer[offset + 1], diffuseBuffer[offset + 2]).toLinearSpace().multiply(factors.diffuseColor);
-                                const specularColor = Color3.FromInts(specularGlossinessBuffer[offset], specularGlossinessBuffer[offset + 1], specularGlossinessBuffer[offset + 2]).toLinearSpace().multiply(factors.specularColor);
-                                const glossiness = (specularGlossinessBuffer[offset + 3] / 255) * factors.glossiness;
+                if (diffusePixels) {
+                    diffuseBuffer = this._convertPixelArrayToFloat32(diffusePixels);
+                }
+                else {
+                    return Promise.reject("Failed to retrieve pixels from diffuse texture!");
+                }
+                if (specularPixels) {
+                    specularGlossinessBuffer = this._convertPixelArrayToFloat32(specularPixels);
+                }
+                else {
+                    return Promise.reject("Failed to retrieve pixels from specular glossiness texture!");
+                }
 
-                                const specularGlossiness: _IPBRSpecularGlossiness = {
-                                    diffuseColor: diffuseColor,
-                                    specularColor: specularColor,
-                                    glossiness: glossiness
-                                };
+                const byteLength = specularGlossinessBuffer.byteLength;
 
-                                const metallicRoughness = this._convertSpecularGlossinessToMetallicRoughness(specularGlossiness);
-                                maxBaseColor.r = Math.max(maxBaseColor.r, metallicRoughness.baseColor.r);
-                                maxBaseColor.g = Math.max(maxBaseColor.g, metallicRoughness.baseColor.g);
-                                maxBaseColor.b = Math.max(maxBaseColor.b, metallicRoughness.baseColor.b);
-                                maxMetallic = Math.max(maxMetallic, metallicRoughness.metallic);
-                                maxRoughness = Math.max(maxRoughness, metallicRoughness.roughness);
+                const metallicRoughnessBuffer = new Uint8Array(byteLength);
+                const baseColorBuffer = new Uint8Array(byteLength);
 
-                                baseColorBuffer[offset] = metallicRoughness.baseColor.r * 255;
-                                baseColorBuffer[offset + 1] = metallicRoughness.baseColor.g * 255;
-                                baseColorBuffer[offset + 2] = metallicRoughness.baseColor.b * 255;
-                                baseColorBuffer[offset + 3] = resizedTextures.texture1.hasAlpha ? diffuseBuffer[offset + 3] : 255;
+                const strideSize = 4;
+                const maxBaseColor = Color3.Black();
+                let maxMetallic = 0;
+                let maxRoughness = 0;
 
-                                metallicRoughnessBuffer[offset] = 0;
-                                metallicRoughnessBuffer[offset + 1] = metallicRoughness.roughness * 255;
-                                metallicRoughnessBuffer[offset + 2] = metallicRoughness.metallic * 255;
-                                metallicRoughnessBuffer[offset + 3] = 255;
+                for (let h = 0; h < height; ++h) {
+                    for (let w = 0; w < width; ++w) {
+                        const offset = (width * h + w) * strideSize;
 
-                            }
-                        }
+                        const diffuseColor = new Color3(diffuseBuffer[offset], diffuseBuffer[offset + 1], diffuseBuffer[offset + 2]).toLinearSpace().multiply(factors.diffuseColor);
+                        const specularColor = new Color3(specularGlossinessBuffer[offset], specularGlossinessBuffer[offset + 1], specularGlossinessBuffer[offset + 2]).toLinearSpace().multiply(factors.specularColor);
+                        const glossiness = (specularGlossinessBuffer[offset + 3]) * factors.glossiness;
 
-                        // Retrieves the metallic roughness factors from the maximum texture values.
-                        const metallicRoughnessFactors: _IPBRMetallicRoughness = {
-                            baseColor: maxBaseColor,
-                            metallic: maxMetallic,
-                            roughness: maxRoughness
+                        const specularGlossiness: _IPBRSpecularGlossiness = {
+                            diffuseColor: diffuseColor,
+                            specularColor: specularColor,
+                            glossiness: glossiness
                         };
 
-                        let writeOutMetallicRoughnessTexture = false;
-                        let writeOutBaseColorTexture = false;
-
-                        for (let h = 0; h < height; ++h) {
-                            for (let w = 0; w < width; ++w) {
-                                const destinationOffset = (width * h + w) * strideSize;
+                        const metallicRoughness = this._convertSpecularGlossinessToMetallicRoughness(specularGlossiness);
+                        maxBaseColor.r = Math.max(maxBaseColor.r, metallicRoughness.baseColor.r);
+                        maxBaseColor.g = Math.max(maxBaseColor.g, metallicRoughness.baseColor.g);
+                        maxBaseColor.b = Math.max(maxBaseColor.b, metallicRoughness.baseColor.b);
+                        maxMetallic = Math.max(maxMetallic, metallicRoughness.metallic);
+                        maxRoughness = Math.max(maxRoughness, metallicRoughness.roughness);
+
+                        baseColorBuffer[offset] = metallicRoughness.baseColor.r * 255;
+                        baseColorBuffer[offset + 1] = metallicRoughness.baseColor.g * 255;
+                        baseColorBuffer[offset + 2] = metallicRoughness.baseColor.b * 255;
+                        baseColorBuffer[offset + 3] = resizedTextures.texture1.hasAlpha ? diffuseBuffer[offset + 3] * 255 : 255;
+
+                        metallicRoughnessBuffer[offset] = 0;
+                        metallicRoughnessBuffer[offset + 1] = metallicRoughness.roughness * 255;
+                        metallicRoughnessBuffer[offset + 2] = metallicRoughness.metallic * 255;
+                        metallicRoughnessBuffer[offset + 3] = 255;
+                    }
+                }
 
-                                baseColorBuffer[destinationOffset] /= metallicRoughnessFactors.baseColor.r > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors.baseColor.r : 1;
-                                baseColorBuffer[destinationOffset + 1] /= metallicRoughnessFactors.baseColor.g > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors.baseColor.g : 1;
-                                baseColorBuffer[destinationOffset + 2] /= metallicRoughnessFactors.baseColor.b > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors.baseColor.b : 1;
+                // Retrieves the metallic roughness factors from the maximum texture values.
+                const metallicRoughnessFactors: _IPBRMetallicRoughness = {
+                    baseColor: maxBaseColor,
+                    metallic: maxMetallic,
+                    roughness: maxRoughness
+                };
 
-                                const linearBaseColorPixel = Color3.FromInts(baseColorBuffer[destinationOffset], baseColorBuffer[destinationOffset + 1], baseColorBuffer[destinationOffset + 2]);
-                                const sRGBBaseColorPixel = linearBaseColorPixel.toGammaSpace();
-                                baseColorBuffer[destinationOffset] = sRGBBaseColorPixel.r * 255;
-                                baseColorBuffer[destinationOffset + 1] = sRGBBaseColorPixel.g * 255;
-                                baseColorBuffer[destinationOffset + 2] = sRGBBaseColorPixel.b * 255;
+                let writeOutMetallicRoughnessTexture = false;
+                let writeOutBaseColorTexture = false;
 
-                                if (!_GLTFMaterialExporter.FuzzyEquals(sRGBBaseColorPixel, Color3.White(), _GLTFMaterialExporter._Epsilon)) {
-                                    writeOutBaseColorTexture = true;
-                                }
+                for (let h = 0; h < height; ++h) {
+                    for (let w = 0; w < width; ++w) {
+                        const destinationOffset = (width * h + w) * strideSize;
 
-                                metallicRoughnessBuffer[destinationOffset + 1] /= metallicRoughnessFactors.roughness > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors.roughness : 1;
-                                metallicRoughnessBuffer[destinationOffset + 2] /= metallicRoughnessFactors.metallic > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors.metallic : 1;
+                        baseColorBuffer[destinationOffset] /= metallicRoughnessFactors.baseColor.r > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors.baseColor.r : 1;
+                        baseColorBuffer[destinationOffset + 1] /= metallicRoughnessFactors.baseColor.g > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors.baseColor.g : 1;
+                        baseColorBuffer[destinationOffset + 2] /= metallicRoughnessFactors.baseColor.b > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors.baseColor.b : 1;
 
-                                const metallicRoughnessPixel = Color3.FromInts(255, metallicRoughnessBuffer[destinationOffset + 1], metallicRoughnessBuffer[destinationOffset + 2]);
+                        const linearBaseColorPixel = Color3.FromInts(baseColorBuffer[destinationOffset], baseColorBuffer[destinationOffset + 1], baseColorBuffer[destinationOffset + 2]);
+                        const sRGBBaseColorPixel = linearBaseColorPixel.toGammaSpace();
+                        baseColorBuffer[destinationOffset] = sRGBBaseColorPixel.r * 255;
+                        baseColorBuffer[destinationOffset + 1] = sRGBBaseColorPixel.g * 255;
+                        baseColorBuffer[destinationOffset + 2] = sRGBBaseColorPixel.b * 255;
 
-                                if (!_GLTFMaterialExporter.FuzzyEquals(metallicRoughnessPixel, Color3.White(), _GLTFMaterialExporter._Epsilon)) {
-                                    writeOutMetallicRoughnessTexture = true;
-                                }
-                            }
+                        if (!_GLTFMaterialExporter.FuzzyEquals(sRGBBaseColorPixel, Color3.White(), _GLTFMaterialExporter._Epsilon)) {
+                            writeOutBaseColorTexture = true;
                         }
 
-                        if (writeOutMetallicRoughnessTexture) {
-                            let promise = this._createBase64FromCanvasAsync(metallicRoughnessBuffer, width, height, mimeType).then(metallicRoughnessBase64 => {
-                                metallicRoughnessFactors.metallicRoughnessTextureBase64 = metallicRoughnessBase64;
-                            });
-                            promises.push(promise);
-                        }
-                        if (writeOutBaseColorTexture) {
-                            let promise = this._createBase64FromCanvasAsync(baseColorBuffer, width, height, mimeType).then(baseColorBase64 => {
-                                metallicRoughnessFactors.baseColorTextureBase64 = baseColorBase64;
-                            });
-                            promises.push(promise);
-                        }
+                        metallicRoughnessBuffer[destinationOffset + 1] /= metallicRoughnessFactors.roughness > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors.roughness : 1;
+                        metallicRoughnessBuffer[destinationOffset + 2] /= metallicRoughnessFactors.metallic > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors.metallic : 1;
 
-                        return Promise.all(promises).then(() => {
-                            return metallicRoughnessFactors;
-                        });
-                    }
-                    else {
-                        return Promise.reject("_ConvertSpecularGlossinessTexturesToMetallicRoughness: Pixel array buffer type not supported for texture: " + resizedTextures.texture2.name);
+                        const metallicRoughnessPixel = Color3.FromInts(255, metallicRoughnessBuffer[destinationOffset + 1], metallicRoughnessBuffer[destinationOffset + 2]);
+
+                        if (!_GLTFMaterialExporter.FuzzyEquals(metallicRoughnessPixel, Color3.White(), _GLTFMaterialExporter._Epsilon)) {
+                            writeOutMetallicRoughnessTexture = true;
+                        }
                     }
                 }
-                else {
-                    return Promise.reject("_ConvertSpecularGlossinessTexturesToMetallicRoughness: Pixel array buffer type not supported for texture: " + resizedTextures.texture1.name);
+
+                if (writeOutMetallicRoughnessTexture) {
+                    let promise = this._createBase64FromCanvasAsync(metallicRoughnessBuffer, width, height, mimeType).then(metallicRoughnessBase64 => {
+                        metallicRoughnessFactors.metallicRoughnessTextureBase64 = metallicRoughnessBase64;
+                    });
+                    promises.push(promise);
+                }
+                if (writeOutBaseColorTexture) {
+                    let promise = this._createBase64FromCanvasAsync(baseColorBuffer, width, height, mimeType).then(baseColorBase64 => {
+                        metallicRoughnessFactors.baseColorTextureBase64 = baseColorBase64;
+                    });
+                    promises.push(promise);
                 }
+
+                return Promise.all(promises).then(() => {
+                    return metallicRoughnessFactors;
+                });
             }
             else {
                 return Promise.reject("_ConvertSpecularGlossinessTexturesToMetallicRoughness: Scene from textures is missing!");
@@ -953,20 +974,20 @@ module BABYLON.GLTF2 {
                 }
                 if ((babylonPBRMaterial.albedoTexture || babylonPBRMaterial.reflectivityTexture) && hasTextureCoords) {
                     return this._convertSpecularGlossinessTexturesToMetallicRoughnessAsync(babylonPBRMaterial.albedoTexture, babylonPBRMaterial.reflectivityTexture, specGloss, mimeType).then(metallicRoughnessFactors => {
-                            if (metallicRoughnessFactors.baseColorTextureBase64) {
-                                const glTFBaseColorTexture = this._getTextureInfoFromBase64(metallicRoughnessFactors.baseColorTextureBase64, "bjsBaseColorTexture_" + (textures.length) + ".png", mimeType, babylonPBRMaterial.albedoTexture ? babylonPBRMaterial.albedoTexture.coordinatesIndex : null, samplerIndex);
-                                if (glTFBaseColorTexture) {
-                                    glTFPbrMetallicRoughness.baseColorTexture = glTFBaseColorTexture;
-                                }
+                        if (metallicRoughnessFactors.baseColorTextureBase64) {
+                            const glTFBaseColorTexture = this._getTextureInfoFromBase64(metallicRoughnessFactors.baseColorTextureBase64, "bjsBaseColorTexture_" + (textures.length) + ".png", mimeType, babylonPBRMaterial.albedoTexture ? babylonPBRMaterial.albedoTexture.coordinatesIndex : null, samplerIndex);
+                            if (glTFBaseColorTexture) {
+                                glTFPbrMetallicRoughness.baseColorTexture = glTFBaseColorTexture;
                             }
-                            if (metallicRoughnessFactors.metallicRoughnessTextureBase64) {
-                                const glTFMRColorTexture = this._getTextureInfoFromBase64(metallicRoughnessFactors.metallicRoughnessTextureBase64, "bjsMetallicRoughnessTexture_" + (textures.length) + ".png", mimeType, babylonPBRMaterial.reflectivityTexture ? babylonPBRMaterial.reflectivityTexture.coordinatesIndex : null, samplerIndex);
-                                if (glTFMRColorTexture) {
-                                    glTFPbrMetallicRoughness.metallicRoughnessTexture = glTFMRColorTexture;
-                                }
+                        }
+                        if (metallicRoughnessFactors.metallicRoughnessTextureBase64) {
+                            const glTFMRColorTexture = this._getTextureInfoFromBase64(metallicRoughnessFactors.metallicRoughnessTextureBase64, "bjsMetallicRoughnessTexture_" + (textures.length) + ".png", mimeType, babylonPBRMaterial.reflectivityTexture ? babylonPBRMaterial.reflectivityTexture.coordinatesIndex : null, samplerIndex);
+                            if (glTFMRColorTexture) {
+                                glTFPbrMetallicRoughness.metallicRoughnessTexture = glTFMRColorTexture;
                             }
+                        }
 
-                            return metallicRoughnessFactors;
+                        return metallicRoughnessFactors;
                     });
                 }
                 else {

+ 3 - 1
src/Cameras/VR/babylon.vrExperienceHelper.ts

@@ -507,7 +507,9 @@ module BABYLON {
          * @param scene The scene the VRExperienceHelper belongs to.
          * @param webVROptions Options to modify the vr experience helper's behavior.
          */
-        constructor(scene: Scene, /** Options to modify the vr experience helper's behavior. */public webVROptions: VRExperienceHelperOptions = {}) {
+        constructor(scene: Scene, 
+            /** Options to modify the vr experience helper's behavior. */
+            public webVROptions: VRExperienceHelperOptions = {}) {
             this._scene = scene;
             this._canvas = scene.getEngine().getRenderingCanvas();
 

+ 6 - 2
src/Cameras/babylon.camera.ts

@@ -557,7 +557,11 @@
             return this._projectionMatrix;
         }
 
-        public getTranformationMatrix(): Matrix {
+        /**
+         * Gets the transformation matrix (ie. the multiplication of view by projection matrices)
+         * @returns a Matrix
+         */
+        public getTransformationMatrix(): Matrix {
             this._computedViewMatrix.multiplyToRef(this._projectionMatrix, this._transformMatrix);
             return this._transformMatrix;
         }
@@ -567,7 +571,7 @@
                 return;
             }
 
-            this.getTranformationMatrix();
+            this.getTransformationMatrix();
 
             if (!this._frustumPlanes) {
                 this._frustumPlanes = Frustum.GetPlanes(this._transformMatrix);

+ 6 - 2
src/Cameras/babylon.targetCamera.ts

@@ -298,12 +298,16 @@
         protected _computeViewMatrix(position: Vector3, target: Vector3, up: Vector3): void {
             if (this.parent) {
                 const parentWorldMatrix = this.parent.getWorldMatrix();
-                Vector3.TransformCoordinatesToRef(this.position, parentWorldMatrix, this._globalPosition);
+                Vector3.TransformCoordinatesToRef(position, parentWorldMatrix, this._globalPosition);
                 Vector3.TransformCoordinatesToRef(target, parentWorldMatrix, this._globalCurrentTarget);
                 Vector3.TransformNormalToRef(up, parentWorldMatrix, this._globalCurrentUpVector);
                 this._markSyncedWithParent();
             } else {
-                this._globalPosition.copyFrom(this.position);
+                if (Scalar.WithinEpsilon(position.y, target.y, BABYLON.Epsilon) && Scalar.WithinEpsilon(position.z, target.z, BABYLON.Epsilon)) {
+                    position.z += BABYLON.Epsilon;
+                }
+
+                this._globalPosition.copyFrom(position);
                 this._globalCurrentTarget.copyFrom(target);
                 this._globalCurrentUpVector.copyFrom(up);
             }

+ 6 - 3
src/Engine/babylon.engine.ts

@@ -435,7 +435,7 @@
          * Returns the current version of the framework
          */
         public static get Version(): string {
-            return "3.3.0-alpha.12";
+            return "3.3.0-alpha.13";
         }
 
         // Updatable statics so stick with vars here
@@ -3321,9 +3321,10 @@
          * @param effect defines the effect to activate
          */
         public enableEffect(effect: Nullable<Effect>): void {
-            if (!effect) {
+            if (!effect || effect === this._currentEffect) {
                 return;
             }
+
             // Use program
             this.bindSamplers(effect);
 
@@ -3332,7 +3333,9 @@
             if (effect.onBind) {
                 effect.onBind(effect);
             }
-            effect.onBindObservable.notifyObservers(effect);
+            if (effect._onBindObservable) {
+                effect._onBindObservable.notifyObservers(effect);
+            }
         }
 
         /**

+ 3 - 1
src/Engine/babylon.nullEngine.ts

@@ -166,7 +166,9 @@
             if (effect.onBind) {
                 effect.onBind(effect);
             }
-            effect.onBindObservable.notifyObservers(effect);
+            if (effect._onBindObservable) {
+                effect._onBindObservable.notifyObservers(effect);
+            }
         }
 
         public setState(culling: boolean, zOffset: number = 0, force?: boolean, reverseSide = false): void {

+ 3 - 1
src/Gizmos/babylon.gizmo.ts

@@ -64,7 +64,9 @@ module BABYLON {
          * Creates a gizmo
          * @param gizmoLayer The utility layer the gizmo will be added to
          */
-        constructor(/** The utility layer the gizmo will be added to */ public gizmoLayer:UtilityLayerRenderer=UtilityLayerRenderer.DefaultUtilityLayer){
+        constructor(
+            /** The utility layer the gizmo will be added to */ 
+            public gizmoLayer: UtilityLayerRenderer = UtilityLayerRenderer.DefaultUtilityLayer){
             this._rootMesh = new BABYLON.Mesh("gizmoRootNode",gizmoLayer.utilityLayerScene);
             this._beforeRenderObserver = this.gizmoLayer.utilityLayerScene.onBeforeRenderObservable.add(()=>{
                 this._update();

+ 14 - 1
src/Lights/babylon.light.ts

@@ -90,12 +90,25 @@ module BABYLON {
         @serialize()
         public intensity = 1.0;
 
+        private _range = Number.MAX_VALUE;
+        protected _inverseSquaredRange = 0;
+
         /**
          * Defines how far from the source the light is impacting in scene units.
          * Note: Unused in PBR material as the distance light falloff is defined following the inverse squared falloff.
          */
         @serialize()
-        public range = Number.MAX_VALUE;
+        public get range(): number {
+            return this._range
+        }
+        /**
+         * Defines how far from the source the light is impacting in scene units.
+         * Note: Unused in PBR material as the distance light falloff is defined following the inverse squared falloff.
+         */
+        public set range(value: number) {
+            this._range = value;
+            this._inverseSquaredRange = 1.0 / (this.range * this.range);
+        }
 
         /**
          * Cached photometric scale default to 1.0 as the automatic intensity mode defaults to 1.0 for every type

+ 12 - 3
src/Lights/babylon.pointLight.ts

@@ -145,6 +145,7 @@
             this._uniformBuffer.addUniform("vLightData", 4);
             this._uniformBuffer.addUniform("vLightDiffuse", 4);
             this._uniformBuffer.addUniform("vLightSpecular", 3);
+            this._uniformBuffer.addUniform("vLightFalloff", 4);
             this._uniformBuffer.addUniform("shadowsInfo", 3);
             this._uniformBuffer.addUniform("depthValues", 2);
             this._uniformBuffer.create();
@@ -163,11 +164,19 @@
                     this.transformedPosition.y,
                     this.transformedPosition.z,
                     0.0,
-                    lightIndex); 
-                return this;
+                    lightIndex);
+            }
+            else {
+                this._uniformBuffer.updateFloat4("vLightData", this.position.x, this.position.y, this.position.z, 0, lightIndex);
             }
 
-            this._uniformBuffer.updateFloat4("vLightData", this.position.x, this.position.y, this.position.z, 0, lightIndex);
+            this._uniformBuffer.updateFloat4("vLightFalloff",
+                this.range,
+                this._inverseSquaredRange,
+                0,
+                0,
+                lightIndex
+            );
             return this;
         }
 

+ 42 - 1
src/Lights/babylon.spotLight.ts

@@ -25,6 +25,12 @@
         */
 
         private _angle: number;
+        private _innerAngle: number = 0;
+        private _cosHalfAngle: number;
+
+        private _lightAngleScale: number;
+        private _lightAngleOffset: number;
+
         /**
          * Gets the cone angle of the spot light in Radians.
          */
@@ -37,8 +43,29 @@
          */
         public set angle(value: number) {
             this._angle = value;
+            this._cosHalfAngle = Math.cos(value * 0.5);
             this._projectionTextureProjectionLightDirty = true;
             this.forceProjectionMatrixCompute();
+            this._computeAngleValues();
+        }
+
+        /**
+         * Only used in gltf falloff mode, this defines the angle where 
+         * the directional falloff will start before cutting at angle which could be seen
+         * as outer angle.
+         */
+        @serialize()
+        public get innerAngle(): number {
+            return this._angle
+        }
+        /**
+         * Only used in gltf falloff mode, this defines the angle where 
+         * the directional falloff will start before cutting at angle which could be seen
+         * as outer angle.
+         */
+        public set innerAngle(value: number) {
+            this._innerAngle = value;
+            this._computeAngleValues();
         }
 
         private _shadowAngleScale: number;
@@ -261,11 +288,17 @@
             this._uniformBuffer.addUniform("vLightDiffuse", 4);
             this._uniformBuffer.addUniform("vLightSpecular", 3);
             this._uniformBuffer.addUniform("vLightDirection", 3);
+            this._uniformBuffer.addUniform("vLightFalloff", 4);
             this._uniformBuffer.addUniform("shadowsInfo", 3);
             this._uniformBuffer.addUniform("depthValues", 2);
             this._uniformBuffer.create();
         }
 
+        private _computeAngleValues(): void {
+            this._lightAngleScale = 1.0 / Math.max(0.001, (Math.cos(this._innerAngle * 0.5) - this._cosHalfAngle));
+            this._lightAngleOffset = -this._cosHalfAngle * this._lightAngleScale;
+        }
+
         /**
          * Sets the passed Effect object with the SpotLight transfomed position (or position if not parented) and normalized direction.  
          * @param effect The effect to update
@@ -299,9 +332,17 @@
                 normalizeDirection.x,
                 normalizeDirection.y,
                 normalizeDirection.z,
-                Math.cos(this.angle * 0.5),
+                this._cosHalfAngle,
                 lightIndex);
 
+            this._uniformBuffer.updateFloat4("vLightFalloff",
+                this.range,
+                this._inverseSquaredRange,
+                this._lightAngleScale,
+                this._lightAngleOffset,
+                lightIndex
+            );
+
             if (this.projectionTexture && this.projectionTexture.isReady()) {
                 if (this._projectionTextureViewLightDirty) {
                     this._computeProjectionTextureViewLightMatrix();

+ 33 - 6
src/Materials/PBR/babylon.pbrBaseMaterial.ts

@@ -125,6 +125,7 @@
         public EXPOSURE = false;
 
         public USEPHYSICALLIGHTFALLOFF = false;
+        public USEGLTFLIGHTFALLOFF = false;
         public TWOSIDEDLIGHTING = false;
         public SHADOWFLOAT = false;
         public CLIPPLANE = false;
@@ -164,6 +165,22 @@
      * http://doc.babylonjs.com/extensions/Physically_Based_Rendering
      */
     export abstract class PBRBaseMaterial extends PushMaterial {
+        /**
+         * PBRMaterialLightFalloff Physical: light is falling off following the inverse squared distance law.
+         */
+        public static readonly LIGHTFALLOFF_PHYSICAL = 0;
+
+        /**
+         * PBRMaterialLightFalloff gltf: light is falling off as described in the gltf moving to PBR document 
+         * to enhance interoperability with other engines.
+         */
+        public static readonly LIGHTFALLOFF_GLTF = 1;
+
+        /**
+         * PBRMaterialLightFalloff Standard: light is falling off like in the standard material 
+         * to enhance interoperability with other materials.
+         */
+        public static readonly LIGHTFALLOFF_STANDARD = 2;
 
         /**
          * Intensity of the direct lights e.g. the four lights available in your scene.
@@ -383,11 +400,10 @@
         protected _useAutoMicroSurfaceFromReflectivityMap = false;
 
         /**
-         * BJS is using an harcoded light falloff based on a manually sets up range.
-         * In PBR, one way to represents the fallof is to use the inverse squared root algorythm.
-         * This parameter can help you switch back to the BJS mode in order to create scenes using both materials.
+         * Defines the  falloff type used in this material.
+         * It by default is Physical.
          */
-        protected _usePhysicalLightFalloff = true;
+        protected _lightFalloff = PBRBaseMaterial.LIGHTFALLOFF_PHYSICAL;
 
         /**
          * Specifies that the material will keeps the reflection highlights over a transparent surface (only the most limunous ones).
@@ -1216,7 +1232,18 @@
 
                 defines.SPECULAROVERALPHA = this._useSpecularOverAlpha;
 
-                defines.USEPHYSICALLIGHTFALLOFF = this._usePhysicalLightFalloff;
+                if (this._lightFalloff === PBRBaseMaterial.LIGHTFALLOFF_STANDARD) {
+                    defines.USEPHYSICALLIGHTFALLOFF = false;
+                    defines.USEGLTFLIGHTFALLOFF = false;
+                }
+                else if (this._lightFalloff === PBRBaseMaterial.LIGHTFALLOFF_GLTF) {
+                    defines.USEPHYSICALLIGHTFALLOFF = false;
+                    defines.USEGLTFLIGHTFALLOFF = true;
+                }
+                else {
+                    defines.USEPHYSICALLIGHTFALLOFF = true;
+                    defines.USEGLTFLIGHTFALLOFF = false;
+                }
 
                 defines.RADIANCEOVERALPHA = this._useRadianceOverAlpha;
 
@@ -1606,7 +1633,7 @@
             if (mustRebind || !this.isFrozen) {
                 // Lights
                 if (scene.lightsEnabled && !this._disableLighting) {
-                    MaterialHelper.BindLights(scene, mesh, this._activeEffect, defines, this._maxSimultaneousLights, this._usePhysicalLightFalloff);
+                    MaterialHelper.BindLights(scene, mesh, this._activeEffect, defines, this._maxSimultaneousLights, this._lightFalloff !== PBRBaseMaterial.LIGHTFALLOFF_STANDARD);
                 }
 
                 // View

+ 53 - 31
src/Materials/PBR/babylon.pbrMaterial.ts

@@ -7,51 +7,26 @@
      * http://doc.babylonjs.com/extensions/Physically_Based_Rendering
      */
     export class PBRMaterial extends PBRBaseMaterial {
-        private static _PBRMATERIAL_OPAQUE = 0;
         /**
          * PBRMaterialTransparencyMode: No transparency mode, Alpha channel is not use.
          */
-        public static get PBRMATERIAL_OPAQUE(): number {
-            return this._PBRMATERIAL_OPAQUE;
-        }
-
-        /**
-         * Alpha Test mode, pixel are discarded below a certain threshold defined by the alpha cutoff value.
-         */
-        private static _PBRMATERIAL_ALPHATEST = 1;
+        public static readonly PBRMATERIAL_OPAQUE = 0;
 
         /**
          * PBRMaterialTransparencyMode: Alpha Test mode, pixel are discarded below a certain threshold defined by the alpha cutoff value.
          */
-        public static get PBRMATERIAL_ALPHATEST(): number {
-            return this._PBRMATERIAL_ALPHATEST;
-        }
-
-        /**
-         * Represents the value for Alpha Blend.  Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer.
-         */
-        private static _PBRMATERIAL_ALPHABLEND = 2;
+        public static readonly PBRMATERIAL_ALPHATEST = 1;
 
         /**
          * PBRMaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer.
          */
-        public static get PBRMATERIAL_ALPHABLEND(): number {
-            return this._PBRMATERIAL_ALPHABLEND;
-        }
-
-        /**
-         * Represents the value for Alpha Test and Blend.  Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer.
-         * They are also discarded below the alpha cutoff threshold to improve performances.
-         */
-        private static _PBRMATERIAL_ALPHATESTANDBLEND = 3;
+        public static readonly PBRMATERIAL_ALPHABLEND = 2;
 
         /**
          * PBRMaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer.
          * They are also discarded below the alpha cutoff threshold to improve performances.
          */
-        public static get PBRMATERIAL_ALPHATESTANDBLEND(): number {
-            return this._PBRMATERIAL_ALPHATESTANDBLEND;
-        }
+        public static readonly PBRMATERIAL_ALPHATESTANDBLEND = 3;
 
         /**
          * Intensity of the direct lights e.g. the four lights available in your scene.
@@ -346,8 +321,55 @@
          * This parameter can help you switch back to the BJS mode in order to create scenes using both materials.
          */
         @serialize()
-        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
-        public usePhysicalLightFalloff = true;
+        public get usePhysicalLightFalloff(): boolean {
+            return this._lightFalloff === PBRBaseMaterial.LIGHTFALLOFF_PHYSICAL;
+        }
+
+        /**
+         * BJS is using an harcoded light falloff based on a manually sets up range.
+         * In PBR, one way to represents the fallof is to use the inverse squared root algorythm.
+         * This parameter can help you switch back to the BJS mode in order to create scenes using both materials.
+         */
+        public set usePhysicalLightFalloff(value: boolean) {
+            if (value !== this.usePhysicalLightFalloff) {
+                // Ensure the effect will be rebuilt.
+                this._markAllSubMeshesAsTexturesDirty();
+
+                if (value) {
+                    this._lightFalloff = PBRBaseMaterial.LIGHTFALLOFF_PHYSICAL;
+                }
+                else {
+                    this._lightFalloff = PBRBaseMaterial.LIGHTFALLOFF_STANDARD;
+                }
+            }
+        }
+
+        /**
+         * In order to support the falloff compatibility with gltf, a special mode has been added 
+         * to reproduce the gltf light falloff.
+         */
+        @serialize()
+        public get useGLTFLightFalloff(): boolean {
+            return this._lightFalloff === PBRBaseMaterial.LIGHTFALLOFF_GLTF;
+        }
+
+        /**
+         * In order to support the falloff compatibility with gltf, a special mode has been added 
+         * to reproduce the gltf light falloff.
+         */
+        public set useGLTFLightFalloff(value: boolean) {
+            if (value !== this.useGLTFLightFalloff) {
+                // Ensure the effect will be rebuilt.
+                this._markAllSubMeshesAsTexturesDirty();
+
+                if (value) {
+                    this._lightFalloff = PBRBaseMaterial.LIGHTFALLOFF_GLTF;
+                }
+                else {
+                    this._lightFalloff = PBRBaseMaterial.LIGHTFALLOFF_STANDARD;
+                }
+            }
+        }
 
         /**
          * Specifies that the material will keeps the reflection highlights over a transparent surface (only the most limunous ones).

+ 0 - 0
src/Materials/Textures/babylon.dynamicTexture.ts


部分文件因为文件数量过多而无法显示