Jaskar 7 rokov pred
rodič
commit
c1e362ecf9
100 zmenil súbory, kde vykonal 43466 pridanie a 39278 odobranie
  1. 5 0
      .gitignore
  2. 1 1
      .vscode/launch.json
  3. 13 6
      .vscode/tasks.json
  4. 11196 10506
      Playground/babylon.d.txt
  5. 4 0
      Playground/scenes/BoomBox/BoomBox.gltf
  6. 19 5
      Tools/Gulp/config.json
  7. 32 12
      Tools/Gulp/gulpfile.js
  8. 0 69
      Viewer/dist/viewer.js
  9. 0 69
      Viewer/dist/viewer.min.js
  10. 2 2
      dist/babylon.glTF2Interface.d.ts
  11. 5565 4881
      dist/preview release/babylon.d.ts
  12. 54 53
      dist/preview release/babylon.js
  13. 1974 870
      dist/preview release/babylon.max.js
  14. 55 54
      dist/preview release/babylon.worker.js
  15. 7228 6544
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  16. 57 56
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  17. 3139 2438
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  18. 3141 2440
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  19. 1976 872
      dist/preview release/es6.js
  20. 13 1
      dist/preview release/gui/babylon.gui.d.ts
  21. 42 5
      dist/preview release/gui/babylon.gui.js
  22. 3 3
      dist/preview release/gui/babylon.gui.min.js
  23. 13 1
      dist/preview release/gui/babylon.gui.module.d.ts
  24. 1 1
      dist/preview release/gui/package.json
  25. 4 4
      dist/preview release/inspector/babylon.inspector.bundle.js
  26. 4 4
      dist/preview release/inspector/babylon.inspector.min.js
  27. 1 1
      dist/preview release/inspector/package.json
  28. 57 23
      dist/preview release/loaders/babylon.glTF1FileLoader.d.ts
  29. 107 81
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  30. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  31. 241 386
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  32. 1183 1519
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  33. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  34. 233 380
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  35. 1232 1558
      dist/preview release/loaders/babylon.glTFFileLoader.js
  36. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  37. 1 1
      dist/preview release/loaders/babylon.objFileLoader.d.ts
  38. 4 7
      dist/preview release/loaders/babylon.objFileLoader.js
  39. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  40. 1 1
      dist/preview release/loaders/babylon.stlFileLoader.d.ts
  41. 4 7
      dist/preview release/loaders/babylon.stlFileLoader.js
  42. 1 1
      dist/preview release/loaders/babylon.stlFileLoader.min.js
  43. 1231 1563
      dist/preview release/loaders/babylonjs.loaders.js
  44. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  45. 235 382
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  46. 1 1
      dist/preview release/loaders/package.json
  47. 1 1
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  48. 1 1
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js
  49. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.min.js
  50. 3 3
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  51. 1 1
      dist/preview release/materialsLibrary/package.json
  52. 1 1
      dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js
  53. 1 1
      dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js
  54. 1 1
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js
  55. 1 1
      dist/preview release/postProcessesLibrary/package.json
  56. 1 1
      dist/preview release/proceduralTexturesLibrary/package.json
  57. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  58. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  59. 2 2
      dist/preview release/serializers/babylonjs.serializers.module.d.ts
  60. 1 1
      dist/preview release/serializers/package.json
  61. 2 907
      dist/preview release/typedocValidationBaseline.json
  62. 68 67
      dist/preview release/viewer/babylon.viewer.js
  63. 1 1
      dist/preview release/viewer/package.json
  64. 24 5
      dist/preview release/what's new.md
  65. 45 7
      gui/src/controls/line.ts
  66. 4 7
      loaders/src/OBJ/babylon.objFileLoader.ts
  67. 4 7
      loaders/src/STL/babylon.stlFileLoader.ts
  68. 42 12
      loaders/src/glTF/1.0/babylon.glTFLoader.ts
  69. 0 24
      loaders/src/glTF/1.0/babylon.glTFLoaderUtils.ts
  70. 77 91
      loaders/src/glTF/2.0/Extensions/KHR_lights.ts
  71. 55 31
      loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts
  72. 108 91
      loaders/src/glTF/2.0/Extensions/MSFT_lod.ts
  73. 900 1177
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  74. 41 50
      loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts
  75. 57 260
      loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts
  76. 21 0
      loaders/src/glTF/2.0/babylon.glTFLoaderUtilities.ts
  77. 0 36
      loaders/src/glTF/2.0/babylon.glTFLoaderUtils.ts
  78. 80 52
      loaders/src/glTF/babylon.glTFFileLoader.ts
  79. 2 2
      package.json
  80. 0 4
      sandbox/index.js
  81. 23 2
      src/Cameras/VR/babylon.vrExperienceHelper.ts
  82. 2 1
      src/Engine/babylon.engine.ts
  83. 94 0
      src/Helpers/babylon.videoDome.ts
  84. 639 0
      src/Layer/babylon.effectLayer.ts
  85. 419 0
      src/Layer/babylon.glowLayer.ts
  86. 667 0
      src/Layer/babylon.highlightLayer.ts
  87. 0 996
      src/Layer/babylon.highlightlayer.ts
  88. 20 0
      src/Lights/Shadows/babylon.shadowGenerator.ts
  89. 292 295
      src/Loading/Plugins/babylon.babylonFileLoader.ts
  90. 224 33
      src/Loading/babylon.sceneLoader.ts
  91. 29 2
      src/Materials/Background/babylon.backgroundMaterial.ts
  92. 319 266
      src/Materials/PBR/babylon.pbrBaseMaterial.ts
  93. 28 0
      src/Materials/Textures/babylon.cubeTexture.ts
  94. 28 0
      src/Materials/Textures/babylon.renderTargetTexture.ts
  95. 8 10
      src/Materials/Textures/babylon.texture.ts
  96. 4 1
      src/Materials/Textures/babylon.videoTexture.ts
  97. 16 2
      src/Materials/babylon.material.ts
  98. 8 3
      src/Materials/babylon.materialHelper.ts
  99. 14 0
      src/Materials/babylon.standardMaterial.ts
  100. 0 0
      src/Mesh/babylon.mesh.ts

+ 5 - 0
.gitignore

@@ -24,6 +24,7 @@ postProcessLibrary/src/**/*.js
 inspector/src/**/*.js
 serializers/src/**/*.js
 gui/src/**/*.js
+viewer/src/**/*.js
 tests/unit/**/*.js
 !tests/unit/karma.conf.js
 
@@ -169,3 +170,7 @@ localDev/src/*
 /localDev/src/index.js
 package-lock.json
 dist/preview release/package/
+
+# viewer dist files
+/Viewer/dist/viewer.js
+/Viewer/dist/viewer.min.js

+ 1 - 1
.vscode/launch.json

@@ -1,5 +1,5 @@
 {
-    "version": "0.1.0",
+    "version": "2.0.0",
     "configurations": [
         {
             "name": "Launch Viewer (Chrome)",

+ 13 - 6
.vscode/tasks.json

@@ -1,19 +1,26 @@
 {
     // See https://go.microsoft.com/fwlink/?LinkId=733558
     // for the documentation about the tasks.json format
-    "version": "0.1.0",
+    "version": "2.0.0",
     "command": "gulp",
-    "isShellCommand": true,
     "args": [],
-    "showOutput": "always",
+    "type": "shell",
     "options": {
         "cwd": "${workspaceRoot}/Tools/Gulp"
     },
+    "presentation": {
+        "echo": true,
+        "reveal": "always",
+        "focus": false,
+        "panel": "shared"
+    },
     "tasks": [
         { 
-            "taskName": "run",
-            // Hijack Test Command for easy shortcut
-            "isTestCommand": true,
+            "label": "run",
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            },
             "isBackground": true,
             "problemMatcher": {
                 "owner": "typescript",

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 11196 - 10506
Playground/babylon.d.txt


+ 4 - 0
Playground/scenes/BoomBox/BoomBox.gltf

@@ -158,15 +158,19 @@
   ],
   "textures": [
     {
+      "name": "baseColor",
       "source": 0
     },
     {
+      "name": "occlusionRoughnessMetallic",
       "source": 1
     },
     {
+      "name": "normal",
       "source": 2
     },
     {
+      "name": "emissive",
       "source": 3
     }
   ]

+ 19 - 5
Tools/Gulp/config.json

@@ -86,7 +86,8 @@
             "nullEngine",
             "instrumentation",
             "backgroundMaterial",
-            "environmentHelper"
+            "environmentHelper",
+            "videoDome"
         ],
         "minimal": [
             "freeCamera",
@@ -178,6 +179,7 @@
                 "../../src/babylon.mixins.js",
                 "../../src/Engine/babylon.webgl2.js",
                 "../../src/Tools/babylon.decorators.js",
+                "../../src/Tools/babylon.deferred.js",
                 "../../src/Tools/babylon.observable.js",
                 "../../src/Tools/babylon.smartArray.js",
                 "../../src/Tools/babylon.tools.js",
@@ -1041,7 +1043,9 @@
             "files": [
                 "../../src/Rendering/babylon.outlineRenderer.js",
                 "../../src/Rendering/babylon.edgesRenderer.js",
-                "../../src/Layer/babylon.highlightlayer.js"
+                "../../src/Layer/babylon.effectLayer.js",
+                "../../src/Layer/babylon.highlightLayer.js",
+                "../../src/Layer/babylon.glowLayer.js"
             ],
             "dependUpon": [
                 "shaderMaterial"
@@ -1120,6 +1124,16 @@
                 "backgroundMaterial",
                 "additionalTextures"
             ]
+        },
+        "videoDome": {
+            "files": [
+                "../../src/Helpers/babylon.videoDome.js"
+            ],
+            "dependUpon": [
+                "core",
+                "meshBuilder",
+                "additionalTextures"
+            ]
         }
     },
     "typescript": [
@@ -1460,9 +1474,9 @@
             {
                 "files": [
                     "../../loaders/src/glTF/babylon.glTFFileLoader.ts",
+                    "../../loaders/src/glTF/2.0/babylon.glTFLoaderUtilities.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoader.ts",
-                    "../../loaders/src/glTF/2.0/babylon.glTFLoaderUtils.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts",
                     "../../loaders/src/glTF/2.0/Extensions/MSFT_lod.ts",
                     "../../loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts",
@@ -1480,9 +1494,9 @@
                     "../../loaders/src/glTF/1.0/babylon.glTFLoaderExtension.ts",
                     "../../loaders/src/glTF/1.0/babylon.glTFBinaryExtension.ts",
                     "../../loaders/src/glTF/1.0/babylon.glTFMaterialsCommonExtension.ts",
+                    "../../loaders/src/glTF/2.0/babylon.glTFLoaderUtilities.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoader.ts",
-                    "../../loaders/src/glTF/2.0/babylon.glTFLoaderUtils.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts",
                     "../../loaders/src/glTF/2.0/Extensions/MSFT_lod.ts",
                     "../../loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts",
@@ -1681,4 +1695,4 @@
             ]
         }
     }
-}
+}

+ 32 - 12
Tools/Gulp/gulpfile.js

@@ -436,22 +436,42 @@ var buildExternalLibrary = function (library, settings, watch) {
                 let build = wpBuild
                     .pipe(addModuleExports(library.moduleDeclaration, false, false, true));
 
+                let unminifiedOutpus = [];
+                let minifiedOutputs = [];
                 settings.build.outputs.forEach(out => {
-                    let outBuild = build;
                     if (out.minified) {
-                        outBuild = build
-                            .pipe(uglify())
-                            .pipe(optimisejs())
+                        out.destination.forEach(dest => {
+                            minifiedOutputs.push(dest);
+                        });
+                    } else {
+                        out.destination.forEach(dest => {
+                            unminifiedOutpus.push(dest);
+                        });
                     }
+                });
 
-                    out.destination.forEach(dest => {
-                        var outputDirectory = config.build.outputDirectory + dest.outputDirectory;
-                        let destBuild = outBuild
-                            .pipe(rename(dest.filename.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
-                            .pipe(gulp.dest(outputDirectory));
-                        sequence.push(destBuild);
-                    });
-                })
+                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));
+                }
+
+                unminifiedOutpus.forEach(dest => {
+                    processDestination(dest);
+                });
+
+                if (minifiedOutputs.length) {
+                    build = build
+                        .pipe(uglify())
+                        .pipe(optimisejs())
+                }
+
+                minifiedOutputs.forEach(dest => {
+                    processDestination(dest);
+                });
+
+                sequence.push(build);
             } else {
                 sequence.push(
                     wpBuild

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 69
Viewer/dist/viewer.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 69
Viewer/dist/viewer.min.js


+ 2 - 2
dist/babylon.glTF2Interface.d.ts

@@ -22,7 +22,7 @@ declare module BABYLON.GLTF2 {
         SCALE = "scale",
         WEIGHTS = "weights",
     }
-    const enum AnimationInterpolation {
+    const enum AnimationSamplerInterpolation {
         LINEAR = "LINEAR",
         STEP = "STEP",
         CUBICSPLINE = "CUBICSPLINE",
@@ -110,7 +110,7 @@ declare module BABYLON.GLTF2 {
     }
     interface IAnimationSampler extends IProperty {
         input: number;
-        interpolation?: AnimationInterpolation;
+        interpolation?: AnimationSamplerInterpolation;
         output: number;
     }
     interface IAnimation extends IChildRootProperty {

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 5565 - 4881
dist/preview release/babylon.d.ts


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 54 - 53
dist/preview release/babylon.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1974 - 870
dist/preview release/babylon.max.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 55 - 54
dist/preview release/babylon.worker.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 7228 - 6544
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 57 - 56
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 3139 - 2438
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 3141 - 2440
dist/preview release/customConfigurations/minimalGLTFViewer/es6.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1976 - 872
dist/preview release/es6.js


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

@@ -436,7 +436,19 @@ declare module BABYLON.GUI {
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _measure(): void;
         protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        _moveToProjectedPosition(projectedPosition: Vector3): void;
+        /**
+         * Move one end of the line given 3D cartesian coordinates.
+         * @param position Targeted world position
+         * @param scene Scene
+         * @param end (opt) Set to true to assign x2 and y2 coordinates of the line. Default assign to x1 and y1.
+         */
+        moveToVector3(position: Vector3, scene: Scene, end?: boolean): void;
+        /**
+         * Move one end of the line to a position in screen absolute space.
+         * @param projectedPosition Position in screen absolute space (X, Y)
+         * @param end (opt) Set to true to assign x2 and y2 coordinates of the line. Default assign to x1 and y1.
+         */
+        _moveToProjectedPosition(projectedPosition: Vector3, end?: boolean): void;
     }
 }
 

+ 42 - 5
dist/preview release/gui/babylon.gui.js

@@ -2600,11 +2600,48 @@ var BABYLON;
                 this._currentMeasure.left = Math.min(this._x1.getValue(this._host), this._effectiveX2) - this._lineWidth / 2;
                 this._currentMeasure.top = Math.min(this._y1.getValue(this._host), this._effectiveY2) - this._lineWidth / 2;
             };
-            Line.prototype._moveToProjectedPosition = function (projectedPosition) {
-                this.x1 = (projectedPosition.x + this._linkOffsetX.getValue(this._host)) + "px";
-                this.y1 = (projectedPosition.y + this._linkOffsetY.getValue(this._host)) + "px";
-                this._x1.ignoreAdaptiveScaling = true;
-                this._y1.ignoreAdaptiveScaling = true;
+            /**
+             * Move one end of the line given 3D cartesian coordinates.
+             * @param position Targeted world position
+             * @param scene Scene
+             * @param end (opt) Set to true to assign x2 and y2 coordinates of the line. Default assign to x1 and y1.
+             */
+            Line.prototype.moveToVector3 = function (position, scene, end) {
+                if (end === void 0) { end = false; }
+                if (!this._host || this._root !== this._host._rootContainer) {
+                    BABYLON.Tools.Error("Cannot move a control to a vector3 if the control is not at root level");
+                    return;
+                }
+                var globalViewport = this._host._getGlobalViewport(scene);
+                var projectedPosition = BABYLON.Vector3.Project(position, BABYLON.Matrix.Identity(), scene.getTransformMatrix(), globalViewport);
+                this._moveToProjectedPosition(projectedPosition, end);
+                if (projectedPosition.z < 0 || projectedPosition.z > 1) {
+                    this.notRenderable = true;
+                    return;
+                }
+                this.notRenderable = false;
+            };
+            /**
+             * Move one end of the line to a position in screen absolute space.
+             * @param projectedPosition Position in screen absolute space (X, Y)
+             * @param end (opt) Set to true to assign x2 and y2 coordinates of the line. Default assign to x1 and y1.
+             */
+            Line.prototype._moveToProjectedPosition = function (projectedPosition, end) {
+                if (end === void 0) { end = false; }
+                var x = (projectedPosition.x + this._linkOffsetX.getValue(this._host)) + "px";
+                var y = (projectedPosition.y + this._linkOffsetY.getValue(this._host)) + "px";
+                if (end) {
+                    this.x2 = x;
+                    this.y2 = y;
+                    this._x2.ignoreAdaptiveScaling = true;
+                    this._y2.ignoreAdaptiveScaling = true;
+                }
+                else {
+                    this.x1 = x;
+                    this.y1 = y;
+                    this._x1.ignoreAdaptiveScaling = true;
+                    this._y1.ignoreAdaptiveScaling = true;
+                }
             };
             return Line;
         }(GUI.Control));

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 3 - 3
dist/preview release/gui/babylon.gui.min.js


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

@@ -442,7 +442,19 @@ declare module BABYLON.GUI {
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _measure(): void;
         protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        _moveToProjectedPosition(projectedPosition: Vector3): void;
+        /**
+         * Move one end of the line given 3D cartesian coordinates.
+         * @param position Targeted world position
+         * @param scene Scene
+         * @param end (opt) Set to true to assign x2 and y2 coordinates of the line. Default assign to x1 and y1.
+         */
+        moveToVector3(position: Vector3, scene: Scene, end?: boolean): void;
+        /**
+         * Move one end of the line to a position in screen absolute space.
+         * @param projectedPosition Position in screen absolute space (X, Y)
+         * @param end (opt) Set to true to assign x2 and y2 coordinates of the line. Default assign to x1 and y1.
+         */
+        _moveToProjectedPosition(projectedPosition: Vector3, end?: boolean): void;
     }
 }
 

+ 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.2.0-alpha6",
+    "version": "3.2.0-alpha7",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 4 - 4
dist/preview release/inspector/babylon.inspector.bundle.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 4 - 4
dist/preview release/inspector/babylon.inspector.min.js


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

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

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

@@ -28,19 +28,40 @@ declare module BABYLON {
         json: Object;
         bin: Nullable<ArrayBufferView>;
     }
+    interface IGLTFLoaderExtension {
+        /**
+         * The name of this extension.
+         */
+        readonly name: string;
+        /**
+         * Whether this extension is enabled.
+         */
+        enabled: boolean;
+    }
+    enum GLTFLoaderState {
+        Loading = 0,
+        Ready = 1,
+        Complete = 2,
+    }
     interface IGLTFLoader extends IDisposable {
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         compileMaterials: boolean;
         useClipPlane: boolean;
         compileShadowGenerators: boolean;
-        onDisposeObservable: Observable<IGLTFLoader>;
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
         onCompleteObservable: Observable<IGLTFLoader>;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+        onDisposeObservable: Observable<IGLTFLoader>;
+        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        state: Nullable<GLTFLoaderState>;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
     }
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         static CreateGLTFLoaderV1: () => IGLTFLoader;
@@ -78,19 +99,19 @@ declare module BABYLON {
         /**
          * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
          */
-        onMeshLoadedObservable: Observable<AbstractMesh>;
+        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
         private _onMeshLoadedObserver;
         onMeshLoaded: (mesh: AbstractMesh) => void;
         /**
          * Raised when the loader creates a texture after parsing the glTF properties of the texture.
          */
-        onTextureLoadedObservable: Observable<BaseTexture>;
+        readonly onTextureLoadedObservable: Observable<BaseTexture>;
         private _onTextureLoadedObserver;
         onTextureLoaded: (Texture: BaseTexture) => void;
         /**
          * Raised when the loader creates a material after parsing the glTF properties of the material.
          */
-        onMaterialLoadedObservable: Observable<Material>;
+        readonly onMaterialLoadedObservable: Observable<Material>;
         private _onMaterialLoadedObserver;
         onMaterialLoaded: (Material: Material) => void;
         /**
@@ -98,15 +119,26 @@ declare module BABYLON {
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets without LODs, raised when the model is complete, immediately after onSuccess.
          */
-        onCompleteObservable: Observable<GLTFFileLoader>;
+        readonly onCompleteObservable: Observable<GLTFFileLoader>;
         private _onCompleteObserver;
         onComplete: () => void;
         /**
         * Raised when the loader is disposed.
         */
-        onDisposeObservable: Observable<GLTFFileLoader>;
+        readonly onDisposeObservable: Observable<GLTFFileLoader>;
         private _onDisposeObserver;
         onDispose: () => void;
+        /**
+         * Raised after a loader extension is created.
+         * Set additional options for a loader extension in this event.
+         */
+        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        private _onExtensionLoadedObserver;
+        onExtensionLoaded: (extension: IGLTFLoaderExtension) => void;
+        /**
+         * The loader state or null if not active.
+         */
+        readonly loaderState: Nullable<GLTFLoaderState>;
         private _loader;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
@@ -114,9 +146,13 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAssetsAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: (assets: AssetContainer) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
         canDirectLoad(data: string): boolean;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
@@ -534,9 +570,17 @@ declare module BABYLON.GLTF1 {
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
         onCompleteObservable: Observable<IGLTFLoader>;
+        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        state: Nullable<GLTFLoaderState>;
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: SceneLoaderProgressEvent) => void, onError: (message: string) => void): boolean;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: SceneLoaderProgressEvent) => void, onError: (message: string) => void): void;
+        private _importMeshAsync(meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError);
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        private _loadAsync(scene, data, rootUrl, onSuccess, onProgress, onError);
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress: (event: SceneLoaderProgressEvent) => void): Promise<void>;
         private _loadShadersAsync(gltfRuntime, onload);
         private _loadBuffersAsync(gltfRuntime, onLoad, onProgress?);
         private _createNodes(gltfRuntime);
@@ -567,16 +611,6 @@ declare module BABYLON.GLTF1 {
          */
         static SetUniform(shaderMaterial: ShaderMaterial | Effect, uniform: string, value: any, type: number): boolean;
         /**
-        * If the uri is a base64 string
-        * @param uri: the uri to test
-        */
-        static IsBase64(uri: string): boolean;
-        /**
-        * Decode the base64 uri
-        * @param uri: the uri to decode
-        */
-        static DecodeBase64(uri: string): ArrayBuffer;
-        /**
         * Returns the wrap mode of the texture
         * @param mode: the mode value
         */

+ 107 - 81
dist/preview release/loaders/babylon.glTF1FileLoader.js

@@ -27,6 +27,12 @@ var BABYLON;
          */
         GLTFLoaderAnimationStartMode[GLTFLoaderAnimationStartMode["ALL"] = 2] = "ALL";
     })(GLTFLoaderAnimationStartMode = BABYLON.GLTFLoaderAnimationStartMode || (BABYLON.GLTFLoaderAnimationStartMode = {}));
+    var GLTFLoaderState;
+    (function (GLTFLoaderState) {
+        GLTFLoaderState[GLTFLoaderState["Loading"] = 0] = "Loading";
+        GLTFLoaderState[GLTFLoaderState["Ready"] = 1] = "Ready";
+        GLTFLoaderState[GLTFLoaderState["Complete"] = 2] = "Complete";
+    })(GLTFLoaderState = BABYLON.GLTFLoaderState || (BABYLON.GLTFLoaderState = {}));
     var GLTFFileLoader = /** @class */ (function () {
         function GLTFFileLoader() {
             // #region Common options
@@ -80,6 +86,11 @@ var BABYLON;
             * Raised when the loader is disposed.
             */
             this.onDisposeObservable = new BABYLON.Observable();
+            /**
+             * Raised after a loader extension is created.
+             * Set additional options for a loader extension in this event.
+             */
+            this.onExtensionLoadedObservable = new BABYLON.Observable();
             // #endregion
             this._loader = null;
             this.name = "gltf";
@@ -148,6 +159,26 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(GLTFFileLoader.prototype, "onExtensionLoaded", {
+            set: function (callback) {
+                if (this._onExtensionLoadedObserver) {
+                    this.onExtensionLoadedObservable.remove(this._onExtensionLoadedObserver);
+                }
+                this._onExtensionLoadedObserver = this.onExtensionLoadedObservable.add(callback);
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(GLTFFileLoader.prototype, "loaderState", {
+            /**
+             * The loader state or null if not active.
+             */
+            get: function () {
+                return this._loader ? this._loader.state : null;
+            },
+            enumerable: true,
+            configurable: true
+        });
         /**
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
@@ -156,65 +187,42 @@ var BABYLON;
                 this._loader.dispose();
                 this._loader = null;
             }
-            this.onParsedObservable.clear();
             this.onMeshLoadedObservable.clear();
             this.onTextureLoadedObservable.clear();
             this.onMaterialLoadedObservable.clear();
-            this.onCompleteObservable.clear();
             this.onDisposeObservable.notifyObservers(this);
             this.onDisposeObservable.clear();
         };
-        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
-            try {
-                var loaderData = this._parse(data);
-                this._loader = this._getLoader(loaderData);
-                this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
-            }
-            catch (e) {
-                if (onError) {
-                    onError(e.message, e);
-                }
-                else {
-                    BABYLON.Tools.Error(e.message);
-                }
-            }
+        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress) {
+            var _this = this;
+            return Promise.resolve().then(function () {
+                var loaderData = _this._parse(data);
+                _this._loader = _this._getLoader(loaderData);
+                return _this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onProgress);
+            });
         };
-        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
-            try {
-                var loaderData = this._parse(data);
-                this._loader = this._getLoader(loaderData);
-                this._loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
-            }
-            catch (e) {
-                if (onError) {
-                    onError(e.message, e);
-                }
-                else {
-                    BABYLON.Tools.Error(e.message);
-                }
-            }
+        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress) {
+            var _this = this;
+            return Promise.resolve().then(function () {
+                var loaderData = _this._parse(data);
+                _this._loader = _this._getLoader(loaderData);
+                return _this._loader.loadAsync(scene, loaderData, rootUrl, onProgress);
+            });
         };
-        GLTFFileLoader.prototype.loadAssetsAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
-            try {
-                var loaderData = this._parse(data);
-                this._loader = this._getLoader(loaderData);
-                this._loader.importMeshAsync(null, scene, loaderData, rootUrl, function (meshes, particleSystems, skeletons) {
+        GLTFFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress) {
+            var _this = this;
+            return Promise.resolve().then(function () {
+                var loaderData = _this._parse(data);
+                _this._loader = _this._getLoader(loaderData);
+                return _this._loader.importMeshAsync(null, scene, loaderData, rootUrl, onProgress).then(function (result) {
                     var container = new BABYLON.AssetContainer(scene);
-                    Array.prototype.push.apply(container.meshes, meshes);
-                    Array.prototype.push.apply(container.particleSystems, particleSystems);
-                    Array.prototype.push.apply(container.skeletons, skeletons);
+                    Array.prototype.push.apply(container.meshes, result.meshes);
+                    Array.prototype.push.apply(container.particleSystems, result.particleSystems);
+                    Array.prototype.push.apply(container.skeletons, result.skeletons);
                     container.removeAllFromScene();
-                    onSuccess(container);
-                }, onProgress, onError);
-            }
-            catch (e) {
-                if (onError) {
-                    onError(e.message, e);
-                }
-                else {
-                    BABYLON.Tools.Error(e.message);
-                }
-            }
+                    return container;
+                });
+            });
         };
         GLTFFileLoader.prototype.canDirectLoad = function (data) {
             return ((data.indexOf("scene") !== -1) && (data.indexOf("node") !== -1));
@@ -234,6 +242,7 @@ var BABYLON;
                 };
             }
             this.onParsedObservable.notifyObservers(parsedData);
+            this.onParsedObservable.clear();
             return parsedData;
         };
         GLTFFileLoader.prototype._getLoader = function (loaderData) {
@@ -270,7 +279,14 @@ var BABYLON;
             loader.onMeshLoadedObservable.add(function (mesh) { return _this.onMeshLoadedObservable.notifyObservers(mesh); });
             loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
             loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
-            loader.onCompleteObservable.add(function () { return _this.onCompleteObservable.notifyObservers(_this); });
+            loader.onExtensionLoadedObservable.add(function (extension) { return _this.onExtensionLoadedObservable.notifyObservers(extension); });
+            loader.onCompleteObservable.add(function () {
+                _this.onMeshLoadedObservable.clear();
+                _this.onTextureLoadedObservable.clear();
+                _this.onMaterialLoadedObservable.clear();
+                _this.onCompleteObservable.notifyObservers(_this);
+                _this.onCompleteObservable.clear();
+            });
             return loader;
         };
         GLTFFileLoader._parseBinary = function (data) {
@@ -1009,8 +1025,7 @@ var BABYLON;
                 return newMesh;
             }
             var subMaterials = [];
-            var vertexData = new BABYLON.VertexData();
-            var geometry = new BABYLON.Geometry(id, gltfRuntime.scene, vertexData, false, newMesh);
+            var vertexData = null;
             var verticesStarts = new Array();
             var verticesCounts = new Array();
             var indexStarts = new Array();
@@ -1094,7 +1109,12 @@ var BABYLON;
                         tempVertexData.indices = new Int32Array(indices);
                         indexCounts.push(tempVertexData.indices.length);
                     }
-                    vertexData.merge(tempVertexData);
+                    if (!vertexData) {
+                        vertexData = tempVertexData;
+                    }
+                    else {
+                        vertexData.merge(tempVertexData);
+                    }
                     // Sub material
                     var material_1 = gltfRuntime.scene.getMaterialByID(primitive.material);
                     subMaterials.push(material_1 === null ? GLTF1.GLTFUtils.GetDefaultMaterial(gltfRuntime.scene) : material_1);
@@ -1118,7 +1138,7 @@ var BABYLON;
                 newMesh.material = material;
             }
             // Apply geometry
-            geometry.setAllVerticesData(vertexData, false);
+            new BABYLON.Geometry(id, gltfRuntime.scene, vertexData, false, newMesh);
             newMesh.computeWorldMatrix(true);
             // Apply submeshes
             newMesh.subMeshes = [];
@@ -1593,8 +1613,8 @@ var BABYLON;
             };
             GLTFLoaderBase.LoadBufferAsync = function (gltfRuntime, id, onSuccess, onError, onProgress) {
                 var buffer = gltfRuntime.buffers[id];
-                if (GLTF1.GLTFUtils.IsBase64(buffer.uri)) {
-                    setTimeout(function () { return onSuccess(new Uint8Array(GLTF1.GLTFUtils.DecodeBase64(buffer.uri))); });
+                if (BABYLON.Tools.IsBase64(buffer.uri)) {
+                    setTimeout(function () { return onSuccess(new Uint8Array(BABYLON.Tools.DecodeBase64(buffer.uri))); });
                 }
                 else {
                     BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + buffer.uri, function (data) { return onSuccess(new Uint8Array(data)); }, onProgress, undefined, true, function (request) {
@@ -1615,8 +1635,8 @@ var BABYLON;
                     return;
                 }
                 var source = gltfRuntime.images[texture.source];
-                if (GLTF1.GLTFUtils.IsBase64(source.uri)) {
-                    setTimeout(function () { return onSuccess(new Uint8Array(GLTF1.GLTFUtils.DecodeBase64(source.uri))); });
+                if (BABYLON.Tools.IsBase64(source.uri)) {
+                    setTimeout(function () { return onSuccess(new Uint8Array(BABYLON.Tools.DecodeBase64(source.uri))); });
                 }
                 else {
                     BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + source.uri, function (data) { return onSuccess(new Uint8Array(data)); }, undefined, undefined, true, function (request) {
@@ -1654,7 +1674,7 @@ var BABYLON;
             };
             GLTFLoaderBase.LoadShaderStringAsync = function (gltfRuntime, id, onSuccess, onError) {
                 var shader = gltfRuntime.shaders[id];
-                if (GLTF1.GLTFUtils.IsBase64(shader.uri)) {
+                if (BABYLON.Tools.IsBase64(shader.uri)) {
                     var shaderString = atob(shader.uri.split(",")[1]);
                     onSuccess(shaderString);
                 }
@@ -1818,6 +1838,8 @@ var BABYLON;
                 this.onTextureLoadedObservable = new BABYLON.Observable();
                 this.onMaterialLoadedObservable = new BABYLON.Observable();
                 this.onCompleteObservable = new BABYLON.Observable();
+                this.onExtensionLoadedObservable = new BABYLON.Observable();
+                this.state = null;
             }
             GLTFLoader.RegisterExtension = function (extension) {
                 if (GLTFLoader.Extensions[extension.name]) {
@@ -1828,7 +1850,7 @@ var BABYLON;
             };
             GLTFLoader.prototype.dispose = function () { };
             // #endregion
-            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
+            GLTFLoader.prototype._importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 scene.useRightHandedSystem = true;
                 GLTF1.GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, function (gltfRuntime) {
@@ -1879,7 +1901,21 @@ var BABYLON;
                 }, onError);
                 return true;
             };
-            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
+            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress) {
+                var _this = this;
+                return new Promise(function (resolve, reject) {
+                    _this._importMeshAsync(meshesNames, scene, data, rootUrl, function (meshes, particleSystems, skeletons) {
+                        resolve({
+                            meshes: meshes,
+                            particleSystems: particleSystems,
+                            skeletons: skeletons
+                        });
+                    }, onProgress, function (message) {
+                        reject(new Error(message));
+                    });
+                });
+            };
+            GLTFLoader.prototype._loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 scene.useRightHandedSystem = true;
                 GLTF1.GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, function (gltfRuntime) {
@@ -1903,6 +1939,16 @@ var BABYLON;
                     }, onError);
                 }, onError);
             };
+            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress) {
+                var _this = this;
+                return new Promise(function (resolve, reject) {
+                    _this._loadAsync(scene, data, rootUrl, function () {
+                        resolve();
+                    }, onProgress, function (message) {
+                        reject(new Error(message));
+                    });
+                });
+            };
             GLTFLoader.prototype._loadShadersAsync = function (gltfRuntime, onload) {
                 var hasShaders = false;
                 var processShader = function (sha, shader) {
@@ -2094,26 +2140,6 @@ var BABYLON;
                 }
             };
             /**
-            * If the uri is a base64 string
-            * @param uri: the uri to test
-            */
-            GLTFUtils.IsBase64 = function (uri) {
-                return uri.length < 5 ? false : uri.substr(0, 5) === "data:";
-            };
-            /**
-            * Decode the base64 uri
-            * @param uri: the uri to decode
-            */
-            GLTFUtils.DecodeBase64 = function (uri) {
-                var decodedString = atob(uri.split(",")[1]);
-                var bufferLength = decodedString.length;
-                var bufferView = new Uint8Array(new ArrayBuffer(bufferLength));
-                for (var i = 0; i < bufferLength; i++) {
-                    bufferView[i] = decodedString.charCodeAt(i);
-                }
-                return bufferView.buffer;
-            };
-            /**
             * Returns the wrap mode of the texture
             * @param mode: the mode value
             */

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


+ 241 - 386
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -28,19 +28,40 @@ declare module BABYLON {
         json: Object;
         bin: Nullable<ArrayBufferView>;
     }
+    interface IGLTFLoaderExtension {
+        /**
+         * The name of this extension.
+         */
+        readonly name: string;
+        /**
+         * Whether this extension is enabled.
+         */
+        enabled: boolean;
+    }
+    enum GLTFLoaderState {
+        Loading = 0,
+        Ready = 1,
+        Complete = 2,
+    }
     interface IGLTFLoader extends IDisposable {
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         compileMaterials: boolean;
         useClipPlane: boolean;
         compileShadowGenerators: boolean;
-        onDisposeObservable: Observable<IGLTFLoader>;
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
         onCompleteObservable: Observable<IGLTFLoader>;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+        onDisposeObservable: Observable<IGLTFLoader>;
+        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        state: Nullable<GLTFLoaderState>;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
     }
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         static CreateGLTFLoaderV1: () => IGLTFLoader;
@@ -78,19 +99,19 @@ declare module BABYLON {
         /**
          * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
          */
-        onMeshLoadedObservable: Observable<AbstractMesh>;
+        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
         private _onMeshLoadedObserver;
         onMeshLoaded: (mesh: AbstractMesh) => void;
         /**
          * Raised when the loader creates a texture after parsing the glTF properties of the texture.
          */
-        onTextureLoadedObservable: Observable<BaseTexture>;
+        readonly onTextureLoadedObservable: Observable<BaseTexture>;
         private _onTextureLoadedObserver;
         onTextureLoaded: (Texture: BaseTexture) => void;
         /**
          * Raised when the loader creates a material after parsing the glTF properties of the material.
          */
-        onMaterialLoadedObservable: Observable<Material>;
+        readonly onMaterialLoadedObservable: Observable<Material>;
         private _onMaterialLoadedObserver;
         onMaterialLoaded: (Material: Material) => void;
         /**
@@ -98,15 +119,26 @@ declare module BABYLON {
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets without LODs, raised when the model is complete, immediately after onSuccess.
          */
-        onCompleteObservable: Observable<GLTFFileLoader>;
+        readonly onCompleteObservable: Observable<GLTFFileLoader>;
         private _onCompleteObserver;
         onComplete: () => void;
         /**
         * Raised when the loader is disposed.
         */
-        onDisposeObservable: Observable<GLTFFileLoader>;
+        readonly onDisposeObservable: Observable<GLTFFileLoader>;
         private _onDisposeObserver;
         onDispose: () => void;
+        /**
+         * Raised after a loader extension is created.
+         * Set additional options for a loader extension in this event.
+         */
+        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        private _onExtensionLoadedObserver;
+        onExtensionLoaded: (extension: IGLTFLoaderExtension) => void;
+        /**
+         * The loader state or null if not active.
+         */
+        readonly loaderState: Nullable<GLTFLoaderState>;
         private _loader;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
@@ -114,9 +146,13 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAssetsAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: (assets: AssetContainer) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
         canDirectLoad(data: string): boolean;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
@@ -133,440 +169,259 @@ declare module BABYLON {
 
 
 declare module BABYLON.GLTF2 {
-    /**
-    * Enums
-    */
-    enum EComponentType {
-        BYTE = 5120,
-        UNSIGNED_BYTE = 5121,
-        SHORT = 5122,
-        UNSIGNED_SHORT = 5123,
-        UNSIGNED_INT = 5125,
-        FLOAT = 5126,
-    }
-    enum EMeshPrimitiveMode {
-        POINTS = 0,
-        LINES = 1,
-        LINE_LOOP = 2,
-        LINE_STRIP = 3,
-        TRIANGLES = 4,
-        TRIANGLE_STRIP = 5,
-        TRIANGLE_FAN = 6,
-    }
-    enum ETextureMagFilter {
-        NEAREST = 9728,
-        LINEAR = 9729,
-    }
-    enum ETextureMinFilter {
-        NEAREST = 9728,
-        LINEAR = 9729,
-        NEAREST_MIPMAP_NEAREST = 9984,
-        LINEAR_MIPMAP_NEAREST = 9985,
-        NEAREST_MIPMAP_LINEAR = 9986,
-        LINEAR_MIPMAP_LINEAR = 9987,
-    }
-    enum ETextureWrapMode {
-        CLAMP_TO_EDGE = 33071,
-        MIRRORED_REPEAT = 33648,
-        REPEAT = 10497,
-    }
-    /**
-    * Interfaces
-    */
-    interface IGLTFProperty {
-        extensions?: {
-            [key: string]: any;
-        };
-        extras?: any;
-    }
-    interface IGLTFChildRootProperty extends IGLTFProperty {
-        name?: string;
-    }
-    interface IGLTFAccessorSparseIndices extends IGLTFProperty {
-        bufferView: number;
-        byteOffset?: number;
-        componentType: EComponentType;
-    }
-    interface IGLTFAccessorSparseValues extends IGLTFProperty {
-        bufferView: number;
-        byteOffset?: number;
-    }
-    interface IGLTFAccessorSparse extends IGLTFProperty {
-        count: number;
-        indices: IGLTFAccessorSparseIndices;
-        values: IGLTFAccessorSparseValues;
-    }
-    interface IGLTFAccessor extends IGLTFChildRootProperty {
-        bufferView?: number;
-        byteOffset?: number;
-        componentType: EComponentType;
-        normalized?: boolean;
-        count: number;
-        type: string;
-        max: number[];
-        min: number[];
-        sparse?: IGLTFAccessorSparse;
-        index: number;
-    }
-    interface IGLTFAnimationChannel extends IGLTFProperty {
-        sampler: number;
-        target: IGLTFAnimationChannelTarget;
-    }
-    interface IGLTFAnimationChannelTarget extends IGLTFProperty {
-        node: number;
-        path: string;
-    }
-    interface IGLTFAnimationSampler extends IGLTFProperty {
-        input: number;
-        interpolation?: string;
-        output: number;
-    }
-    interface IGLTFAnimation extends IGLTFChildRootProperty {
-        channels: IGLTFAnimationChannel[];
-        samplers: IGLTFAnimationSampler[];
-        index: number;
-        babylonAnimationGroup: AnimationGroup;
-    }
-    interface IGLTFAsset extends IGLTFChildRootProperty {
-        copyright?: string;
-        generator?: string;
-        version: string;
-        minVersion?: string;
-    }
-    interface IGLTFBuffer extends IGLTFChildRootProperty {
-        uri?: string;
-        byteLength: number;
-        index: number;
-        loadedData?: ArrayBufferView;
-        loadedObservable?: Observable<IGLTFBuffer>;
-    }
-    interface IGLTFBufferView extends IGLTFChildRootProperty {
-        buffer: number;
-        byteOffset?: number;
-        byteLength: number;
-        byteStride?: number;
-        index: number;
-    }
-    interface IGLTFCameraOrthographic extends IGLTFProperty {
-        xmag: number;
-        ymag: number;
-        zfar: number;
-        znear: number;
-    }
-    interface IGLTFCameraPerspective extends IGLTFProperty {
-        aspectRatio: number;
-        yfov: number;
-        zfar: number;
-        znear: number;
-    }
-    interface IGLTFCamera extends IGLTFChildRootProperty {
-        orthographic?: IGLTFCameraOrthographic;
-        perspective?: IGLTFCameraPerspective;
-        type: string;
-    }
-    interface IGLTFImage extends IGLTFChildRootProperty {
-        uri?: string;
-        mimeType?: string;
-        bufferView?: number;
-        index: number;
-    }
-    interface IGLTFMaterialNormalTextureInfo extends IGLTFTextureInfo {
-        scale: number;
-    }
-    interface IGLTFMaterialOcclusionTextureInfo extends IGLTFTextureInfo {
-        strength: number;
-    }
-    interface IGLTFMaterialPbrMetallicRoughness {
-        baseColorFactor: number[];
-        baseColorTexture: IGLTFTextureInfo;
-        metallicFactor: number;
-        roughnessFactor: number;
-        metallicRoughnessTexture: IGLTFTextureInfo;
-    }
-    interface IGLTFMaterial extends IGLTFChildRootProperty {
-        pbrMetallicRoughness?: IGLTFMaterialPbrMetallicRoughness;
-        normalTexture?: IGLTFMaterialNormalTextureInfo;
-        occlusionTexture?: IGLTFMaterialOcclusionTextureInfo;
-        emissiveTexture?: IGLTFTextureInfo;
-        emissiveFactor?: number[];
-        alphaMode?: string;
-        alphaCutoff: number;
-        doubleSided?: boolean;
-        index: number;
-        babylonMaterial: Material;
-    }
-    interface IGLTFMeshPrimitive extends IGLTFProperty {
-        attributes: {
-            [name: string]: number;
-        };
-        indices?: number;
-        material?: number;
-        mode?: EMeshPrimitiveMode;
-        targets?: {
-            [name: string]: number;
-        }[];
-        vertexData: VertexData;
-        targetsVertexData: VertexData[];
-    }
-    interface IGLTFMesh extends IGLTFChildRootProperty {
-        primitives: IGLTFMeshPrimitive[];
-        weights?: number[];
-        index: number;
-        hasVertexAlpha: boolean;
-    }
-    interface IGLTFNode extends IGLTFChildRootProperty {
-        camera?: number;
-        children?: number[];
-        skin?: number;
-        matrix?: number[];
-        mesh?: number;
-        rotation?: number[];
-        scale?: number[];
-        translation?: number[];
-        weights?: number[];
-        index: number;
-        parent: IGLTFNode;
-        babylonMesh: Mesh;
-        babylonAnimationTargets?: Node[];
-    }
-    interface IGLTFSampler extends IGLTFChildRootProperty {
-        magFilter?: ETextureMagFilter;
-        minFilter?: ETextureMinFilter;
-        wrapS?: ETextureWrapMode;
-        wrapT?: ETextureWrapMode;
-        index: number;
+    interface TypedArray extends ArrayBufferView {
+        [index: number]: number;
+    }
+    interface IArrayItem {
+        _index: number;
+    }
+    class ArrayItem {
+        static Assign(values?: IArrayItem[]): void;
+    }
+}
+
+
+
+declare module BABYLON.GLTF2 {
+    interface ILoaderAccessor extends IAccessor, IArrayItem {
+        _data?: Promise<TypedArray>;
+    }
+    interface ILoaderAnimationChannel extends IAnimationChannel, IArrayItem {
+        _babylonAnimationGroup: AnimationGroup;
+    }
+    interface ILoaderAnimationSamplerData {
+        input: Float32Array;
+        interpolation: AnimationSamplerInterpolation;
+        output: Float32Array;
+    }
+    interface ILoaderAnimationSampler extends IAnimationSampler, IArrayItem {
+        _data: Promise<ILoaderAnimationSamplerData>;
+    }
+    interface ILoaderAnimation extends IAnimation, IArrayItem {
+        channels: ILoaderAnimationChannel[];
+        samplers: ILoaderAnimationSampler[];
+        _babylonAnimationGroup: Nullable<AnimationGroup>;
+    }
+    interface ILoaderBuffer extends IBuffer, IArrayItem {
+        _data?: Promise<ArrayBufferView>;
+    }
+    interface ILoaderBufferView extends IBufferView, IArrayItem {
+        _data?: Promise<ArrayBufferView>;
+    }
+    interface ILoaderCamera extends ICamera, IArrayItem {
+    }
+    interface ILoaderImage extends IImage, IArrayItem {
+        _objectURL?: Promise<string>;
+    }
+    interface ILoaderMaterial extends IMaterial, IArrayItem {
+        _babylonMaterial?: Material;
+        _babylonMeshes?: AbstractMesh[];
+        _loaded?: Promise<void>;
+    }
+    interface ILoaderMesh extends IMesh, IArrayItem {
+        primitives: ILoaderMeshPrimitive[];
+    }
+    interface ILoaderMeshPrimitive extends IMeshPrimitive, IArrayItem {
+    }
+    interface ILoaderNode extends INode, IArrayItem {
+        _parent: ILoaderNode;
+        _babylonMesh?: Mesh;
+        _primitiveBabylonMeshes?: Mesh[];
+        _babylonAnimationTargets?: Node[];
+        _numMorphTargets?: number;
+    }
+    interface ILoaderSamplerData {
         noMipMaps: boolean;
         samplingMode: number;
         wrapU: number;
         wrapV: number;
     }
-    interface IGLTFScene extends IGLTFChildRootProperty {
-        nodes: number[];
-        index: number;
-    }
-    interface IGLTFSkin extends IGLTFChildRootProperty {
-        inverseBindMatrices?: number;
-        skeleton?: number;
-        joints: number[];
-        index: number;
-        babylonSkeleton: Skeleton;
-    }
-    interface IGLTFTexture extends IGLTFChildRootProperty {
-        sampler?: number;
-        source: number;
-        index: number;
-        url?: string;
-        dataReadyObservable?: Observable<IGLTFTexture>;
-    }
-    interface IGLTFTextureInfo {
-        index: number;
-        texCoord?: number;
-    }
-    interface _IGLTF extends IGLTFProperty {
-        accessors?: IGLTFAccessor[];
-        animations?: IGLTFAnimation[];
-        asset: IGLTFAsset;
-        buffers?: IGLTFBuffer[];
-        bufferViews?: IGLTFBufferView[];
-        cameras?: IGLTFCamera[];
-        extensionsUsed?: string[];
-        extensionsRequired?: string[];
-        images?: IGLTFImage[];
-        materials?: IGLTFMaterial[];
-        meshes?: IGLTFMesh[];
-        nodes?: IGLTFNode[];
-        samplers?: IGLTFSampler[];
-        scene?: number;
-        scenes?: IGLTFScene[];
-        skins?: IGLTFSkin[];
-        textures?: IGLTFTexture[];
+    interface ILoaderSampler extends ISampler, IArrayItem {
+        _data?: ILoaderSamplerData;
+    }
+    interface ILoaderScene extends IScene, IArrayItem {
+    }
+    interface ILoaderSkin extends ISkin, IArrayItem {
+        _babylonSkeleton: Nullable<Skeleton>;
+        _loaded?: Promise<void>;
+    }
+    interface ILoaderTexture extends ITexture, IArrayItem {
+    }
+    interface ILoaderGLTF extends IGLTF {
+        accessors?: ILoaderAccessor[];
+        animations?: ILoaderAnimation[];
+        buffers?: ILoaderBuffer[];
+        bufferViews?: ILoaderBufferView[];
+        cameras?: ILoaderCamera[];
+        images?: ILoaderImage[];
+        materials?: ILoaderMaterial[];
+        meshes?: ILoaderMesh[];
+        nodes?: ILoaderNode[];
+        samplers?: ILoaderSampler[];
+        scenes?: ILoaderScene[];
+        skins?: ILoaderSkin[];
+        textures?: ILoaderTexture[];
     }
 }
 
 
 declare module BABYLON.GLTF2 {
     class GLTFLoader implements IGLTFLoader {
-        _gltf: _IGLTF;
+        _gltf: ILoaderGLTF;
         _babylonScene: Scene;
+        _completePromises: Promise<void>[];
         private _disposed;
+        private _state;
+        private _extensions;
         private _rootUrl;
-        private _defaultMaterial;
+        private _rootBabylonMesh;
         private _defaultSampler;
-        private _rootNode;
-        private _successCallback?;
         private _progressCallback?;
-        private _errorCallback?;
-        private _renderReady;
         private _requests;
-        private _renderReadyObservable;
-        private _renderPendingCount;
-        private _loaderPendingCount;
-        private _loaderTrackers;
-        static Extensions: {
-            [name: string]: GLTFLoaderExtension;
-        };
-        static RegisterExtension(extension: GLTFLoaderExtension): void;
+        private static _Names;
+        private static _Factories;
+        static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         compileMaterials: boolean;
         useClipPlane: boolean;
         compileShadowGenerators: boolean;
-        onDisposeObservable: Observable<IGLTFLoader>;
-        onMeshLoadedObservable: Observable<AbstractMesh>;
-        onTextureLoadedObservable: Observable<BaseTexture>;
-        onMaterialLoadedObservable: Observable<Material>;
-        onCompleteObservable: Observable<IGLTFLoader>;
+        readonly onDisposeObservable: Observable<IGLTFLoader>;
+        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
+        readonly onTextureLoadedObservable: Observable<BaseTexture>;
+        readonly onMaterialLoadedObservable: Observable<Material>;
+        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        readonly onCompleteObservable: Observable<IGLTFLoader>;
+        readonly state: Nullable<GLTFLoaderState>;
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess?, onProgress?, onError?);
-        private _onProgress();
-        _executeWhenRenderReady(func: () => void): void;
-        private _onRenderReady();
-        private _onComplete();
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        private _loadAsync(nodes, scene, data, rootUrl, onProgress?);
+        private _loadExtensions();
         private _loadData(data);
+        private _setupData();
+        private _createRootNode();
+        private _loadNodesAsync(nodes);
+        _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;
         private _getMeshes();
         private _getSkeletons();
         private _startAnimations();
-        private _loadDefaultScene(nodeNames);
-        private _loadScene(context, scene, nodeNames);
-        _loadNode(context: string, node: IGLTFNode): void;
-        private _loadMesh(context, node, mesh);
-        private _loadAllVertexDataAsync(context, mesh, onSuccess);
-        /**
-         * Converts a data bufferview into a Float4 Texture Coordinate Array, based on the accessor component type
-         * @param {ArrayBufferView} data
-         * @param {IGLTFAccessor} accessor
-         */
-        private _convertToFloat4TextureCoordArray(context, data, accessor);
-        /**
-         * Converts a data bufferview into a Float4 Color Array, based on the accessor component type
-         * @param {ArrayBufferView} data
-         * @param {IGLTFAccessor} accessor
-         */
-        private _convertToFloat4ColorArray(context, data, accessor);
-        private _loadVertexDataAsync(context, mesh, primitive, onSuccess);
-        private _createMorphTargets(context, node, mesh);
-        private _loadMorphTargets(context, node, mesh);
-        private _loadAllMorphTargetVertexDataAsync(context, node, mesh, onSuccess);
-        private _loadMorphTargetVertexDataAsync(context, vertexData, attributes, onSuccess);
-        private _loadTransform(node);
-        private _loadSkinAsync(context, skin, onSuccess);
+        _loadNodeAsync(context: string, node: ILoaderNode): Promise<void>;
+        private _loadMeshAsync(context, node, mesh);
+        private _loadPrimitiveAsync(context, node, mesh, primitive);
+        private _loadVertexDataAsync(context, primitive, babylonMesh);
+        private _createMorphTargets(context, node, mesh, primitive, babylonMesh);
+        private _loadMorphTargetsAsync(context, primitive, babylonMesh, babylonVertexData);
+        private _loadMorphTargetVertexDataAsync(context, babylonVertexData, attributes, babylonMorphTarget);
+        private static _ConvertToFloat32Array(context, accessor, data);
+        private static _ConvertVec3ToVec4(context, data);
+        private static _LoadTransform(node, babylonNode);
+        private _loadSkinAsync(context, node, mesh, skin);
+        private _loadSkinInverseBindMatricesDataAsync(context, skin);
         private _createBone(node, skin, parent, localMatrix, baseMatrix, index);
-        private _loadBones(context, skin, inverseBindMatrixData);
-        private _loadBone(node, skin, inverseBindMatrixData, babylonBones);
+        private _loadBones(context, skin, inverseBindMatricesData);
+        private _loadBone(node, skin, inverseBindMatricesData, babylonBones);
         private _getNodeMatrix(node);
-        private _traverseNodes(context, indices, action, parentNode);
-        _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): void;
-        private _loadAnimations();
-        private _loadAnimation(context, animation);
-        private _loadAnimationChannel(animation, channelContext, channel, samplerContext, sampler);
-        private _loadBufferAsync(context, buffer, onSuccess);
-        private _loadBufferViewAsync(context, bufferView, onSuccess);
-        private _loadAccessorAsync(context, accessor, onSuccess);
+        private _loadAnimationsAsync();
+        private _loadAnimationAsync(context, animation);
+        private _loadAnimationChannelAsync(context, animationContext, animation, channel, babylonAnimationGroup);
+        private _loadAnimationSamplerAsync(context, sampler);
+        private _loadBufferAsync(context, buffer);
+        private _loadBufferViewAsync(context, bufferView);
+        private _loadAccessorAsync(context, accessor);
         private _buildArrayBuffer<T>(typedArray, data, byteOffset, count, numComponents, byteStride?);
-        _addPendingData(data: any): void;
-        _removePendingData(data: any): void;
-        _addLoaderPendingData(data: any): void;
-        _removeLoaderPendingData(data: any): void;
-        _whenAction(action: () => void, onComplete: () => void): void;
         private _getDefaultMaterial();
-        private _loadMaterialMetallicRoughnessProperties(context, material);
-        _loadMaterial(context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): void;
-        _createPbrMaterial(material: IGLTFMaterial): void;
-        _loadMaterialBaseProperties(context: string, material: IGLTFMaterial): void;
-        _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
-        _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture;
+        private _loadMaterialMetallicRoughnessPropertiesAsync(context, material);
+        _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Promise<void>;
+        _createMaterial(material: ILoaderMaterial): PBRMaterial;
+        _loadMaterialBasePropertiesAsync(context: string, material: ILoaderMaterial): Promise<void>;
+        _loadMaterialAlphaProperties(context: string, material: ILoaderMaterial): void;
+        _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Promise<void>;
         private _loadSampler(context, sampler);
-        private _loadImageAsync(context, image, onSuccess);
-        _loadUriAsync(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
-        _tryCatchOnError(handler: () => void): void;
-        private static _AssignIndices(array?);
-        static _GetProperty<T extends IGLTFProperty>(array?: ArrayLike<T>, index?: number): Nullable<T>;
-        private static _GetTextureWrapMode(context, mode?);
+        private _loadImageAsync(context, image);
+        _loadUriAsync(context: string, uri: string): Promise<ArrayBufferView>;
+        private _onProgress();
+        static _GetProperty<T>(context: string, array: ArrayLike<T> | undefined, index: number | undefined): T;
+        private static _GetTextureWrapMode(context, mode);
         private static _GetTextureSamplingMode(context, magFilter?, minFilter?);
         private static _GetNumComponents(context, type);
-        private _compileMaterialAsync(babylonMaterial, babylonMesh, onSuccess);
-        private _compileMaterialsAsync(onSuccess);
-        private _compileShadowGeneratorsAsync(onSuccess);
-        private _abortRequests();
-        private _releaseResources();
-    }
-}
-
-
-declare module BABYLON.GLTF2 {
-    /**
-    * Utils functions for GLTF
-    */
-    class GLTFUtils {
-        /**
-        * If the uri is a base64 string
-        * @param uri: the uri to test
-        */
-        static IsBase64(uri: string): boolean;
-        /**
-        * Decode the base64 uri
-        * @param uri: the uri to decode
-        */
-        static DecodeBase64(uri: string): ArrayBuffer;
-        static ValidateUri(uri: string): boolean;
+        private static _ValidateUri(uri);
+        private _compileMaterialsAsync();
+        private _compileShadowGeneratorsAsync();
+        private _clear();
+        _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>): Nullable<Promise<T>>;
     }
 }
 
 
 declare module BABYLON.GLTF2 {
-    abstract class GLTFLoaderExtension {
+    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension {
         enabled: boolean;
         readonly abstract name: string;
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        protected _loadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean;
-        protected _loadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean;
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        protected _loadExtension<T>(context: string, property: IGLTFProperty, action: (context: string, extension: T, onComplete: () => void) => void): boolean;
-        static _Extensions: GLTFLoaderExtension[];
-        static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
-        static LoadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean;
-        static LoadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean;
-        static LoadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        static LoadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private static _ApplyExtensions(action);
+        protected _loader: GLTFLoader;
+        constructor(loader: GLTFLoader);
+        /** Override this method to modify the default behavior for loading scenes. */
+        protected _loadSceneAsync(context: string, node: ILoaderScene): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading nodes. */
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading materials. */
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading uris. */
+        protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
+        /** Helper method called by a loader extension to load an glTF extension. */
+        protected _loadExtensionAsync<T>(context: string, property: IProperty, actionAsync: (context: string, extension: T) => Promise<void>): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading scenes. */
+        static _LoadSceneAsync(loader: GLTFLoader, context: string, scene: ILoaderScene): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading nodes. */
+        static _LoadNodeAsync(loader: GLTFLoader, context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading materials. */
+        static _LoadMaterialAsync(loader: GLTFLoader, context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading uris. */
+        static _LoadUriAsync(loader: GLTFLoader, context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
     }
 }
 
 
 declare module BABYLON.GLTF2.Extensions {
-    class MSFTLOD extends GLTFLoaderExtension {
+    class MSFT_lod extends GLTFLoaderExtension {
+        readonly name: string;
         /**
-         * Specify the minimal delay between LODs in ms (default = 250)
+         * Maximum number of LODs to load, starting from the lowest LOD.
          */
-        Delay: number;
-        readonly name: string;
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        private _loadNodeLOD(loader, context, nodes, index, onComplete);
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private _loadMaterialLOD(loader, context, materials, index, assign, onComplete);
+        maxLODsToLoad: number;
+        private _loadingNodeLOD;
+        private _loadNodeSignals;
+        private _loadingMaterialLOD;
+        private _loadMaterialSignals;
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
+        /**
+         * Gets an array of LOD properties from lowest to highest.
+         */
+        private _getLODs<T>(context, property, array, ids);
     }
 }
 
 
 declare module BABYLON.GLTF2.Extensions {
-    class KHRMaterialsPbrSpecularGlossiness extends GLTFLoaderExtension {
+    class KHR_materials_pbrSpecularGlossiness extends GLTFLoaderExtension {
         readonly name: string;
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private _loadSpecularGlossinessProperties(loader, context, material, properties);
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        private _loadSpecularGlossinessPropertiesAsync(loader, context, material, properties);
     }
 }
 
 
 declare module BABYLON.GLTF2.Extensions {
-    class KHRLights extends GLTFLoaderExtension {
+    class KHR_lights extends GLTFLoaderExtension {
         readonly name: string;
-        private applyCommonProperties(light, lightInfo);
-        protected _loadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean;
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        protected _loadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean;
+        protected _loadSceneAsync(context: string, scene: ILoaderScene): Nullable<Promise<void>>;
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        private readonly _lights;
     }
 }

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1183 - 1519
dist/preview release/loaders/babylon.glTF2FileLoader.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 233 - 380
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -28,19 +28,40 @@ declare module BABYLON {
         json: Object;
         bin: Nullable<ArrayBufferView>;
     }
+    interface IGLTFLoaderExtension {
+        /**
+         * The name of this extension.
+         */
+        readonly name: string;
+        /**
+         * Whether this extension is enabled.
+         */
+        enabled: boolean;
+    }
+    enum GLTFLoaderState {
+        Loading = 0,
+        Ready = 1,
+        Complete = 2,
+    }
     interface IGLTFLoader extends IDisposable {
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         compileMaterials: boolean;
         useClipPlane: boolean;
         compileShadowGenerators: boolean;
-        onDisposeObservable: Observable<IGLTFLoader>;
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
         onCompleteObservable: Observable<IGLTFLoader>;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+        onDisposeObservable: Observable<IGLTFLoader>;
+        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        state: Nullable<GLTFLoaderState>;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
     }
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         static CreateGLTFLoaderV1: () => IGLTFLoader;
@@ -78,19 +99,19 @@ declare module BABYLON {
         /**
          * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
          */
-        onMeshLoadedObservable: Observable<AbstractMesh>;
+        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
         private _onMeshLoadedObserver;
         onMeshLoaded: (mesh: AbstractMesh) => void;
         /**
          * Raised when the loader creates a texture after parsing the glTF properties of the texture.
          */
-        onTextureLoadedObservable: Observable<BaseTexture>;
+        readonly onTextureLoadedObservable: Observable<BaseTexture>;
         private _onTextureLoadedObserver;
         onTextureLoaded: (Texture: BaseTexture) => void;
         /**
          * Raised when the loader creates a material after parsing the glTF properties of the material.
          */
-        onMaterialLoadedObservable: Observable<Material>;
+        readonly onMaterialLoadedObservable: Observable<Material>;
         private _onMaterialLoadedObserver;
         onMaterialLoaded: (Material: Material) => void;
         /**
@@ -98,15 +119,26 @@ declare module BABYLON {
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets without LODs, raised when the model is complete, immediately after onSuccess.
          */
-        onCompleteObservable: Observable<GLTFFileLoader>;
+        readonly onCompleteObservable: Observable<GLTFFileLoader>;
         private _onCompleteObserver;
         onComplete: () => void;
         /**
         * Raised when the loader is disposed.
         */
-        onDisposeObservable: Observable<GLTFFileLoader>;
+        readonly onDisposeObservable: Observable<GLTFFileLoader>;
         private _onDisposeObserver;
         onDispose: () => void;
+        /**
+         * Raised after a loader extension is created.
+         * Set additional options for a loader extension in this event.
+         */
+        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        private _onExtensionLoadedObserver;
+        onExtensionLoaded: (extension: IGLTFLoaderExtension) => void;
+        /**
+         * The loader state or null if not active.
+         */
+        readonly loaderState: Nullable<GLTFLoaderState>;
         private _loader;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
@@ -114,9 +146,13 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAssetsAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: (assets: AssetContainer) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
         canDirectLoad(data: string): boolean;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
@@ -534,9 +570,17 @@ declare module BABYLON.GLTF1 {
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
         onCompleteObservable: Observable<IGLTFLoader>;
+        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        state: Nullable<GLTFLoaderState>;
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: SceneLoaderProgressEvent) => void, onError: (message: string) => void): boolean;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: SceneLoaderProgressEvent) => void, onError: (message: string) => void): void;
+        private _importMeshAsync(meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError);
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        private _loadAsync(scene, data, rootUrl, onSuccess, onProgress, onError);
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress: (event: SceneLoaderProgressEvent) => void): Promise<void>;
         private _loadShadersAsync(gltfRuntime, onload);
         private _loadBuffersAsync(gltfRuntime, onLoad, onProgress?);
         private _createNodes(gltfRuntime);
@@ -567,16 +611,6 @@ declare module BABYLON.GLTF1 {
          */
         static SetUniform(shaderMaterial: ShaderMaterial | Effect, uniform: string, value: any, type: number): boolean;
         /**
-        * If the uri is a base64 string
-        * @param uri: the uri to test
-        */
-        static IsBase64(uri: string): boolean;
-        /**
-        * Decode the base64 uri
-        * @param uri: the uri to decode
-        */
-        static DecodeBase64(uri: string): ArrayBuffer;
-        /**
         * Returns the wrap mode of the texture
         * @param mode: the mode value
         */
@@ -690,440 +724,259 @@ declare module BABYLON.GLTF1 {
 
 
 declare module BABYLON.GLTF2 {
-    /**
-    * Enums
-    */
-    enum EComponentType {
-        BYTE = 5120,
-        UNSIGNED_BYTE = 5121,
-        SHORT = 5122,
-        UNSIGNED_SHORT = 5123,
-        UNSIGNED_INT = 5125,
-        FLOAT = 5126,
+    interface TypedArray extends ArrayBufferView {
+        [index: number]: number;
     }
-    enum EMeshPrimitiveMode {
-        POINTS = 0,
-        LINES = 1,
-        LINE_LOOP = 2,
-        LINE_STRIP = 3,
-        TRIANGLES = 4,
-        TRIANGLE_STRIP = 5,
-        TRIANGLE_FAN = 6,
+    interface IArrayItem {
+        _index: number;
     }
-    enum ETextureMagFilter {
-        NEAREST = 9728,
-        LINEAR = 9729,
+    class ArrayItem {
+        static Assign(values?: IArrayItem[]): void;
     }
-    enum ETextureMinFilter {
-        NEAREST = 9728,
-        LINEAR = 9729,
-        NEAREST_MIPMAP_NEAREST = 9984,
-        LINEAR_MIPMAP_NEAREST = 9985,
-        NEAREST_MIPMAP_LINEAR = 9986,
-        LINEAR_MIPMAP_LINEAR = 9987,
-    }
-    enum ETextureWrapMode {
-        CLAMP_TO_EDGE = 33071,
-        MIRRORED_REPEAT = 33648,
-        REPEAT = 10497,
-    }
-    /**
-    * Interfaces
-    */
-    interface IGLTFProperty {
-        extensions?: {
-            [key: string]: any;
-        };
-        extras?: any;
-    }
-    interface IGLTFChildRootProperty extends IGLTFProperty {
-        name?: string;
-    }
-    interface IGLTFAccessorSparseIndices extends IGLTFProperty {
-        bufferView: number;
-        byteOffset?: number;
-        componentType: EComponentType;
-    }
-    interface IGLTFAccessorSparseValues extends IGLTFProperty {
-        bufferView: number;
-        byteOffset?: number;
-    }
-    interface IGLTFAccessorSparse extends IGLTFProperty {
-        count: number;
-        indices: IGLTFAccessorSparseIndices;
-        values: IGLTFAccessorSparseValues;
-    }
-    interface IGLTFAccessor extends IGLTFChildRootProperty {
-        bufferView?: number;
-        byteOffset?: number;
-        componentType: EComponentType;
-        normalized?: boolean;
-        count: number;
-        type: string;
-        max: number[];
-        min: number[];
-        sparse?: IGLTFAccessorSparse;
-        index: number;
-    }
-    interface IGLTFAnimationChannel extends IGLTFProperty {
-        sampler: number;
-        target: IGLTFAnimationChannelTarget;
-    }
-    interface IGLTFAnimationChannelTarget extends IGLTFProperty {
-        node: number;
-        path: string;
-    }
-    interface IGLTFAnimationSampler extends IGLTFProperty {
-        input: number;
-        interpolation?: string;
-        output: number;
-    }
-    interface IGLTFAnimation extends IGLTFChildRootProperty {
-        channels: IGLTFAnimationChannel[];
-        samplers: IGLTFAnimationSampler[];
-        index: number;
-        babylonAnimationGroup: AnimationGroup;
+}
+
+
+
+declare module BABYLON.GLTF2 {
+    interface ILoaderAccessor extends IAccessor, IArrayItem {
+        _data?: Promise<TypedArray>;
     }
-    interface IGLTFAsset extends IGLTFChildRootProperty {
-        copyright?: string;
-        generator?: string;
-        version: string;
-        minVersion?: string;
+    interface ILoaderAnimationChannel extends IAnimationChannel, IArrayItem {
+        _babylonAnimationGroup: AnimationGroup;
     }
-    interface IGLTFBuffer extends IGLTFChildRootProperty {
-        uri?: string;
-        byteLength: number;
-        index: number;
-        loadedData?: ArrayBufferView;
-        loadedObservable?: Observable<IGLTFBuffer>;
+    interface ILoaderAnimationSamplerData {
+        input: Float32Array;
+        interpolation: AnimationSamplerInterpolation;
+        output: Float32Array;
     }
-    interface IGLTFBufferView extends IGLTFChildRootProperty {
-        buffer: number;
-        byteOffset?: number;
-        byteLength: number;
-        byteStride?: number;
-        index: number;
+    interface ILoaderAnimationSampler extends IAnimationSampler, IArrayItem {
+        _data: Promise<ILoaderAnimationSamplerData>;
     }
-    interface IGLTFCameraOrthographic extends IGLTFProperty {
-        xmag: number;
-        ymag: number;
-        zfar: number;
-        znear: number;
+    interface ILoaderAnimation extends IAnimation, IArrayItem {
+        channels: ILoaderAnimationChannel[];
+        samplers: ILoaderAnimationSampler[];
+        _babylonAnimationGroup: Nullable<AnimationGroup>;
     }
-    interface IGLTFCameraPerspective extends IGLTFProperty {
-        aspectRatio: number;
-        yfov: number;
-        zfar: number;
-        znear: number;
+    interface ILoaderBuffer extends IBuffer, IArrayItem {
+        _data?: Promise<ArrayBufferView>;
     }
-    interface IGLTFCamera extends IGLTFChildRootProperty {
-        orthographic?: IGLTFCameraOrthographic;
-        perspective?: IGLTFCameraPerspective;
-        type: string;
+    interface ILoaderBufferView extends IBufferView, IArrayItem {
+        _data?: Promise<ArrayBufferView>;
     }
-    interface IGLTFImage extends IGLTFChildRootProperty {
-        uri?: string;
-        mimeType?: string;
-        bufferView?: number;
-        index: number;
+    interface ILoaderCamera extends ICamera, IArrayItem {
     }
-    interface IGLTFMaterialNormalTextureInfo extends IGLTFTextureInfo {
-        scale: number;
+    interface ILoaderImage extends IImage, IArrayItem {
+        _objectURL?: Promise<string>;
     }
-    interface IGLTFMaterialOcclusionTextureInfo extends IGLTFTextureInfo {
-        strength: number;
+    interface ILoaderMaterial extends IMaterial, IArrayItem {
+        _babylonMaterial?: Material;
+        _babylonMeshes?: AbstractMesh[];
+        _loaded?: Promise<void>;
     }
-    interface IGLTFMaterialPbrMetallicRoughness {
-        baseColorFactor: number[];
-        baseColorTexture: IGLTFTextureInfo;
-        metallicFactor: number;
-        roughnessFactor: number;
-        metallicRoughnessTexture: IGLTFTextureInfo;
+    interface ILoaderMesh extends IMesh, IArrayItem {
+        primitives: ILoaderMeshPrimitive[];
     }
-    interface IGLTFMaterial extends IGLTFChildRootProperty {
-        pbrMetallicRoughness?: IGLTFMaterialPbrMetallicRoughness;
-        normalTexture?: IGLTFMaterialNormalTextureInfo;
-        occlusionTexture?: IGLTFMaterialOcclusionTextureInfo;
-        emissiveTexture?: IGLTFTextureInfo;
-        emissiveFactor?: number[];
-        alphaMode?: string;
-        alphaCutoff: number;
-        doubleSided?: boolean;
-        index: number;
-        babylonMaterial: Material;
+    interface ILoaderMeshPrimitive extends IMeshPrimitive, IArrayItem {
     }
-    interface IGLTFMeshPrimitive extends IGLTFProperty {
-        attributes: {
-            [name: string]: number;
-        };
-        indices?: number;
-        material?: number;
-        mode?: EMeshPrimitiveMode;
-        targets?: {
-            [name: string]: number;
-        }[];
-        vertexData: VertexData;
-        targetsVertexData: VertexData[];
-    }
-    interface IGLTFMesh extends IGLTFChildRootProperty {
-        primitives: IGLTFMeshPrimitive[];
-        weights?: number[];
-        index: number;
-        hasVertexAlpha: boolean;
+    interface ILoaderNode extends INode, IArrayItem {
+        _parent: ILoaderNode;
+        _babylonMesh?: Mesh;
+        _primitiveBabylonMeshes?: Mesh[];
+        _babylonAnimationTargets?: Node[];
+        _numMorphTargets?: number;
     }
-    interface IGLTFNode extends IGLTFChildRootProperty {
-        camera?: number;
-        children?: number[];
-        skin?: number;
-        matrix?: number[];
-        mesh?: number;
-        rotation?: number[];
-        scale?: number[];
-        translation?: number[];
-        weights?: number[];
-        index: number;
-        parent: IGLTFNode;
-        babylonMesh: Mesh;
-        babylonAnimationTargets?: Node[];
-    }
-    interface IGLTFSampler extends IGLTFChildRootProperty {
-        magFilter?: ETextureMagFilter;
-        minFilter?: ETextureMinFilter;
-        wrapS?: ETextureWrapMode;
-        wrapT?: ETextureWrapMode;
-        index: number;
+    interface ILoaderSamplerData {
         noMipMaps: boolean;
         samplingMode: number;
         wrapU: number;
         wrapV: number;
     }
-    interface IGLTFScene extends IGLTFChildRootProperty {
-        nodes: number[];
-        index: number;
+    interface ILoaderSampler extends ISampler, IArrayItem {
+        _data?: ILoaderSamplerData;
     }
-    interface IGLTFSkin extends IGLTFChildRootProperty {
-        inverseBindMatrices?: number;
-        skeleton?: number;
-        joints: number[];
-        index: number;
-        babylonSkeleton: Skeleton;
+    interface ILoaderScene extends IScene, IArrayItem {
     }
-    interface IGLTFTexture extends IGLTFChildRootProperty {
-        sampler?: number;
-        source: number;
-        index: number;
-        url?: string;
-        dataReadyObservable?: Observable<IGLTFTexture>;
-    }
-    interface IGLTFTextureInfo {
-        index: number;
-        texCoord?: number;
-    }
-    interface _IGLTF extends IGLTFProperty {
-        accessors?: IGLTFAccessor[];
-        animations?: IGLTFAnimation[];
-        asset: IGLTFAsset;
-        buffers?: IGLTFBuffer[];
-        bufferViews?: IGLTFBufferView[];
-        cameras?: IGLTFCamera[];
-        extensionsUsed?: string[];
-        extensionsRequired?: string[];
-        images?: IGLTFImage[];
-        materials?: IGLTFMaterial[];
-        meshes?: IGLTFMesh[];
-        nodes?: IGLTFNode[];
-        samplers?: IGLTFSampler[];
-        scene?: number;
-        scenes?: IGLTFScene[];
-        skins?: IGLTFSkin[];
-        textures?: IGLTFTexture[];
+    interface ILoaderSkin extends ISkin, IArrayItem {
+        _babylonSkeleton: Nullable<Skeleton>;
+        _loaded?: Promise<void>;
+    }
+    interface ILoaderTexture extends ITexture, IArrayItem {
+    }
+    interface ILoaderGLTF extends IGLTF {
+        accessors?: ILoaderAccessor[];
+        animations?: ILoaderAnimation[];
+        buffers?: ILoaderBuffer[];
+        bufferViews?: ILoaderBufferView[];
+        cameras?: ILoaderCamera[];
+        images?: ILoaderImage[];
+        materials?: ILoaderMaterial[];
+        meshes?: ILoaderMesh[];
+        nodes?: ILoaderNode[];
+        samplers?: ILoaderSampler[];
+        scenes?: ILoaderScene[];
+        skins?: ILoaderSkin[];
+        textures?: ILoaderTexture[];
     }
 }
 
 
 declare module BABYLON.GLTF2 {
     class GLTFLoader implements IGLTFLoader {
-        _gltf: _IGLTF;
+        _gltf: ILoaderGLTF;
         _babylonScene: Scene;
+        _completePromises: Promise<void>[];
         private _disposed;
+        private _state;
+        private _extensions;
         private _rootUrl;
-        private _defaultMaterial;
+        private _rootBabylonMesh;
         private _defaultSampler;
-        private _rootNode;
-        private _successCallback?;
         private _progressCallback?;
-        private _errorCallback?;
-        private _renderReady;
         private _requests;
-        private _renderReadyObservable;
-        private _renderPendingCount;
-        private _loaderPendingCount;
-        private _loaderTrackers;
-        static Extensions: {
-            [name: string]: GLTFLoaderExtension;
-        };
-        static RegisterExtension(extension: GLTFLoaderExtension): void;
+        private static _Names;
+        private static _Factories;
+        static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         compileMaterials: boolean;
         useClipPlane: boolean;
         compileShadowGenerators: boolean;
-        onDisposeObservable: Observable<IGLTFLoader>;
-        onMeshLoadedObservable: Observable<AbstractMesh>;
-        onTextureLoadedObservable: Observable<BaseTexture>;
-        onMaterialLoadedObservable: Observable<Material>;
-        onCompleteObservable: Observable<IGLTFLoader>;
+        readonly onDisposeObservable: Observable<IGLTFLoader>;
+        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
+        readonly onTextureLoadedObservable: Observable<BaseTexture>;
+        readonly onMaterialLoadedObservable: Observable<Material>;
+        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        readonly onCompleteObservable: Observable<IGLTFLoader>;
+        readonly state: Nullable<GLTFLoaderState>;
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess?, onProgress?, onError?);
-        private _onProgress();
-        _executeWhenRenderReady(func: () => void): void;
-        private _onRenderReady();
-        private _onComplete();
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        private _loadAsync(nodes, scene, data, rootUrl, onProgress?);
+        private _loadExtensions();
         private _loadData(data);
+        private _setupData();
+        private _createRootNode();
+        private _loadNodesAsync(nodes);
+        _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;
         private _getMeshes();
         private _getSkeletons();
         private _startAnimations();
-        private _loadDefaultScene(nodeNames);
-        private _loadScene(context, scene, nodeNames);
-        _loadNode(context: string, node: IGLTFNode): void;
-        private _loadMesh(context, node, mesh);
-        private _loadAllVertexDataAsync(context, mesh, onSuccess);
-        /**
-         * Converts a data bufferview into a Float4 Texture Coordinate Array, based on the accessor component type
-         * @param {ArrayBufferView} data
-         * @param {IGLTFAccessor} accessor
-         */
-        private _convertToFloat4TextureCoordArray(context, data, accessor);
-        /**
-         * Converts a data bufferview into a Float4 Color Array, based on the accessor component type
-         * @param {ArrayBufferView} data
-         * @param {IGLTFAccessor} accessor
-         */
-        private _convertToFloat4ColorArray(context, data, accessor);
-        private _loadVertexDataAsync(context, mesh, primitive, onSuccess);
-        private _createMorphTargets(context, node, mesh);
-        private _loadMorphTargets(context, node, mesh);
-        private _loadAllMorphTargetVertexDataAsync(context, node, mesh, onSuccess);
-        private _loadMorphTargetVertexDataAsync(context, vertexData, attributes, onSuccess);
-        private _loadTransform(node);
-        private _loadSkinAsync(context, skin, onSuccess);
+        _loadNodeAsync(context: string, node: ILoaderNode): Promise<void>;
+        private _loadMeshAsync(context, node, mesh);
+        private _loadPrimitiveAsync(context, node, mesh, primitive);
+        private _loadVertexDataAsync(context, primitive, babylonMesh);
+        private _createMorphTargets(context, node, mesh, primitive, babylonMesh);
+        private _loadMorphTargetsAsync(context, primitive, babylonMesh, babylonVertexData);
+        private _loadMorphTargetVertexDataAsync(context, babylonVertexData, attributes, babylonMorphTarget);
+        private static _ConvertToFloat32Array(context, accessor, data);
+        private static _ConvertVec3ToVec4(context, data);
+        private static _LoadTransform(node, babylonNode);
+        private _loadSkinAsync(context, node, mesh, skin);
+        private _loadSkinInverseBindMatricesDataAsync(context, skin);
         private _createBone(node, skin, parent, localMatrix, baseMatrix, index);
-        private _loadBones(context, skin, inverseBindMatrixData);
-        private _loadBone(node, skin, inverseBindMatrixData, babylonBones);
+        private _loadBones(context, skin, inverseBindMatricesData);
+        private _loadBone(node, skin, inverseBindMatricesData, babylonBones);
         private _getNodeMatrix(node);
-        private _traverseNodes(context, indices, action, parentNode);
-        _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): void;
-        private _loadAnimations();
-        private _loadAnimation(context, animation);
-        private _loadAnimationChannel(animation, channelContext, channel, samplerContext, sampler);
-        private _loadBufferAsync(context, buffer, onSuccess);
-        private _loadBufferViewAsync(context, bufferView, onSuccess);
-        private _loadAccessorAsync(context, accessor, onSuccess);
+        private _loadAnimationsAsync();
+        private _loadAnimationAsync(context, animation);
+        private _loadAnimationChannelAsync(context, animationContext, animation, channel, babylonAnimationGroup);
+        private _loadAnimationSamplerAsync(context, sampler);
+        private _loadBufferAsync(context, buffer);
+        private _loadBufferViewAsync(context, bufferView);
+        private _loadAccessorAsync(context, accessor);
         private _buildArrayBuffer<T>(typedArray, data, byteOffset, count, numComponents, byteStride?);
-        _addPendingData(data: any): void;
-        _removePendingData(data: any): void;
-        _addLoaderPendingData(data: any): void;
-        _removeLoaderPendingData(data: any): void;
-        _whenAction(action: () => void, onComplete: () => void): void;
         private _getDefaultMaterial();
-        private _loadMaterialMetallicRoughnessProperties(context, material);
-        _loadMaterial(context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): void;
-        _createPbrMaterial(material: IGLTFMaterial): void;
-        _loadMaterialBaseProperties(context: string, material: IGLTFMaterial): void;
-        _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
-        _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture;
+        private _loadMaterialMetallicRoughnessPropertiesAsync(context, material);
+        _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Promise<void>;
+        _createMaterial(material: ILoaderMaterial): PBRMaterial;
+        _loadMaterialBasePropertiesAsync(context: string, material: ILoaderMaterial): Promise<void>;
+        _loadMaterialAlphaProperties(context: string, material: ILoaderMaterial): void;
+        _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Promise<void>;
         private _loadSampler(context, sampler);
-        private _loadImageAsync(context, image, onSuccess);
-        _loadUriAsync(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
-        _tryCatchOnError(handler: () => void): void;
-        private static _AssignIndices(array?);
-        static _GetProperty<T extends IGLTFProperty>(array?: ArrayLike<T>, index?: number): Nullable<T>;
-        private static _GetTextureWrapMode(context, mode?);
+        private _loadImageAsync(context, image);
+        _loadUriAsync(context: string, uri: string): Promise<ArrayBufferView>;
+        private _onProgress();
+        static _GetProperty<T>(context: string, array: ArrayLike<T> | undefined, index: number | undefined): T;
+        private static _GetTextureWrapMode(context, mode);
         private static _GetTextureSamplingMode(context, magFilter?, minFilter?);
         private static _GetNumComponents(context, type);
-        private _compileMaterialAsync(babylonMaterial, babylonMesh, onSuccess);
-        private _compileMaterialsAsync(onSuccess);
-        private _compileShadowGeneratorsAsync(onSuccess);
-        private _abortRequests();
-        private _releaseResources();
+        private static _ValidateUri(uri);
+        private _compileMaterialsAsync();
+        private _compileShadowGeneratorsAsync();
+        private _clear();
+        _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>): Nullable<Promise<T>>;
     }
 }
 
 
 declare module BABYLON.GLTF2 {
-    /**
-    * Utils functions for GLTF
-    */
-    class GLTFUtils {
-        /**
-        * If the uri is a base64 string
-        * @param uri: the uri to test
-        */
-        static IsBase64(uri: string): boolean;
-        /**
-        * Decode the base64 uri
-        * @param uri: the uri to decode
-        */
-        static DecodeBase64(uri: string): ArrayBuffer;
-        static ValidateUri(uri: string): boolean;
-    }
-}
-
-
-declare module BABYLON.GLTF2 {
-    abstract class GLTFLoaderExtension {
+    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension {
         enabled: boolean;
         readonly abstract name: string;
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        protected _loadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean;
-        protected _loadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean;
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        protected _loadExtension<T>(context: string, property: IGLTFProperty, action: (context: string, extension: T, onComplete: () => void) => void): boolean;
-        static _Extensions: GLTFLoaderExtension[];
-        static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
-        static LoadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean;
-        static LoadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean;
-        static LoadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        static LoadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private static _ApplyExtensions(action);
+        protected _loader: GLTFLoader;
+        constructor(loader: GLTFLoader);
+        /** Override this method to modify the default behavior for loading scenes. */
+        protected _loadSceneAsync(context: string, node: ILoaderScene): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading nodes. */
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading materials. */
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading uris. */
+        protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
+        /** Helper method called by a loader extension to load an glTF extension. */
+        protected _loadExtensionAsync<T>(context: string, property: IProperty, actionAsync: (context: string, extension: T) => Promise<void>): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading scenes. */
+        static _LoadSceneAsync(loader: GLTFLoader, context: string, scene: ILoaderScene): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading nodes. */
+        static _LoadNodeAsync(loader: GLTFLoader, context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading materials. */
+        static _LoadMaterialAsync(loader: GLTFLoader, context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading uris. */
+        static _LoadUriAsync(loader: GLTFLoader, context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
     }
 }
 
 
 declare module BABYLON.GLTF2.Extensions {
-    class MSFTLOD extends GLTFLoaderExtension {
+    class MSFT_lod extends GLTFLoaderExtension {
+        readonly name: string;
         /**
-         * Specify the minimal delay between LODs in ms (default = 250)
+         * Maximum number of LODs to load, starting from the lowest LOD.
          */
-        Delay: number;
-        readonly name: string;
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        private _loadNodeLOD(loader, context, nodes, index, onComplete);
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private _loadMaterialLOD(loader, context, materials, index, assign, onComplete);
+        maxLODsToLoad: number;
+        private _loadingNodeLOD;
+        private _loadNodeSignals;
+        private _loadingMaterialLOD;
+        private _loadMaterialSignals;
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
+        /**
+         * Gets an array of LOD properties from lowest to highest.
+         */
+        private _getLODs<T>(context, property, array, ids);
     }
 }
 
 
 declare module BABYLON.GLTF2.Extensions {
-    class KHRMaterialsPbrSpecularGlossiness extends GLTFLoaderExtension {
+    class KHR_materials_pbrSpecularGlossiness extends GLTFLoaderExtension {
         readonly name: string;
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private _loadSpecularGlossinessProperties(loader, context, material, properties);
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        private _loadSpecularGlossinessPropertiesAsync(loader, context, material, properties);
     }
 }
 
 
 declare module BABYLON.GLTF2.Extensions {
-    class KHRLights extends GLTFLoaderExtension {
+    class KHR_lights extends GLTFLoaderExtension {
         readonly name: string;
-        private applyCommonProperties(light, lightInfo);
-        protected _loadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean;
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        protected _loadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean;
+        protected _loadSceneAsync(context: string, scene: ILoaderScene): Nullable<Promise<void>>;
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        private readonly _lights;
     }
 }

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1232 - 1558
dist/preview release/loaders/babylon.glTFFileLoader.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 3 - 3
dist/preview release/loaders/babylon.glTFFileLoader.min.js


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

@@ -58,7 +58,7 @@ declare module BABYLON {
         private _loadMTL(url, rootUrl, onSuccess);
         importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: Nullable<AbstractMesh[]>, particleSystems: Nullable<ParticleSystem[]>, skeletons: Nullable<Skeleton[]>): boolean;
         load(scene: Scene, data: string, rootUrl: string): boolean;
-        loadAssets(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): Nullable<AssetContainer>;
+        loadAssetContainer(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): AssetContainer;
         /**
          * Read the OBJ file and create an Array of meshes.
          * Each mesh contains all information given by the OBJ and the MTL file.

+ 4 - 7
dist/preview release/loaders/babylon.objFileLoader.js

@@ -260,14 +260,11 @@ var BABYLON;
             //Get the 3D model
             return this.importMesh(null, scene, data, rootUrl, null, null, null);
         };
-        OBJFileLoader.prototype.loadAssets = function (scene, data, rootUrl, onError) {
+        OBJFileLoader.prototype.loadAssetContainer = function (scene, data, rootUrl, onError) {
             var container = new BABYLON.AssetContainer(scene);
-            var result = this.importMesh(null, scene, data, rootUrl, container.meshes, null, null);
-            if (result) {
-                container.removeAllFromScene();
-                return container;
-            }
-            return null;
+            this.importMesh(null, scene, data, rootUrl, container.meshes, null, null);
+            container.removeAllFromScene();
+            return container;
         };
         /**
          * Read the OBJ file and create an Array of meshes.

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.min.js


+ 1 - 1
dist/preview release/loaders/babylon.stlFileLoader.d.ts

@@ -9,7 +9,7 @@ declare module BABYLON {
         extensions: ISceneLoaderPluginExtensions;
         importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: Nullable<AbstractMesh[]>, particleSystems: Nullable<ParticleSystem[]>, skeletons: Nullable<Skeleton[]>): boolean;
         load(scene: Scene, data: any, rootUrl: string): boolean;
-        loadAssets(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): Nullable<AssetContainer>;
+        loadAssetContainer(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): AssetContainer;
         private isBinary(data);
         private parseBinary(mesh, data);
         private parseASCII(mesh, solidData);

+ 4 - 7
dist/preview release/loaders/babylon.stlFileLoader.js

@@ -70,14 +70,11 @@ var BABYLON;
             }
             return result;
         };
-        STLFileLoader.prototype.loadAssets = function (scene, data, rootUrl, onError) {
+        STLFileLoader.prototype.loadAssetContainer = function (scene, data, rootUrl, onError) {
             var container = new BABYLON.AssetContainer(scene);
-            var result = this.importMesh(null, scene, data, rootUrl, container.meshes, null, null);
-            if (result) {
-                container.removeAllFromScene();
-                return container;
-            }
-            return null;
+            this.importMesh(null, scene, data, rootUrl, container.meshes, null, null);
+            container.removeAllFromScene();
+            return container;
         };
         STLFileLoader.prototype.isBinary = function (data) {
             // check if file size is correct for binary stl

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 1
dist/preview release/loaders/babylon.stlFileLoader.min.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1231 - 1563
dist/preview release/loaders/babylonjs.loaders.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 3 - 3
dist/preview release/loaders/babylonjs.loaders.min.js


+ 235 - 382
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -15,7 +15,7 @@ declare module BABYLON {
         extensions: ISceneLoaderPluginExtensions;
         importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: Nullable<AbstractMesh[]>, particleSystems: Nullable<ParticleSystem[]>, skeletons: Nullable<Skeleton[]>): boolean;
         load(scene: Scene, data: any, rootUrl: string): boolean;
-        loadAssets(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): Nullable<AssetContainer>;
+        loadAssetContainer(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): AssetContainer;
         private isBinary(data);
         private parseBinary(mesh, data);
         private parseASCII(mesh, solidData);
@@ -82,7 +82,7 @@ declare module BABYLON {
         private _loadMTL(url, rootUrl, onSuccess);
         importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: Nullable<AbstractMesh[]>, particleSystems: Nullable<ParticleSystem[]>, skeletons: Nullable<Skeleton[]>): boolean;
         load(scene: Scene, data: string, rootUrl: string): boolean;
-        loadAssets(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): Nullable<AssetContainer>;
+        loadAssetContainer(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): AssetContainer;
         /**
          * Read the OBJ file and create an Array of meshes.
          * Each mesh contains all information given by the OBJ and the MTL file.
@@ -129,19 +129,40 @@ declare module BABYLON {
         json: Object;
         bin: Nullable<ArrayBufferView>;
     }
+    interface IGLTFLoaderExtension {
+        /**
+         * The name of this extension.
+         */
+        readonly name: string;
+        /**
+         * Whether this extension is enabled.
+         */
+        enabled: boolean;
+    }
+    enum GLTFLoaderState {
+        Loading = 0,
+        Ready = 1,
+        Complete = 2,
+    }
     interface IGLTFLoader extends IDisposable {
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         compileMaterials: boolean;
         useClipPlane: boolean;
         compileShadowGenerators: boolean;
-        onDisposeObservable: Observable<IGLTFLoader>;
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
         onCompleteObservable: Observable<IGLTFLoader>;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+        onDisposeObservable: Observable<IGLTFLoader>;
+        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        state: Nullable<GLTFLoaderState>;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
     }
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         static CreateGLTFLoaderV1: () => IGLTFLoader;
@@ -179,19 +200,19 @@ declare module BABYLON {
         /**
          * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
          */
-        onMeshLoadedObservable: Observable<AbstractMesh>;
+        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
         private _onMeshLoadedObserver;
         onMeshLoaded: (mesh: AbstractMesh) => void;
         /**
          * Raised when the loader creates a texture after parsing the glTF properties of the texture.
          */
-        onTextureLoadedObservable: Observable<BaseTexture>;
+        readonly onTextureLoadedObservable: Observable<BaseTexture>;
         private _onTextureLoadedObserver;
         onTextureLoaded: (Texture: BaseTexture) => void;
         /**
          * Raised when the loader creates a material after parsing the glTF properties of the material.
          */
-        onMaterialLoadedObservable: Observable<Material>;
+        readonly onMaterialLoadedObservable: Observable<Material>;
         private _onMaterialLoadedObserver;
         onMaterialLoaded: (Material: Material) => void;
         /**
@@ -199,15 +220,26 @@ declare module BABYLON {
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets without LODs, raised when the model is complete, immediately after onSuccess.
          */
-        onCompleteObservable: Observable<GLTFFileLoader>;
+        readonly onCompleteObservable: Observable<GLTFFileLoader>;
         private _onCompleteObserver;
         onComplete: () => void;
         /**
         * Raised when the loader is disposed.
         */
-        onDisposeObservable: Observable<GLTFFileLoader>;
+        readonly onDisposeObservable: Observable<GLTFFileLoader>;
         private _onDisposeObserver;
         onDispose: () => void;
+        /**
+         * Raised after a loader extension is created.
+         * Set additional options for a loader extension in this event.
+         */
+        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        private _onExtensionLoadedObserver;
+        onExtensionLoaded: (extension: IGLTFLoaderExtension) => void;
+        /**
+         * The loader state or null if not active.
+         */
+        readonly loaderState: Nullable<GLTFLoaderState>;
         private _loader;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
@@ -215,9 +247,13 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAssetsAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: (assets: AssetContainer) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
         canDirectLoad(data: string): boolean;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
@@ -635,9 +671,17 @@ declare module BABYLON.GLTF1 {
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
         onCompleteObservable: Observable<IGLTFLoader>;
+        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        state: Nullable<GLTFLoaderState>;
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: SceneLoaderProgressEvent) => void, onError: (message: string) => void): boolean;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: SceneLoaderProgressEvent) => void, onError: (message: string) => void): void;
+        private _importMeshAsync(meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError);
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        private _loadAsync(scene, data, rootUrl, onSuccess, onProgress, onError);
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress: (event: SceneLoaderProgressEvent) => void): Promise<void>;
         private _loadShadersAsync(gltfRuntime, onload);
         private _loadBuffersAsync(gltfRuntime, onLoad, onProgress?);
         private _createNodes(gltfRuntime);
@@ -668,16 +712,6 @@ declare module BABYLON.GLTF1 {
          */
         static SetUniform(shaderMaterial: ShaderMaterial | Effect, uniform: string, value: any, type: number): boolean;
         /**
-        * If the uri is a base64 string
-        * @param uri: the uri to test
-        */
-        static IsBase64(uri: string): boolean;
-        /**
-        * Decode the base64 uri
-        * @param uri: the uri to decode
-        */
-        static DecodeBase64(uri: string): ArrayBuffer;
-        /**
         * Returns the wrap mode of the texture
         * @param mode: the mode value
         */
@@ -791,440 +825,259 @@ declare module BABYLON.GLTF1 {
 
 
 declare module BABYLON.GLTF2 {
-    /**
-    * Enums
-    */
-    enum EComponentType {
-        BYTE = 5120,
-        UNSIGNED_BYTE = 5121,
-        SHORT = 5122,
-        UNSIGNED_SHORT = 5123,
-        UNSIGNED_INT = 5125,
-        FLOAT = 5126,
-    }
-    enum EMeshPrimitiveMode {
-        POINTS = 0,
-        LINES = 1,
-        LINE_LOOP = 2,
-        LINE_STRIP = 3,
-        TRIANGLES = 4,
-        TRIANGLE_STRIP = 5,
-        TRIANGLE_FAN = 6,
-    }
-    enum ETextureMagFilter {
-        NEAREST = 9728,
-        LINEAR = 9729,
-    }
-    enum ETextureMinFilter {
-        NEAREST = 9728,
-        LINEAR = 9729,
-        NEAREST_MIPMAP_NEAREST = 9984,
-        LINEAR_MIPMAP_NEAREST = 9985,
-        NEAREST_MIPMAP_LINEAR = 9986,
-        LINEAR_MIPMAP_LINEAR = 9987,
-    }
-    enum ETextureWrapMode {
-        CLAMP_TO_EDGE = 33071,
-        MIRRORED_REPEAT = 33648,
-        REPEAT = 10497,
-    }
-    /**
-    * Interfaces
-    */
-    interface IGLTFProperty {
-        extensions?: {
-            [key: string]: any;
-        };
-        extras?: any;
-    }
-    interface IGLTFChildRootProperty extends IGLTFProperty {
-        name?: string;
-    }
-    interface IGLTFAccessorSparseIndices extends IGLTFProperty {
-        bufferView: number;
-        byteOffset?: number;
-        componentType: EComponentType;
-    }
-    interface IGLTFAccessorSparseValues extends IGLTFProperty {
-        bufferView: number;
-        byteOffset?: number;
-    }
-    interface IGLTFAccessorSparse extends IGLTFProperty {
-        count: number;
-        indices: IGLTFAccessorSparseIndices;
-        values: IGLTFAccessorSparseValues;
-    }
-    interface IGLTFAccessor extends IGLTFChildRootProperty {
-        bufferView?: number;
-        byteOffset?: number;
-        componentType: EComponentType;
-        normalized?: boolean;
-        count: number;
-        type: string;
-        max: number[];
-        min: number[];
-        sparse?: IGLTFAccessorSparse;
-        index: number;
-    }
-    interface IGLTFAnimationChannel extends IGLTFProperty {
-        sampler: number;
-        target: IGLTFAnimationChannelTarget;
-    }
-    interface IGLTFAnimationChannelTarget extends IGLTFProperty {
-        node: number;
-        path: string;
-    }
-    interface IGLTFAnimationSampler extends IGLTFProperty {
-        input: number;
-        interpolation?: string;
-        output: number;
+    interface TypedArray extends ArrayBufferView {
+        [index: number]: number;
     }
-    interface IGLTFAnimation extends IGLTFChildRootProperty {
-        channels: IGLTFAnimationChannel[];
-        samplers: IGLTFAnimationSampler[];
-        index: number;
-        babylonAnimationGroup: AnimationGroup;
+    interface IArrayItem {
+        _index: number;
     }
-    interface IGLTFAsset extends IGLTFChildRootProperty {
-        copyright?: string;
-        generator?: string;
-        version: string;
-        minVersion?: string;
+    class ArrayItem {
+        static Assign(values?: IArrayItem[]): void;
     }
-    interface IGLTFBuffer extends IGLTFChildRootProperty {
-        uri?: string;
-        byteLength: number;
-        index: number;
-        loadedData?: ArrayBufferView;
-        loadedObservable?: Observable<IGLTFBuffer>;
+}
+
+
+
+declare module BABYLON.GLTF2 {
+    interface ILoaderAccessor extends IAccessor, IArrayItem {
+        _data?: Promise<TypedArray>;
     }
-    interface IGLTFBufferView extends IGLTFChildRootProperty {
-        buffer: number;
-        byteOffset?: number;
-        byteLength: number;
-        byteStride?: number;
-        index: number;
+    interface ILoaderAnimationChannel extends IAnimationChannel, IArrayItem {
+        _babylonAnimationGroup: AnimationGroup;
     }
-    interface IGLTFCameraOrthographic extends IGLTFProperty {
-        xmag: number;
-        ymag: number;
-        zfar: number;
-        znear: number;
+    interface ILoaderAnimationSamplerData {
+        input: Float32Array;
+        interpolation: AnimationSamplerInterpolation;
+        output: Float32Array;
     }
-    interface IGLTFCameraPerspective extends IGLTFProperty {
-        aspectRatio: number;
-        yfov: number;
-        zfar: number;
-        znear: number;
+    interface ILoaderAnimationSampler extends IAnimationSampler, IArrayItem {
+        _data: Promise<ILoaderAnimationSamplerData>;
     }
-    interface IGLTFCamera extends IGLTFChildRootProperty {
-        orthographic?: IGLTFCameraOrthographic;
-        perspective?: IGLTFCameraPerspective;
-        type: string;
+    interface ILoaderAnimation extends IAnimation, IArrayItem {
+        channels: ILoaderAnimationChannel[];
+        samplers: ILoaderAnimationSampler[];
+        _babylonAnimationGroup: Nullable<AnimationGroup>;
     }
-    interface IGLTFImage extends IGLTFChildRootProperty {
-        uri?: string;
-        mimeType?: string;
-        bufferView?: number;
-        index: number;
+    interface ILoaderBuffer extends IBuffer, IArrayItem {
+        _data?: Promise<ArrayBufferView>;
     }
-    interface IGLTFMaterialNormalTextureInfo extends IGLTFTextureInfo {
-        scale: number;
+    interface ILoaderBufferView extends IBufferView, IArrayItem {
+        _data?: Promise<ArrayBufferView>;
     }
-    interface IGLTFMaterialOcclusionTextureInfo extends IGLTFTextureInfo {
-        strength: number;
+    interface ILoaderCamera extends ICamera, IArrayItem {
     }
-    interface IGLTFMaterialPbrMetallicRoughness {
-        baseColorFactor: number[];
-        baseColorTexture: IGLTFTextureInfo;
-        metallicFactor: number;
-        roughnessFactor: number;
-        metallicRoughnessTexture: IGLTFTextureInfo;
+    interface ILoaderImage extends IImage, IArrayItem {
+        _objectURL?: Promise<string>;
     }
-    interface IGLTFMaterial extends IGLTFChildRootProperty {
-        pbrMetallicRoughness?: IGLTFMaterialPbrMetallicRoughness;
-        normalTexture?: IGLTFMaterialNormalTextureInfo;
-        occlusionTexture?: IGLTFMaterialOcclusionTextureInfo;
-        emissiveTexture?: IGLTFTextureInfo;
-        emissiveFactor?: number[];
-        alphaMode?: string;
-        alphaCutoff: number;
-        doubleSided?: boolean;
-        index: number;
-        babylonMaterial: Material;
+    interface ILoaderMaterial extends IMaterial, IArrayItem {
+        _babylonMaterial?: Material;
+        _babylonMeshes?: AbstractMesh[];
+        _loaded?: Promise<void>;
     }
-    interface IGLTFMeshPrimitive extends IGLTFProperty {
-        attributes: {
-            [name: string]: number;
-        };
-        indices?: number;
-        material?: number;
-        mode?: EMeshPrimitiveMode;
-        targets?: {
-            [name: string]: number;
-        }[];
-        vertexData: VertexData;
-        targetsVertexData: VertexData[];
+    interface ILoaderMesh extends IMesh, IArrayItem {
+        primitives: ILoaderMeshPrimitive[];
     }
-    interface IGLTFMesh extends IGLTFChildRootProperty {
-        primitives: IGLTFMeshPrimitive[];
-        weights?: number[];
-        index: number;
-        hasVertexAlpha: boolean;
+    interface ILoaderMeshPrimitive extends IMeshPrimitive, IArrayItem {
     }
-    interface IGLTFNode extends IGLTFChildRootProperty {
-        camera?: number;
-        children?: number[];
-        skin?: number;
-        matrix?: number[];
-        mesh?: number;
-        rotation?: number[];
-        scale?: number[];
-        translation?: number[];
-        weights?: number[];
-        index: number;
-        parent: IGLTFNode;
-        babylonMesh: Mesh;
-        babylonAnimationTargets?: Node[];
+    interface ILoaderNode extends INode, IArrayItem {
+        _parent: ILoaderNode;
+        _babylonMesh?: Mesh;
+        _primitiveBabylonMeshes?: Mesh[];
+        _babylonAnimationTargets?: Node[];
+        _numMorphTargets?: number;
     }
-    interface IGLTFSampler extends IGLTFChildRootProperty {
-        magFilter?: ETextureMagFilter;
-        minFilter?: ETextureMinFilter;
-        wrapS?: ETextureWrapMode;
-        wrapT?: ETextureWrapMode;
-        index: number;
+    interface ILoaderSamplerData {
         noMipMaps: boolean;
         samplingMode: number;
         wrapU: number;
         wrapV: number;
     }
-    interface IGLTFScene extends IGLTFChildRootProperty {
-        nodes: number[];
-        index: number;
+    interface ILoaderSampler extends ISampler, IArrayItem {
+        _data?: ILoaderSamplerData;
     }
-    interface IGLTFSkin extends IGLTFChildRootProperty {
-        inverseBindMatrices?: number;
-        skeleton?: number;
-        joints: number[];
-        index: number;
-        babylonSkeleton: Skeleton;
+    interface ILoaderScene extends IScene, IArrayItem {
     }
-    interface IGLTFTexture extends IGLTFChildRootProperty {
-        sampler?: number;
-        source: number;
-        index: number;
-        url?: string;
-        dataReadyObservable?: Observable<IGLTFTexture>;
-    }
-    interface IGLTFTextureInfo {
-        index: number;
-        texCoord?: number;
-    }
-    interface _IGLTF extends IGLTFProperty {
-        accessors?: IGLTFAccessor[];
-        animations?: IGLTFAnimation[];
-        asset: IGLTFAsset;
-        buffers?: IGLTFBuffer[];
-        bufferViews?: IGLTFBufferView[];
-        cameras?: IGLTFCamera[];
-        extensionsUsed?: string[];
-        extensionsRequired?: string[];
-        images?: IGLTFImage[];
-        materials?: IGLTFMaterial[];
-        meshes?: IGLTFMesh[];
-        nodes?: IGLTFNode[];
-        samplers?: IGLTFSampler[];
-        scene?: number;
-        scenes?: IGLTFScene[];
-        skins?: IGLTFSkin[];
-        textures?: IGLTFTexture[];
+    interface ILoaderSkin extends ISkin, IArrayItem {
+        _babylonSkeleton: Nullable<Skeleton>;
+        _loaded?: Promise<void>;
+    }
+    interface ILoaderTexture extends ITexture, IArrayItem {
+    }
+    interface ILoaderGLTF extends IGLTF {
+        accessors?: ILoaderAccessor[];
+        animations?: ILoaderAnimation[];
+        buffers?: ILoaderBuffer[];
+        bufferViews?: ILoaderBufferView[];
+        cameras?: ILoaderCamera[];
+        images?: ILoaderImage[];
+        materials?: ILoaderMaterial[];
+        meshes?: ILoaderMesh[];
+        nodes?: ILoaderNode[];
+        samplers?: ILoaderSampler[];
+        scenes?: ILoaderScene[];
+        skins?: ILoaderSkin[];
+        textures?: ILoaderTexture[];
     }
 }
 
 
 declare module BABYLON.GLTF2 {
     class GLTFLoader implements IGLTFLoader {
-        _gltf: _IGLTF;
+        _gltf: ILoaderGLTF;
         _babylonScene: Scene;
+        _completePromises: Promise<void>[];
         private _disposed;
+        private _state;
+        private _extensions;
         private _rootUrl;
-        private _defaultMaterial;
+        private _rootBabylonMesh;
         private _defaultSampler;
-        private _rootNode;
-        private _successCallback?;
         private _progressCallback?;
-        private _errorCallback?;
-        private _renderReady;
         private _requests;
-        private _renderReadyObservable;
-        private _renderPendingCount;
-        private _loaderPendingCount;
-        private _loaderTrackers;
-        static Extensions: {
-            [name: string]: GLTFLoaderExtension;
-        };
-        static RegisterExtension(extension: GLTFLoaderExtension): void;
+        private static _Names;
+        private static _Factories;
+        static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         compileMaterials: boolean;
         useClipPlane: boolean;
         compileShadowGenerators: boolean;
-        onDisposeObservable: Observable<IGLTFLoader>;
-        onMeshLoadedObservable: Observable<AbstractMesh>;
-        onTextureLoadedObservable: Observable<BaseTexture>;
-        onMaterialLoadedObservable: Observable<Material>;
-        onCompleteObservable: Observable<IGLTFLoader>;
+        readonly onDisposeObservable: Observable<IGLTFLoader>;
+        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
+        readonly onTextureLoadedObservable: Observable<BaseTexture>;
+        readonly onMaterialLoadedObservable: Observable<Material>;
+        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        readonly onCompleteObservable: Observable<IGLTFLoader>;
+        readonly state: Nullable<GLTFLoaderState>;
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess?, onProgress?, onError?);
-        private _onProgress();
-        _executeWhenRenderReady(func: () => void): void;
-        private _onRenderReady();
-        private _onComplete();
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        private _loadAsync(nodes, scene, data, rootUrl, onProgress?);
+        private _loadExtensions();
         private _loadData(data);
+        private _setupData();
+        private _createRootNode();
+        private _loadNodesAsync(nodes);
+        _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;
         private _getMeshes();
         private _getSkeletons();
         private _startAnimations();
-        private _loadDefaultScene(nodeNames);
-        private _loadScene(context, scene, nodeNames);
-        _loadNode(context: string, node: IGLTFNode): void;
-        private _loadMesh(context, node, mesh);
-        private _loadAllVertexDataAsync(context, mesh, onSuccess);
-        /**
-         * Converts a data bufferview into a Float4 Texture Coordinate Array, based on the accessor component type
-         * @param {ArrayBufferView} data
-         * @param {IGLTFAccessor} accessor
-         */
-        private _convertToFloat4TextureCoordArray(context, data, accessor);
-        /**
-         * Converts a data bufferview into a Float4 Color Array, based on the accessor component type
-         * @param {ArrayBufferView} data
-         * @param {IGLTFAccessor} accessor
-         */
-        private _convertToFloat4ColorArray(context, data, accessor);
-        private _loadVertexDataAsync(context, mesh, primitive, onSuccess);
-        private _createMorphTargets(context, node, mesh);
-        private _loadMorphTargets(context, node, mesh);
-        private _loadAllMorphTargetVertexDataAsync(context, node, mesh, onSuccess);
-        private _loadMorphTargetVertexDataAsync(context, vertexData, attributes, onSuccess);
-        private _loadTransform(node);
-        private _loadSkinAsync(context, skin, onSuccess);
+        _loadNodeAsync(context: string, node: ILoaderNode): Promise<void>;
+        private _loadMeshAsync(context, node, mesh);
+        private _loadPrimitiveAsync(context, node, mesh, primitive);
+        private _loadVertexDataAsync(context, primitive, babylonMesh);
+        private _createMorphTargets(context, node, mesh, primitive, babylonMesh);
+        private _loadMorphTargetsAsync(context, primitive, babylonMesh, babylonVertexData);
+        private _loadMorphTargetVertexDataAsync(context, babylonVertexData, attributes, babylonMorphTarget);
+        private static _ConvertToFloat32Array(context, accessor, data);
+        private static _ConvertVec3ToVec4(context, data);
+        private static _LoadTransform(node, babylonNode);
+        private _loadSkinAsync(context, node, mesh, skin);
+        private _loadSkinInverseBindMatricesDataAsync(context, skin);
         private _createBone(node, skin, parent, localMatrix, baseMatrix, index);
-        private _loadBones(context, skin, inverseBindMatrixData);
-        private _loadBone(node, skin, inverseBindMatrixData, babylonBones);
+        private _loadBones(context, skin, inverseBindMatricesData);
+        private _loadBone(node, skin, inverseBindMatricesData, babylonBones);
         private _getNodeMatrix(node);
-        private _traverseNodes(context, indices, action, parentNode);
-        _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): void;
-        private _loadAnimations();
-        private _loadAnimation(context, animation);
-        private _loadAnimationChannel(animation, channelContext, channel, samplerContext, sampler);
-        private _loadBufferAsync(context, buffer, onSuccess);
-        private _loadBufferViewAsync(context, bufferView, onSuccess);
-        private _loadAccessorAsync(context, accessor, onSuccess);
+        private _loadAnimationsAsync();
+        private _loadAnimationAsync(context, animation);
+        private _loadAnimationChannelAsync(context, animationContext, animation, channel, babylonAnimationGroup);
+        private _loadAnimationSamplerAsync(context, sampler);
+        private _loadBufferAsync(context, buffer);
+        private _loadBufferViewAsync(context, bufferView);
+        private _loadAccessorAsync(context, accessor);
         private _buildArrayBuffer<T>(typedArray, data, byteOffset, count, numComponents, byteStride?);
-        _addPendingData(data: any): void;
-        _removePendingData(data: any): void;
-        _addLoaderPendingData(data: any): void;
-        _removeLoaderPendingData(data: any): void;
-        _whenAction(action: () => void, onComplete: () => void): void;
         private _getDefaultMaterial();
-        private _loadMaterialMetallicRoughnessProperties(context, material);
-        _loadMaterial(context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): void;
-        _createPbrMaterial(material: IGLTFMaterial): void;
-        _loadMaterialBaseProperties(context: string, material: IGLTFMaterial): void;
-        _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
-        _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture;
+        private _loadMaterialMetallicRoughnessPropertiesAsync(context, material);
+        _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Promise<void>;
+        _createMaterial(material: ILoaderMaterial): PBRMaterial;
+        _loadMaterialBasePropertiesAsync(context: string, material: ILoaderMaterial): Promise<void>;
+        _loadMaterialAlphaProperties(context: string, material: ILoaderMaterial): void;
+        _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Promise<void>;
         private _loadSampler(context, sampler);
-        private _loadImageAsync(context, image, onSuccess);
-        _loadUriAsync(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
-        _tryCatchOnError(handler: () => void): void;
-        private static _AssignIndices(array?);
-        static _GetProperty<T extends IGLTFProperty>(array?: ArrayLike<T>, index?: number): Nullable<T>;
-        private static _GetTextureWrapMode(context, mode?);
+        private _loadImageAsync(context, image);
+        _loadUriAsync(context: string, uri: string): Promise<ArrayBufferView>;
+        private _onProgress();
+        static _GetProperty<T>(context: string, array: ArrayLike<T> | undefined, index: number | undefined): T;
+        private static _GetTextureWrapMode(context, mode);
         private static _GetTextureSamplingMode(context, magFilter?, minFilter?);
         private static _GetNumComponents(context, type);
-        private _compileMaterialAsync(babylonMaterial, babylonMesh, onSuccess);
-        private _compileMaterialsAsync(onSuccess);
-        private _compileShadowGeneratorsAsync(onSuccess);
-        private _abortRequests();
-        private _releaseResources();
+        private static _ValidateUri(uri);
+        private _compileMaterialsAsync();
+        private _compileShadowGeneratorsAsync();
+        private _clear();
+        _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>): Nullable<Promise<T>>;
     }
 }
 
 
 declare module BABYLON.GLTF2 {
-    /**
-    * Utils functions for GLTF
-    */
-    class GLTFUtils {
-        /**
-        * If the uri is a base64 string
-        * @param uri: the uri to test
-        */
-        static IsBase64(uri: string): boolean;
-        /**
-        * Decode the base64 uri
-        * @param uri: the uri to decode
-        */
-        static DecodeBase64(uri: string): ArrayBuffer;
-        static ValidateUri(uri: string): boolean;
-    }
-}
-
-
-declare module BABYLON.GLTF2 {
-    abstract class GLTFLoaderExtension {
+    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension {
         enabled: boolean;
         readonly abstract name: string;
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        protected _loadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean;
-        protected _loadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean;
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        protected _loadExtension<T>(context: string, property: IGLTFProperty, action: (context: string, extension: T, onComplete: () => void) => void): boolean;
-        static _Extensions: GLTFLoaderExtension[];
-        static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
-        static LoadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean;
-        static LoadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean;
-        static LoadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        static LoadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private static _ApplyExtensions(action);
+        protected _loader: GLTFLoader;
+        constructor(loader: GLTFLoader);
+        /** Override this method to modify the default behavior for loading scenes. */
+        protected _loadSceneAsync(context: string, node: ILoaderScene): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading nodes. */
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading materials. */
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading uris. */
+        protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
+        /** Helper method called by a loader extension to load an glTF extension. */
+        protected _loadExtensionAsync<T>(context: string, property: IProperty, actionAsync: (context: string, extension: T) => Promise<void>): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading scenes. */
+        static _LoadSceneAsync(loader: GLTFLoader, context: string, scene: ILoaderScene): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading nodes. */
+        static _LoadNodeAsync(loader: GLTFLoader, context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading materials. */
+        static _LoadMaterialAsync(loader: GLTFLoader, context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading uris. */
+        static _LoadUriAsync(loader: GLTFLoader, context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
     }
 }
 
 
 declare module BABYLON.GLTF2.Extensions {
-    class MSFTLOD extends GLTFLoaderExtension {
+    class MSFT_lod extends GLTFLoaderExtension {
+        readonly name: string;
         /**
-         * Specify the minimal delay between LODs in ms (default = 250)
+         * Maximum number of LODs to load, starting from the lowest LOD.
          */
-        Delay: number;
-        readonly name: string;
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        private _loadNodeLOD(loader, context, nodes, index, onComplete);
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private _loadMaterialLOD(loader, context, materials, index, assign, onComplete);
+        maxLODsToLoad: number;
+        private _loadingNodeLOD;
+        private _loadNodeSignals;
+        private _loadingMaterialLOD;
+        private _loadMaterialSignals;
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
+        /**
+         * Gets an array of LOD properties from lowest to highest.
+         */
+        private _getLODs<T>(context, property, array, ids);
     }
 }
 
 
 declare module BABYLON.GLTF2.Extensions {
-    class KHRMaterialsPbrSpecularGlossiness extends GLTFLoaderExtension {
+    class KHR_materials_pbrSpecularGlossiness extends GLTFLoaderExtension {
         readonly name: string;
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private _loadSpecularGlossinessProperties(loader, context, material, properties);
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        private _loadSpecularGlossinessPropertiesAsync(loader, context, material, properties);
     }
 }
 
 
 declare module BABYLON.GLTF2.Extensions {
-    class KHRLights extends GLTFLoaderExtension {
+    class KHR_lights extends GLTFLoaderExtension {
         readonly name: string;
-        private applyCommonProperties(light, lightInfo);
-        protected _loadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean;
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        protected _loadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean;
+        protected _loadSceneAsync(context: string, scene: ILoaderScene): Nullable<Promise<void>>;
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        private readonly _lights;
     }
 }

+ 1 - 1
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.2.0-alpha6",
+    "version": "3.2.0-alpha7",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 1
dist/preview release/materialsLibrary/babylon.customMaterial.min.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 1
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.min.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 3 - 3
dist/preview release/materialsLibrary/babylonjs.materials.min.js


+ 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.2.0-alpha6",
+    "version": "3.2.0-alpha7",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 1
dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js


+ 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.2.0-alpha6",
+    "version": "3.2.0-alpha7",
     "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.2.0-alpha6",
+    "version": "3.2.0-alpha7",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.min.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.min.js


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

@@ -28,7 +28,7 @@ declare module BABYLON.GLTF2 {
         SCALE = "scale",
         WEIGHTS = "weights",
     }
-    const enum AnimationInterpolation {
+    const enum AnimationSamplerInterpolation {
         LINEAR = "LINEAR",
         STEP = "STEP",
         CUBICSPLINE = "CUBICSPLINE",
@@ -116,7 +116,7 @@ declare module BABYLON.GLTF2 {
     }
     interface IAnimationSampler extends IProperty {
         input: number;
-        interpolation?: AnimationInterpolation;
+        interpolation?: AnimationSamplerInterpolation;
         output: number;
     }
     interface IAnimation extends IChildRootProperty {

+ 1 - 1
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.2.0-alpha6",
+    "version": "3.2.0-alpha7",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -1,7 +1,7 @@
 {
-  "errors": 7550,
+  "errors": 7341,
   "babylon.typedoc.json": {
-    "errors": 7550,
+    "errors": 7341,
     "AnimationKeyInterpolation": {
       "Enumeration": {
         "Comments": {
@@ -14674,42 +14674,6 @@
         }
       }
     },
-    "HighlightLayer": {
-      "Property": {
-        "name": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "glowingMeshStencilReference": {
-          "Naming": {
-            "NotPascalCase": true
-          }
-        },
-        "neutralColor": {
-          "Naming": {
-            "NotPascalCase": true
-          }
-        },
-        "normalMeshStencilReference": {
-          "Naming": {
-            "NotPascalCase": true
-          }
-        }
-      },
-      "Method": {
-        "_rebuild": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "shouldRender": {
-          "Comments": {
-            "MissingReturn": true
-          }
-        }
-      }
-    },
     "HighlightsPostProcess": {
       "Class": {
         "Comments": {
@@ -27406,11 +27370,6 @@
             "MissingText": true
           }
         },
-        "highlightLayers": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "hoverCursor": {
           "Comments": {
             "MissingText": true
@@ -27441,11 +27400,6 @@
             "MissingText": true
           }
         },
-        "layers": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "lensFlareSystems": {
           "Comments": {
             "MissingText": true
@@ -29338,18 +29292,6 @@
         }
       },
       "Method": {
-        "Append": {
-          "Comments": {
-            "MissingReturn": true
-          },
-          "Parameter": {
-            "pluginExtension": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
         "GetPluginForExtension": {
           "Comments": {
             "MissingText": true
@@ -29362,18 +29304,6 @@
             }
           }
         },
-        "ImportMesh": {
-          "Comments": {
-            "MissingReturn": true
-          },
-          "Parameter": {
-            "pluginExtension": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
         "IsPluginForExtensionAvailable": {
           "Comments": {
             "MissingText": true
@@ -29386,60 +29316,6 @@
             }
           }
         },
-        "Load": {
-          "Comments": {
-            "MissingReturn": true
-          },
-          "Parameter": {
-            "pluginExtension": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "LoadAssetContainer": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "rootUrl": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "sceneFilename": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "scene": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "onSuccess": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "onProgress": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "onError": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "pluginExtension": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
         "RegisterPlugin": {
           "Comments": {
             "MissingText": true
@@ -31969,708 +31845,6 @@
         }
       }
     },
-    "StandardMaterialDefines": {
-      "Class": {
-        "Comments": {
-          "MissingText": true
-        }
-      },
-      "Constructor": {
-        "new StandardMaterialDefines": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      },
-      "Property": {
-        "ALPHAFROMDIFFUSE": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "ALPHATEST": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "AMBIENT": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "AMBIENTDIRECTUV": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "BUMP": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "BUMPDIRECTUV": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "BonesPerMesh": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "CLIPPLANE": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "COLORCURVES": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "COLORGRADING": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "COLORGRADING3D": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "CONTRAST": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "DEPTHPREPASS": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "DIFFUSE": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "DIFFUSEDIRECTUV": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "DIFFUSEFRESNEL": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "EMISSIVE": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "EMISSIVEASILLUMINATION": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "EMISSIVEDIRECTUV": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "EMISSIVEFRESNEL": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "EXPOSURE": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "FOG": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "FRESNEL": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "GLOSSINESS": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "IMAGEPROCESSING": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "IMAGEPROCESSINGPOSTPROCESS": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "INSTANCES": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "INVERTCUBICMAP": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "LIGHTMAP": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "LIGHTMAPDIRECTUV": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "LINKEMISSIVEWITHDIFFUSE": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "LOGARITHMICDEPTH": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "MAINUV1": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "MAINUV2": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "MORPHTARGETS": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "MORPHTARGETS_NORMAL": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "MORPHTARGETS_TANGENT": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "NONUNIFORMSCALING": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "NORMAL": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "NUM_BONE_INFLUENCERS": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "NUM_MORPH_INFLUENCERS": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "OPACITY": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "OPACITYDIRECTUV": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "OPACITYFRESNEL": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "OPACITYRGB": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "PARALLAX": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "PARALLAXOCCLUSION": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "POINTSIZE": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "PREMULTIPLYALPHA": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "REFLECTION": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "REFLECTIONFRESNEL": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "REFLECTIONFRESNELFROMSPECULAR": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "REFLECTIONMAP_3D": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "REFLECTIONMAP_CUBIC": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "REFLECTIONMAP_EQUIRECTANGULAR": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "REFLECTIONMAP_EQUIRECTANGULAR_FIXED": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "REFLECTIONMAP_EXPLICIT": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "REFLECTIONMAP_PLANAR": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "REFLECTIONMAP_PROJECTION": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "REFLECTIONMAP_SKYBOX": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "REFLECTIONMAP_SPHERICAL": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "REFLECTIONOVERALPHA": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "REFRACTION": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "REFRACTIONFRESNEL": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "REFRACTIONMAP_3D": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "ROUGHNESS": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "SAMPLER3DBGRMAP": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "SAMPLER3DGREENDEPTH": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "SHADOWFLOAT": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "SPECULAR": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "SPECULARDIRECTUV": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "SPECULAROVERALPHA": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "SPECULARTERM": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "TONEMAPPING": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "TWOSIDEDLIGHTING": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "USELIGHTMAPASSHADOWMAP": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "UV1": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "UV2": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "VERTEXALPHA": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "VERTEXCOLOR": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "VIGNETTE": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "VIGNETTEBLENDMODEMULTIPLY": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "VIGNETTEBLENDMODEOPAQUE": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      },
-      "Method": {
-        "setReflectionMode": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "modeToEnable": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        }
-      }
-    },
     "StandardRenderingPipeline": {
       "Class": {
         "Comments": {
@@ -38212,11 +37386,6 @@
               "Comments": {
                 "MissingText": true
               }
-            },
-            "options": {
-              "Comments": {
-                "MissingText": true
-              }
             }
           }
         },
@@ -41279,43 +40448,6 @@
         "Comments": {
           "MissingText": true
         }
-      },
-      "Property": {
-        "canDirectLoad": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "extensions": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "importMesh": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "load": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "loadAssets": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "name": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "rewriteRootURL": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
       }
     },
     "ISceneLoaderPluginAsync": {
@@ -41323,43 +40455,6 @@
         "Comments": {
           "MissingText": true
         }
-      },
-      "Property": {
-        "canDirectLoad": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "extensions": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "importMeshAsync": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "loadAssetsAsync": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "loadAsync": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "name": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "rewriteRootURL": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
       }
     },
     "ISceneLoaderPluginExtensions": {

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 68 - 67
dist/preview release/viewer/babylon.viewer.js


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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-viewer",
     "description": "A simple-to-use viewer based on BabylonJS to display 3D elements natively",
-    "version": "3.2.0-alpha6",
+    "version": "3.2.0-alpha7",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 24 - 5
dist/preview release/what's new.md

@@ -1,6 +1,7 @@
 # 3.2.0
 
 ## Major updates
+
 - Improved building process: We now run a full visual validation test for each pull request. Furthermore, code comments and what's new updates are now mandatory ([sebavan](https://github.com/sebavan))
 - Introduced texture binding atlas. This optimization allows the engine to reuse texture bindings instead of rebinding textures when they are not on constant sampler indexes ([deltakosh](https://github.com/deltakosh))
 - New [AnimationGroup class](http://doc.babylonjs.com/how_to/group) to control simultaneously multiple animations with different targets ([deltakosh](https://github.com/deltakosh))
@@ -8,8 +9,12 @@
 - New glTF [serializer](https://github.com/BabylonJS/Babylon.js/tree/master/serializers/src/glTF/2.0). You can now export glTF or glb files directly from a Babylon scene ([kcoley](https://github.com/kcoley))
 - Babylon.js now uses Promises in addition to callbacks. We created several `xxxAsync` functions all over the framework (`SceneLoader.AppendAsync` for instance, which returns a Promise). A polyfill is also integrated to support older browsers ([deltakosh](https://github.com/deltakosh))
 - Introduced [Projection Texture on SpotLight](http://doc.babylonjs.com/babylon101/lights#projection-texture) ([lostink](https://github.com/lostink))
+- Introduced support for [local cubemaps](http://doc.babylonjs.com/how_to/reflect#using-local-cubemap-mode) ([deltakosh](https://github.com/deltakosh))
+- Added [VideoDome](http://doc.babylonjs.com/how_to/360videodome) class to easily support 360 videos ([DavidHGillen](https://github.com/DavidHGillen))
+- Added [GlowLayer](https://doc.babylonjs.com/how_to/glow_layer) to easily support glow from emissive materials ([sebavan](https://github.com/sebavan))
 
 ## Updates
+
 - Tons of functions and classes received the code comments they deserved (All the community)
 - Added support for all RGBA orders (BGR, RGB, etc..) for the DDS loader ([deltakosh](https://github.com/deltakosh))
 - Improved [SceneOptimizer](http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer) to provide better adaptability ([deltakosh](https://github.com/deltakosh))
@@ -34,7 +39,7 @@
    ([carloslanderas](https://github.com/carloslanderas))
 - (Viewer) initScene and initEngine can now be extended. onProgress during model loading is implemented as observable. ([RaananW](https://github.com/RaananW))
 - glTF loader now supports the KHR_lights extension ([MiiBond](https://github.com/MiiBond))
-- Added depth of field effect to default pipeline ([trevordev](https://github.com/trevordev))
+- Added depth of field effect to the default pipeline ([trevordev](https://github.com/trevordev))
 - The observable can now notify observers using promise-based callback chain. ([RaananW](https://github.com/RaananW))
 - Added base64 helper functions to `Tools` ([bghgary](https://github.com/bghgary))
 - Added `createDefaultCamera` and `createDefaultLight` functions to `Scene` ([bghgary](https://github.com/bghgary))
@@ -44,16 +49,30 @@
 - Documented PostProcessRenderEffect, DefaultRenderingPipeline, BlurPostProcess, DepthOfFieldEffect, PostProcess, PostProcessManager, Effect classes ([trevordev](https://github.com/trevordev))
 - SPS internal storage of each solid particle rotation matrix ([jbousquie](https://github.com/jbousquie)) 
 - (Viewer) Introducing the viewer labs - testing new features. ([RaananW](https://github.com/RaananW))
-- AssetContainer Class and loading methods. ([trevordev](https://github.com/trevordev))
-- KeepAssets class and AssetContainer.moveAllFromScene ([HoloLite](http://www.html5gamedevs.com/profile/28694-hololite/), [trevordev](https://github.com/trevordev))
+- AssetContainer Class and loading methods ([trevordev](https://github.com/trevordev))
+- KeepAssets class and AssetContainer.moveAllFromScene ([HoloLite](http://www.html5gamedevs.com/profile/28694-hololite/) [trevordev](https://github.com/trevordev))
 - (Viewer) It is now possible to update parts of the configuration without rcreating the objects. ([RaananW](https://github.com/RaananW))
+- (Gulp) extra/external declarations can be prepended to final declarations during build. ([RaananW](https://github.com/RaananW))
 - (Viewer) Model can be normalized using configuration. ([RaananW](https://github.com/RaananW))
 - (Gulp) extra/external declarations can be prepended to final NPM declarations during build. ([RaananW](https://github.com/RaananW))
+- GUI.Line can have its world position set from one end or the other ([SvenFrankson](https://github.com/SvenFrankson))
+- Added FOV system to background material for zoom effects in skyboxes without adjusting camera FOV ([DavidHGillen](https://github.com/DavidHGillen))
+- Improved glTF loader by using promises for asynchronous operations. ([bghgary](https://github.com/bghgary)]
+- Improved glTF loader performance by compiling materials in parallel with downloading external resources. ([bghgary](https://github.com/bghgary)]
+- Added unit tests for the glTF 2.0 loader. ([bghgary](https://github.com/bghgary)]
+- Added promise-based async functions to the SceneLoader, Scene.whenReadyAsync, and material.forceCompilationAsync. ([bghgary](https://github.com/bghgary)]
+- Added checks to VertexData.merge to ensure data is valid before merging. ([bghgary](https://github.com/bghgary)]
+- Ability to set a mesh to customize the webVR gaze tracker ([trevordev](https://github.com/trevordev))
 
 ## Bug fixes
+
 - `setPivotMatrix` ws not setting pivot correctly. This is now fixed. We also introduced a new `setPreTransformMatrix` to reproduce the sometimes needed behavior of the previous `setPivotMatrix` function ([deltakosh](https://github.com/deltakosh))
+- SPS solid particle `.pivot` property now also behaves like the standard mesh pivot. Former behavior (particle translation) can be kept with the particle property `.translateFromPivot` set to true ([jbousquie](https://github.com/jbousquie))
 - Texture extension detection in `Engine.CreateTexture` ([sebavan](https://github.com/sebavan))
-- Fixed a bug with merging vertex data ([bghgary](https://github.com/bghgary))
+- SPS internal temporary vector3 instead of Tmp.Vector3 to avoid possible concurrent uses ([jbousquie](https://github.com/jbousquie))
 
 ## Breaking changes
-- Removed unused PostProcessRenderPass class and extended postProcessingRenderingEffect to support multiple PostProcesses ([trevordev](https://github.com/trevordev))
+
+- Removed the unused PostProcessRenderPass class and extended postProcessingRenderingEffect to support multiple PostProcesses ([trevordev](https://github.com/trevordev))
+- VertexData.merge no longer supports merging of data that do not have the same set of attributes. ([bghgary](https://github.com/bghgary)]
+- glTF 2.0 loader will now create a mesh for each primitive instead of merging the primitives together into one mesh. ([bghgary](https://github.com/bghgary)]

+ 45 - 7
gui/src/controls/line.ts

@@ -179,14 +179,52 @@ module BABYLON.GUI {
         protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void {          
             this._currentMeasure.left = Math.min(this._x1.getValue(this._host), this._effectiveX2) - this._lineWidth / 2;
             this._currentMeasure.top = Math.min(this._y1.getValue(this._host), this._effectiveY2) - this._lineWidth / 2;            
-        }   
+        }
+
+        /**
+         * Move one end of the line given 3D cartesian coordinates.
+         * @param position Targeted world position
+         * @param scene Scene
+         * @param end (opt) Set to true to assign x2 and y2 coordinates of the line. Default assign to x1 and y1.
+         */
+        public moveToVector3(position: Vector3, scene: Scene, end: boolean = false): void {
+            if (!this._host || this._root !== this._host._rootContainer) {
+                Tools.Error("Cannot move a control to a vector3 if the control is not at root level");
+                return;
+            }
+
+            var globalViewport = this._host._getGlobalViewport(scene);
+            var projectedPosition = Vector3.Project(position, Matrix.Identity(), scene.getTransformMatrix(), globalViewport);
 
-        public _moveToProjectedPosition(projectedPosition: Vector3): void {
-            this.x1 = (projectedPosition.x + this._linkOffsetX.getValue(this._host)) + "px";
-            this.y1 = (projectedPosition.y + this._linkOffsetY.getValue(this._host)) + "px";
+            this._moveToProjectedPosition(projectedPosition, end)
 
-            this._x1.ignoreAdaptiveScaling = true;
-            this._y1.ignoreAdaptiveScaling = true;
+            if (projectedPosition.z < 0 || projectedPosition.z > 1) {
+                this.notRenderable = true;
+                return;
+            }
+            this.notRenderable = false;
+        }
+
+        /**
+         * Move one end of the line to a position in screen absolute space.
+         * @param projectedPosition Position in screen absolute space (X, Y)
+         * @param end (opt) Set to true to assign x2 and y2 coordinates of the line. Default assign to x1 and y1.
+         */
+        public _moveToProjectedPosition(projectedPosition: Vector3, end: boolean = false): void {
+            let x: string = (projectedPosition.x + this._linkOffsetX.getValue(this._host)) + "px";
+            let y: string = (projectedPosition.y + this._linkOffsetY.getValue(this._host)) + "px";
+
+            if (end) {
+                this.x2 = x;
+                this.y2 = y;
+                this._x2.ignoreAdaptiveScaling = true;
+                this._y2.ignoreAdaptiveScaling = true;
+            } else {
+                this.x1 = x;
+                this.y1 = y;
+                this._x1.ignoreAdaptiveScaling = true;
+                this._y1.ignoreAdaptiveScaling = true;
+            }
         }
     }    
-}
+}

+ 4 - 7
loaders/src/OBJ/babylon.objFileLoader.ts

@@ -264,14 +264,11 @@ module BABYLON {
             return this.importMesh(null, scene, data, rootUrl, null, null, null);
         }
 
-        public loadAssets(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void):Nullable<AssetContainer>{
+        public loadAssetContainer(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): AssetContainer {
             var container = new AssetContainer(scene);
-            var result = this.importMesh(null, scene, data, rootUrl, container.meshes, null, null);
-            if(result){
-                container.removeAllFromScene();
-                return container;
-            }
-            return null;
+            this.importMesh(null, scene, data, rootUrl, container.meshes, null, null);
+            container.removeAllFromScene();
+            return container;
         }
 
         /**

+ 4 - 7
loaders/src/STL/babylon.stlFileLoader.ts

@@ -86,14 +86,11 @@ module BABYLON {
             return result;
         }
 
-        public loadAssets(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void):Nullable<AssetContainer>{
+        public loadAssetContainer(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): AssetContainer {
             var container = new AssetContainer(scene);
-            var result = this.importMesh(null, scene, data, rootUrl, container.meshes, null, null);
-            if(result){
-                container.removeAllFromScene();
-                return container;
-            }
-            return null;
+            this.importMesh(null, scene, data, rootUrl, container.meshes, null, null);
+            container.removeAllFromScene();
+            return container;
         }
 
         private isBinary (data: any) {

+ 42 - 12
loaders/src/glTF/1.0/babylon.glTFLoader.ts

@@ -584,9 +584,7 @@ module BABYLON.GLTF1 {
 
         const subMaterials: Material[] = [];
 
-        var vertexData = new VertexData();
-        var geometry = new Geometry(id, gltfRuntime.scene, vertexData, false, newMesh);
-
+        var vertexData: Nullable<VertexData> = null;
         var verticesStarts = new Array<number>();
         var verticesCounts = new Array<number>();
         var indexStarts = new Array<number>();
@@ -684,7 +682,12 @@ module BABYLON.GLTF1 {
                     indexCounts.push(tempVertexData.indices.length);
                 }
 
-                vertexData.merge(tempVertexData);
+                if (!vertexData) {
+                    vertexData = tempVertexData;
+                }
+                else {
+                    vertexData.merge(tempVertexData);
+                }
 
                 // Sub material
                 let material = gltfRuntime.scene.getMaterialByID(primitive.material);
@@ -714,7 +717,7 @@ module BABYLON.GLTF1 {
         }
 
         // Apply geometry
-        geometry.setAllVerticesData(vertexData, false);
+        new Geometry(id, gltfRuntime.scene, vertexData!, false, newMesh);
         newMesh.computeWorldMatrix(true);
 
         // Apply submeshes
@@ -1292,8 +1295,8 @@ module BABYLON.GLTF1 {
         public static LoadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: (message: string) => void, onProgress?: () => void): void {
             var buffer: IGLTFBuffer = gltfRuntime.buffers[id];
 
-            if (GLTFUtils.IsBase64(buffer.uri)) {
-                setTimeout(() => onSuccess(new Uint8Array(GLTFUtils.DecodeBase64(buffer.uri))));
+            if (Tools.IsBase64(buffer.uri)) {
+                setTimeout(() => onSuccess(new Uint8Array(Tools.DecodeBase64(buffer.uri))));
             }
             else {
                 Tools.LoadFile(gltfRuntime.rootUrl + buffer.uri, data => onSuccess(new Uint8Array(data as ArrayBuffer)), onProgress, undefined, true, request => {
@@ -1319,8 +1322,8 @@ module BABYLON.GLTF1 {
 
             var source: IGLTFImage = gltfRuntime.images[texture.source];
 
-            if (GLTFUtils.IsBase64(source.uri)) {
-                setTimeout(() => onSuccess(new Uint8Array(GLTFUtils.DecodeBase64(source.uri))));
+            if (Tools.IsBase64(source.uri)) {
+                setTimeout(() => onSuccess(new Uint8Array(Tools.DecodeBase64(source.uri))));
             }
             else {
                 Tools.LoadFile(gltfRuntime.rootUrl + source.uri, data => onSuccess(new Uint8Array(data as ArrayBuffer)), undefined, undefined, true, request => {
@@ -1368,7 +1371,7 @@ module BABYLON.GLTF1 {
         public static LoadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderString: string) => void, onError: (message: string) => void): void {
             var shader: IGLTFShader = gltfRuntime.shaders[id];
 
-            if (GLTFUtils.IsBase64(shader.uri)) {
+            if (Tools.IsBase64(shader.uri)) {
                 var shaderString = atob(shader.uri.split(",")[1]);
                 onSuccess(shaderString);
             }
@@ -1569,11 +1572,14 @@ module BABYLON.GLTF1 {
         public onTextureLoadedObservable = new Observable<BaseTexture>();
         public onMaterialLoadedObservable = new Observable<Material>();
         public onCompleteObservable = new Observable<IGLTFLoader>();
+        public onExtensionLoadedObservable = new Observable<IGLTFLoaderExtension>();
+
+        public state: Nullable<GLTFLoaderState> = null;
 
         public dispose(): void {}
         // #endregion
 
-        public importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: SceneLoaderProgressEvent) => void, onError: (message: string) => void): boolean {
+        private _importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: SceneLoaderProgressEvent) => void, onError: (message: string) => void): boolean {
             scene.useRightHandedSystem = true;
 
             GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, gltfRuntime => {
@@ -1636,7 +1642,21 @@ module BABYLON.GLTF1 {
             return true;
         }
 
-        public loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: SceneLoaderProgressEvent) => void, onError: (message: string) => void): void {
+        public importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress: (event: SceneLoaderProgressEvent) => void): Promise<{ meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[] }> {
+            return new Promise((resolve, reject) => {
+                this._importMeshAsync(meshesNames, scene, data, rootUrl, (meshes, particleSystems, skeletons) => {
+                    resolve({
+                        meshes: meshes,
+                        particleSystems: particleSystems,
+                        skeletons: skeletons
+                    });
+                }, onProgress, message => {
+                    reject(new Error(message));
+                });
+            });
+        }
+
+        private _loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: SceneLoaderProgressEvent) => void, onError: (message: string) => void): void {
             scene.useRightHandedSystem = true;
 
             GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, gltfRuntime => {
@@ -1664,6 +1684,16 @@ module BABYLON.GLTF1 {
             }, onError);
         }
 
+        public loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress: (event: SceneLoaderProgressEvent) => void): Promise<void> {
+            return new Promise((resolve, reject) => {
+                this._loadAsync(scene, data, rootUrl, () => {
+                    resolve();
+                }, onProgress, message => {
+                    reject(new Error(message));
+                });
+            });
+        }
+
         private _loadShadersAsync(gltfRuntime: IGLTFRuntime, onload: () => void): void {
             var hasShaders = false;
 

+ 0 - 24
loaders/src/glTF/1.0/babylon.glTFLoaderUtils.ts

@@ -84,30 +84,6 @@ module BABYLON.GLTF1 {
         }
 
         /**
-        * If the uri is a base64 string
-        * @param uri: the uri to test
-        */
-        public static IsBase64(uri: string): boolean {
-            return uri.length < 5 ? false : uri.substr(0, 5) === "data:";
-        }
-
-        /**
-        * Decode the base64 uri
-        * @param uri: the uri to decode
-        */
-        public static DecodeBase64(uri: string): ArrayBuffer {
-            var decodedString = atob(uri.split(",")[1]);
-            var bufferLength = decodedString.length;
-            var bufferView = new Uint8Array(new ArrayBuffer(bufferLength));
-
-            for (var i = 0; i < bufferLength; i++) {
-                bufferView[i] = decodedString.charCodeAt(i);
-            }
-
-            return bufferView.buffer;
-        }
-
-        /**
         * Returns the wrap mode of the texture
         * @param mode: the mode value
         */

+ 77 - 91
loaders/src/glTF/2.0/Extensions/KHR_lights.ts

@@ -1,119 +1,105 @@
 /// <reference path="../../../../../dist/preview release/babylon.d.ts"/>
 
 module BABYLON.GLTF2.Extensions {
-    interface IGLTFLight {
-        type: "directional" | "point" | "spot";
-        color: [number, number, number];
-        intensity: number;
-        // Runtime values
-        index: number;
-    }
+    // https://github.com/MiiBond/glTF/tree/khr_lights_v1/extensions/Khronos/KHR_lights
+
+    const NAME = "KHR_lights";
 
-    interface IKHRLights {
-        lights: IGLTFLight[];
+    enum LightType {
+        AMBIENT = "ambient",
+        DIRECTIONAL = "directional",
+        POINT = "point",
+        SPOT = "spot"
     }
 
-    interface IGLTFLightReference {
+    interface ILightReference {
         light: number;
-        // Runtime values
-        babylonLight: Light;
     }
 
-    export class KHRLights extends GLTFLoaderExtension {
-        public get name(): string {
-            return "KHR_lights";
-        }
+    interface ILight {
+        type: LightType;
+        color?: number[];
+        intensity?: number;
+    }
 
-        private applyCommonProperties(light: Light, lightInfo: IGLTFLight): void {
-            if (lightInfo.color) {
-                light.diffuse.copyFromFloats(lightInfo.color[0], lightInfo.color[1], lightInfo.color[2]);
-            } else {
-                light.diffuse.copyFromFloats(1, 1, 1);
-            }
+    interface ISpotLight extends ILight {
+        innerConeAngle?: number;
+        outerConeAngle?: number;
+    }
 
-            if (lightInfo.intensity !== undefined) {
-                light.intensity = lightInfo.intensity;
-            } else {
-                light.intensity = 1;
-            }
-        }
+    interface ILights {
+        lights: ILight[];
+    }
 
-        protected _loadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean { 
-            return this._loadExtension<IGLTFLightReference>(context, scene, (context, extension, onComplete) => {
-                if (extension.light >= 0 && loader._gltf.extensions) {
-                    const lightInfo = loader._gltf.extensions.KHR_lights.lights[extension.light];
-                    if (lightInfo.type !== 'ambient') {
-                        return;
-                    }
+    export class KHR_lights extends GLTFLoaderExtension {
+        public readonly name = NAME;
+
+        protected _loadSceneAsync(context: string, scene: ILoaderScene): Nullable<Promise<void>> { 
+            return this._loadExtensionAsync<ILightReference>(context, scene, (context, extension) => {
+                const promise = this._loader._loadSceneAsync(context, scene);
 
-                    const lightColor = lightInfo.color ? lightInfo.color : [1, 1, 1];
-                    loader._babylonScene.ambientColor.copyFromFloats(lightColor[0], lightColor[1], lightColor[2]);
+                const light = GLTFLoader._GetProperty(context, this._lights, extension.light);
+                if (light.type !== LightType.AMBIENT) {
+                    throw new Error(context + ": Only ambient lights are allowed on a scene");
                 }
-                
-                onComplete();
+
+                this._loader._babylonScene.ambientColor = light.color ? Color3.FromArray(light.color) : Color3.Black();
+
+                return promise;
             });
         }
 
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean { 
-            return this._loadExtension<IGLTFLightReference>(context, node, (context, extension, onComplete) => {
-                if (extension.light >= 0 && loader._gltf.extensions) {
-                    const lightInfo = loader._gltf.extensions.KHR_lights.lights[extension.light];
-                    const name = node.name || 'Light';
-                    let matrix: Matrix;
-                    if (node.matrix) {
-                        matrix = Matrix.FromArray(node.matrix);
-                    } else {
-                        matrix = Matrix.Identity();
-                    }
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>> { 
+            return this._loadExtensionAsync<ILightReference>(context, node, (context, extension) => {
+                const promise = this._loader._loadNodeAsync(context, node);
 
-                    const direction = new Vector3(0, 0, 1);
-                    if (lightInfo.type == 'directional' || lightInfo.type == 'spot') {
-                        const rotationMatrix = matrix.getRotationMatrix();
-                        Vector3.TransformCoordinatesToRef(direction, rotationMatrix, direction);
-                    }
+                let babylonLight: Light;
 
-                    let light: Light;
-                    if (lightInfo.type == 'directional') {
-                        light = new DirectionalLight(name, direction, loader._babylonScene);
-                    } else {
-                        const position = matrix.getTranslation();
-                        if (lightInfo.type == 'spot') {
-                            const angle = lightInfo.spot && lightInfo.spot.outerConeAngle ? lightInfo.spot.outerConeAngle : Math.PI / 2;
-                            light = new SpotLight(name, position, direction, angle, 2, loader._babylonScene);
-                        } else {
-                            light = new PointLight(name, position, loader._babylonScene);
-                        }
-                    } 
-
-                    this.applyCommonProperties(light, lightInfo);
-                    
-                    extension.babylonLight = light;
-                    extension.babylonLight.parent = node.parent ? node.parent.babylonMesh : null;
-                    
-                    if (node.children) {
-                        for (const index of node.children) {
-                            const childNode = GLTFLoader._GetProperty(loader._gltf.nodes, index);
-                            if (!childNode) {
-                                throw new Error(context + ": Failed to find child node " + index);
-                            }
-        
-                            loader._loadNode("#/nodes/" + index, childNode);
-                        }
+                const light = GLTFLoader._GetProperty(context, this._lights, extension.light);
+                const name = node._babylonMesh!.name;
+                switch (light.type) {
+                    case LightType.AMBIENT: {
+                        throw new Error(context + ": Ambient lights are not allowed on a node");
+                    }
+                    case LightType.DIRECTIONAL: {
+                        babylonLight = new DirectionalLight(name, Vector3.Forward(), this._loader._babylonScene);
+                        break;
+                    }
+                    case LightType.POINT: {
+                        babylonLight = new PointLight(name, Vector3.Zero(), this._loader._babylonScene);
+                        break;
+                    }
+                    case LightType.SPOT: {
+                        const spotLight = light as ISpotLight;
+                        // TODO: support inner and outer cone angles
+                        //const innerConeAngle = spotLight.innerConeAngle || 0;
+                        const outerConeAngle = spotLight.outerConeAngle || Math.PI / 4;
+                        babylonLight = new SpotLight(name, Vector3.Zero(), Vector3.Forward(), outerConeAngle, 2, this._loader._babylonScene);
+                        break;
+                    }
+                    default: {
+                        throw new Error(context + ": Invalid light type " + light.type);
                     }
                 }
-                onComplete();
+
+                babylonLight.diffuse = light.color ? Color3.FromArray(light.color) : Color3.White();
+                babylonLight.intensity = light.intensity == undefined ? 1 : light.intensity;
+                babylonLight.parent = node._babylonMesh!;
+
+                return promise;
             });
         }
 
-        protected _loadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean {
-            return this._loadExtension<IKHRLights>(context, root, (context, extension, onComplete) => {
-                extension.lights.forEach((light: IGLTFLight, idx: number) => {
-                    light.index = idx;
-                });
-                onComplete();
-            });
+        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.RegisterExtension(new KHRLights());
+    GLTFLoader._Register(NAME, loader => new KHR_lights(loader));
 }

+ 55 - 31
loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts

@@ -1,59 +1,83 @@
 /// <reference path="../../../../../dist/preview release/babylon.d.ts"/>
 
 module BABYLON.GLTF2.Extensions {
+    // https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness
+
+    const NAME = "KHR_materials_pbrSpecularGlossiness";
+
     interface IKHRMaterialsPbrSpecularGlossiness {
         diffuseFactor: number[];
-        diffuseTexture: IGLTFTextureInfo;
+        diffuseTexture: ITextureInfo;
         specularFactor: number[];
         glossinessFactor: number;
-        specularGlossinessTexture: IGLTFTextureInfo;
+        specularGlossinessTexture: ITextureInfo;
     }
 
-    export class KHRMaterialsPbrSpecularGlossiness extends GLTFLoaderExtension {
-        public get name(): string {
-            return "KHR_materials_pbrSpecularGlossiness";
-        }
+    export class KHR_materials_pbrSpecularGlossiness extends GLTFLoaderExtension {
+        public readonly name = NAME;
+
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>> {
+            return this._loadExtensionAsync<IKHRMaterialsPbrSpecularGlossiness>(context, material, (context, extension) => {
+                material._babylonMeshes = material._babylonMeshes || [];
+                material._babylonMeshes.push(babylonMesh);
+
+                if (material._loaded) {
+                    babylonMesh.material = material._babylonMaterial!;
+                    return material._loaded;
+                }
+
+                const promises = new Array<Promise<void>>();
+
+                const babylonMaterial = this._loader._createMaterial(material);
+                material._babylonMaterial = babylonMaterial;
+
+                promises.push(this._loader._loadMaterialBasePropertiesAsync(context, material));
+                promises.push(this._loadSpecularGlossinessPropertiesAsync(this._loader, context, material, extension));
+
+                this._loader.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
 
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean {
-            return this._loadExtension<IKHRMaterialsPbrSpecularGlossiness>(context, material, (context, extension, onComplete) => {
-                loader._createPbrMaterial(material);
-                loader._loadMaterialBaseProperties(context, material);
-                this._loadSpecularGlossinessProperties(loader, context, material, extension);
-                assign(material.babylonMaterial, true);
-                onComplete();
+                babylonMesh.material = babylonMaterial;
+
+                return (material._loaded = Promise.all(promises).then(() => {}));
             });
         }
 
-        private _loadSpecularGlossinessProperties(loader: GLTFLoader, context: string, material: IGLTFMaterial, properties: IKHRMaterialsPbrSpecularGlossiness): void {
-            const babylonMaterial = material.babylonMaterial as PBRMaterial;
+        private _loadSpecularGlossinessPropertiesAsync(loader: GLTFLoader, context: string, material: ILoaderMaterial, properties: IKHRMaterialsPbrSpecularGlossiness): Promise<void> {
+            const promises = new Array<Promise<void>>();
 
-            babylonMaterial.albedoColor = properties.diffuseFactor ? Color3.FromArray(properties.diffuseFactor) : new Color3(1, 1, 1);
-            babylonMaterial.reflectivityColor = properties.specularFactor ? Color3.FromArray(properties.specularFactor) : new Color3(1, 1, 1);
-            babylonMaterial.microSurface = properties.glossinessFactor == null ? 1 : properties.glossinessFactor;
+            const babylonMaterial = material._babylonMaterial as PBRMaterial;
 
-            if (properties.diffuseTexture) {
-                const texture = GLTFLoader._GetProperty(loader._gltf.textures, properties.diffuseTexture.index);
-                if (!texture) {
-                    throw new Error(context + ": Failed to find diffuse texture " + properties.diffuseTexture.index);
-                }
+            if (properties.diffuseFactor) {
+                babylonMaterial.albedoColor = Color3.FromArray(properties.diffuseFactor);
+                babylonMaterial.alpha = properties.diffuseFactor[3];
+            }
+            else {
+                babylonMaterial.albedoColor = Color3.White();
+            }
 
-                babylonMaterial.albedoTexture = loader._loadTexture("textures[" + texture.index + "]", texture, properties.diffuseTexture.texCoord);
+            babylonMaterial.reflectivityColor = properties.specularFactor ? Color3.FromArray(properties.specularFactor) : Color3.White();
+            babylonMaterial.microSurface = properties.glossinessFactor == undefined ? 1 : properties.glossinessFactor;
+
+            if (properties.diffuseTexture) {
+                promises.push(loader._loadTextureAsync(context + "/diffuseTexture", properties.diffuseTexture, texture => {
+                    babylonMaterial.albedoTexture = texture;
+                }));
             }
 
             if (properties.specularGlossinessTexture) {
-                const texture = GLTFLoader._GetProperty(loader._gltf.textures, properties.specularGlossinessTexture.index);
-                if (!texture) {
-                    throw new Error(context + ": Failed to find diffuse texture " + properties.specularGlossinessTexture.index);
-                }
+                promises.push(loader._loadTextureAsync(context + "/specularGlossinessTexture", properties.specularGlossinessTexture, texture => {
+                    babylonMaterial.reflectivityTexture = texture;
+                }));
 
-                babylonMaterial.reflectivityTexture = loader._loadTexture("textures[" + texture.index + "]", texture, properties.specularGlossinessTexture.texCoord);
                 babylonMaterial.reflectivityTexture.hasAlpha = true;
                 babylonMaterial.useMicroSurfaceFromReflectivityMapAlpha = true;
             }
 
-            loader._loadMaterialAlphaProperties(context, material, properties.diffuseFactor);
+            loader._loadMaterialAlphaProperties(context, material);
+
+            return Promise.all(promises).then(() => {});
         }
     }
 
-    GLTFLoader.RegisterExtension(new KHRMaterialsPbrSpecularGlossiness());
+    GLTFLoader._Register(NAME, loader => new KHR_materials_pbrSpecularGlossiness(loader));
 }

+ 108 - 91
loaders/src/glTF/2.0/Extensions/MSFT_lod.ts

@@ -1,128 +1,145 @@
 /// <reference path="../../../../../dist/preview release/babylon.d.ts"/>
 
 module BABYLON.GLTF2.Extensions {
+    // https://github.com/sbtron/glTF/tree/MSFT_lod/extensions/Vendor/MSFT_lod
+
+    const NAME = "MSFT_lod";
+
     interface IMSFTLOD {
         ids: number[];
     }
 
-    // See https://github.com/sbtron/glTF/tree/MSFT_lod/extensions/Vendor/MSFT_lod for more information about this extension.
-    export class MSFTLOD extends GLTFLoaderExtension {
+    export class MSFT_lod extends GLTFLoaderExtension {
+        public readonly name = NAME;
+
         /**
-         * Specify the minimal delay between LODs in ms (default = 250)
+         * Maximum number of LODs to load, starting from the lowest LOD.
          */
-        public Delay = 250;
+        public maxLODsToLoad = Number.MAX_VALUE;
 
-        public get name() {
-            return "MSFT_lod";
-        }
+        private _loadingNodeLOD: Nullable<ILoaderNode> = null;
+        private _loadNodeSignals: { [nodeIndex: number]: Deferred<void> } = {};
 
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean {
-            return this._loadExtension<IMSFTLOD>(context, node, (context, extension, onComplete) => {
-                for (let i = extension.ids.length - 1; i >= 0; i--) {
-                    const lodNode = GLTFLoader._GetProperty(loader._gltf.nodes, extension.ids[i]);
-                    if (!lodNode) {
-                        throw new Error(context + ": Failed to find node " + extension.ids[i]);
-                    }
+        private _loadingMaterialLOD: Nullable<ILoaderMaterial> = null;
+        private _loadMaterialSignals: { [materialIndex: number]: Deferred<void> } = {};
 
-                    loader._traverseNode(context, lodNode, action, parentNode);
-                }
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>> {
+            return this._loadExtensionAsync<IMSFTLOD>(context, node, (context, extension) => {
+                let firstPromise: Promise<void>;
 
-                loader._traverseNode(context, node, action, parentNode);
-                onComplete();
-            });
-        }
+                const nodeLODs = this._getLODs(context, node, this._loader._gltf.nodes, extension.ids);
+                for (let indexLOD = 0; indexLOD < nodeLODs.length; indexLOD++) {
+                    const nodeLOD = nodeLODs[indexLOD];
 
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean {
-            return this._loadExtension<IMSFTLOD>(context, node, (context, extension, onComplete) => {
-                const nodes = [node];
-                for (let index of extension.ids) {
-                    const lodNode = GLTFLoader._GetProperty(loader._gltf.nodes, index);
-                    if (!lodNode) {
-                        throw new Error(context + ": Failed to find node " + index);
+                    if (indexLOD !== 0) {
+                        this._loadingNodeLOD = nodeLOD;
+                        this._loadNodeSignals[nodeLOD._index] = new Deferred<void>();
                     }
 
-                    nodes.push(lodNode);
+                    const promise = this._loader._loadNodeAsync("#/nodes/" + nodeLOD._index, nodeLOD).then(() => {
+                        if (indexLOD !== 0) {
+                            const previousNodeLOD = nodeLODs[indexLOD - 1];
+                            previousNodeLOD._babylonMesh!.setEnabled(false);
+                        }
+
+                        if (indexLOD !== nodeLODs.length - 1) {
+                            const nodeIndex = nodeLODs[indexLOD + 1]._index;
+                            this._loadNodeSignals[nodeIndex].resolve();
+                            delete this._loadNodeSignals[nodeIndex];
+                        }
+                    });
+
+                    if (indexLOD === 0) {
+                        firstPromise = promise;
+                    }
+                    else {
+                        this._loader._completePromises.push(promise);
+                        this._loadingNodeLOD = null;
+                    }
                 }
 
-                loader._addLoaderPendingData(node);
-                this._loadNodeLOD(loader, context, nodes, nodes.length - 1, () => {
-                    loader._removeLoaderPendingData(node);
-                    onComplete();
-                });
+                return firstPromise!;
             });
         }
 
-        private _loadNodeLOD(loader: GLTFLoader, context: string, nodes: IGLTFNode[], index: number, onComplete: () => void): void {
-            loader._whenAction(() => {
-                loader._loadNode(context, nodes[index]);
-            }, () => {
-                if (index !== nodes.length - 1) {
-                    const previousNode = nodes[index + 1];
-                    previousNode.babylonMesh.setEnabled(false);
-                }
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>> {
+            // Don't load material LODs if already loading a node LOD.
+            if (this._loadingNodeLOD) {
+                return null;
+            }
 
-                if (index === 0) {
-                    onComplete();
-                    return;
-                }
+            return this._loadExtensionAsync<IMSFTLOD>(context, material, (context, extension) => {
+                let firstPromise: Promise<void>;
 
-                setTimeout(() => {
-                    loader._tryCatchOnError(() => {
-                        this._loadNodeLOD(loader, context, nodes, index - 1, onComplete);
-                    });
-                }, this.Delay);
-            });
-        }
+                const materialLODs = this._getLODs(context, material, this._loader._gltf.materials, extension.ids);
+                for (let indexLOD = 0; indexLOD < materialLODs.length; indexLOD++) {
+                    const materialLOD = materialLODs[indexLOD];
 
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean {
-            return this._loadExtension<IMSFTLOD>(context, material, (context, extension, onComplete) => {
-                const materials = [material];
-                for (let index of extension.ids) {
-                    const lodMaterial = GLTFLoader._GetProperty(loader._gltf.materials, index);
-                    if (!lodMaterial) {
-                        throw new Error(context + ": Failed to find material " + index);
+                    if (indexLOD !== 0) {
+                        this._loadingMaterialLOD = materialLOD;
+                        this._loadMaterialSignals[materialLOD._index] = new Deferred<void>();
                     }
 
-                    materials.push(lodMaterial);
+                    const promise = this._loader._loadMaterialAsync("#/materials/" + materialLOD._index, materialLOD, babylonMesh).then(() => {
+                        if (indexLOD !== materialLODs.length - 1) {
+                            const materialIndex = materialLODs[indexLOD + 1]._index;
+                            this._loadMaterialSignals[materialIndex].resolve();
+                            delete this._loadMaterialSignals[materialIndex];
+                        }
+                    });
+
+                    if (indexLOD === 0) {
+                        firstPromise = promise;
+                    }
+                    else {
+                        this._loader._completePromises.push(promise);
+                        this._loadingMaterialLOD = null;
+                    }
                 }
 
-                loader._addLoaderPendingData(material);
-                this._loadMaterialLOD(loader, context, materials, materials.length - 1, assign, () => {
-                    loader._removeLoaderPendingData(material);
-                    onComplete();
-                });
+                return firstPromise!;
             });
         }
 
-        private _loadMaterialLOD(loader: GLTFLoader, context: string, materials: IGLTFMaterial[], index: number, assign: (babylonMaterial: Material, isNew: boolean) => void, onComplete: () => void): void {
-            loader._loadMaterial(context, materials[index], (babylonMaterial, isNew) => {
-                if (index === materials.length - 1) {
-                    assign(babylonMaterial, isNew);
+        protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>> {
+            // Defer the loading of uris if loading a material or node LOD.
+            if (this._loadingMaterialLOD) {
+                const index = this._loadingMaterialLOD._index;
+                return this._loadMaterialSignals[index].promise.then(() => {
+                    return this._loader._loadUriAsync(context, uri);
+                });
+            }
+            else if (this._loadingNodeLOD) {
+                const index = this._loadingNodeLOD._index;
+                return this._loadNodeSignals[index].promise.then(() => {
+                    return this._loader._loadUriAsync(context, uri);
+                });
+            }
 
-                    // Load the next LOD when the loader is ready to render.
-                    loader._executeWhenRenderReady(() => {
-                        this._loadMaterialLOD(loader, context, materials, index - 1, assign, onComplete);
-                    });
-                }
-                else {
-                    BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), () => {
-                        assign(babylonMaterial, isNew);
+            return null;
+        }
 
-                        if (index === 0) {
-                            onComplete();
-                        }
-                        else {
-                            setTimeout(() => {
-                                loader._tryCatchOnError(() => {
-                                    this._loadMaterialLOD(loader, context, materials, index - 1, assign, onComplete);
-                                });
-                            }, this.Delay);
-                        }
-                    });
+        /**
+         * Gets an array of LOD properties from lowest to highest.
+         */
+        private _getLODs<T>(context: string, property: T, array: ArrayLike<T> | undefined, ids: number[]): T[] {
+            if (this.maxLODsToLoad <= 0) {
+                throw new Error("maxLODsToLoad must be greater than zero");
+            }
+
+            const properties = new Array<T>();
+
+            for (let i = ids.length - 1; i >= 0; i--) {
+                properties.push(GLTFLoader._GetProperty(context + "/ids/" + ids[i], array, ids[i]));
+                if (properties.length === this.maxLODsToLoad) {
+                    return properties;
                 }
-            });
+            }
+
+            properties.push(property);
+            return properties;
         }
     }
 
-    GLTFLoader.RegisterExtension(new MSFTLOD());
-}
+    GLTFLoader._Register(NAME, loader => new MSFT_lod(loader));
+}

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 900 - 1177
loaders/src/glTF/2.0/babylon.glTFLoader.ts


+ 41 - 50
loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts

@@ -1,81 +1,72 @@
 /// <reference path="../../../../dist/preview release/babylon.d.ts"/>
 
 module BABYLON.GLTF2 {
-    export abstract class GLTFLoaderExtension {
-        public enabled: boolean = true;
+    export abstract class GLTFLoaderExtension implements IGLTFLoaderExtension {
+        public enabled = true;
+        public abstract readonly name: string;
 
-        public abstract get name(): string;
+        protected _loader: GLTFLoader;
 
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean { return false; }
+        constructor(loader: GLTFLoader) {
+            this._loader = loader;
+        }
+
+        // #region Overridable Methods
 
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean { return false; }
+        /** Override this method to modify the default behavior for loading scenes. */
+        protected _loadSceneAsync(context: string, node: ILoaderScene): Nullable<Promise<void>> { return null; }
 
-        protected _loadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean { return false; }
+        /** Override this method to modify the default behavior for loading nodes. */
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>> { return null; }
 
-        protected _loadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean { return false; }
+        /** Override this method to modify the default behavior for loading materials. */
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>> { return null; }
 
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean { return false; }
+        /** Override this method to modify the default behavior for loading uris. */
+        protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>> { return null; }
 
-        protected _loadExtension<T>(context: string, property: IGLTFProperty, action: (context: string, extension: T, onComplete: () => void) => void): boolean {
+        // #endregion
+
+        /** Helper method called by a loader extension to load an glTF extension. */
+        protected _loadExtensionAsync<T>(context: string, property: IProperty, actionAsync: (context: string, extension: T) => Promise<void>): Nullable<Promise<void>> {
             if (!property.extensions) {
-                return false;
+                return null;
             }
 
-            const extension = property.extensions[this.name] as T;
+            const extensions = property.extensions;
+
+            const extension = extensions[this.name] as T;
             if (!extension) {
-                return false;
+                return null;
             }
 
             // Clear out the extension before executing the action to avoid recursing into the same property.
-            property.extensions[this.name] = undefined;
+            delete extensions[this.name];
 
-            action(context + "extensions/" + this.name, extension, () => {
+            return actionAsync(context + "/extensions/" + this.name, extension).then(() => {
                 // Restore the extension after completing the action.
-                property.extensions![this.name] = extension;
+                extensions[this.name] = extension;
             });
-
-            return true;
         }
 
-        //
-        // Utilities
-        //
-
-        public static _Extensions: GLTFLoaderExtension[] = [];
-
-        public static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean {
-            return this._ApplyExtensions(extension => extension._traverseNode(loader, context, node, action, parentNode));
+        /** Helper method called by the loader to allow extensions to override loading scenes. */
+        public static _LoadSceneAsync(loader: GLTFLoader, context: string, scene: ILoaderScene): Nullable<Promise<void>> {
+            return loader._applyExtensions(extension => extension._loadSceneAsync(context, scene));
         }
 
-        public static LoadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean {
-            return this._ApplyExtensions(extension => extension._loadRoot(loader, context, root));
+        /** Helper method called by the loader to allow extensions to override loading nodes. */
+        public static _LoadNodeAsync(loader: GLTFLoader, context: string, node: ILoaderNode): Nullable<Promise<void>> {
+            return loader._applyExtensions(extension => extension._loadNodeAsync(context, node));
         }
 
-        public static LoadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean {
-            return this._ApplyExtensions(extension => extension._loadScene(loader, context, scene));
+        /** Helper method called by the loader to allow extensions to override loading materials. */
+        public static _LoadMaterialAsync(loader: GLTFLoader, context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>> {
+            return loader._applyExtensions(extension => extension._loadMaterialAsync(context, material, babylonMesh));
         }
 
-        public static LoadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean {
-            return this._ApplyExtensions(extension => extension._loadNode(loader, context, node));
-        }
-
-        public static LoadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean {
-            return this._ApplyExtensions(extension => extension._loadMaterial(loader, context, material, assign));
-        }
-
-        private static _ApplyExtensions(action: (extension: GLTFLoaderExtension) => boolean) {
-            const extensions = GLTFLoaderExtension._Extensions;
-            if (!extensions) {
-                return false;
-            }
-
-            for (const extension of extensions) {
-                if (extension.enabled && action(extension)) {
-                    return true;
-                }
-            }
-
-            return false;
+        /** Helper method called by the loader to allow extensions to override loading uris. */
+        public static _LoadUriAsync(loader: GLTFLoader, context: string, uri: string): Nullable<Promise<ArrayBufferView>> {
+            return loader._applyExtensions(extension => extension._loadUriAsync(context, uri));
         }
     }
 }

+ 57 - 260
loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts

@@ -1,306 +1,103 @@
 /// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+/// <reference path="../../../../dist/babylon.glTF2Interface.d.ts"/>
 
 module BABYLON.GLTF2 {
-    /**
-    * Enums
-    */
-    export enum EComponentType {
-        BYTE = 5120,
-        UNSIGNED_BYTE = 5121,
-        SHORT = 5122,
-        UNSIGNED_SHORT = 5123,
-        UNSIGNED_INT = 5125,
-        FLOAT = 5126
+    export interface ILoaderAccessor extends IAccessor, IArrayItem {
+        _data?: Promise<TypedArray>;
     }
 
-    export enum EMeshPrimitiveMode {
-        POINTS = 0,
-        LINES = 1,
-        LINE_LOOP = 2,
-        LINE_STRIP = 3,
-        TRIANGLES = 4,
-        TRIANGLE_STRIP = 5,
-        TRIANGLE_FAN = 6
+    export interface ILoaderAnimationChannel extends IAnimationChannel, IArrayItem {
+        _babylonAnimationGroup: AnimationGroup;
     }
 
-    export enum ETextureMagFilter {
-        NEAREST = 9728,
-        LINEAR = 9729,
+    export interface ILoaderAnimationSamplerData {
+        input: Float32Array;
+        interpolation: AnimationSamplerInterpolation;
+        output: Float32Array;
     }
 
-    export enum ETextureMinFilter {
-        NEAREST = 9728,
-        LINEAR = 9729,
-        NEAREST_MIPMAP_NEAREST = 9984,
-        LINEAR_MIPMAP_NEAREST = 9985,
-        NEAREST_MIPMAP_LINEAR = 9986,
-        LINEAR_MIPMAP_LINEAR = 9987
+    export interface ILoaderAnimationSampler extends IAnimationSampler, IArrayItem {
+        _data: Promise<ILoaderAnimationSamplerData>;
     }
 
-    export enum ETextureWrapMode {
-        CLAMP_TO_EDGE = 33071,
-        MIRRORED_REPEAT = 33648,
-        REPEAT = 10497
-    }
-
-    /**
-    * Interfaces
-    */
-    export interface IGLTFProperty {
-        extensions?: { [key: string]: any };
-        extras?: any;
-    }
-
-    export interface IGLTFChildRootProperty extends IGLTFProperty {
-        name?: string;
-    }
-
-    export interface IGLTFAccessorSparseIndices extends IGLTFProperty {
-        bufferView: number;
-        byteOffset?: number;
-        componentType: EComponentType;
-    }
-
-    export interface IGLTFAccessorSparseValues extends IGLTFProperty {
-        bufferView: number;
-        byteOffset?: number;
-    }
-
-    export interface IGLTFAccessorSparse extends IGLTFProperty {
-        count: number;
-        indices: IGLTFAccessorSparseIndices;
-        values: IGLTFAccessorSparseValues;
-    }
-
-    export interface IGLTFAccessor extends IGLTFChildRootProperty {
-        bufferView?: number;
-        byteOffset?: number;
-        componentType: EComponentType;
-        normalized?: boolean;
-        count: number;
-        type: string;
-        max: number[];
-        min: number[];
-        sparse?: IGLTFAccessorSparse;
-
-        // Runtime values
-        index: number;
-    }
-
-    export interface IGLTFAnimationChannel extends IGLTFProperty {
-        sampler: number;
-        target: IGLTFAnimationChannelTarget;
-    }
-
-    export interface IGLTFAnimationChannelTarget extends IGLTFProperty {
-        node: number;
-        path: string;
-    }
-
-    export interface IGLTFAnimationSampler extends IGLTFProperty {
-        input: number;
-        interpolation?: string;
-        output: number;
-    }
-
-    export interface IGLTFAnimation extends IGLTFChildRootProperty {
-        channels: IGLTFAnimationChannel[];
-        samplers: IGLTFAnimationSampler[];
-
-        // Runtime values
-        index: number;
-        babylonAnimationGroup: AnimationGroup;
-    }
-
-    export interface IGLTFAsset extends IGLTFChildRootProperty {
-        copyright?: string;
-        generator?: string;
-        version: string;
-        minVersion?: string;
-    }
-
-    export interface IGLTFBuffer extends IGLTFChildRootProperty {
-        uri?: string;
-        byteLength: number;
-
-        // Runtime values
-        index: number;
-        loadedData?: ArrayBufferView;
-        loadedObservable?: Observable<IGLTFBuffer>;
-    }
-
-    export interface IGLTFBufferView extends IGLTFChildRootProperty {
-        buffer: number;
-        byteOffset?: number;
-        byteLength: number;
-        byteStride?: number;
-
-        // Runtime values
-        index: number;
-    }
-
-    export interface IGLTFCameraOrthographic extends IGLTFProperty {
-        xmag: number;
-        ymag: number;
-        zfar: number;
-        znear: number;
-    }
+    export interface ILoaderAnimation extends IAnimation, IArrayItem {
+        channels: ILoaderAnimationChannel[];
+        samplers: ILoaderAnimationSampler[];
 
-    export interface IGLTFCameraPerspective extends IGLTFProperty {
-        aspectRatio: number;
-        yfov: number;
-        zfar: number;
-        znear: number;
+        _babylonAnimationGroup: Nullable<AnimationGroup>;
     }
 
-    export interface IGLTFCamera extends IGLTFChildRootProperty {
-        orthographic?: IGLTFCameraOrthographic;
-        perspective?: IGLTFCameraPerspective;
-        type: string;
+    export interface ILoaderBuffer extends IBuffer, IArrayItem {
+        _data?: Promise<ArrayBufferView>;
     }
 
-    export interface IGLTFImage extends IGLTFChildRootProperty {
-        uri?: string;
-        mimeType?: string;
-        bufferView?: number;
-
-        // Runtime values
-        index: number;
+    export interface ILoaderBufferView extends IBufferView, IArrayItem {
+        _data?: Promise<ArrayBufferView>;
     }
 
-    export interface IGLTFMaterialNormalTextureInfo extends IGLTFTextureInfo {
-        scale: number;
+    export interface ILoaderCamera extends ICamera, IArrayItem {
     }
 
-    export interface IGLTFMaterialOcclusionTextureInfo extends IGLTFTextureInfo {
-        strength: number;
+    export interface ILoaderImage extends IImage, IArrayItem {
+        _objectURL?: Promise<string>;
     }
 
-    export interface IGLTFMaterialPbrMetallicRoughness {
-        baseColorFactor: number[];
-        baseColorTexture: IGLTFTextureInfo;
-        metallicFactor: number;
-        roughnessFactor: number;
-        metallicRoughnessTexture: IGLTFTextureInfo;
+    export interface ILoaderMaterial extends IMaterial, IArrayItem {
+        _babylonMaterial?: Material;
+        _babylonMeshes?: AbstractMesh[];
+        _loaded?: Promise<void>;
     }
 
-    export interface IGLTFMaterial extends IGLTFChildRootProperty {
-        pbrMetallicRoughness?: IGLTFMaterialPbrMetallicRoughness;
-        normalTexture?: IGLTFMaterialNormalTextureInfo;
-        occlusionTexture?: IGLTFMaterialOcclusionTextureInfo;
-        emissiveTexture?: IGLTFTextureInfo;
-        emissiveFactor?: number[];
-        alphaMode?: string;
-        alphaCutoff: number;
-        doubleSided?: boolean;
-
-        // Runtime values
-        index: number;
-        babylonMaterial: Material;
+    export interface ILoaderMesh extends IMesh, IArrayItem {
+        primitives: ILoaderMeshPrimitive[];
     }
 
-    export interface IGLTFMeshPrimitive extends IGLTFProperty {
-        attributes: { [name: string]: number };
-        indices?: number;
-        material?: number;
-        mode?: EMeshPrimitiveMode;
-        targets?: { [name: string]: number }[];
-
-        // Runtime values
-        vertexData: VertexData;
-        targetsVertexData: VertexData[];
+    export interface ILoaderMeshPrimitive extends IMeshPrimitive, IArrayItem {
     }
 
-    export interface IGLTFMesh extends IGLTFChildRootProperty {
-        primitives: IGLTFMeshPrimitive[];
-        weights?: number[];
-
-        // Runtime values
-        index: number;
-        hasVertexAlpha: boolean;
+    export interface ILoaderNode extends INode, IArrayItem {
+        _parent: ILoaderNode;
+        _babylonMesh?: Mesh;
+        _primitiveBabylonMeshes?: Mesh[];
+        _babylonAnimationTargets?: Node[];
+        _numMorphTargets?: number;
     }
 
-    export interface IGLTFNode extends IGLTFChildRootProperty {
-        camera?: number;
-        children?: number[];
-        skin?: number;
-        matrix?: number[];
-        mesh?: number;
-        rotation?: number[];
-        scale?: number[];
-        translation?: number[];
-        weights?: number[];
-
-        // Runtime values
-        index: number;
-        parent: IGLTFNode;
-        babylonMesh: Mesh;
-        babylonAnimationTargets?: Node[];
-    }
-
-    export interface IGLTFSampler extends IGLTFChildRootProperty {
-        magFilter?: ETextureMagFilter;
-        minFilter?: ETextureMinFilter;
-        wrapS?: ETextureWrapMode;
-        wrapT?: ETextureWrapMode;
-
-        // Runtime values
-        index: number;
+    export interface ILoaderSamplerData {
         noMipMaps: boolean;
         samplingMode: number;
         wrapU: number;
         wrapV: number;
     }
 
-    export interface IGLTFScene extends IGLTFChildRootProperty {
-        nodes: number[];
-
-        // Runtime values
-        index: number;
+    export interface ILoaderSampler extends ISampler, IArrayItem {
+        _data?: ILoaderSamplerData;
     }
 
-    export interface IGLTFSkin extends IGLTFChildRootProperty {
-        inverseBindMatrices?: number;
-        skeleton?: number;
-        joints: number[];
-
-        // Runtime values
-        index: number;
-        babylonSkeleton: Skeleton;
+    export interface ILoaderScene extends IScene, IArrayItem {
     }
 
-    export interface IGLTFTexture extends IGLTFChildRootProperty {
-        sampler?: number;
-        source: number;
-
-        // Runtime values
-        index: number;
-        url?: string;
-        dataReadyObservable?: Observable<IGLTFTexture>;
+    export interface ILoaderSkin extends ISkin, IArrayItem {
+        _babylonSkeleton: Nullable<Skeleton>;
+        _loaded?: Promise<void>;
     }
 
-    export interface IGLTFTextureInfo {
-        index: number;
-        texCoord?: number;
+    export interface ILoaderTexture extends ITexture, IArrayItem {
     }
 
-    export interface _IGLTF extends IGLTFProperty {
-        accessors?: IGLTFAccessor[];
-        animations?: IGLTFAnimation[];
-        asset: IGLTFAsset;
-        buffers?: IGLTFBuffer[];
-        bufferViews?: IGLTFBufferView[];
-        cameras?: IGLTFCamera[];
-        extensionsUsed?: string[];
-        extensionsRequired?: string[];
-        images?: IGLTFImage[];
-        materials?: IGLTFMaterial[];
-        meshes?: IGLTFMesh[];
-        nodes?: IGLTFNode[];
-        samplers?: IGLTFSampler[];
-        scene?: number;
-        scenes?: IGLTFScene[];
-        skins?: IGLTFSkin[];
-        textures?: IGLTFTexture[];
+    export interface ILoaderGLTF extends IGLTF {
+        accessors?: ILoaderAccessor[];
+        animations?: ILoaderAnimation[];
+        buffers?: ILoaderBuffer[];
+        bufferViews?: ILoaderBufferView[];
+        cameras?: ILoaderCamera[];
+        images?: ILoaderImage[];
+        materials?: ILoaderMaterial[];
+        meshes?: ILoaderMesh[];
+        nodes?: ILoaderNode[];
+        samplers?: ILoaderSampler[];
+        scenes?: ILoaderScene[];
+        skins?: ILoaderSkin[];
+        textures?: ILoaderTexture[];
     }
 }

+ 21 - 0
loaders/src/glTF/2.0/babylon.glTFLoaderUtilities.ts

@@ -0,0 +1,21 @@
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON.GLTF2 {
+    export interface TypedArray extends ArrayBufferView {
+        [index: number]: number;
+    }
+
+    export interface IArrayItem {
+        _index: number;
+    }
+
+    export class ArrayItem {
+        public static Assign(values?: IArrayItem[]): void {
+            if (values) {
+                for (let index = 0; index < values.length; index++) {
+                    values[index]._index = index;
+                }
+            }
+        }
+    }
+}

+ 0 - 36
loaders/src/glTF/2.0/babylon.glTFLoaderUtils.ts

@@ -1,36 +0,0 @@
-/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
-
-module BABYLON.GLTF2 {
-    /**
-    * Utils functions for GLTF
-    */
-    export class GLTFUtils {
-        /**
-        * If the uri is a base64 string
-        * @param uri: the uri to test
-        */
-        public static IsBase64(uri: string): boolean {
-            return uri.length < 5 ? false : uri.substr(0, 5) === "data:";
-        }
-
-        /**
-        * Decode the base64 uri
-        * @param uri: the uri to decode
-        */
-        public static DecodeBase64(uri: string): ArrayBuffer {
-            const decodedString = atob(uri.split(",")[1]);
-            const bufferLength = decodedString.length;
-            const bufferView = new Uint8Array(new ArrayBuffer(bufferLength));
-
-            for (let i = 0; i < bufferLength; i++) {
-                bufferView[i] = decodedString.charCodeAt(i);
-            }
-
-            return bufferView.buffer;
-        }
-
-        public static ValidateUri(uri: string): boolean {
-            return (uri.indexOf("..") === -1);
-        }
-    }
-}

+ 80 - 52
loaders/src/glTF/babylon.glTFFileLoader.ts

@@ -35,6 +35,24 @@ module BABYLON {
         bin: Nullable<ArrayBufferView>;
     }
 
+    export interface IGLTFLoaderExtension {
+        /**
+         * The name of this extension.
+         */
+        readonly name: string;
+
+        /**
+         * Whether this extension is enabled.
+         */
+        enabled: boolean;
+    }
+
+    export enum GLTFLoaderState {
+        Loading,
+        Ready,
+        Complete
+    }
+
     export interface IGLTFLoader extends IDisposable {
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
@@ -42,14 +60,17 @@ module BABYLON {
         useClipPlane: boolean;
         compileShadowGenerators: boolean;
 
-        onDisposeObservable: Observable<IGLTFLoader>;
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
         onCompleteObservable: Observable<IGLTFLoader>;
+        onDisposeObservable: Observable<IGLTFLoader>;
+        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+
+        state: Nullable<GLTFLoaderState>;
 
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<{ meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[] }>;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
     }
 
     export class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
@@ -113,7 +134,7 @@ module BABYLON {
         /**
          * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
          */
-        public onMeshLoadedObservable = new Observable<AbstractMesh>();
+        public readonly onMeshLoadedObservable = new Observable<AbstractMesh>();
 
         private _onMeshLoadedObserver: Nullable<Observer<AbstractMesh>>;
         public set onMeshLoaded(callback: (mesh: AbstractMesh) => void) {
@@ -126,7 +147,7 @@ module BABYLON {
         /**
          * Raised when the loader creates a texture after parsing the glTF properties of the texture.
          */
-        public onTextureLoadedObservable = new Observable<BaseTexture>();
+        public readonly onTextureLoadedObservable = new Observable<BaseTexture>();
 
         private _onTextureLoadedObserver: Nullable<Observer<BaseTexture>>;
         public set onTextureLoaded(callback: (Texture: BaseTexture) => void) {
@@ -139,7 +160,7 @@ module BABYLON {
         /**
          * Raised when the loader creates a material after parsing the glTF properties of the material.
          */
-        public onMaterialLoadedObservable = new Observable<Material>();
+        public readonly onMaterialLoadedObservable = new Observable<Material>();
 
         private _onMaterialLoadedObserver: Nullable<Observer<Material>>;
         public set onMaterialLoaded(callback: (Material: Material) => void) {
@@ -154,7 +175,7 @@ module BABYLON {
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets without LODs, raised when the model is complete, immediately after onSuccess.
          */
-        public onCompleteObservable = new Observable<GLTFFileLoader>();
+        public readonly onCompleteObservable = new Observable<GLTFFileLoader>();
 
         private _onCompleteObserver: Nullable<Observer<GLTFFileLoader>>;
         public set onComplete(callback: () => void) {
@@ -167,7 +188,7 @@ module BABYLON {
         /**
         * Raised when the loader is disposed.
         */
-        public onDisposeObservable = new Observable<GLTFFileLoader>();
+        public readonly onDisposeObservable = new Observable<GLTFFileLoader>();
 
         private _onDisposeObserver: Nullable<Observer<GLTFFileLoader>>;
         public set onDispose(callback: () => void) {
@@ -177,6 +198,27 @@ module BABYLON {
             this._onDisposeObserver = this.onDisposeObservable.add(callback);
         }
 
+        /**
+         * Raised after a loader extension is created.
+         * Set additional options for a loader extension in this event.
+         */
+        public readonly onExtensionLoadedObservable = new Observable<IGLTFLoaderExtension>();
+
+        private _onExtensionLoadedObserver: Nullable<Observer<IGLTFLoaderExtension>>;
+        public set onExtensionLoaded(callback: (extension: IGLTFLoaderExtension) => void) {
+            if (this._onExtensionLoadedObserver) {
+                this.onExtensionLoadedObservable.remove(this._onExtensionLoadedObserver);
+            }
+            this._onExtensionLoadedObserver = this.onExtensionLoadedObservable.add(callback);
+        }
+
+        /**
+         * The loader state or null if not active.
+         */
+        public get loaderState(): Nullable<GLTFLoaderState> {
+            return this._loader ? this._loader.state : null;
+        }
+
         // #endregion
 
         private _loader: Nullable<IGLTFLoader> = null;
@@ -197,69 +239,43 @@ module BABYLON {
                 this._loader = null;
             }
 
-            this.onParsedObservable.clear();
             this.onMeshLoadedObservable.clear();
             this.onTextureLoadedObservable.clear();
             this.onMaterialLoadedObservable.clear();
-            this.onCompleteObservable.clear();
 
             this.onDisposeObservable.notifyObservers(this);
             this.onDisposeObservable.clear();
         }
 
-        public importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void {
-            try {
+        public importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{ meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[] }> {
+            return Promise.resolve().then(() => {
                 const loaderData = this._parse(data);
                 this._loader = this._getLoader(loaderData);
-                this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
-            }
-            catch (e) {
-                if (onError) {
-                    onError(e.message, e);
-                }
-                else {
-                    Tools.Error(e.message);
-                }
-            }
+                return this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onProgress);
+            });
         }
 
-        public loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void {
-            try {
+        public loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void> {
+            return Promise.resolve().then(() => {
                 const loaderData = this._parse(data);
                 this._loader = this._getLoader(loaderData);
-                this._loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
-            }
-            catch (e) {
-                if (onError) {
-                    onError(e.message, e);
-                }
-                else {
-                    Tools.Error(e.message);
-                }
-            }
+                return this._loader.loadAsync(scene, loaderData, rootUrl, onProgress);
+            });
         }
 
-        public loadAssetsAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: (assets:AssetContainer) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void {
-            try {
+        public loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer> {
+            return Promise.resolve().then(() => {
                 const loaderData = this._parse(data);
                 this._loader = this._getLoader(loaderData);
-                this._loader.importMeshAsync(null, scene, loaderData, rootUrl,  (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => {
+                return this._loader.importMeshAsync(null, scene, loaderData, rootUrl, onProgress).then(result => {
                     var container = new AssetContainer(scene);
-                    Array.prototype.push.apply(container.meshes, meshes)
-                    Array.prototype.push.apply(container.particleSystems, particleSystems)
-                    Array.prototype.push.apply(container.skeletons, skeletons)
+                    Array.prototype.push.apply(container.meshes, result.meshes);
+                    Array.prototype.push.apply(container.particleSystems, result.particleSystems);
+                    Array.prototype.push.apply(container.skeletons, result.skeletons);
                     container.removeAllFromScene();
-                    onSuccess(container)
-                }, onProgress, onError);
-            }
-            catch (e) {
-                if (onError) {
-                    onError(e.message, e);
-                }
-                else {
-                    Tools.Error(e.message);
-                }
-            }
+                    return container;
+                });
+            });
         }
 
         public canDirectLoad(data: string): boolean {
@@ -285,6 +301,8 @@ module BABYLON {
             }
 
             this.onParsedObservable.notifyObservers(parsedData);
+            this.onParsedObservable.clear();
+
             return parsedData;
         }
 
@@ -328,7 +346,17 @@ module BABYLON {
             loader.onMeshLoadedObservable.add(mesh => this.onMeshLoadedObservable.notifyObservers(mesh));
             loader.onTextureLoadedObservable.add(texture => this.onTextureLoadedObservable.notifyObservers(texture));
             loader.onMaterialLoadedObservable.add(material => this.onMaterialLoadedObservable.notifyObservers(material));
-            loader.onCompleteObservable.add(() => this.onCompleteObservable.notifyObservers(this));
+            loader.onExtensionLoadedObservable.add(extension => this.onExtensionLoadedObservable.notifyObservers(extension));
+
+            loader.onCompleteObservable.add(() => {
+                this.onMeshLoadedObservable.clear();
+                this.onTextureLoadedObservable.clear();
+                this.onMaterialLoadedObservable.clear();
+
+                this.onCompleteObservable.notifyObservers(this);
+                this.onCompleteObservable.clear();
+            });
+
             return loader;
         }
 

+ 2 - 2
package.json

@@ -9,7 +9,7 @@
     ],
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "3.2.0-alpha6",
+    "version": "3.2.0-alpha7",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -41,4 +41,4 @@
     },
     "readme": "Babylon.js is a 3D engine based on webgl and javascript",
     "readmeFilename": "README.md"
-}
+}

+ 0 - 4
sandbox/index.js

@@ -36,10 +36,6 @@ if (BABYLON.Engine.isSupported()) {
     BABYLON.GLTFFileLoader.IncrementalLoading = false;
     BABYLON.SceneLoader.OnPluginActivatedObservable.add(function (plugin) {
         currentPluginName = plugin.name;
-
-        if (plugin.name === "gltf" && plugin instanceof BABYLON.GLTFFileLoader) {
-            plugin.compileMaterials = true;
-        }
     });
 
     // Resize

+ 23 - 2
src/Cameras/VR/babylon.vrExperienceHelper.ts

@@ -207,6 +207,25 @@ module BABYLON {
         }
 
         /**
+         * The mesh used to display where the user is selecting.
+         */
+        public get gazeTrackerMesh(): Mesh {
+            return this._gazeTracker;
+        }
+
+        /**
+         * Sets the mesh to be used to display where the user is selecting.
+         */
+        public set gazeTrackerMesh(value: Mesh) {
+            if (value) {
+                this._gazeTracker = value;
+                this._gazeTracker.bakeCurrentTransformIntoVertices();
+                this._gazeTracker.isPickable = false;
+                this._gazeTracker.isVisible = false;
+            }
+        }
+
+        /**
          * If the ray of the gaze should be displayed.
          */
         public get displayGaze(): boolean {
@@ -670,7 +689,9 @@ module BABYLON {
                     this._enableInteractionOnController(this._webVRCamera.rightController)
                 }
 
-                this._createGazeTracker();
+                if(!this._gazeTracker){
+                    this._createGazeTracker();
+                }                
 
                 this.raySelectionPredicate = (mesh) => {
                     return mesh.isVisible;
@@ -681,7 +702,7 @@ module BABYLON {
                 }
 
                 this._raySelectionPredicate = (mesh) => {
-                    if (this._isTeleportationFloor(mesh) || (mesh.name.indexOf("gazeTracker") === -1
+                    if (this._isTeleportationFloor(mesh) || (mesh != this._gazeTracker
                         && mesh.name.indexOf("teleportationTarget") === -1
                         && mesh.name.indexOf("torusTeleportation") === -1
                         && mesh.name.indexOf("laserPointer") === -1)) {

+ 2 - 1
src/Engine/babylon.engine.ts

@@ -2629,6 +2629,7 @@
                 if (onCompiled && compiledEffect.isReady()) {
                     onCompiled(compiledEffect);
                 }
+
                 return compiledEffect;
             }
             var effect = new Effect(baseName, attributesNamesOrOptions, uniformsNamesOrEngine, samplers, this, defines, fallbacks, onCompiled, onError, indexParameters);
@@ -5007,7 +5008,7 @@
 
                 if (internalTexture && internalTexture._cachedWrapR !== texture.wrapR) {
                     internalTexture._cachedWrapR = texture.wrapR;
-                    switch (texture.wrapV) {
+                    switch (texture.wrapR) {
                         case Texture.WRAP_ADDRESSMODE:
                             this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_WRAP_R, this._gl.REPEAT);
                             break;

+ 94 - 0
src/Helpers/babylon.videoDome.ts

@@ -0,0 +1,94 @@
+module BABYLON {
+    /**
+     * Display a 360 degree video on an approximately spherical surface, useful for VR applications or skyboxes.
+     * As a subclass of Node, this allow parenting to the camera or multiple videos with different locations in the scene.
+     * This class achieves its effect with a VideoTexture and a correctly configured BackgroundMaterial on an inverted sphere.
+     * Potential additions to this helper include zoom and and non-infinite distance rendering effects.
+     */
+    export class VideoDome extends Node {
+
+        /**
+         * The video texture being displayed on the sphere
+         */
+        protected _videoTexture: VideoTexture;
+
+        /**
+         * The skybox material
+         */
+        protected _material: BackgroundMaterial;
+
+        /**
+         * The surface used for the skybox
+         */
+        protected _mesh: Mesh;
+
+        /**
+         * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
+         * Also see the options.resolution property.
+         */
+        public get fovMultiplier(): number {
+            return this._material.fovMultiplier;
+        }
+        public set fovMultiplier(value: number) {
+            this._material.fovMultiplier = value;
+        }
+
+        /**
+         * Create an instance of this class and pass through the parameters to the relevant classes, VideoTexture, StandardMaterial, and Mesh.
+         * @param name Element's name, child elements will append suffixes for their own names.
+         * @param urlsOrVideo
+         * @param options An object containing optional or exposed sub element properties:
+         * @param options **resolution=12** Integer, lower resolutions have more artifacts at extreme fovs
+         * @param options **clickToPlay=false** Add a click to play listener to the video, does not prevent autoplay.
+         * @param options **autoPlay=true** Automatically attempt to being playing the video.
+         * @param options **loop=true** Automatically loop video on end.
+         * @param options **size=1000** Physical radius to create the dome at, defaults to approximately half the far clip plane.
+         */
+        constructor(name: string, urlsOrVideo: string | string[] | HTMLVideoElement, options: {
+            resolution?: number,
+            clickToPlay?: boolean,
+            autoPlay?: boolean,
+            loop?: boolean,
+            size?: number
+        }, scene: Scene) {
+            super(name, scene);
+
+            // set defaults and manage values
+            name = name || "videoDome";
+            options.resolution = (Math.abs(options.resolution as any) | 0) || 12;
+            options.clickToPlay = Boolean(options.clickToPlay);
+            options.autoPlay = options.autoPlay === undefined ? true : Boolean(options.autoPlay);
+            options.loop = options.loop === undefined ? true : Boolean(options.loop);
+            options.size = Math.abs(options.size as any) || (scene.activeCamera ? scene.activeCamera.maxZ * 0.48 : 1000);
+
+            // create
+            let tempOptions:VideoTextureSettings = {loop: options.loop, autoPlay: options.autoPlay, autoUpdateTexture: true};
+            let material = this._material = new BABYLON.BackgroundMaterial(name+"_material", scene);
+            let texture = this._videoTexture = new BABYLON.VideoTexture(name+"_texture", urlsOrVideo, scene, false, false, Texture.TRILINEAR_SAMPLINGMODE, tempOptions);
+            this._mesh = BABYLON.MeshBuilder.CreateIcoSphere(name+"_mesh", {
+                flat: false, // saves on vertex data
+                radius: options.size,
+                subdivisions: options.resolution,
+                sideOrientation: BABYLON.Mesh.BACKSIDE // needs to be inside out
+            }, scene);
+
+            // configure material
+            texture.coordinatesMode = BABYLON.Texture.FIXED_EQUIRECTANGULAR_MIRRORED_MODE; // matches orientation
+            texture.wrapV = Texture.CLAMP_ADDRESSMODE; // always clamp the up/down
+            material.reflectionTexture = this._videoTexture;
+            material.useEquirectangularFOV = true;
+            material.fovMultiplier = 1.0;
+
+            // configure mesh
+            this._mesh.material = material;
+            this._mesh.parent = this;
+
+            // optional configuration
+            if(options.clickToPlay) {
+                scene.onPointerUp = () => {
+                    this._videoTexture.video.play();
+                }
+            }
+        }
+    }
+}

+ 639 - 0
src/Layer/babylon.effectLayer.ts

@@ -0,0 +1,639 @@
+module BABYLON {
+    /**
+     * Effect layer options. This helps customizing the behaviour
+     * of the effect layer.
+     */
+    export interface IEffectLayerOptions {
+        /**
+         * Multiplication factor apply to the canvas size to compute the render target size
+         * used to generated the objects (the smaller the faster).
+         */
+        mainTextureRatio: number;
+
+        /**
+         * Enforces a fixed size texture to ensure effect stability across devices.
+         */
+        mainTextureFixedSize?: number;
+
+        /**
+         * Alpha blending mode used to apply the blur. Default depends of the implementation.
+         */
+        alphaBlendingMode: number;
+
+        /**
+         * The camera attached to the layer.
+         */
+        camera: Nullable<Camera>;
+    }
+
+    /**
+     * The effect layer Helps adding post process effect blended with the main pass.
+     * 
+     * This can be for instance use to generate glow or higlight effects on the scene.
+     * 
+     * The effect layer class can not be used directly and is intented to inherited from to be 
+     * customized per effects.
+     */
+    export abstract class EffectLayer {
+
+        private _vertexBuffers: { [key: string]: Nullable<VertexBuffer> } = {};
+        private _indexBuffer: Nullable<WebGLBuffer>;
+        private _cachedDefines: string;
+        private _effectLayerMapGenerationEffect: Effect;
+        private _effectLayerOptions: IEffectLayerOptions;
+        private _mergeEffect: Effect;
+
+        protected _scene: Scene;
+        protected _engine: Engine;
+        protected _maxSize: number = 0;
+        protected _mainTextureDesiredSize: ISize = { width: 0, height: 0 };
+        protected _mainTexture: RenderTargetTexture;
+        protected _shouldRender = true;
+        protected _postProcesses: PostProcess[] = [];
+        protected _textures: BaseTexture[] = [];
+        protected _emissiveTextureAndColor: { texture: Nullable<BaseTexture>, color: Color4 } = { texture: null, color: new Color4() };
+
+        /**
+         * The clear color of the texture used to generate the glow map.
+         */
+        public neutralColor: Color4 = new Color4();
+
+        /**
+         * Specifies wether the highlight layer is enabled or not.
+         */
+        public isEnabled: boolean = true;
+
+        /**
+         * Gets the camera attached to the layer.
+         */
+        public get camera(): Nullable<Camera> {
+            return this._effectLayerOptions.camera;
+        }
+
+        /**
+         * An event triggered when the effect layer has been disposed.
+         */
+        public onDisposeObservable = new Observable<EffectLayer>();
+
+        /**
+         * An event triggered when the effect layer is about rendering the main texture with the glowy parts.
+         */
+        public onBeforeRenderMainTextureObservable = new Observable<EffectLayer>();
+
+        /**
+         * An event triggered when the generated texture is being merged in the scene.
+         */
+        public onBeforeComposeObservable = new Observable<EffectLayer>();
+
+        /**
+         * An event triggered when the generated texture has been merged in the scene.
+         */
+        public onAfterComposeObservable = new Observable<EffectLayer>();
+
+        /**
+         * An event triggered when the efffect layer changes its size.
+         */
+        public onSizeChangedObservable = new Observable<EffectLayer>();
+
+        /**
+         * Instantiates a new effect Layer and references it in the scene.
+         * @param name The name of the layer
+         * @param scene The scene to use the layer in
+         */
+        constructor(
+            /** The Friendly of the effect in the scene */
+            public name: string, 
+            scene: Scene) {
+            this._scene = scene || Engine.LastCreatedScene;
+            this._engine = scene.getEngine();
+            this._maxSize = this._engine.getCaps().maxTextureSize;
+            this._scene.effectLayers.push(this);
+
+            // Generate Buffers
+            this._generateIndexBuffer();
+            this._genrateVertexBuffer();
+        }
+
+        /**
+         * Get the effect name of the layer.
+         * @return The effect name
+         */ 
+        public abstract getEffectName(): string;
+
+        /**
+         * Checks for the readiness of the element composing the layer.
+         * @param subMesh the mesh to check for
+         * @param useInstances specify wether or not to use instances to render the mesh
+         * @return true if ready otherwise, false
+         */ 
+        public abstract isReady(subMesh: SubMesh, useInstances: boolean): boolean;
+
+        /**
+         * Returns wether or nood the layer needs stencil enabled during the mesh rendering.
+         * @returns true if the effect requires stencil during the main canvas render pass.
+         */
+        public abstract needStencil(): boolean;
+
+        /**
+         * Create the merge effect. This is the shader use to blit the information back
+         * to the main canvas at the end of the scene rendering.
+         * @returns The effect containing the shader used to merge the effect on the  main canvas
+         */
+        protected abstract _createMergeEffect(): Effect;
+        
+        /**
+         * Creates the render target textures and post processes used in the effect layer.
+         */
+        protected abstract _createTextureAndPostProcesses(): void;
+        
+        /**
+         * Implementation specific of rendering the generating effect on the main canvas.
+         * @param effect The effect used to render through
+         */
+        protected abstract _internalRender(effect: Effect): void;
+
+        /**
+         * Sets the required values for both the emissive texture and and the main color.
+         */
+        protected abstract _setEmissiveTextureAndColor(mesh: Mesh, subMesh: SubMesh, material: Material): void;
+
+        /**
+         * Free any resources and references associated to a mesh.
+         * Internal use
+         * @param mesh The mesh to free.
+         */
+        public abstract _disposeMesh(mesh: Mesh): void;
+
+        /**
+         * Initializes the effect layer with the required options.
+         * @param options Sets of none mandatory options to use with the layer (see IEffectLayerOptions for more information)
+         */
+        protected _init(options: Partial<IEffectLayerOptions>): void {
+            // Adapt options
+            this._effectLayerOptions = {
+                mainTextureRatio: 0.5,
+                alphaBlendingMode: Engine.ALPHA_COMBINE,
+                camera: null,
+                ...options,
+            };
+
+            this._setMainTextureSize();
+            this._createMainTexture();
+            this._createTextureAndPostProcesses();
+            this._mergeEffect = this._createMergeEffect();
+        }
+
+        /**
+         * Generates the index buffer of the full screen quad blending to the main canvas.
+         */
+        private _generateIndexBuffer(): void {
+            // Indices
+            var indices = [];
+            indices.push(0);
+            indices.push(1);
+            indices.push(2);
+
+            indices.push(0);
+            indices.push(2);
+            indices.push(3);
+
+            this._indexBuffer = this._engine.createIndexBuffer(indices);
+        }
+
+        /**
+         * Generates the vertex buffer of the full screen quad blending to the main canvas.
+         */
+        private _genrateVertexBuffer(): void {
+            // VBO
+            var vertices = [];
+            vertices.push(1, 1);
+            vertices.push(-1, 1);
+            vertices.push(-1, -1);
+            vertices.push(1, -1);
+
+            var vertexBuffer = new VertexBuffer(this._engine, vertices, VertexBuffer.PositionKind, false, false, 2);
+            this._vertexBuffers[VertexBuffer.PositionKind] = vertexBuffer;
+        }
+
+        /**
+         * Sets the main texture desired size which is the closest power of two
+         * of the engine canvas size.
+         */
+        private _setMainTextureSize(): void {
+            if (this._effectLayerOptions.mainTextureFixedSize) {
+                this._mainTextureDesiredSize.width = this._effectLayerOptions.mainTextureFixedSize;
+                this._mainTextureDesiredSize.height = this._effectLayerOptions.mainTextureFixedSize;
+            }
+            else {
+                this._mainTextureDesiredSize.width = this._engine.getRenderWidth() * this._effectLayerOptions.mainTextureRatio;
+                this._mainTextureDesiredSize.height = this._engine.getRenderHeight() * this._effectLayerOptions.mainTextureRatio;
+
+                this._mainTextureDesiredSize.width = this._engine.needPOTTextures ? Tools.GetExponentOfTwo(this._mainTextureDesiredSize.width, this._maxSize) : this._mainTextureDesiredSize.width;
+                this._mainTextureDesiredSize.height = this._engine.needPOTTextures ? Tools.GetExponentOfTwo(this._mainTextureDesiredSize.height, this._maxSize) : this._mainTextureDesiredSize.height;
+            }
+
+            this._mainTextureDesiredSize.width = Math.floor(this._mainTextureDesiredSize.width);
+            this._mainTextureDesiredSize.height = Math.floor(this._mainTextureDesiredSize.height);
+        }
+
+        /**
+         * Creates the main texture for the effect layer.
+         */
+        protected _createMainTexture(): void {
+            this._mainTexture = new RenderTargetTexture("HighlightLayerMainRTT",
+                {
+                    width: this._mainTextureDesiredSize.width,
+                    height: this._mainTextureDesiredSize.height
+                },
+                this._scene,
+                false,
+                true,
+                Engine.TEXTURETYPE_UNSIGNED_INT);
+            this._mainTexture.activeCamera = this._effectLayerOptions.camera;
+            this._mainTexture.wrapU = Texture.CLAMP_ADDRESSMODE;
+            this._mainTexture.wrapV = Texture.CLAMP_ADDRESSMODE;
+            this._mainTexture.anisotropicFilteringLevel = 1;
+            this._mainTexture.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
+            this._mainTexture.renderParticles = false;
+            this._mainTexture.renderList = null;
+            this._mainTexture.ignoreCameraViewport = true;
+
+            // Custom render function
+            this._mainTexture.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>): void => {
+                this.onBeforeRenderMainTextureObservable.notifyObservers(this);
+
+                var index: number;
+
+                let engine = this._scene.getEngine();
+
+                if (depthOnlySubMeshes.length) {
+                    engine.setColorWrite(false);
+                    for (index = 0; index < depthOnlySubMeshes.length; index++) {
+                        this._renderSubMesh(depthOnlySubMeshes.data[index]);
+                    }
+                    engine.setColorWrite(true);
+                }
+
+                for (index = 0; index < opaqueSubMeshes.length; index++) {
+                    this._renderSubMesh(opaqueSubMeshes.data[index]);
+                }
+
+                for (index = 0; index < alphaTestSubMeshes.length; index++) {
+                    this._renderSubMesh(alphaTestSubMeshes.data[index]);
+                }
+
+                for (index = 0; index < transparentSubMeshes.length; index++) {
+                    this._renderSubMesh(transparentSubMeshes.data[index]);
+                }
+            };
+
+            this._mainTexture.onClearObservable.add((engine: Engine) => {
+                engine.clear(this.neutralColor, true, true, true);
+            });
+        }
+
+        /**
+         * Checks for the readiness of the element composing the layer.
+         * @param subMesh the mesh to check for
+         * @param useInstances specify wether or not to use instances to render the mesh
+         * @param emissiveTexture the associated emissive texture used to generate the glow
+         * @return true if ready otherwise, false
+         */
+        protected _isReady(subMesh: SubMesh, useInstances: boolean, emissiveTexture: Nullable<BaseTexture>): boolean {
+            let material = subMesh.getMaterial();
+
+            if (!material) {
+                return false;
+            }
+
+            if (!material.isReady(subMesh.getMesh(), useInstances)) {
+                return false;
+            }
+
+            var defines = [];
+
+            var attribs = [VertexBuffer.PositionKind];
+
+            var mesh = subMesh.getMesh();
+            var uv1 = false;
+            var uv2 = false;
+
+            // Alpha test
+            if (material && material.needAlphaTesting()) {
+                var alphaTexture = material.getAlphaTestTexture();
+                if (alphaTexture) {
+                    defines.push("#define ALPHATEST");
+                    if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind) &&
+                        alphaTexture.coordinatesIndex === 1) {
+                        defines.push("#define DIFFUSEUV2");
+                        uv2 = true;
+                    }
+                    else if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
+                        defines.push("#define DIFFUSEUV1");
+                        uv1 = true;
+                    }
+                }
+            }
+
+            // Emissive
+            if (emissiveTexture) {
+                defines.push("#define EMISSIVE");
+                if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind) &&
+                    emissiveTexture.coordinatesIndex === 1) {
+                    defines.push("#define EMISSIVEUV2");
+                    uv2 = true;
+                }
+                else if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
+                    defines.push("#define EMISSIVEUV1");
+                    uv1 = true;
+                }
+            }
+
+            if (uv1) {
+                attribs.push(VertexBuffer.UVKind);
+                defines.push("#define UV1");
+            }
+            if (uv2) {
+                attribs.push(VertexBuffer.UV2Kind);
+                defines.push("#define UV2");
+            }
+
+            // Bones
+            if (mesh.useBones && mesh.computeBonesUsingShaders) {
+                attribs.push(VertexBuffer.MatricesIndicesKind);
+                attribs.push(VertexBuffer.MatricesWeightsKind);
+                if (mesh.numBoneInfluencers > 4) {
+                    attribs.push(VertexBuffer.MatricesIndicesExtraKind);
+                    attribs.push(VertexBuffer.MatricesWeightsExtraKind);
+                }
+                defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
+                defines.push("#define BonesPerMesh " + (mesh.skeleton ? (mesh.skeleton.bones.length + 1) : 0));
+            } else {
+                defines.push("#define NUM_BONE_INFLUENCERS 0");
+            }
+
+            // Instances
+            if (useInstances) {
+                defines.push("#define INSTANCES");
+                attribs.push("world0");
+                attribs.push("world1");
+                attribs.push("world2");
+                attribs.push("world3");
+            }
+
+            // Get correct effect
+            var join = defines.join("\n");
+            if (this._cachedDefines !== join) {
+                this._cachedDefines = join;
+                this._effectLayerMapGenerationEffect = this._scene.getEngine().createEffect("glowMapGeneration",
+                    attribs,
+                    ["world", "mBones", "viewProjection", "diffuseMatrix", "color", "emissiveMatrix"],
+                    ["diffuseSampler", "emissiveSampler"], join);
+            }
+
+            return this._effectLayerMapGenerationEffect.isReady();
+        }
+
+        /**
+         * Renders the glowing part of the scene by blending the blurred glowing meshes on top of the rendered scene.
+         */
+        public render(): void {
+            var currentEffect = this._mergeEffect;
+
+            // Check
+            if (!currentEffect.isReady())
+                return;
+
+            for (var i = 0; i < this._postProcesses.length; i++) {
+                if (!this._postProcesses[i].isReady()) {
+                    return;
+                }
+            }
+
+            var engine = this._scene.getEngine();
+
+            this.onBeforeComposeObservable.notifyObservers(this);
+
+            // Render
+            engine.enableEffect(currentEffect);
+            engine.setState(false);
+            
+            // VBOs
+            engine.bindBuffers(this._vertexBuffers, this._indexBuffer, currentEffect);
+
+            // Cache
+            var previousAlphaMode = engine.getAlphaMode();
+
+            // Go Blend.
+            engine.setAlphaMode(this._effectLayerOptions.alphaBlendingMode);
+
+            // Blends the map on the main canvas.
+            this._internalRender(currentEffect);
+
+            // Restore Alpha
+            engine.setAlphaMode(previousAlphaMode);
+
+            this.onAfterComposeObservable.notifyObservers(this);
+
+            // Handle size changes.
+            var size = this._mainTexture.getSize();
+            this._setMainTextureSize();
+            if (size.width !== this._mainTextureDesiredSize.width || size.height !== this._mainTextureDesiredSize.height) {
+                // Recreate RTT and post processes on size change.
+                this.onSizeChangedObservable.notifyObservers(this);
+                this._disposeTextureAndPostProcesses();
+                this._createMainTexture();
+                this._createTextureAndPostProcesses();
+            }
+        }
+
+        /**
+         * Determine if a given mesh will be used in the current effect.
+         * @param mesh mesh to test
+         * @returns true if the mesh will be used
+         */
+        public hasMesh(mesh: AbstractMesh): boolean {
+            return true;
+        }
+
+        /**
+         * Returns true if the layer contains information to display, otherwise false.
+         * @returns true if the glow layer should be rendered
+         */
+        public shouldRender(): boolean {
+            return this.isEnabled && this._shouldRender;
+        }
+
+        /**
+         * Returns true if the mesh should render, otherwise false.
+         * @param mesh The mesh to render
+         * @returns true if it should render otherwise false
+         */
+        protected _shouldRenderMesh(mesh: Mesh): boolean {
+            return true;
+        }
+
+        /**
+         * Returns true if the mesh should render, otherwise false.
+         * @param mesh The mesh to render
+         * @returns true if it should render otherwise false
+         */
+        protected _shouldRenderEmissiveTextureForMesh(mesh: Mesh): boolean {
+            return true;
+        }
+
+        /**
+         * Renders the submesh passed in parameter to the generation map.
+         */
+        protected _renderSubMesh(subMesh: SubMesh): void {
+            if (!this.shouldRender()) {
+                return;
+            }
+
+            var material = subMesh.getMaterial();
+            var mesh = subMesh.getRenderingMesh();
+            var scene = this._scene;
+            var engine = scene.getEngine();
+
+            if (!material) {
+                return;
+            }
+
+            // Do not block in blend mode.
+            if (material.needAlphaBlendingForMesh(mesh)) {
+                return;
+            }
+
+            // Culling
+            engine.setState(material.backFaceCulling);
+
+            // Managing instances
+            var batch = mesh._getInstancesRenderList(subMesh._id);
+            if (batch.mustReturn) {
+                return;
+            }
+
+            // Early Exit per mesh
+            if (!this._shouldRenderMesh(mesh)) {
+                return;
+            }
+
+            var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined);
+
+            this._setEmissiveTextureAndColor(mesh, subMesh, material);
+
+            if (this._isReady(subMesh, hardwareInstancedRendering, this._emissiveTextureAndColor.texture)) {
+                engine.enableEffect(this._effectLayerMapGenerationEffect);
+                mesh._bind(subMesh, this._effectLayerMapGenerationEffect, Material.TriangleFillMode);
+
+                this._effectLayerMapGenerationEffect.setMatrix("viewProjection", scene.getTransformMatrix());
+
+                this._effectLayerMapGenerationEffect.setFloat4("color",
+                    this._emissiveTextureAndColor.color.r,
+                    this._emissiveTextureAndColor.color.g,
+                    this._emissiveTextureAndColor.color.b,
+                    this._emissiveTextureAndColor.color.a);
+
+                // Alpha test
+                if (material && material.needAlphaTesting()) {
+                    var alphaTexture = material.getAlphaTestTexture();
+                    if (alphaTexture) {
+                        this._effectLayerMapGenerationEffect.setTexture("diffuseSampler", alphaTexture);
+                        let textureMatrix = alphaTexture.getTextureMatrix();
+
+                        if (textureMatrix) {
+                            this._effectLayerMapGenerationEffect.setMatrix("diffuseMatrix", textureMatrix);
+                        }
+                    }
+                }
+
+                // Glow emissive only
+                if (this._emissiveTextureAndColor.texture) {
+                    this._effectLayerMapGenerationEffect.setTexture("emissiveSampler", this._emissiveTextureAndColor.texture);
+                    this._effectLayerMapGenerationEffect.setMatrix("emissiveMatrix", this._emissiveTextureAndColor.texture.getTextureMatrix());
+                }
+
+                // Bones
+                if (mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) {
+                    this._effectLayerMapGenerationEffect.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
+                }
+
+                // Draw
+                mesh._processRendering(subMesh, this._effectLayerMapGenerationEffect, Material.TriangleFillMode, batch, hardwareInstancedRendering,
+                    (isInstance, world) => this._effectLayerMapGenerationEffect.setMatrix("world", world));
+            } else {
+                // Need to reset refresh rate of the shadowMap
+                this._mainTexture.resetRefreshCounter();
+            }
+        }
+
+        /**
+         * Rebuild the required buffers.
+         * @ignore Internal use only.
+         */
+        public _rebuild(): void {
+            let vb = this._vertexBuffers[VertexBuffer.PositionKind];
+
+            if (vb) {
+                vb._rebuild();
+            }
+
+            this._generateIndexBuffer();
+        }
+
+        /**
+         * Dispose only the render target textures and post process.
+         */
+        private _disposeTextureAndPostProcesses(): void {
+            this._mainTexture.dispose();
+
+            for (var i = 0; i < this._postProcesses.length; i++) {
+                if (this._postProcesses[i]) {
+                    this._postProcesses[i].dispose();
+                }
+            }
+            this._postProcesses = [];
+
+            for (var i = 0; i < this._textures.length; i++) {
+                if (this._textures[i]) {
+                    this._textures[i].dispose();
+                }
+            }
+            this._textures = [];
+        }
+
+        /**
+         * Dispose the highlight layer and free resources.
+         */
+        public dispose(): void {
+            var vertexBuffer = this._vertexBuffers[VertexBuffer.PositionKind];
+            if (vertexBuffer) {
+                vertexBuffer.dispose();
+                this._vertexBuffers[VertexBuffer.PositionKind] = null;
+            }
+
+            if (this._indexBuffer) {
+                this._scene.getEngine()._releaseBuffer(this._indexBuffer);
+                this._indexBuffer = null;
+            }
+
+            // Clean textures and post processes
+            this._disposeTextureAndPostProcesses();
+
+            // Remove from scene
+            var index = this._scene.effectLayers.indexOf(this, 0);
+            if (index > -1) {
+                this._scene.effectLayers.splice(index, 1);
+            }
+
+            // Callback
+            this.onDisposeObservable.notifyObservers(this);
+
+            this.onDisposeObservable.clear();
+            this.onBeforeRenderMainTextureObservable.clear();
+            this.onBeforeComposeObservable.clear();
+            this.onAfterComposeObservable.clear();
+            this.onSizeChangedObservable.clear();
+        }
+    }
+} 

+ 419 - 0
src/Layer/babylon.glowLayer.ts

@@ -0,0 +1,419 @@
+module BABYLON {
+    /**
+     * Glow layer options. This helps customizing the behaviour
+     * of the glow layer.
+     */
+    export interface IGlowLayerOptions {
+        /**
+         * Multiplication factor apply to the canvas size to compute the render target size
+         * used to generated the glowing objects (the smaller the faster).
+         */
+        mainTextureRatio: number;
+
+        /**
+         * Enforces a fixed size texture to ensure resize independant blur.
+         */
+        mainTextureFixedSize?: number;
+
+        /**
+         * How big is the kernel of the blur texture.
+         */
+        blurKernelSize: number;
+
+        /**
+         * The camera attached to the layer.
+         */
+        camera: Nullable<Camera>;
+
+        /**
+         * Enable MSAA by chosing the number of samples.
+         */
+        mainTextureSamples?: number;
+    }
+
+    /**
+     * The glow layer Helps adding a glow effect around the emissive parts of a mesh.
+     * 
+     * Once instantiated in a scene, simply use the pushMesh or removeMesh method to add or remove
+     * glowy meshes to your scene.
+     * 
+     * Documentation: https://doc.babylonjs.com/how_to/glow_layer
+     */
+    export class GlowLayer extends EffectLayer {
+        /**
+         * Effect Name of the layer.
+         */
+        public static readonly EffectName = "GlowLayer";
+
+        /**
+         * The default blur kernel size used for the glow.
+         */
+        public static DefaultBlurKernelSize = 32;
+
+        /**
+         * The default texture size ratio used for the glow.
+         */
+        public static DefaultTextureRatio = 0.5;
+
+        /**
+         * Sets the kernel size of the blur.
+         */
+        public set blurKernelSize(value: number) {
+            this._horizontalBlurPostprocess1.kernel = value;
+            this._verticalBlurPostprocess1.kernel = value;
+            this._horizontalBlurPostprocess2.kernel = value;
+            this._verticalBlurPostprocess2.kernel = value;
+        }
+
+        /**
+         * Gets the kernel size of the blur.
+         */
+        public get blurKernelSize(): number {
+            return this._horizontalBlurPostprocess1.kernel;
+        }
+
+        /**
+         * Sets the glow intensity.
+         */
+        public set intensity(value: number) {
+            this._intensity = value;
+        }
+
+        /**
+         * Gets the glow intensity.
+         */
+        public get intensity(): number {
+            return this._intensity;
+        }
+
+        private _options: IGlowLayerOptions;
+        private _intensity: number = 1.0;
+        private _horizontalBlurPostprocess1: BlurPostProcess;
+        private _verticalBlurPostprocess1: BlurPostProcess;
+        private _horizontalBlurPostprocess2: BlurPostProcess;
+        private _verticalBlurPostprocess2: BlurPostProcess;
+        private _blurTexture1: RenderTargetTexture;
+        private _blurTexture2: RenderTargetTexture;
+        private _postProcesses1: PostProcess[];
+        private _postProcesses2: PostProcess[];
+
+        private _includedOnlyMeshes: number[] = [];
+        private _excludedMeshes: number[] = [];
+
+        /**
+         * Instantiates a new glow Layer and references it to the scene.
+         * @param name The name of the layer
+         * @param scene The scene to use the layer in
+         * @param options Sets of none mandatory options to use with the layer (see IGlowLayerOptions for more information)
+         */
+        constructor(public name: string, scene: Scene, options?: Partial<IGlowLayerOptions>) {
+            super(name, scene);
+            this.neutralColor = new Color4(0, 0, 0, 1);
+
+            // Adapt options
+            this._options = {
+                mainTextureRatio: GlowLayer.DefaultTextureRatio,
+                blurKernelSize: 32,
+                mainTextureFixedSize: undefined,
+                camera: null,
+                mainTextureSamples: 1,
+                ...options,
+            };
+
+            // Initialize the layer
+            this._init({
+                alphaBlendingMode: Engine.ALPHA_ADD,
+                camera: this._options.camera,
+                mainTextureFixedSize: this._options.mainTextureFixedSize,
+                mainTextureRatio: this._options.mainTextureRatio
+            });
+        }
+
+        /**
+         * Get the effect name of the layer.
+         * @return The effect name
+         */ 
+        public getEffectName(): string {
+            return GlowLayer.EffectName;
+        }
+
+        /**
+         * Create the merge effect. This is the shader use to blit the information back
+         * to the main canvas at the end of the scene rendering.
+         */
+        protected _createMergeEffect(): Effect {
+             // Effect
+             return this._engine.createEffect("glowMapMerge",
+                [VertexBuffer.PositionKind],
+                ["offset"],
+                ["textureSampler", "textureSampler2"],
+                "#define EMISSIVE \n");
+
+        }
+
+        /**
+         * Creates the render target textures and post processes used in the glow layer.
+         */
+        protected _createTextureAndPostProcesses(): void {
+            var blurTextureWidth = this._mainTextureDesiredSize.width;
+            var blurTextureHeight = this._mainTextureDesiredSize.height;
+            blurTextureWidth = this._engine.needPOTTextures ? Tools.GetExponentOfTwo(blurTextureWidth, this._maxSize) : blurTextureWidth;
+            blurTextureHeight = this._engine.needPOTTextures ? Tools.GetExponentOfTwo(blurTextureHeight, this._maxSize) : blurTextureHeight;
+
+            this._blurTexture1 = new RenderTargetTexture("GlowLayerBlurRTT",
+                {
+                    width: blurTextureWidth,
+                    height: blurTextureHeight
+                },
+                this._scene,
+                false,
+                true,
+                Engine.TEXTURETYPE_HALF_FLOAT);
+            this._blurTexture1.wrapU = Texture.CLAMP_ADDRESSMODE;
+            this._blurTexture1.wrapV = Texture.CLAMP_ADDRESSMODE;
+            this._blurTexture1.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
+            this._blurTexture1.renderParticles = false;
+            this._blurTexture1.ignoreCameraViewport = true;
+
+            var blurTextureWidth2 = Math.floor(blurTextureWidth / 2);
+            var blurTextureHeight2 = Math.floor(blurTextureHeight / 2);
+
+            this._blurTexture2 = new RenderTargetTexture("GlowLayerBlurRTT2",
+                {
+                    width: blurTextureWidth2,
+                    height: blurTextureHeight2
+                },
+                this._scene,
+                false,
+                true,
+                Engine.TEXTURETYPE_HALF_FLOAT);
+            this._blurTexture2.wrapU = Texture.CLAMP_ADDRESSMODE;
+            this._blurTexture2.wrapV = Texture.CLAMP_ADDRESSMODE;
+            this._blurTexture2.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
+            this._blurTexture2.renderParticles = false;
+            this._blurTexture2.ignoreCameraViewport = true;
+
+            this._textures = [ this._blurTexture1, this._blurTexture2 ];
+
+            this._horizontalBlurPostprocess1 = new BlurPostProcess("GlowLayerHBP1", new Vector2(1.0, 0), this._options.blurKernelSize / 2, {
+                    width:  blurTextureWidth,
+                    height: blurTextureHeight
+                },
+                null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, Engine.TEXTURETYPE_HALF_FLOAT);
+            this._horizontalBlurPostprocess1.width = blurTextureWidth;
+            this._horizontalBlurPostprocess1.height = blurTextureHeight;
+            this._horizontalBlurPostprocess1.onApplyObservable.add(effect => {
+                effect.setTexture("textureSampler", this._mainTexture);
+            });
+
+            this._verticalBlurPostprocess1 = new BlurPostProcess("GlowLayerVBP1", new Vector2(0, 1.0), this._options.blurKernelSize / 2, {
+                    width:  blurTextureWidth,
+                    height: blurTextureHeight
+                },
+                null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, Engine.TEXTURETYPE_HALF_FLOAT);
+
+            this._horizontalBlurPostprocess2 = new BlurPostProcess("GlowLayerHBP2", new Vector2(1.0, 0), this._options.blurKernelSize / 2, {
+                    width:  blurTextureWidth2,
+                    height: blurTextureHeight2
+                },
+                null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, Engine.TEXTURETYPE_HALF_FLOAT);
+            this._horizontalBlurPostprocess2.width = blurTextureWidth2;
+            this._horizontalBlurPostprocess2.height = blurTextureHeight2;
+            this._horizontalBlurPostprocess2.onApplyObservable.add(effect => {
+                effect.setTexture("textureSampler", this._blurTexture1);
+            });
+
+            this._verticalBlurPostprocess2 = new BlurPostProcess("GlowLayerVBP2", new Vector2(0, 1.0), this._options.blurKernelSize / 2, {
+                    width:  blurTextureWidth2,
+                    height: blurTextureHeight2
+                },
+                null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, Engine.TEXTURETYPE_HALF_FLOAT);
+
+            this._postProcesses = [ this._horizontalBlurPostprocess1, this._verticalBlurPostprocess1, this._horizontalBlurPostprocess2, this._verticalBlurPostprocess2 ];
+            this._postProcesses1 = [ this._horizontalBlurPostprocess1, this._verticalBlurPostprocess1 ];
+            this._postProcesses2 = [ this._horizontalBlurPostprocess2, this._verticalBlurPostprocess2 ];
+
+            this._mainTexture.samples = this._options.mainTextureSamples!;
+            this._mainTexture.onAfterUnbindObservable.add(() => {
+                let internalTexture = this._blurTexture1.getInternalTexture();
+                if (internalTexture) {
+                    this._scene.postProcessManager.directRender(
+                        this._postProcesses1,
+                        internalTexture, 
+                        true);
+
+                        internalTexture = this._blurTexture2.getInternalTexture();
+                        if (internalTexture) {
+                            this._scene.postProcessManager.directRender(
+                                this._postProcesses2,
+                                internalTexture, 
+                                true);
+                        }
+                }
+            });
+
+            // Prevent autoClear.
+            this._postProcesses.map(pp => { pp.autoClear = false; });
+        }
+
+        /**
+         * Checks for the readiness of the element composing the layer.
+         * @param subMesh the mesh to check for
+         * @param useInstances specify wether or not to use instances to render the mesh
+         * @param emissiveTexture the associated emissive texture used to generate the glow
+         * @return true if ready otherwise, false
+         */
+        public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
+            let material = subMesh.getMaterial();
+            let mesh = subMesh.getRenderingMesh();
+
+            if (!material || !mesh) {
+                return false;
+            }
+
+            let emissiveTexture = (<any>material).emissiveTexture;
+            return super._isReady(subMesh, useInstances, emissiveTexture);
+        }
+
+        /**
+         * Returns wether or nood the layer needs stencil enabled during the mesh rendering.
+         */
+        public needStencil(): boolean {
+            return false;
+        }
+
+        /**
+         * Implementation specific of rendering the generating effect on the main canvas.
+         * @param effect The effect used to render through
+         */
+        protected _internalRender(effect: Effect): void {
+            // Texture
+            effect.setTexture("textureSampler", this._blurTexture1);
+            effect.setTexture("textureSampler2", this._blurTexture2);
+            effect.setFloat("offset", this._intensity);
+
+            // Cache
+            var engine = this._engine;
+            var previousStencilBuffer = engine.getStencilBuffer();
+                
+            // Draw order
+            engine.setStencilBuffer(false);
+
+            engine.drawElementsType(Material.TriangleFillMode, 0, 6);
+
+            // Draw order
+            engine.setStencilBuffer(previousStencilBuffer);
+        }
+
+        /**
+         * Sets the required values for both the emissive texture and and the main color.
+         */
+        protected _setEmissiveTextureAndColor(mesh: Mesh, subMesh: SubMesh, material: Material): void {
+            var textureLevel = 1.0;
+            if (material) {
+                this._emissiveTextureAndColor.texture = (<any>material).emissiveTexture;
+                if (this._emissiveTextureAndColor.texture) {
+                    textureLevel = this._emissiveTextureAndColor.texture.level;
+                }
+            }
+            else {
+                this._emissiveTextureAndColor.texture = null;
+            }
+
+            if ((<any>material).emissiveColor) {
+                this._emissiveTextureAndColor.color.set(
+                    (<any>material).emissiveColor.r * textureLevel,
+                    (<any>material).emissiveColor.g * textureLevel,
+                    (<any>material).emissiveColor .b * textureLevel,
+                    1.0);
+            }
+            else {
+                this._emissiveTextureAndColor.color.set(
+                    this.neutralColor.r,
+                    this.neutralColor.g,
+                    this.neutralColor.b,
+                    this.neutralColor.a);
+            }
+        }
+
+        /**
+         * Returns true if the mesh should render, otherwise false.
+         * @param mesh The mesh to render
+         * @returns true if it should render otherwise false
+         */
+        protected _shouldRenderMesh(mesh: Mesh): boolean {
+            return this.hasMesh(mesh);
+        }
+
+        /**
+         * Add a mesh in the exclusion list to prevent it to impact or being impacted by the glow layer.
+         * @param mesh The mesh to exclude from the glow layer
+         */
+        public addExcludedMesh(mesh: Mesh): void {
+            if (this._excludedMeshes.indexOf(mesh.uniqueId) === -1) {
+                this._excludedMeshes.push(mesh.uniqueId);
+            }
+        }
+
+        /**
+          * Remove a mesh from the exclusion list to let it impact or being impacted by the glow layer.
+          * @param mesh The mesh to remove
+          */
+        public removeExcludedMesh(mesh: Mesh): void {
+            var index = this._excludedMeshes.indexOf(mesh.uniqueId);
+            if (index !== -1) {
+                this._excludedMeshes.splice(index, 1);
+            } 
+        }
+
+        /**
+         * Add a mesh in the inclusion list to impact or being impacted by the glow layer.
+         * @param mesh The mesh to include in the glow layer
+         */
+        public addIncludedOnlyMesh(mesh: Mesh): void {
+            if (this._includedOnlyMeshes.indexOf(mesh.uniqueId) === -1) {
+                this._includedOnlyMeshes.push(mesh.uniqueId);
+            }
+        }
+
+        /**
+          * Remove a mesh from the Inclusion list to prevent it to impact or being impacted by the glow layer.
+          * @param mesh The mesh to remove
+          */
+        public removeIncludedOnlyMesh(mesh: Mesh): void {
+            var index = this._includedOnlyMeshes.indexOf(mesh.uniqueId);
+            if (index !== -1) {
+                this._includedOnlyMeshes.splice(index, 1);
+            } 
+        }
+
+        /**
+         * Determine if a given mesh will be used in the glow layer
+         * @param mesh The mesh to test
+         * @returns true if the mesh will be highlighted by the current glow layer
+         */
+        public hasMesh(mesh: AbstractMesh): boolean {
+            // Included Mesh
+            if (this._includedOnlyMeshes.length) {
+                return this._includedOnlyMeshes.indexOf(mesh.uniqueId) !== -1;
+            };
+
+            // Excluded Mesh
+            if (this._excludedMeshes.length) {
+                return this._excludedMeshes.indexOf(mesh.uniqueId) === -1;
+            };
+
+            return true;
+        }
+
+        /**
+         * Free any resources and references associated to a mesh.
+         * Internal use
+         * @param mesh The mesh to free.
+         */
+        public _disposeMesh(mesh: Mesh): void {
+            this.removeIncludedOnlyMesh(mesh);
+            this.removeExcludedMesh(mesh);
+        }
+    }
+} 

+ 667 - 0
src/Layer/babylon.highlightLayer.ts

@@ -0,0 +1,667 @@
+module BABYLON {
+    /**
+     * Special Glow Blur post process only blurring the alpha channel
+     * It enforces keeping the most luminous color in the color channel.
+     */
+    class GlowBlurPostProcess extends PostProcess {
+        constructor(name: string, public direction: Vector2, public kernel: number, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode: number = Texture.BILINEAR_SAMPLINGMODE, engine?: Engine, reusable?: boolean) {
+            super(name, "glowBlurPostProcess", ["screenSize", "direction", "blurWidth"], null, options, camera, samplingMode, engine, reusable);
+            
+            this.onApplyObservable.add((effect: Effect) => {
+                effect.setFloat2("screenSize", this.width, this.height);
+                effect.setVector2("direction", this.direction);
+                effect.setFloat("blurWidth", this.kernel);
+            });
+        }
+    }
+
+    /**
+     * Highlight layer options. This helps customizing the behaviour
+     * of the highlight layer.
+     */
+    export interface IHighlightLayerOptions {
+        /**
+         * Multiplication factor apply to the canvas size to compute the render target size
+         * used to generated the glowing objects (the smaller the faster).
+         */
+        mainTextureRatio: number;
+
+        /**
+         * Enforces a fixed size texture to ensure resize independant blur.
+         */
+        mainTextureFixedSize?: number;
+
+        /**
+         * Multiplication factor apply to the main texture size in the first step of the blur to reduce the size 
+         * of the picture to blur (the smaller the faster).
+         */
+        blurTextureSizeRatio: number;
+
+        /**
+         * How big in texel of the blur texture is the vertical blur.
+         */
+        blurVerticalSize: number;
+
+        /**
+         * How big in texel of the blur texture is the horizontal blur.
+         */
+        blurHorizontalSize: number;
+
+        /**
+         * Alpha blending mode used to apply the blur. Default is combine.
+         */
+        alphaBlendingMode: number
+
+        /**
+         * The camera attached to the layer.
+         */
+        camera: Nullable<Camera>;
+
+        /**
+         * Should we display highlight as a solid stroke?
+         */
+        isStroke?: boolean;
+    }
+
+    /**
+     * Storage interface grouping all the information required for glowing a mesh.
+     */
+    interface IHighlightLayerMesh {
+        /** 
+         * The glowy mesh
+         */
+        mesh: Mesh;
+        /**
+         * The color of the glow
+         */
+        color: Color3;
+        /**
+         * The mesh render callback use to insert stencil information
+         */
+        observerHighlight: Nullable<Observer<Mesh>>;
+        /**
+         * The mesh render callback use to come to the default behavior
+         */
+        observerDefault: Nullable<Observer<Mesh>>;
+        /**
+         * If it exists, the emissive color of the material will be used to generate the glow.
+         * Else it falls back to the current color.
+         */
+        glowEmissiveOnly: boolean;
+    }
+
+    /**
+     * Storage interface grouping all the information required for an excluded mesh.
+     */
+    interface IHighlightLayerExcludedMesh {
+        /** 
+         * The glowy mesh
+         */
+        mesh: Mesh;
+        /**
+         * The mesh render callback use to prevent stencil use
+         */
+        beforeRender: Nullable<Observer<Mesh>>;
+        /**
+         * The mesh render callback use to restore previous stencil use
+         */
+        afterRender: Nullable<Observer<Mesh>>;
+    }
+
+    /**
+     * The highlight layer Helps adding a glow effect around a mesh.
+     * 
+     * Once instantiated in a scene, simply use the pushMesh or removeMesh method to add or remove
+     * glowy meshes to your scene.
+     * 
+     * !!! THIS REQUIRES AN ACTIVE STENCIL BUFFER ON THE CANVAS !!!
+     */
+    export class HighlightLayer extends EffectLayer {
+        /**
+         * Effect Name of the highlight layer.
+         */
+        public static readonly EffectName = "HighlightLayer";
+
+        /**
+         * The neutral color used during the preparation of the glow effect.
+         * This is black by default as the blend operation is a blend operation. 
+         */
+        public static NeutralColor: Color4 = new Color4(0, 0, 0, 0);
+
+        /**
+         * Stencil value used for glowing meshes.
+         */
+        public static GlowingMeshStencilReference = 0x02;
+
+        /**
+         * Stencil value used for the other meshes in the scene.
+         */
+        public static NormalMeshStencilReference = 0x01;
+
+        /**
+         * Specifies whether or not the inner glow is ACTIVE in the layer.
+         */
+        public innerGlow: boolean = true;
+
+        /**
+         * Specifies whether or not the outer glow is ACTIVE in the layer.
+         */
+        public outerGlow: boolean = true;
+
+        /**
+         * Specifies the horizontal size of the blur.
+         */
+        public set blurHorizontalSize(value: number) {
+            this._horizontalBlurPostprocess.kernel = value;
+        }
+
+        /**
+         * Specifies the vertical size of the blur.
+         */
+        public set blurVerticalSize(value: number) {
+            this._verticalBlurPostprocess.kernel = value;
+        }
+
+        /**
+         * Gets the horizontal size of the blur.
+         */
+        public get blurHorizontalSize(): number {
+            return this._horizontalBlurPostprocess.kernel
+        }
+
+        /**
+         * Gets the vertical size of the blur.
+         */
+        public get blurVerticalSize(): number {
+            return this._verticalBlurPostprocess.kernel;
+        }
+
+        /**
+         * An event triggered when the highlight layer is being blurred.
+         */
+        public onBeforeBlurObservable = new Observable<HighlightLayer>();
+
+        /**
+         * An event triggered when the highlight layer has been blurred.
+         */
+        public onAfterBlurObservable = new Observable<HighlightLayer>();
+
+        private _instanceGlowingMeshStencilReference = HighlightLayer.GlowingMeshStencilReference++;
+
+        private _options: IHighlightLayerOptions;
+        private _downSamplePostprocess: PassPostProcess;
+        private _horizontalBlurPostprocess: GlowBlurPostProcess;
+        private _verticalBlurPostprocess: GlowBlurPostProcess;
+        private _blurTexture: RenderTargetTexture;
+
+        private _meshes: Nullable<{ [id: string]: Nullable<IHighlightLayerMesh> }> = {};
+        private _excludedMeshes: Nullable<{ [id: string]: Nullable<IHighlightLayerExcludedMesh> }> = {};
+
+        /**
+         * Instantiates a new highlight Layer and references it to the scene..
+         * @param name The name of the layer
+         * @param scene The scene to use the layer in
+         * @param options Sets of none mandatory options to use with the layer (see IHighlightLayerOptions for more information)
+         */
+        constructor(public name: string, scene: Scene, options?: Partial<IHighlightLayerOptions>) {
+            super(name, scene);
+            this.neutralColor = HighlightLayer.NeutralColor;
+
+            // Warn on stencil
+            if (!this._engine.isStencilEnable) {
+                Tools.Warn("Rendering the Highlight Layer requires the stencil to be active on the canvas. var engine = new BABYLON.Engine(canvas, antialias, { stencil: true }");
+            }
+
+            // Adapt options
+            this._options = {
+                mainTextureRatio: 0.5,
+                blurTextureSizeRatio: 0.5,
+                blurHorizontalSize: 1.0,
+                blurVerticalSize: 1.0,
+                alphaBlendingMode: Engine.ALPHA_COMBINE,
+                camera: null,
+                ...options,
+            };
+
+            // Initialize the layer
+            this._init({
+                alphaBlendingMode: this._options.alphaBlendingMode,
+                camera: this._options.camera,
+                mainTextureFixedSize: this._options.mainTextureFixedSize,
+                mainTextureRatio: this._options.mainTextureRatio
+            });
+        }
+
+        /**
+         * Get the effect name of the layer.
+         * @return The effect name
+         */ 
+        public getEffectName(): string {
+            return HighlightLayer.EffectName;
+        }
+
+        /**
+         * Create the merge effect. This is the shader use to blit the information back
+         * to the main canvas at the end of the scene rendering.
+         */
+        protected _createMergeEffect(): Effect {
+             // Effect
+             return this._engine.createEffect("glowMapMerge",
+                [VertexBuffer.PositionKind],
+                ["offset"],
+                ["textureSampler"],
+                this._options.isStroke ? "#define STROKE \n" : undefined);
+
+        }
+
+        /**
+         * Creates the render target textures and post processes used in the highlight layer.
+         */
+        protected _createTextureAndPostProcesses(): void {
+            var blurTextureWidth = this._mainTextureDesiredSize.width * this._options.blurTextureSizeRatio;
+            var blurTextureHeight = this._mainTextureDesiredSize.height * this._options.blurTextureSizeRatio;
+            blurTextureWidth = this._engine.needPOTTextures ? Tools.GetExponentOfTwo(blurTextureWidth, this._maxSize) : blurTextureWidth;
+            blurTextureHeight = this._engine.needPOTTextures ? Tools.GetExponentOfTwo(blurTextureHeight, this._maxSize) : blurTextureHeight;
+
+            this._blurTexture = new RenderTargetTexture("HighlightLayerBlurRTT",
+                {
+                    width: blurTextureWidth,
+                    height: blurTextureHeight
+                },
+                this._scene,
+                false,
+                true,
+                Engine.TEXTURETYPE_HALF_FLOAT);
+            this._blurTexture.wrapU = Texture.CLAMP_ADDRESSMODE;
+            this._blurTexture.wrapV = Texture.CLAMP_ADDRESSMODE;
+            this._blurTexture.anisotropicFilteringLevel = 16;
+            this._blurTexture.updateSamplingMode(Texture.TRILINEAR_SAMPLINGMODE);
+            this._blurTexture.renderParticles = false;
+            this._blurTexture.ignoreCameraViewport = true;
+
+            this._textures = [ this._blurTexture ];
+
+            if (this._options.alphaBlendingMode === Engine.ALPHA_COMBINE) {
+                this._downSamplePostprocess = new PassPostProcess("HighlightLayerPPP", this._options.blurTextureSizeRatio,
+                    null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine());
+                this._downSamplePostprocess.onApplyObservable.add(effect => {
+                    effect.setTexture("textureSampler", this._mainTexture);
+                });
+
+                this._horizontalBlurPostprocess = new GlowBlurPostProcess("HighlightLayerHBP", new Vector2(1.0, 0), this._options.blurHorizontalSize, 1,
+                    null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine());
+                this._horizontalBlurPostprocess.onApplyObservable.add(effect => {
+                    effect.setFloat2("screenSize", blurTextureWidth, blurTextureHeight);
+                });
+
+                this._verticalBlurPostprocess = new GlowBlurPostProcess("HighlightLayerVBP", new Vector2(0, 1.0), this._options.blurVerticalSize, 1,
+                    null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine());
+                this._verticalBlurPostprocess.onApplyObservable.add(effect => {
+                    effect.setFloat2("screenSize", blurTextureWidth, blurTextureHeight);
+                });
+
+                this._postProcesses = [this._downSamplePostprocess, this._horizontalBlurPostprocess, this._verticalBlurPostprocess];
+            }
+            else {
+                this._horizontalBlurPostprocess = new BlurPostProcess("HighlightLayerHBP", new Vector2(1.0, 0), this._options.blurHorizontalSize / 2, {
+                        width:  blurTextureWidth,
+                        height: blurTextureHeight
+                    },
+                    null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, Engine.TEXTURETYPE_HALF_FLOAT);
+                this._horizontalBlurPostprocess.width = blurTextureWidth;
+                this._horizontalBlurPostprocess.height = blurTextureHeight;
+                this._horizontalBlurPostprocess.onApplyObservable.add(effect => {
+                    effect.setTexture("textureSampler", this._mainTexture);
+                });
+
+                this._verticalBlurPostprocess = new BlurPostProcess("HighlightLayerVBP", new Vector2(0, 1.0), this._options.blurVerticalSize / 2, {
+                        width:  blurTextureWidth,
+                        height: blurTextureHeight
+                    },
+                    null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, Engine.TEXTURETYPE_HALF_FLOAT);
+
+                this._postProcesses = [this._horizontalBlurPostprocess, this._verticalBlurPostprocess];
+            }
+
+            this._mainTexture.onAfterUnbindObservable.add(() => {
+                this.onBeforeBlurObservable.notifyObservers(this);
+
+                let internalTexture = this._blurTexture.getInternalTexture();
+                if (internalTexture) {
+                    this._scene.postProcessManager.directRender(
+                        this._postProcesses,
+                        internalTexture, 
+                        true);
+                }
+
+                this.onAfterBlurObservable.notifyObservers(this);
+            });
+
+            // Prevent autoClear.
+            this._postProcesses.map(pp => { pp.autoClear = false; });
+        }
+
+        /**
+         * Returns wether or nood the layer needs stencil enabled during the mesh rendering.
+         */
+        public needStencil(): boolean {
+            return true;
+        }
+
+        /**
+         * Checks for the readiness of the element composing the layer.
+         * @param subMesh the mesh to check for
+         * @param useInstances specify wether or not to use instances to render the mesh
+         * @param emissiveTexture the associated emissive texture used to generate the glow
+         * @return true if ready otherwise, false
+         */
+        public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
+            let material = subMesh.getMaterial();
+            let mesh = subMesh.getRenderingMesh();
+
+            if (!material || !mesh || !this._meshes) {
+                return false;
+            }
+
+            let emissiveTexture: Nullable<Texture> = null;
+            let highlightLayerMesh = this._meshes[mesh.uniqueId];
+
+            if (highlightLayerMesh && highlightLayerMesh.glowEmissiveOnly && material) {
+                emissiveTexture = (<any>material).emissiveTexture;
+            }
+            return super._isReady(subMesh, useInstances, emissiveTexture);
+        }
+
+        /**
+         * Implementation specific of rendering the generating effect on the main canvas.
+         * @param effect The effect used to render through
+         */
+        protected _internalRender(effect: Effect): void {
+            // Texture
+            effect.setTexture("textureSampler", this._blurTexture);
+
+            // Cache
+            var engine = this._engine;
+            var previousStencilBuffer = engine.getStencilBuffer();
+            var previousStencilFunction = engine.getStencilFunction();
+            var previousStencilMask = engine.getStencilMask();
+            var previousStencilOperationPass = engine.getStencilOperationPass();
+            var previousStencilOperationFail = engine.getStencilOperationFail();
+            var previousStencilOperationDepthFail = engine.getStencilOperationDepthFail();
+
+            // Stencil operations
+            engine.setStencilOperationPass(Engine.REPLACE);
+            engine.setStencilOperationFail(Engine.KEEP);
+            engine.setStencilOperationDepthFail(Engine.KEEP);
+
+            // Draw order
+            engine.setStencilMask(0x00);
+            engine.setStencilBuffer(true);
+            engine.setStencilFunctionReference(this._instanceGlowingMeshStencilReference);
+
+            // 2 passes inner outer
+            if (this.outerGlow) {
+                effect.setFloat("offset", 0);
+                engine.setStencilFunction(Engine.NOTEQUAL);
+                engine.drawElementsType(Material.TriangleFillMode, 0, 6);
+            }
+            if (this.innerGlow) {
+                effect.setFloat("offset", 1);
+                engine.setStencilFunction(Engine.EQUAL);
+                engine.drawElementsType(Material.TriangleFillMode, 0, 6);
+            }
+
+            // Restore Cache
+            engine.setStencilFunction(previousStencilFunction);
+            engine.setStencilMask(previousStencilMask);
+            engine.setStencilBuffer(previousStencilBuffer);
+            engine.setStencilOperationPass(previousStencilOperationPass);
+            engine.setStencilOperationFail(previousStencilOperationFail);
+            engine.setStencilOperationDepthFail(previousStencilOperationDepthFail);
+        }
+
+        /**
+         * Returns true if the layer contains information to display, otherwise false.
+         */
+        public shouldRender(): boolean {
+            if (super.shouldRender()) {
+                return this._meshes ? true : false;
+            }
+
+            return false;
+        }
+
+        /**
+         * Returns true if the mesh should render, otherwise false.
+         * @param mesh The mesh to render
+         * @returns true if it should render otherwise false
+         */
+        protected _shouldRenderMesh(mesh: Mesh): boolean {
+            // Excluded Mesh
+            if (this._excludedMeshes && this._excludedMeshes[mesh.uniqueId]) {
+                return false;
+            };
+
+            return true;
+        }
+
+        /**
+         * Sets the required values for both the emissive texture and and the main color.
+         */
+        protected _setEmissiveTextureAndColor(mesh: Mesh, subMesh: SubMesh, material: Material): void {
+            var highlightLayerMesh = this._meshes![mesh.uniqueId];
+            if (highlightLayerMesh) {
+                this._emissiveTextureAndColor.color.set(
+                    highlightLayerMesh.color.r,
+                    highlightLayerMesh.color.g,
+                    highlightLayerMesh.color.b,
+                    1.0);
+            }
+            else {
+                this._emissiveTextureAndColor.color.set(
+                    this.neutralColor.r,
+                    this.neutralColor.g,
+                    this.neutralColor.b,
+                    this.neutralColor.a);
+            }
+
+            if (highlightLayerMesh && highlightLayerMesh.glowEmissiveOnly && material) {
+                this._emissiveTextureAndColor.texture = (<any>material).emissiveTexture;
+                this._emissiveTextureAndColor.color.set(
+                    1.0,
+                    1.0,
+                    1.0,
+                    1.0);
+            }
+            else {
+                this._emissiveTextureAndColor.texture = null;
+            }
+
+        }
+
+        /**
+         * Add a mesh in the exclusion list to prevent it to impact or being impacted by the highlight layer.
+         * @param mesh The mesh to exclude from the highlight layer
+         */
+        public addExcludedMesh(mesh: Mesh) {
+            if (!this._excludedMeshes) {
+                return;
+            }
+
+            var meshExcluded = this._excludedMeshes[mesh.uniqueId];
+            if (!meshExcluded) {
+                this._excludedMeshes[mesh.uniqueId] = {
+                    mesh: mesh,
+                    beforeRender: mesh.onBeforeRenderObservable.add((mesh: Mesh) => {
+                        mesh.getEngine().setStencilBuffer(false);
+                    }),
+                    afterRender: mesh.onAfterRenderObservable.add((mesh: Mesh) => {
+                        mesh.getEngine().setStencilBuffer(true);
+                    }),
+                }
+            }
+        }
+
+        /**
+          * Remove a mesh from the exclusion list to let it impact or being impacted by the highlight layer.
+          * @param mesh The mesh to highlight
+          */
+        public removeExcludedMesh(mesh: Mesh) {
+            if (!this._excludedMeshes) {
+                return;
+            }
+
+            var meshExcluded = this._excludedMeshes[mesh.uniqueId];
+            if (meshExcluded) {
+                if (meshExcluded.beforeRender) {
+                    mesh.onBeforeRenderObservable.remove(meshExcluded.beforeRender);
+                }
+
+                if (meshExcluded.afterRender) {
+                    mesh.onAfterRenderObservable.remove(meshExcluded.afterRender);
+                }
+            }
+
+            this._excludedMeshes[mesh.uniqueId] = null;
+        }
+
+        /**
+         * Determine if a given mesh will be highlighted by the current HighlightLayer
+         * @param mesh mesh to test
+         * @returns true if the mesh will be highlighted by the current HighlightLayer
+         */
+        public hasMesh(mesh: AbstractMesh): boolean {
+            if (!this._meshes) {
+                return false;
+            }
+
+            return this._meshes[mesh.uniqueId] !== undefined && this._meshes[mesh.uniqueId] !== null;
+        }
+
+        /**
+         * Add a mesh in the highlight layer in order to make it glow with the chosen color.
+         * @param mesh The mesh to highlight
+         * @param color The color of the highlight
+         * @param glowEmissiveOnly Extract the glow from the emissive texture
+         */
+        public addMesh(mesh: Mesh, color: Color3, glowEmissiveOnly = false) {
+            if (!this._meshes) {
+                return;
+            }
+
+            var meshHighlight = this._meshes[mesh.uniqueId];
+            if (meshHighlight) {
+                meshHighlight.color = color;
+            }
+            else {
+                this._meshes[mesh.uniqueId] = {
+                    mesh: mesh,
+                    color: color,
+                    // Lambda required for capture due to Observable this context
+                    observerHighlight: mesh.onBeforeRenderObservable.add((mesh: Mesh) => {
+                        if (this._excludedMeshes && this._excludedMeshes[mesh.uniqueId]) {
+                            this._defaultStencilReference(mesh);
+                        }
+                        else {
+                            mesh.getScene().getEngine().setStencilFunctionReference(this._instanceGlowingMeshStencilReference);
+                        }
+                    }),
+                    observerDefault: mesh.onAfterRenderObservable.add(this._defaultStencilReference),
+                    glowEmissiveOnly: glowEmissiveOnly
+                };
+            }
+
+            this._shouldRender = true;
+        }
+
+        /**
+         * Remove a mesh from the highlight layer in order to make it stop glowing.
+         * @param mesh The mesh to highlight
+         */
+        public removeMesh(mesh: Mesh) {
+            if (!this._meshes) {
+                return;
+            }
+
+            var meshHighlight = this._meshes[mesh.uniqueId];
+            if (meshHighlight) {
+
+                if (meshHighlight.observerHighlight) {
+                    mesh.onBeforeRenderObservable.remove(meshHighlight.observerHighlight);
+                }
+
+                if (meshHighlight.observerDefault) {
+                    mesh.onAfterRenderObservable.remove(meshHighlight.observerDefault);
+                }
+                delete this._meshes[mesh.uniqueId];
+            }
+
+            this._shouldRender = false;
+            for (var meshHighlightToCheck in this._meshes) {
+                if (this._meshes[meshHighlightToCheck]) {
+                    this._shouldRender = true;
+                    break;
+                }
+            }
+        }
+
+        /**
+         * Force the stencil to the normal expected value for none glowing parts
+         */
+        private _defaultStencilReference(mesh: Mesh) {
+            mesh.getScene().getEngine().setStencilFunctionReference(HighlightLayer.NormalMeshStencilReference);
+        }
+
+        /**
+         * Free any resources and references associated to a mesh.
+         * Internal use
+         * @param mesh The mesh to free.
+         */
+        public _disposeMesh(mesh: Mesh): void {
+            this.removeMesh(mesh);
+            this.removeExcludedMesh(mesh);
+        }
+
+        /**
+         * Dispose the highlight layer and free resources.
+         */
+        public dispose(): void {
+            if (this._meshes) {
+                // Clean mesh references 
+                for (let id in this._meshes) {
+                    let meshHighlight = this._meshes[id];
+                    if (meshHighlight && meshHighlight.mesh) {
+
+                        if (meshHighlight.observerHighlight) {
+                            meshHighlight.mesh.onBeforeRenderObservable.remove(meshHighlight.observerHighlight);
+                        }
+
+                        if (meshHighlight.observerDefault) {
+                            meshHighlight.mesh.onAfterRenderObservable.remove(meshHighlight.observerDefault);
+                        }
+                    }
+                }
+                this._meshes = null;
+            }
+
+            if (this._excludedMeshes) {
+                for (let id in this._excludedMeshes) {
+                    let meshHighlight = this._excludedMeshes[id];
+                    if (meshHighlight) {
+
+                        if (meshHighlight.beforeRender) {
+                            meshHighlight.mesh.onBeforeRenderObservable.remove(meshHighlight.beforeRender);
+                        }
+
+                        if (meshHighlight.afterRender) {
+                            meshHighlight.mesh.onAfterRenderObservable.remove(meshHighlight.afterRender);
+                        }
+                    }
+                }
+                this._excludedMeshes = null;
+            }
+
+            super.dispose();
+        }
+    }
+} 

+ 0 - 996
src/Layer/babylon.highlightlayer.ts

@@ -1,996 +0,0 @@
-module BABYLON {
-    /**
-     * Special Glow Blur post process only blurring the alpha channel
-     * It enforces keeping the most luminous color in the color channel.
-     */
-    class GlowBlurPostProcess extends PostProcess {
-        constructor(name: string, public direction: Vector2, public kernel: number, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode: number = Texture.BILINEAR_SAMPLINGMODE, engine?: Engine, reusable?: boolean) {
-            super(name, "glowBlurPostProcess", ["screenSize", "direction", "blurWidth"], null, options, camera, samplingMode, engine, reusable);
-            
-            this.onApplyObservable.add((effect: Effect) => {
-                effect.setFloat2("screenSize", this.width, this.height);
-                effect.setVector2("direction", this.direction);
-                effect.setFloat("blurWidth", this.kernel);
-            });
-        }
-    }
-
-    /**
-     * Highlight layer options. This helps customizing the behaviour
-     * of the highlight layer.
-     */
-    export interface IHighlightLayerOptions {
-        /**
-         * Multiplication factor apply to the canvas size to compute the render target size
-         * used to generated the glowing objects (the smaller the faster).
-         */
-        mainTextureRatio: number;
-
-        /**
-         * Enforces a fixed size texture to ensure resize independant blur.
-         */
-        mainTextureFixedSize?: number;
-
-        /**
-         * Multiplication factor apply to the main texture size in the first step of the blur to reduce the size 
-         * of the picture to blur (the smaller the faster).
-         */
-        blurTextureSizeRatio: number;
-
-        /**
-         * How big in texel of the blur texture is the vertical blur.
-         */
-        blurVerticalSize: number;
-
-        /**
-         * How big in texel of the blur texture is the horizontal blur.
-         */
-        blurHorizontalSize: number;
-
-        /**
-         * Alpha blending mode used to apply the blur. Default is combine.
-         */
-        alphaBlendingMode: number
-
-        /**
-         * The camera attached to the layer.
-         */
-        camera: Nullable<Camera>;
-
-        /**
-         * Should we display highlight as a solid stroke?
-         */
-        isStroke?: boolean;
-    }
-
-    /**
-     * Storage interface grouping all the information required for glowing a mesh.
-     */
-    interface IHighlightLayerMesh {
-        /** 
-         * The glowy mesh
-         */
-        mesh: Mesh;
-        /**
-         * The color of the glow
-         */
-        color: Color3;
-        /**
-         * The mesh render callback use to insert stencil information
-         */
-        observerHighlight: Nullable<Observer<Mesh>>;
-        /**
-         * The mesh render callback use to come to the default behavior
-         */
-        observerDefault: Nullable<Observer<Mesh>>;
-        /**
-         * If it exists, the emissive color of the material will be used to generate the glow.
-         * Else it falls back to the current color.
-         */
-        glowEmissiveOnly: boolean;
-    }
-
-    /**
-     * Storage interface grouping all the information required for an excluded mesh.
-     */
-    interface IHighlightLayerExcludedMesh {
-        /** 
-         * The glowy mesh
-         */
-        mesh: Mesh;
-        /**
-         * The mesh render callback use to prevent stencil use
-         */
-        beforeRender: Nullable<Observer<Mesh>>;
-        /**
-         * The mesh render callback use to restore previous stencil use
-         */
-        afterRender: Nullable<Observer<Mesh>>;
-    }
-
-    /**
-     * The highlight layer Helps adding a glow effect around a mesh.
-     * 
-     * Once instantiated in a scene, simply use the pushMesh or removeMesh method to add or remove
-     * glowy meshes to your scene.
-     * 
-     * !!! THIS REQUIRES AN ACTIVE STENCIL BUFFER ON THE CANVAS !!!
-     */
-    export class HighlightLayer {
-        /**
-         * The neutral color used during the preparation of the glow effect.
-         * This is black by default as the blend operation is a blend operation. 
-         */
-        public static neutralColor: Color4 = new Color4(0, 0, 0, 0);
-
-        /**
-         * Stencil value used for glowing meshes.
-         */
-        public static glowingMeshStencilReference = 0x02;
-
-        /**
-         * Stencil value used for the other meshes in the scene.
-         */
-        public static normalMeshStencilReference = 0x01;
-
-        private _scene: Scene;
-        private _engine: Engine;
-        private _options: IHighlightLayerOptions;
-        private _vertexBuffers: { [key: string]: Nullable<VertexBuffer> } = {};
-        private _indexBuffer: Nullable<WebGLBuffer>;
-        private _downSamplePostprocess: PassPostProcess;
-        private _horizontalBlurPostprocess: GlowBlurPostProcess;
-        private _verticalBlurPostprocess: GlowBlurPostProcess;
-        private _cachedDefines: string;
-        private _glowMapGenerationEffect: Effect;
-        private _glowMapMergeEffect: Effect;
-        private _blurTexture: RenderTargetTexture;
-        private _mainTexture: RenderTargetTexture;
-        private _mainTextureDesiredSize: ISize = { width: 0, height: 0 };
-        private _meshes: Nullable<{ [id: string]: Nullable<IHighlightLayerMesh> }> = {};
-        private _maxSize: number = 0;
-        private _shouldRender = false;
-        private _instanceGlowingMeshStencilReference = HighlightLayer.glowingMeshStencilReference++;
-        private _excludedMeshes: Nullable<{ [id: string]: Nullable<IHighlightLayerExcludedMesh> }> = {};
-
-        /**
-         * Specifies whether or not the inner glow is ACTIVE in the layer.
-         */
-        public innerGlow: boolean = true;
-
-        /**
-         * Specifies whether or not the outer glow is ACTIVE in the layer.
-         */
-        public outerGlow: boolean = true;
-
-        /**
-         * Specifies wether the highlight layer is enabled or not.
-         */
-        public isEnabled: boolean = true;
-
-        /**
-         * Specifies the horizontal size of the blur.
-         */
-        public set blurHorizontalSize(value: number) {
-            this._horizontalBlurPostprocess.kernel = value;
-        }
-
-        /**
-         * Specifies the vertical size of the blur.
-         */
-        public set blurVerticalSize(value: number) {
-            this._verticalBlurPostprocess.kernel = value;
-        }
-
-        /**
-         * Gets the horizontal size of the blur.
-         */
-        public get blurHorizontalSize(): number {
-            return this._horizontalBlurPostprocess.kernel
-        }
-
-        /**
-         * Gets the vertical size of the blur.
-         */
-        public get blurVerticalSize(): number {
-            return this._verticalBlurPostprocess.kernel;
-        }
-
-        /**
-         * Gets the camera attached to the layer.
-         */
-        public get camera(): Nullable<Camera> {
-            return this._options.camera;
-        }
-
-        /**
-         * An event triggered when the highlight layer has been disposed.
-         * @type {BABYLON.Observable}
-         */
-        public onDisposeObservable = new Observable<HighlightLayer>();
-
-        /**
-         * An event triggered when the highlight layer is about rendering the main texture with the glowy parts.
-         * @type {BABYLON.Observable}
-         */
-        public onBeforeRenderMainTextureObservable = new Observable<HighlightLayer>();
-
-        /**
-         * An event triggered when the highlight layer is being blurred.
-         * @type {BABYLON.Observable}
-         */
-        public onBeforeBlurObservable = new Observable<HighlightLayer>();
-
-        /**
-         * An event triggered when the highlight layer has been blurred.
-         * @type {BABYLON.Observable}
-         */
-        public onAfterBlurObservable = new Observable<HighlightLayer>();
-
-        /**
-         * An event triggered when the glowing blurred texture is being merged in the scene.
-         * @type {BABYLON.Observable}
-         */
-        public onBeforeComposeObservable = new Observable<HighlightLayer>();
-
-        /**
-         * An event triggered when the glowing blurred texture has been merged in the scene.
-         * @type {BABYLON.Observable}
-         */
-        public onAfterComposeObservable = new Observable<HighlightLayer>();
-
-        /**
-         * An event triggered when the highlight layer changes its size.
-         * @type {BABYLON.Observable}
-         */
-        public onSizeChangedObservable = new Observable<HighlightLayer>();
-
-        /**
-         * Instantiates a new highlight Layer and references it to the scene..
-         * @param name The name of the layer
-         * @param scene The scene to use the layer in
-         * @param options Sets of none mandatory options to use with the layer (see IHighlightLayerOptions for more information)
-         */
-        constructor(public name: string, scene: Scene, options?: IHighlightLayerOptions) {
-            this._scene = scene || Engine.LastCreatedScene;
-            var engine = scene.getEngine();
-            this._engine = engine;
-            this._maxSize = this._engine.getCaps().maxTextureSize;
-            this._scene.highlightLayers.push(this);
-
-            // Warn on stencil.
-            if (!this._engine.isStencilEnable) {
-                Tools.Warn("Rendering the Highlight Layer requires the stencil to be active on the canvas. var engine = new BABYLON.Engine(canvas, antialias, { stencil: true }");
-            }
-
-            // Adapt options
-            this._options = options || {
-                mainTextureRatio: 0.5,
-                blurTextureSizeRatio: 0.5,
-                blurHorizontalSize: 1.0,
-                blurVerticalSize: 1.0,
-                alphaBlendingMode: Engine.ALPHA_COMBINE,
-                camera: null
-            };
-            this._options.mainTextureRatio = this._options.mainTextureRatio || 0.5;
-            this._options.blurTextureSizeRatio = this._options.blurTextureSizeRatio || 1.0;
-            this._options.blurHorizontalSize = this._options.blurHorizontalSize || 1;
-            this._options.blurVerticalSize = this._options.blurVerticalSize || 1;
-            this._options.alphaBlendingMode = this._options.alphaBlendingMode || Engine.ALPHA_COMBINE;
-
-            // VBO
-            var vertices = [];
-            vertices.push(1, 1);
-            vertices.push(-1, 1);
-            vertices.push(-1, -1);
-            vertices.push(1, -1);
-
-            var vertexBuffer = new VertexBuffer(engine, vertices, VertexBuffer.PositionKind, false, false, 2);
-            this._vertexBuffers[VertexBuffer.PositionKind] = vertexBuffer;
-
-            this._createIndexBuffer();
-
-            // Effect
-            this._glowMapMergeEffect = engine.createEffect("glowMapMerge",
-                [VertexBuffer.PositionKind],
-                ["offset"],
-                ["textureSampler"],
-                this._options.isStroke ? "#define STROKE \n" : undefined);
-
-            // Render target
-            this.setMainTextureSize();
-
-            // Create Textures and post processes
-            this.createTextureAndPostProcesses();
-        }
-
-        private _createIndexBuffer(): void {
-            var engine = this._scene.getEngine();
-
-            // Indices
-            var indices = [];
-            indices.push(0);
-            indices.push(1);
-            indices.push(2);
-
-            indices.push(0);
-            indices.push(2);
-            indices.push(3);
-
-            this._indexBuffer = engine.createIndexBuffer(indices);
-        }
-
-        public _rebuild(): void {
-            let vb = this._vertexBuffers[VertexBuffer.PositionKind];
-
-            if (vb) {
-                vb._rebuild();
-            }
-
-            this._createIndexBuffer();
-        }
-
-        /**
-         * Creates the render target textures and post processes used in the highlight layer.
-         */
-        private createTextureAndPostProcesses(): void {
-            var blurTextureWidth = this._mainTextureDesiredSize.width * this._options.blurTextureSizeRatio;
-            var blurTextureHeight = this._mainTextureDesiredSize.height * this._options.blurTextureSizeRatio;
-            blurTextureWidth = this._engine.needPOTTextures ? Tools.GetExponentOfTwo(blurTextureWidth, this._maxSize) : blurTextureWidth;
-            blurTextureHeight = this._engine.needPOTTextures ? Tools.GetExponentOfTwo(blurTextureHeight, this._maxSize) : blurTextureHeight;
-
-            this._mainTexture = new RenderTargetTexture("HighlightLayerMainRTT",
-                {
-                    width: this._mainTextureDesiredSize.width,
-                    height: this._mainTextureDesiredSize.height
-                },
-                this._scene,
-                false,
-                true,
-                Engine.TEXTURETYPE_UNSIGNED_INT);
-            this._mainTexture.activeCamera = this._options.camera;
-            this._mainTexture.wrapU = Texture.CLAMP_ADDRESSMODE;
-            this._mainTexture.wrapV = Texture.CLAMP_ADDRESSMODE;
-            this._mainTexture.anisotropicFilteringLevel = 1;
-            this._mainTexture.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
-            this._mainTexture.renderParticles = false;
-            this._mainTexture.renderList = null;
-            this._mainTexture.ignoreCameraViewport = true;
-
-            this._blurTexture = new RenderTargetTexture("HighlightLayerBlurRTT",
-                {
-                    width: blurTextureWidth,
-                    height: blurTextureHeight
-                },
-                this._scene,
-                false,
-                true,
-                Engine.TEXTURETYPE_UNSIGNED_INT);
-            this._blurTexture.wrapU = Texture.CLAMP_ADDRESSMODE;
-            this._blurTexture.wrapV = Texture.CLAMP_ADDRESSMODE;
-            this._blurTexture.anisotropicFilteringLevel = 16;
-            this._blurTexture.updateSamplingMode(Texture.TRILINEAR_SAMPLINGMODE);
-            this._blurTexture.renderParticles = false;
-            this._blurTexture.ignoreCameraViewport = true;
-
-            this._downSamplePostprocess = new PassPostProcess("HighlightLayerPPP", this._options.blurTextureSizeRatio,
-                null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine());
-            this._downSamplePostprocess.onApplyObservable.add(effect => {
-                effect.setTexture("textureSampler", this._mainTexture);
-            });
-
-            if (this._options.alphaBlendingMode === Engine.ALPHA_COMBINE) {
-                this._horizontalBlurPostprocess = new GlowBlurPostProcess("HighlightLayerHBP", new Vector2(1.0, 0), this._options.blurHorizontalSize, 1,
-                    null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine());
-                this._horizontalBlurPostprocess.onApplyObservable.add(effect => {
-                    effect.setFloat2("screenSize", blurTextureWidth, blurTextureHeight);
-                });
-
-                this._verticalBlurPostprocess = new GlowBlurPostProcess("HighlightLayerVBP", new Vector2(0, 1.0), this._options.blurVerticalSize, 1,
-                    null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine());
-                this._verticalBlurPostprocess.onApplyObservable.add(effect => {
-                    effect.setFloat2("screenSize", blurTextureWidth, blurTextureHeight);
-                });
-            }
-            else {
-                this._horizontalBlurPostprocess = new BlurPostProcess("HighlightLayerHBP", new Vector2(1.0, 0), this._options.blurHorizontalSize, 1,
-                    null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine());
-                this._horizontalBlurPostprocess.onApplyObservable.add(effect => {
-                    effect.setFloat2("screenSize", blurTextureWidth, blurTextureHeight);
-                });
-
-                this._verticalBlurPostprocess = new BlurPostProcess("HighlightLayerVBP", new Vector2(0, 1.0), this._options.blurVerticalSize, 1,
-                    null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine());
-                this._verticalBlurPostprocess.onApplyObservable.add(effect => {
-                    effect.setFloat2("screenSize", blurTextureWidth, blurTextureHeight);
-                });
-            }
-
-            this._mainTexture.onAfterUnbindObservable.add(() => {
-                this.onBeforeBlurObservable.notifyObservers(this);
-
-                let internalTexture = this._blurTexture.getInternalTexture();
-
-                if (internalTexture) {
-                    this._scene.postProcessManager.directRender(
-                        [this._downSamplePostprocess, this._horizontalBlurPostprocess, this._verticalBlurPostprocess],
-                        internalTexture, true);
-                }
-
-                this.onAfterBlurObservable.notifyObservers(this);
-            });
-
-            // Custom render function
-            var renderSubMesh = (subMesh: SubMesh): void => {
-                if (!this._meshes) {
-                    return;
-                }
-
-                var material = subMesh.getMaterial();
-                var mesh = subMesh.getRenderingMesh();
-                var scene = this._scene;
-                var engine = scene.getEngine();
-
-                if (!material) {
-                    return;
-                }
-
-                // Do not block in blend mode.
-                if (material.needAlphaBlendingForMesh(mesh)) {
-                    return;
-                }
-
-                // Culling
-                engine.setState(material.backFaceCulling);
-
-                // Managing instances
-                var batch = mesh._getInstancesRenderList(subMesh._id);
-                if (batch.mustReturn) {
-                    return;
-                }
-
-                // Excluded Mesh
-                if (this._excludedMeshes && this._excludedMeshes[mesh.uniqueId]) {
-                    return;
-                };
-
-                var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined);
-
-                var highlightLayerMesh = this._meshes[mesh.uniqueId];
-                var emissiveTexture: Nullable<Texture> = null;
-                if (highlightLayerMesh && highlightLayerMesh.glowEmissiveOnly && material) {
-                    emissiveTexture = (<any>material).emissiveTexture;
-                }
-
-                if (this._isReady(subMesh, hardwareInstancedRendering, emissiveTexture)) {
-                    engine.enableEffect(this._glowMapGenerationEffect);
-                    mesh._bind(subMesh, this._glowMapGenerationEffect, Material.TriangleFillMode);
-
-                    this._glowMapGenerationEffect.setMatrix("viewProjection", scene.getTransformMatrix());
-                    if (highlightLayerMesh) {
-                        this._glowMapGenerationEffect.setFloat4("color",
-                            highlightLayerMesh.color.r,
-                            highlightLayerMesh.color.g,
-                            highlightLayerMesh.color.b,
-                            1.0);
-                    }
-                    else {
-                        this._glowMapGenerationEffect.setFloat4("color",
-                            HighlightLayer.neutralColor.r,
-                            HighlightLayer.neutralColor.g,
-                            HighlightLayer.neutralColor.b,
-                            HighlightLayer.neutralColor.a);
-                    }
-
-                    // Alpha test
-                    if (material && material.needAlphaTesting()) {
-                        var alphaTexture = material.getAlphaTestTexture();
-                        if (alphaTexture) {
-                            this._glowMapGenerationEffect.setTexture("diffuseSampler", alphaTexture);
-                            let textureMatrix = alphaTexture.getTextureMatrix();
-
-                            if (textureMatrix) {
-                                this._glowMapGenerationEffect.setMatrix("diffuseMatrix", textureMatrix);
-                            }
-                        }
-                    }
-
-                    // Glow emissive only
-                    if (emissiveTexture) {
-                        this._glowMapGenerationEffect.setTexture("emissiveSampler", emissiveTexture);
-                        this._glowMapGenerationEffect.setMatrix("emissiveMatrix", emissiveTexture.getTextureMatrix());
-                    }
-
-                    // Bones
-                    if (mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) {
-                        this._glowMapGenerationEffect.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
-                    }
-
-                    // Draw
-                    mesh._processRendering(subMesh, this._glowMapGenerationEffect, Material.TriangleFillMode, batch, hardwareInstancedRendering,
-                        (isInstance, world) => this._glowMapGenerationEffect.setMatrix("world", world));
-                } else {
-                    // Need to reset refresh rate of the shadowMap
-                    this._mainTexture.resetRefreshCounter();
-                }
-            };
-
-            this._mainTexture.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>): void => {
-                this.onBeforeRenderMainTextureObservable.notifyObservers(this);
-
-                var index: number;
-
-                let engine = this._scene.getEngine();
-
-                if (depthOnlySubMeshes.length) {
-                    engine.setColorWrite(false);
-                    for (index = 0; index < depthOnlySubMeshes.length; index++) {
-                        renderSubMesh(depthOnlySubMeshes.data[index]);
-                    }
-                    engine.setColorWrite(true);
-                }
-
-                for (index = 0; index < opaqueSubMeshes.length; index++) {
-                    renderSubMesh(opaqueSubMeshes.data[index]);
-                }
-
-                for (index = 0; index < alphaTestSubMeshes.length; index++) {
-                    renderSubMesh(alphaTestSubMeshes.data[index]);
-                }
-
-                for (index = 0; index < transparentSubMeshes.length; index++) {
-                    renderSubMesh(transparentSubMeshes.data[index]);
-                }
-            };
-
-            this._mainTexture.onClearObservable.add((engine: Engine) => {
-                engine.clear(HighlightLayer.neutralColor, true, true, true);
-            });
-        }
-
-        /**
-         * Checks for the readiness of the element composing the layer.
-         * @param subMesh the mesh to check for
-         * @param useInstances specify wether or not to use instances to render the mesh
-         * @param emissiveTexture the associated emissive texture used to generate the glow
-         * @return true if ready otherwise, false
-         */
-        public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
-            let material = subMesh.getMaterial();
-            let mesh = subMesh.getRenderingMesh();
-
-            if (!material || !mesh || !this._meshes) {
-                return false;
-            }
-
-            let emissiveTexture: Nullable<Texture> = null;
-            let highlightLayerMesh = this._meshes[mesh.uniqueId];
-
-            if (highlightLayerMesh && highlightLayerMesh.glowEmissiveOnly && material) {
-                emissiveTexture = (<any>material).emissiveTexture;
-            }
-            return this._isReady(subMesh, useInstances, emissiveTexture);
-        }
-
-        /**
-         * Checks for the readiness of the element composing the layer.
-         * @param subMesh the mesh to check for
-         * @param useInstances specify wether or not to use instances to render the mesh
-         * @param emissiveTexture the associated emissive texture used to generate the glow
-         * @return true if ready otherwise, false
-         */
-        private _isReady(subMesh: SubMesh, useInstances: boolean, emissiveTexture: Nullable<Texture>): boolean {
-            let material = subMesh.getMaterial();
-
-            if (!material) {
-                return false;
-            }
-
-            if (!material.isReady(subMesh.getMesh(), useInstances)) {
-                return false;
-            }
-
-            var defines = [];
-
-            var attribs = [VertexBuffer.PositionKind];
-
-            var mesh = subMesh.getMesh();
-            var uv1 = false;
-            var uv2 = false;
-
-            // Alpha test
-            if (material && material.needAlphaTesting()) {
-                var alphaTexture = material.getAlphaTestTexture();
-                if (alphaTexture) {
-                    defines.push("#define ALPHATEST");
-                    if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind) &&
-                        alphaTexture.coordinatesIndex === 1) {
-                        defines.push("#define DIFFUSEUV2");
-                        uv2 = true;
-                    }
-                    else if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
-                        defines.push("#define DIFFUSEUV1");
-                        uv1 = true;
-                    }
-                }
-            }
-
-            // Emissive
-            if (emissiveTexture) {
-                defines.push("#define EMISSIVE");
-                if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind) &&
-                    emissiveTexture.coordinatesIndex === 1) {
-                    defines.push("#define EMISSIVEUV2");
-                    uv2 = true;
-                }
-                else if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
-                    defines.push("#define EMISSIVEUV1");
-                    uv1 = true;
-                }
-            }
-
-            if (uv1) {
-                attribs.push(VertexBuffer.UVKind);
-                defines.push("#define UV1");
-            }
-            if (uv2) {
-                attribs.push(VertexBuffer.UV2Kind);
-                defines.push("#define UV2");
-            }
-
-            // Bones
-            if (mesh.useBones && mesh.computeBonesUsingShaders) {
-                attribs.push(VertexBuffer.MatricesIndicesKind);
-                attribs.push(VertexBuffer.MatricesWeightsKind);
-                if (mesh.numBoneInfluencers > 4) {
-                    attribs.push(VertexBuffer.MatricesIndicesExtraKind);
-                    attribs.push(VertexBuffer.MatricesWeightsExtraKind);
-                }
-                defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
-                defines.push("#define BonesPerMesh " + (mesh.skeleton ? (mesh.skeleton.bones.length + 1) : 0));
-            } else {
-                defines.push("#define NUM_BONE_INFLUENCERS 0");
-            }
-
-            // Instances
-            if (useInstances) {
-                defines.push("#define INSTANCES");
-                attribs.push("world0");
-                attribs.push("world1");
-                attribs.push("world2");
-                attribs.push("world3");
-            }
-
-            // Get correct effect      
-            var join = defines.join("\n");
-            if (this._cachedDefines !== join) {
-                this._cachedDefines = join;
-                this._glowMapGenerationEffect = this._scene.getEngine().createEffect("glowMapGeneration",
-                    attribs,
-                    ["world", "mBones", "viewProjection", "diffuseMatrix", "color", "emissiveMatrix"],
-                    ["diffuseSampler", "emissiveSampler"], join);
-            }
-
-            return this._glowMapGenerationEffect.isReady();
-        }
-
-        /**
-         * Renders the glowing part of the scene by blending the blurred glowing meshes on top of the rendered scene.
-         */
-        public render(): void {
-            var currentEffect = this._glowMapMergeEffect;
-
-            // Check
-            if (!currentEffect.isReady() || !this._blurTexture.isReady())
-                return;
-
-            var engine = this._scene.getEngine();
-
-            this.onBeforeComposeObservable.notifyObservers(this);
-
-            // Render
-            engine.enableEffect(currentEffect);
-            engine.setState(false);
-
-            // Cache
-            var previousStencilBuffer = engine.getStencilBuffer();
-            var previousStencilFunction = engine.getStencilFunction();
-            var previousStencilMask = engine.getStencilMask();
-            var previousStencilOperationPass = engine.getStencilOperationPass();
-            var previousStencilOperationFail = engine.getStencilOperationFail();
-            var previousStencilOperationDepthFail = engine.getStencilOperationDepthFail();
-            var previousAlphaMode = engine.getAlphaMode();
-
-            // Texture
-            currentEffect.setTexture("textureSampler", this._blurTexture);
-
-            // VBOs
-            engine.bindBuffers(this._vertexBuffers, this._indexBuffer, currentEffect);
-
-            // Stencil operations
-            engine.setStencilOperationPass(Engine.REPLACE);
-            engine.setStencilOperationFail(Engine.KEEP);
-            engine.setStencilOperationDepthFail(Engine.KEEP);
-
-            // Draw order
-            engine.setAlphaMode(this._options.alphaBlendingMode);
-            engine.setStencilMask(0x00);
-            engine.setStencilBuffer(true);
-            engine.setStencilFunctionReference(this._instanceGlowingMeshStencilReference);
-
-            if (this.outerGlow) {
-                currentEffect.setFloat("offset", 0);
-                engine.setStencilFunction(Engine.NOTEQUAL);
-                engine.drawElementsType(Material.TriangleFillMode, 0, 6);
-            }
-            if (this.innerGlow) {
-                currentEffect.setFloat("offset", 1);
-                engine.setStencilFunction(Engine.EQUAL);
-                engine.drawElementsType(Material.TriangleFillMode, 0, 6);
-            }
-
-            // Restore Cache
-            engine.setStencilFunction(previousStencilFunction);
-            engine.setStencilMask(previousStencilMask);
-            engine.setAlphaMode(previousAlphaMode);
-            engine.setStencilBuffer(previousStencilBuffer);
-            engine.setStencilOperationPass(previousStencilOperationPass);
-            engine.setStencilOperationFail(previousStencilOperationFail);
-            engine.setStencilOperationDepthFail(previousStencilOperationDepthFail);
-
-            (<any>engine)._stencilState.reset();
-
-            this.onAfterComposeObservable.notifyObservers(this);
-
-            // Handle size changes.
-            var size = this._mainTexture.getSize();
-            this.setMainTextureSize();
-            if (size.width !== this._mainTextureDesiredSize.width || size.height !== this._mainTextureDesiredSize.height) {
-                // Recreate RTT and post processes on size change.
-                this.onSizeChangedObservable.notifyObservers(this);
-                this.disposeTextureAndPostProcesses();
-                this.createTextureAndPostProcesses();
-            }
-        }
-
-        /**
-         * Add a mesh in the exclusion list to prevent it to impact or being impacted by the highlight layer.
-         * @param mesh The mesh to exclude from the highlight layer
-         */
-        public addExcludedMesh(mesh: Mesh) {
-            if (!this._excludedMeshes) {
-                return;
-            }
-
-            var meshExcluded = this._excludedMeshes[mesh.uniqueId];
-            if (!meshExcluded) {
-                this._excludedMeshes[mesh.uniqueId] = {
-                    mesh: mesh,
-                    beforeRender: mesh.onBeforeRenderObservable.add((mesh: Mesh) => {
-                        mesh.getEngine().setStencilBuffer(false);
-                    }),
-                    afterRender: mesh.onAfterRenderObservable.add((mesh: Mesh) => {
-                        mesh.getEngine().setStencilBuffer(true);
-                    }),
-                }
-            }
-        }
-
-        /**
-          * Remove a mesh from the exclusion list to let it impact or being impacted by the highlight layer.
-          * @param mesh The mesh to highlight
-          */
-        public removeExcludedMesh(mesh: Mesh) {
-            if (!this._excludedMeshes) {
-                return;
-            }
-
-            var meshExcluded = this._excludedMeshes[mesh.uniqueId];
-            if (meshExcluded) {
-                if (meshExcluded.beforeRender) {
-                    mesh.onBeforeRenderObservable.remove(meshExcluded.beforeRender);
-                }
-
-                if (meshExcluded.afterRender) {
-                    mesh.onAfterRenderObservable.remove(meshExcluded.afterRender);
-                }
-            }
-
-            this._excludedMeshes[mesh.uniqueId] = null;
-        }
-
-        /**
-         * Determine if a given mesh will be highlighted by the current HighlightLayer
-         * @param mesh mesh to test
-         * @returns true if the mesh will be highlighted by the current HighlightLayer
-         */
-        public hasMesh(mesh: AbstractMesh): boolean {
-            if (!this._meshes) {
-                return false;
-            }
-
-            return this._meshes[mesh.uniqueId] !== undefined && this._meshes[mesh.uniqueId] !== null;
-        }
-
-        /**
-         * Add a mesh in the highlight layer in order to make it glow with the chosen color.
-         * @param mesh The mesh to highlight
-         * @param color The color of the highlight
-         * @param glowEmissiveOnly Extract the glow from the emissive texture
-         */
-        public addMesh(mesh: Mesh, color: Color3, glowEmissiveOnly = false) {
-            if (!this._meshes) {
-                return;
-            }
-
-            var meshHighlight = this._meshes[mesh.uniqueId];
-            if (meshHighlight) {
-                meshHighlight.color = color;
-            }
-            else {
-                this._meshes[mesh.uniqueId] = {
-                    mesh: mesh,
-                    color: color,
-                    // Lambda required for capture due to Observable this context
-                    observerHighlight: mesh.onBeforeRenderObservable.add((mesh: Mesh) => {
-                        if (this._excludedMeshes && this._excludedMeshes[mesh.uniqueId]) {
-                            this.defaultStencilReference(mesh);
-                        }
-                        else {
-                            mesh.getScene().getEngine().setStencilFunctionReference(this._instanceGlowingMeshStencilReference);
-                        }
-                    }),
-                    observerDefault: mesh.onAfterRenderObservable.add(this.defaultStencilReference),
-                    glowEmissiveOnly: glowEmissiveOnly
-                };
-            }
-
-            this._shouldRender = true;
-        }
-
-        /**
-         * Remove a mesh from the highlight layer in order to make it stop glowing.
-         * @param mesh The mesh to highlight
-         */
-        public removeMesh(mesh: Mesh) {
-            if (!this._meshes) {
-                return;
-            }
-
-            var meshHighlight = this._meshes[mesh.uniqueId];
-            if (meshHighlight) {
-
-                if (meshHighlight.observerHighlight) {
-                    mesh.onBeforeRenderObservable.remove(meshHighlight.observerHighlight);
-                }
-
-                if (meshHighlight.observerDefault) {
-                    mesh.onAfterRenderObservable.remove(meshHighlight.observerDefault);
-                }
-                delete this._meshes[mesh.uniqueId];
-            }
-
-            this._shouldRender = false;
-            for (var meshHighlightToCheck in this._meshes) {
-                if (this._meshes[meshHighlightToCheck]) {
-                    this._shouldRender = true;
-                    break;
-                }
-            }
-        }
-
-        /**
-         * Returns true if the layer contains information to display, otherwise false.
-         */
-        public shouldRender(): boolean {
-            return this.isEnabled && this._shouldRender;
-        }
-
-        /**
-         * Sets the main texture desired size which is the closest power of two
-         * of the engine canvas size.
-         */
-        private setMainTextureSize(): void {
-            if (this._options.mainTextureFixedSize) {
-                this._mainTextureDesiredSize.width = this._options.mainTextureFixedSize;
-                this._mainTextureDesiredSize.height = this._options.mainTextureFixedSize;
-            }
-            else {
-                this._mainTextureDesiredSize.width = this._engine.getRenderWidth() * this._options.mainTextureRatio;
-                this._mainTextureDesiredSize.height = this._engine.getRenderHeight() * this._options.mainTextureRatio;
-
-                this._mainTextureDesiredSize.width = this._engine.needPOTTextures ? Tools.GetExponentOfTwo(this._mainTextureDesiredSize.width, this._maxSize) : this._mainTextureDesiredSize.width;
-                this._mainTextureDesiredSize.height = this._engine.needPOTTextures ? Tools.GetExponentOfTwo(this._mainTextureDesiredSize.height, this._maxSize) : this._mainTextureDesiredSize.height;
-            }
-        }
-
-        /**
-         * Force the stencil to the normal expected value for none glowing parts
-         */
-        private defaultStencilReference(mesh: Mesh) {
-            mesh.getScene().getEngine().setStencilFunctionReference(HighlightLayer.normalMeshStencilReference);
-        }
-
-        /**
-         * Dispose only the render target textures and post process.
-         */
-        private disposeTextureAndPostProcesses(): void {
-            this._blurTexture.dispose();
-            this._mainTexture.dispose();
-
-            this._downSamplePostprocess.dispose();
-            this._horizontalBlurPostprocess.dispose();
-            this._verticalBlurPostprocess.dispose();
-        }
-
-        /**
-         * Dispose the highlight layer and free resources.
-         */
-        public dispose(): void {
-            var vertexBuffer = this._vertexBuffers[VertexBuffer.PositionKind];
-            if (vertexBuffer) {
-                vertexBuffer.dispose();
-                this._vertexBuffers[VertexBuffer.PositionKind] = null;
-            }
-
-            if (this._indexBuffer) {
-                this._scene.getEngine()._releaseBuffer(this._indexBuffer);
-                this._indexBuffer = null;
-            }
-
-            // Clean textures and post processes
-            this.disposeTextureAndPostProcesses();
-
-            if (this._meshes) {
-                // Clean mesh references 
-                for (let id in this._meshes) {
-                    let meshHighlight = this._meshes[id];
-                    if (meshHighlight && meshHighlight.mesh) {
-
-                        if (meshHighlight.observerHighlight) {
-                            meshHighlight.mesh.onBeforeRenderObservable.remove(meshHighlight.observerHighlight);
-                        }
-
-                        if (meshHighlight.observerDefault) {
-                            meshHighlight.mesh.onAfterRenderObservable.remove(meshHighlight.observerDefault);
-                        }
-                    }
-                }
-                this._meshes = null;
-            }
-
-            if (this._excludedMeshes) {
-                for (let id in this._excludedMeshes) {
-                    let meshHighlight = this._excludedMeshes[id];
-                    if (meshHighlight) {
-
-                        if (meshHighlight.beforeRender) {
-                            meshHighlight.mesh.onBeforeRenderObservable.remove(meshHighlight.beforeRender);
-                        }
-
-                        if (meshHighlight.afterRender) {
-                            meshHighlight.mesh.onAfterRenderObservable.remove(meshHighlight.afterRender);
-                        }
-                    }
-                }
-                this._excludedMeshes = null;
-            }
-
-            // Remove from scene
-            var index = this._scene.highlightLayers.indexOf(this, 0);
-            if (index > -1) {
-                this._scene.highlightLayers.splice(index, 1);
-            }
-
-            // Callback
-            this.onDisposeObservable.notifyObservers(this);
-
-            this.onDisposeObservable.clear();
-            this.onBeforeRenderMainTextureObservable.clear();
-            this.onBeforeBlurObservable.clear();
-            this.onBeforeComposeObservable.clear();
-            this.onAfterComposeObservable.clear();
-            this.onSizeChangedObservable.clear();
-        }
-    }
-} 

+ 20 - 0
src/Lights/Shadows/babylon.shadowGenerator.ts

@@ -57,6 +57,13 @@
         forceCompilation(onCompiled?: (generator: ShadowGenerator) => void, options?: Partial<{ useInstances: boolean }>): void;
 
         /**
+         * Forces all the attached effect to compile to enable rendering only once ready vs. lazyly compiling effects.
+         * @param options Sets of optional options forcing the compilation with different modes 
+         * @returns A promise that resolves when the compilation completes
+         */
+        forceCompilationAsync(options?: Partial<{ useInstances: boolean }>): Promise<void>;
+
+        /**
          * Serializes the shadow generator setup to a json object.
          * @returns The serialized JSON object 
          */
@@ -846,6 +853,19 @@
         }
 
         /**
+         * Forces all the attached effect to compile to enable rendering only once ready vs. lazyly compiling effects.
+         * @param options Sets of optional options forcing the compilation with different modes 
+         * @returns A promise that resolves when the compilation completes
+         */
+        public forceCompilationAsync(options?: Partial<{ useInstances: boolean }>): Promise<void> {
+            return new Promise(resolve => {
+                this.forceCompilation(() => {
+                    resolve();
+                }, options);
+            });
+        }
+
+        /**
          * Determine wheter the shadow generator is ready or not (mainly all effects and related post processes needs to be ready).
          * @param subMesh The submesh we want to render in the shadow map
          * @param useInstances Defines wether will draw in the map using instances

+ 292 - 295
src/Loading/Plugins/babylon.babylonFileLoader.ts

@@ -28,355 +28,352 @@
         return operation + " of " + (producer ? producer.file + " from " + producer.name + " version: " + producer.version + ", exporter version: " + producer.exporter_version : "unknown");
     }
 
-    var loadAssets = (scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void, addToScene = false):Nullable<AssetContainer> => {
+    var loadAssetContainer = (scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void, addToScene = false): AssetContainer => {
         var container = new AssetContainer(scene);
 
-            // Entire method running in try block, so ALWAYS logs as far as it got, only actually writes details
-            // when SceneLoader.debugLogging = true (default), or exception encountered.
-            // Everything stored in var log instead of writing separate lines to support only writing in exception,
-            // and avoid problems with multiple concurrent .babylon loads.
-            var log = "importScene has failed JSON parse";
-            try {
-                var parsedData = JSON.parse(data);
-                log = "";
-                var fullDetails = SceneLoader.loggingLevel === SceneLoader.DETAILED_LOGGING;               
-
-                var index: number;
-                var cache: number;
-                // Lights
-                if (parsedData.lights !== undefined && parsedData.lights !== null) {
-                    for (index = 0, cache = parsedData.lights.length; index < cache; index++) {
-                        var parsedLight = parsedData.lights[index];
-                        var light = Light.Parse(parsedLight, scene);
-                        if (light) {
-                            container.lights.push(light);
-                            log += (index === 0 ? "\n\tLights:" : "");
-                            log += "\n\t\t" + light.toString(fullDetails);
-                        }
+        // Entire method running in try block, so ALWAYS logs as far as it got, only actually writes details
+        // when SceneLoader.debugLogging = true (default), or exception encountered.
+        // Everything stored in var log instead of writing separate lines to support only writing in exception,
+        // and avoid problems with multiple concurrent .babylon loads.
+        var log = "importScene has failed JSON parse";
+        try {
+            var parsedData = JSON.parse(data);
+            log = "";
+            var fullDetails = SceneLoader.loggingLevel === SceneLoader.DETAILED_LOGGING;
+
+            var index: number;
+            var cache: number;
+            // Lights
+            if (parsedData.lights !== undefined && parsedData.lights !== null) {
+                for (index = 0, cache = parsedData.lights.length; index < cache; index++) {
+                    var parsedLight = parsedData.lights[index];
+                    var light = Light.Parse(parsedLight, scene);
+                    if (light) {
+                        container.lights.push(light);
+                        log += (index === 0 ? "\n\tLights:" : "");
+                        log += "\n\t\t" + light.toString(fullDetails);
                     }
                 }
+            }
 
-                // Animations
-                if (parsedData.animations !== undefined && parsedData.animations !== null) {
-                    for (index = 0, cache = parsedData.animations.length; index < cache; index++) {
-                        var parsedAnimation = parsedData.animations[index];
-                        var animation = Animation.Parse(parsedAnimation);
-                        scene.animations.push(animation);
-                        container.animations.push(animation);
-                        log += (index === 0 ? "\n\tAnimations:" : "");
-                        log += "\n\t\t" + animation.toString(fullDetails);
-                    }
+            // Animations
+            if (parsedData.animations !== undefined && parsedData.animations !== null) {
+                for (index = 0, cache = parsedData.animations.length; index < cache; index++) {
+                    var parsedAnimation = parsedData.animations[index];
+                    var animation = Animation.Parse(parsedAnimation);
+                    scene.animations.push(animation);
+                    container.animations.push(animation);
+                    log += (index === 0 ? "\n\tAnimations:" : "");
+                    log += "\n\t\t" + animation.toString(fullDetails);
                 }
+            }
 
-                // Materials
-                if (parsedData.materials !== undefined && parsedData.materials !== null) {
-                    for (index = 0, cache = parsedData.materials.length; index < cache; index++) {
-                        var parsedMaterial = parsedData.materials[index];
-                        var mat = Material.Parse(parsedMaterial, scene, rootUrl);
-                        container.materials.push(mat);
-                        log += (index === 0 ? "\n\tMaterials:" : "");
-                        log += "\n\t\t" + mat.toString(fullDetails);
-                    }
+            // Materials
+            if (parsedData.materials !== undefined && parsedData.materials !== null) {
+                for (index = 0, cache = parsedData.materials.length; index < cache; index++) {
+                    var parsedMaterial = parsedData.materials[index];
+                    var mat = Material.Parse(parsedMaterial, scene, rootUrl);
+                    container.materials.push(mat);
+                    log += (index === 0 ? "\n\tMaterials:" : "");
+                    log += "\n\t\t" + mat.toString(fullDetails);
                 }
+            }
 
-                if (parsedData.multiMaterials !== undefined && parsedData.multiMaterials !== null) {
-                    for (index = 0, cache = parsedData.multiMaterials.length; index < cache; index++) {
-                        var parsedMultiMaterial = parsedData.multiMaterials[index];
-                        var mmat = Material.ParseMultiMaterial(parsedMultiMaterial, scene);
-                        container.multiMaterials.push(mmat);
-                        log += (index === 0 ? "\n\tMultiMaterials:" : "");
-                        log += "\n\t\t" + mmat.toString(fullDetails);
-                    }
+            if (parsedData.multiMaterials !== undefined && parsedData.multiMaterials !== null) {
+                for (index = 0, cache = parsedData.multiMaterials.length; index < cache; index++) {
+                    var parsedMultiMaterial = parsedData.multiMaterials[index];
+                    var mmat = Material.ParseMultiMaterial(parsedMultiMaterial, scene);
+                    container.multiMaterials.push(mmat);
+                    log += (index === 0 ? "\n\tMultiMaterials:" : "");
+                    log += "\n\t\t" + mmat.toString(fullDetails);
                 }
+            }
 
-                // Morph targets
-                if (parsedData.morphTargetManagers !== undefined && parsedData.morphTargetManagers !== null) {
-                    for (var managerData of parsedData.morphTargetManagers) {
-                        container.morphTargetManagers.push(MorphTargetManager.Parse(managerData, scene));
-                    }
+            // Morph targets
+            if (parsedData.morphTargetManagers !== undefined && parsedData.morphTargetManagers !== null) {
+                for (var managerData of parsedData.morphTargetManagers) {
+                    container.morphTargetManagers.push(MorphTargetManager.Parse(managerData, scene));
                 }
+            }
 
-                // Skeletons
-                if (parsedData.skeletons !== undefined && parsedData.skeletons !== null) {
-                    for (index = 0, cache = parsedData.skeletons.length; index < cache; index++) {
-                        var parsedSkeleton = parsedData.skeletons[index];
-                        var skeleton = Skeleton.Parse(parsedSkeleton, scene);
-                        container.skeletons.push(skeleton);
-                        log += (index === 0 ? "\n\tSkeletons:" : "");
-                        log += "\n\t\t" + skeleton.toString(fullDetails);
-                    }
+            // Skeletons
+            if (parsedData.skeletons !== undefined && parsedData.skeletons !== null) {
+                for (index = 0, cache = parsedData.skeletons.length; index < cache; index++) {
+                    var parsedSkeleton = parsedData.skeletons[index];
+                    var skeleton = Skeleton.Parse(parsedSkeleton, scene);
+                    container.skeletons.push(skeleton);
+                    log += (index === 0 ? "\n\tSkeletons:" : "");
+                    log += "\n\t\t" + skeleton.toString(fullDetails);
                 }
+            }
 
-                // Geometries
-                var geometries = parsedData.geometries;
-                if (geometries !== undefined && geometries !== null) {
-                    var addedGeometry = new Array<Nullable<Geometry>>();
-                    // Boxes
-                    var boxes = geometries.boxes;
-                    if (boxes !== undefined && boxes !== null) {
-                        for (index = 0, cache = boxes.length; index < cache; index++) {
-                            var parsedBox = boxes[index];
-                            addedGeometry.push(BoxGeometry.Parse(parsedBox, scene));
-                        }
+            // Geometries
+            var geometries = parsedData.geometries;
+            if (geometries !== undefined && geometries !== null) {
+                var addedGeometry = new Array<Nullable<Geometry>>();
+                // Boxes
+                var boxes = geometries.boxes;
+                if (boxes !== undefined && boxes !== null) {
+                    for (index = 0, cache = boxes.length; index < cache; index++) {
+                        var parsedBox = boxes[index];
+                        addedGeometry.push(BoxGeometry.Parse(parsedBox, scene));
                     }
+                }
 
-                    // Spheres
-                    var spheres = geometries.spheres;
-                    if (spheres !== undefined && spheres !== null) {
-                        for (index = 0, cache = spheres.length; index < cache; index++) {
-                            var parsedSphere = spheres[index];
-                            addedGeometry.push(SphereGeometry.Parse(parsedSphere, scene));
-                        }
+                // Spheres
+                var spheres = geometries.spheres;
+                if (spheres !== undefined && spheres !== null) {
+                    for (index = 0, cache = spheres.length; index < cache; index++) {
+                        var parsedSphere = spheres[index];
+                        addedGeometry.push(SphereGeometry.Parse(parsedSphere, scene));
                     }
+                }
 
-                    // Cylinders
-                    var cylinders = geometries.cylinders;
-                    if (cylinders !== undefined && cylinders !== null) {
-                        for (index = 0, cache = cylinders.length; index < cache; index++) {
-                            var parsedCylinder = cylinders[index];
-                            addedGeometry.push(CylinderGeometry.Parse(parsedCylinder, scene));
-                        }
+                // Cylinders
+                var cylinders = geometries.cylinders;
+                if (cylinders !== undefined && cylinders !== null) {
+                    for (index = 0, cache = cylinders.length; index < cache; index++) {
+                        var parsedCylinder = cylinders[index];
+                        addedGeometry.push(CylinderGeometry.Parse(parsedCylinder, scene));
                     }
+                }
 
-                    // Toruses
-                    var toruses = geometries.toruses;
-                    if (toruses !== undefined && toruses !== null) {
-                        for (index = 0, cache = toruses.length; index < cache; index++) {
-                            var parsedTorus = toruses[index];
-                            addedGeometry.push(TorusGeometry.Parse(parsedTorus, scene));
-                        }
+                // Toruses
+                var toruses = geometries.toruses;
+                if (toruses !== undefined && toruses !== null) {
+                    for (index = 0, cache = toruses.length; index < cache; index++) {
+                        var parsedTorus = toruses[index];
+                        addedGeometry.push(TorusGeometry.Parse(parsedTorus, scene));
                     }
+                }
 
-                    // Grounds
-                    var grounds = geometries.grounds;
-                    if (grounds !== undefined && grounds !== null) {
-                        for (index = 0, cache = grounds.length; index < cache; index++) {
-                            var parsedGround = grounds[index];
-                            addedGeometry.push(GroundGeometry.Parse(parsedGround, scene));
-                        }
+                // Grounds
+                var grounds = geometries.grounds;
+                if (grounds !== undefined && grounds !== null) {
+                    for (index = 0, cache = grounds.length; index < cache; index++) {
+                        var parsedGround = grounds[index];
+                        addedGeometry.push(GroundGeometry.Parse(parsedGround, scene));
                     }
+                }
 
-                    // Planes
-                    var planes = geometries.planes;
-                    if (planes !== undefined && planes !== null) {
-                        for (index = 0, cache = planes.length; index < cache; index++) {
-                            var parsedPlane = planes[index];
-                            addedGeometry.push(PlaneGeometry.Parse(parsedPlane, scene));
-                        }
+                // Planes
+                var planes = geometries.planes;
+                if (planes !== undefined && planes !== null) {
+                    for (index = 0, cache = planes.length; index < cache; index++) {
+                        var parsedPlane = planes[index];
+                        addedGeometry.push(PlaneGeometry.Parse(parsedPlane, scene));
                     }
+                }
 
-                    // TorusKnots
-                    var torusKnots = geometries.torusKnots;
-                    if (torusKnots !== undefined && torusKnots !== null) {
-                        for (index = 0, cache = torusKnots.length; index < cache; index++) {
-                            var parsedTorusKnot = torusKnots[index];
-                            addedGeometry.push(TorusKnotGeometry.Parse(parsedTorusKnot, scene));
-                        }
+                // TorusKnots
+                var torusKnots = geometries.torusKnots;
+                if (torusKnots !== undefined && torusKnots !== null) {
+                    for (index = 0, cache = torusKnots.length; index < cache; index++) {
+                        var parsedTorusKnot = torusKnots[index];
+                        addedGeometry.push(TorusKnotGeometry.Parse(parsedTorusKnot, scene));
                     }
+                }
 
-                    // VertexData
-                    var vertexData = geometries.vertexData;
-                    if (vertexData !== undefined && vertexData !== null) {
-                        for (index = 0, cache = vertexData.length; index < cache; index++) {
-                            var parsedVertexData = vertexData[index];
-                            addedGeometry.push(Geometry.Parse(parsedVertexData, scene, rootUrl));
-                        }
+                // VertexData
+                var vertexData = geometries.vertexData;
+                if (vertexData !== undefined && vertexData !== null) {
+                    for (index = 0, cache = vertexData.length; index < cache; index++) {
+                        var parsedVertexData = vertexData[index];
+                        addedGeometry.push(Geometry.Parse(parsedVertexData, scene, rootUrl));
                     }
+                }
 
-                    addedGeometry.forEach((g)=>{
-                        if(g){
-                            container.geometries.push(g);
-                        }
-                    })
-                }
-                
-                // Transform nodes
-                if (parsedData.transformNodes !== undefined && parsedData.transformNodes !== null) {
-                    for (index = 0, cache = parsedData.transformNodes.length; index < cache; index++) {
-                        var parsedTransformNode = parsedData.transformNodes[index];
-                        var node = TransformNode.Parse(parsedTransformNode, scene, rootUrl);
-                        container.transformNodes.push(node);
+                addedGeometry.forEach((g) => {
+                    if (g) {
+                        container.geometries.push(g);
                     }
-                }                
+                })
+            }
 
-                // Meshes
-                if (parsedData.meshes !== undefined && parsedData.meshes !== null) {
-                    for (index = 0, cache = parsedData.meshes.length; index < cache; index++) {
-                        var parsedMesh = parsedData.meshes[index];
-                        var mesh = <AbstractMesh>Mesh.Parse(parsedMesh, scene, rootUrl);
-                        container.meshes.push(mesh);
-                        log += (index === 0 ? "\n\tMeshes:" : "");
-                        log += "\n\t\t" + mesh.toString(fullDetails);
-                    }
+            // Transform nodes
+            if (parsedData.transformNodes !== undefined && parsedData.transformNodes !== null) {
+                for (index = 0, cache = parsedData.transformNodes.length; index < cache; index++) {
+                    var parsedTransformNode = parsedData.transformNodes[index];
+                    var node = TransformNode.Parse(parsedTransformNode, scene, rootUrl);
+                    container.transformNodes.push(node);
                 }
+            }
 
-                // Cameras
-                if (parsedData.cameras !== undefined && parsedData.cameras !== null) {
-                    for (index = 0, cache = parsedData.cameras.length; index < cache; index++) {
-                        var parsedCamera = parsedData.cameras[index];
-                        var camera = Camera.Parse(parsedCamera, scene);
-                        container.cameras.push(camera);
-                        log += (index === 0 ? "\n\tCameras:" : "");
-                        log += "\n\t\t" + camera.toString(fullDetails);
-                    }
+            // Meshes
+            if (parsedData.meshes !== undefined && parsedData.meshes !== null) {
+                for (index = 0, cache = parsedData.meshes.length; index < cache; index++) {
+                    var parsedMesh = parsedData.meshes[index];
+                    var mesh = <AbstractMesh>Mesh.Parse(parsedMesh, scene, rootUrl);
+                    container.meshes.push(mesh);
+                    log += (index === 0 ? "\n\tMeshes:" : "");
+                    log += "\n\t\t" + mesh.toString(fullDetails);
                 }
+            }
 
-                // Browsing all the graph to connect the dots
-                for (index = 0, cache = scene.cameras.length; index < cache; index++) {
-                    var camera = scene.cameras[index];
-                    if (camera._waitingParentId) {
-                        camera.parent = scene.getLastEntryByID(camera._waitingParentId);
-                        camera._waitingParentId = null;
-                    }
+            // Cameras
+            if (parsedData.cameras !== undefined && parsedData.cameras !== null) {
+                for (index = 0, cache = parsedData.cameras.length; index < cache; index++) {
+                    var parsedCamera = parsedData.cameras[index];
+                    var camera = Camera.Parse(parsedCamera, scene);
+                    container.cameras.push(camera);
+                    log += (index === 0 ? "\n\tCameras:" : "");
+                    log += "\n\t\t" + camera.toString(fullDetails);
                 }
+            }
 
-                for (index = 0, cache = scene.lights.length; index < cache; index++) {
-                    let light = scene.lights[index];
-                    if (light && light._waitingParentId) {
-                        light.parent = scene.getLastEntryByID(light._waitingParentId);
-                        light._waitingParentId = null;
-                    }
+            // Browsing all the graph to connect the dots
+            for (index = 0, cache = scene.cameras.length; index < cache; index++) {
+                var camera = scene.cameras[index];
+                if (camera._waitingParentId) {
+                    camera.parent = scene.getLastEntryByID(camera._waitingParentId);
+                    camera._waitingParentId = null;
                 }
+            }
 
-                // Sounds
-                // TODO: add sound
-                var loadedSounds: Sound[] = [];
-                var loadedSound: Sound;
-                if (AudioEngine && parsedData.sounds !== undefined && parsedData.sounds !== null) {
-                    for (index = 0, cache = parsedData.sounds.length; index < cache; index++) {
-                        var parsedSound = parsedData.sounds[index];
-                        if (Engine.audioEngine.canUseWebAudio) {
-                            if (!parsedSound.url) parsedSound.url = parsedSound.name;
-                            if (!loadedSounds[parsedSound.url]) {
-                                loadedSound = Sound.Parse(parsedSound, scene, rootUrl);
-                                loadedSounds[parsedSound.url] = loadedSound;
-                                container.sounds.push(loadedSound);
-                            }
-                            else {
-                                container.sounds.push(Sound.Parse(parsedSound, scene, rootUrl, loadedSounds[parsedSound.url]));
-                            }
-                        } else {
-                            container.sounds.push(new Sound(parsedSound.name, null, scene));
+            for (index = 0, cache = scene.lights.length; index < cache; index++) {
+                let light = scene.lights[index];
+                if (light && light._waitingParentId) {
+                    light.parent = scene.getLastEntryByID(light._waitingParentId);
+                    light._waitingParentId = null;
+                }
+            }
+
+            // Sounds
+            // TODO: add sound
+            var loadedSounds: Sound[] = [];
+            var loadedSound: Sound;
+            if (AudioEngine && parsedData.sounds !== undefined && parsedData.sounds !== null) {
+                for (index = 0, cache = parsedData.sounds.length; index < cache; index++) {
+                    var parsedSound = parsedData.sounds[index];
+                    if (Engine.audioEngine.canUseWebAudio) {
+                        if (!parsedSound.url) parsedSound.url = parsedSound.name;
+                        if (!loadedSounds[parsedSound.url]) {
+                            loadedSound = Sound.Parse(parsedSound, scene, rootUrl);
+                            loadedSounds[parsedSound.url] = loadedSound;
+                            container.sounds.push(loadedSound);
                         }
+                        else {
+                            container.sounds.push(Sound.Parse(parsedSound, scene, rootUrl, loadedSounds[parsedSound.url]));
+                        }
+                    } else {
+                        container.sounds.push(new Sound(parsedSound.name, null, scene));
                     }
                 }
+            }
 
-                loadedSounds = [];
+            loadedSounds = [];
 
-                // Connect parents & children and parse actions
-                for (index = 0, cache = scene.transformNodes.length; index < cache; index++) {
-                    var transformNode = scene.transformNodes[index];
-                    if (transformNode._waitingParentId) {
-                        transformNode.parent = scene.getLastEntryByID(transformNode._waitingParentId);
-                        transformNode._waitingParentId = null;
-                    }
-                }                
-                for (index = 0, cache = scene.meshes.length; index < cache; index++) {
-                    var mesh = scene.meshes[index];
-                    if (mesh._waitingParentId) {
-                        mesh.parent = scene.getLastEntryByID(mesh._waitingParentId);
-                        mesh._waitingParentId = null;
-                    }
-                    if (mesh._waitingActions) {
-                        ActionManager.Parse(mesh._waitingActions, mesh, scene);
-                        mesh._waitingActions = null;
-                    }
+            // Connect parents & children and parse actions
+            for (index = 0, cache = scene.transformNodes.length; index < cache; index++) {
+                var transformNode = scene.transformNodes[index];
+                if (transformNode._waitingParentId) {
+                    transformNode.parent = scene.getLastEntryByID(transformNode._waitingParentId);
+                    transformNode._waitingParentId = null;
+                }
+            }
+            for (index = 0, cache = scene.meshes.length; index < cache; index++) {
+                var mesh = scene.meshes[index];
+                if (mesh._waitingParentId) {
+                    mesh.parent = scene.getLastEntryByID(mesh._waitingParentId);
+                    mesh._waitingParentId = null;
+                }
+                if (mesh._waitingActions) {
+                    ActionManager.Parse(mesh._waitingActions, mesh, scene);
+                    mesh._waitingActions = null;
                 }
+            }
 
-                // freeze world matrix application
-                for (index = 0, cache = scene.meshes.length; index < cache; index++) {
-                    var currentMesh = scene.meshes[index];
-                    if (currentMesh._waitingFreezeWorldMatrix) {
-                        currentMesh.freezeWorldMatrix();
-                        currentMesh._waitingFreezeWorldMatrix = null;
-                    } else {
-                        currentMesh.computeWorldMatrix(true);
-                    }
+            // freeze world matrix application
+            for (index = 0, cache = scene.meshes.length; index < cache; index++) {
+                var currentMesh = scene.meshes[index];
+                if (currentMesh._waitingFreezeWorldMatrix) {
+                    currentMesh.freezeWorldMatrix();
+                    currentMesh._waitingFreezeWorldMatrix = null;
+                } else {
+                    currentMesh.computeWorldMatrix(true);
                 }
+            }
 
-                // Particles Systems
-                if (parsedData.particleSystems !== undefined && parsedData.particleSystems !== null) {
-                    for (index = 0, cache = parsedData.particleSystems.length; index < cache; index++) {
-                        var parsedParticleSystem = parsedData.particleSystems[index];
-                        var ps = ParticleSystem.Parse(parsedParticleSystem, scene, rootUrl);
-                        container.particleSystems.push(ps);
-                    }
+            // Particles Systems
+            if (parsedData.particleSystems !== undefined && parsedData.particleSystems !== null) {
+                for (index = 0, cache = parsedData.particleSystems.length; index < cache; index++) {
+                    var parsedParticleSystem = parsedData.particleSystems[index];
+                    var ps = ParticleSystem.Parse(parsedParticleSystem, scene, rootUrl);
+                    container.particleSystems.push(ps);
                 }
+            }
 
-                // Lens flares
-                if (parsedData.lensFlareSystems !== undefined && parsedData.lensFlareSystems !== null) {
-                    for (index = 0, cache = parsedData.lensFlareSystems.length; index < cache; index++) {
-                        var parsedLensFlareSystem = parsedData.lensFlareSystems[index];
-                        var lf = LensFlareSystem.Parse(parsedLensFlareSystem, scene, rootUrl);
-                        container.lensFlareSystems.push(lf);
-                    }
+            // Lens flares
+            if (parsedData.lensFlareSystems !== undefined && parsedData.lensFlareSystems !== null) {
+                for (index = 0, cache = parsedData.lensFlareSystems.length; index < cache; index++) {
+                    var parsedLensFlareSystem = parsedData.lensFlareSystems[index];
+                    var lf = LensFlareSystem.Parse(parsedLensFlareSystem, scene, rootUrl);
+                    container.lensFlareSystems.push(lf);
                 }
+            }
 
-                // Shadows
-                if (parsedData.shadowGenerators !== undefined && parsedData.shadowGenerators !== null) {
-                    for (index = 0, cache = parsedData.shadowGenerators.length; index < cache; index++) {
-                        var parsedShadowGenerator = parsedData.shadowGenerators[index];
-                        var sg = ShadowGenerator.Parse(parsedShadowGenerator, scene);
-                        container.shadowGenerators.push(sg);
-                    }
+            // Shadows
+            if (parsedData.shadowGenerators !== undefined && parsedData.shadowGenerators !== null) {
+                for (index = 0, cache = parsedData.shadowGenerators.length; index < cache; index++) {
+                    var parsedShadowGenerator = parsedData.shadowGenerators[index];
+                    var sg = ShadowGenerator.Parse(parsedShadowGenerator, scene);
+                    container.shadowGenerators.push(sg);
                 }
+            }
 
-                // Lights exclusions / inclusions
-                for (index = 0, cache = scene.lights.length; index < cache; index++) {
-                    let light = scene.lights[index];
-                    // Excluded check
-                    if (light._excludedMeshesIds.length > 0) {
-                        for (var excludedIndex = 0; excludedIndex < light._excludedMeshesIds.length; excludedIndex++) {
-                            var excludedMesh = scene.getMeshByID(light._excludedMeshesIds[excludedIndex]);
+            // Lights exclusions / inclusions
+            for (index = 0, cache = scene.lights.length; index < cache; index++) {
+                let light = scene.lights[index];
+                // Excluded check
+                if (light._excludedMeshesIds.length > 0) {
+                    for (var excludedIndex = 0; excludedIndex < light._excludedMeshesIds.length; excludedIndex++) {
+                        var excludedMesh = scene.getMeshByID(light._excludedMeshesIds[excludedIndex]);
 
-                            if (excludedMesh) {
-                                light.excludedMeshes.push(excludedMesh);
-                            }
+                        if (excludedMesh) {
+                            light.excludedMeshes.push(excludedMesh);
                         }
-
-                        light._excludedMeshesIds = [];
                     }
 
-                    // Included check
-                    if (light._includedOnlyMeshesIds.length > 0) {
-                        for (var includedOnlyIndex = 0; includedOnlyIndex < light._includedOnlyMeshesIds.length; includedOnlyIndex++) {
-                            var includedOnlyMesh = scene.getMeshByID(light._includedOnlyMeshesIds[includedOnlyIndex]);
+                    light._excludedMeshesIds = [];
+                }
 
-                            if (includedOnlyMesh) {
-                                light.includedOnlyMeshes.push(includedOnlyMesh);
-                            }
-                        }
+                // Included check
+                if (light._includedOnlyMeshesIds.length > 0) {
+                    for (var includedOnlyIndex = 0; includedOnlyIndex < light._includedOnlyMeshesIds.length; includedOnlyIndex++) {
+                        var includedOnlyMesh = scene.getMeshByID(light._includedOnlyMeshesIds[includedOnlyIndex]);
 
-                        light._includedOnlyMeshesIds = [];
+                        if (includedOnlyMesh) {
+                            light.includedOnlyMeshes.push(includedOnlyMesh);
+                        }
                     }
-                }
 
-                // Actions (scene)
-                if (parsedData.actions !== undefined && parsedData.actions !== null) {
-                    ActionManager.Parse(parsedData.actions, null, scene);
-                }
-                
-                if(!addToScene){
-                    container.removeAllFromScene();
+                    light._includedOnlyMeshesIds = [];
                 }
+            }
 
-                return container;
+            // Actions (scene)
+            if (parsedData.actions !== undefined && parsedData.actions !== null) {
+                ActionManager.Parse(parsedData.actions, null, scene);
+            }
 
-            } catch (err) {
-                let msg = logOperation("loadAssts", parsedData ? parsedData.producer : "Unknown") + log;
-                if (onError) {
-                    onError(msg, err);
-                } else {
-                    Tools.Log(msg);
-                    throw err;
-                }
-            } finally {
-                if (log !== null && SceneLoader.loggingLevel !== SceneLoader.NO_LOGGING) {
-                    Tools.Log(logOperation("loadAssts", parsedData ? parsedData.producer : "Unknown") + (SceneLoader.loggingLevel !== SceneLoader.MINIMAL_LOGGING ? log : ""));
-                }
+            if (!addToScene) {
+                container.removeAllFromScene();
+            }
+        } catch (err) {
+            let msg = logOperation("loadAssts", parsedData ? parsedData.producer : "Unknown") + log;
+            if (onError) {
+                onError(msg, err);
+            } else {
+                Tools.Log(msg);
+                throw err;
             }
+        } finally {
+            if (log !== null && SceneLoader.loggingLevel !== SceneLoader.NO_LOGGING) {
+                Tools.Log(logOperation("loadAssts", parsedData ? parsedData.producer : "Unknown") + (SceneLoader.loggingLevel !== SceneLoader.MINIMAL_LOGGING ? log : ""));
+            }
+        }
 
-            return null;
+        return container;
     }
 
     SceneLoader.RegisterPlugin({
@@ -647,26 +644,26 @@
                 }
                 scene.workerCollisions = !!parsedData.workerCollisions;
 
-                var container = loadAssets(scene, data, rootUrl, onerror, true);
-                if(!container){
+                var container = loadAssetContainer(scene, data, rootUrl, onerror, true);
+                if (!container) {
                     return false;
                 }
-                
-                if (parsedData.autoAnimate) {		
-                    scene.beginAnimation(scene, parsedData.autoAnimateFrom, parsedData.autoAnimateTo, parsedData.autoAnimateLoop, parsedData.autoAnimateSpeed || 1.0);		
+
+                if (parsedData.autoAnimate) {
+                    scene.beginAnimation(scene, parsedData.autoAnimateFrom, parsedData.autoAnimateTo, parsedData.autoAnimateLoop, parsedData.autoAnimateSpeed || 1.0);
                 }
 
-                if (parsedData.activeCameraID !== undefined && parsedData.activeCameraID !== null) {		
-                    scene.setActiveCameraByID(parsedData.activeCameraID);		
+                if (parsedData.activeCameraID !== undefined && parsedData.activeCameraID !== null) {
+                    scene.setActiveCameraByID(parsedData.activeCameraID);
                 }
 
                 // Environment texture		
-                if (parsedData.environmentTexture !== undefined && parsedData.environmentTexture !== null) {		
-                    scene.environmentTexture = CubeTexture.CreateFromPrefilteredData(rootUrl + parsedData.environmentTexture, scene);		
-                    if (parsedData.createDefaultSkybox === true) {		
-                        var skyboxScale = (scene.activeCamera !== undefined && scene.activeCamera !== null) ? (scene.activeCamera.maxZ - scene.activeCamera.minZ) / 2 : 1000;		
-                        var skyboxBlurLevel = parsedData.skyboxBlurLevel || 0;		
-                        scene.createDefaultSkybox(undefined, true, skyboxScale, skyboxBlurLevel);		
+                if (parsedData.environmentTexture !== undefined && parsedData.environmentTexture !== null) {
+                    scene.environmentTexture = CubeTexture.CreateFromPrefilteredData(rootUrl + parsedData.environmentTexture, scene);
+                    if (parsedData.createDefaultSkybox === true) {
+                        var skyboxScale = (scene.activeCamera !== undefined && scene.activeCamera !== null) ? (scene.activeCamera.maxZ - scene.activeCamera.minZ) / 2 : 1000;
+                        var skyboxBlurLevel = parsedData.skyboxBlurLevel || 0;
+                        scene.createDefaultSkybox(undefined, true, skyboxScale, skyboxBlurLevel);
                     }
                 }
                 // Finish
@@ -686,8 +683,8 @@
             }
             return false;
         },
-        loadAssets: (scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): Nullable<AssetContainer> =>{
-            var container = loadAssets(scene, data, rootUrl, onerror);
+        loadAssetContainer: (scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): AssetContainer => {
+            var container = loadAssetContainer(scene, data, rootUrl, onerror);
             return container;
         }
     });

+ 224 - 33
src/Loading/babylon.sceneLoader.ts

@@ -21,23 +21,112 @@
     }
 
     export interface ISceneLoaderPlugin {
+        /**
+         * The friendly name of this plugin.
+         */
         name: string;
+
+        /**
+         * The file extensions supported by this plugin.
+         */
         extensions: string | ISceneLoaderPluginExtensions;
-        importMesh: (meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[], onError?: (message: string, exception?: any) => void) => boolean;
-        load: (scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void) => boolean;
+
+        /**
+         * Import meshes into a scene.
+         * @param meshesNames An array of mesh names, a single mesh name, or empty string for all meshes that filter what meshes are imported
+         * @param scene The scene to import into
+         * @param data The data to import
+         * @param rootUrl The root url for scene and resources
+         * @param meshes The meshes array to import into
+         * @param particleSystems The particle systems array to import into
+         * @param skeletons The skeletons array to import into
+         * @param onError The callback when import fails
+         * @returns True if successful or false otherwise
+         */
+        importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[], onError?: (message: string, exception?: any) => void): boolean;
+
+        /**
+         * Load into a scene.
+         * @param scene The scene to load into
+         * @param data The data to import
+         * @param rootUrl The root url for scene and resources
+         * @param onError The callback when import fails
+         * @returns true if successful or false otherwise
+         */
+        load(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): boolean;
+
+        /**
+         * The callback that returns true if the data can be directly loaded.
+         */
         canDirectLoad?: (data: string) => boolean;
+
+        /**
+         * The callback that allows custom handling of the root url based on the response url.
+         */
         rewriteRootURL?: (rootUrl: string, responseURL?: string) => string;
-        loadAssets: (scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void) => Nullable<AssetContainer>;
+
+        /**
+         * Load into an asset container.
+         * @param scene The scene to load into
+         * @param data The data to import
+         * @param rootUrl The root url for scene and resources
+         * @param onError The callback when import fails
+         * @returns The loaded asset container
+         */
+        loadAssetContainer(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): AssetContainer;
     }
 
     export interface ISceneLoaderPluginAsync {
+        /**
+         * The friendly name of this plugin.
+         */
         name: string;
+
+        /**
+         * The file extensions supported by this plugin.
+         */
         extensions: string | ISceneLoaderPluginExtensions;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
-        loadAsync: (scene: Scene, data: string, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+
+        /**
+         * Import meshes into a scene.
+         * @param meshesNames An array of mesh names, a single mesh name, or empty string for all meshes that filter what meshes are imported
+         * @param scene The scene to import into
+         * @param data The data to import
+         * @param rootUrl The root url for scene and resources
+         * @param onProgress The callback when the load progresses
+         * @returns The loaded meshes, particle systems, and skeletons
+         */
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{ meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[] }>;
+
+        /**
+         * Load into a scene.
+         * @param scene The scene to load into
+         * @param data The data to import
+         * @param rootUrl The root url for scene and resources
+         * @param onProgress The callback when the load progresses
+         * @returns Nothing
+         */
+        loadAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+
+        /**
+         * The callback that returns true if the data can be directly loaded.
+         */
         canDirectLoad?: (data: string) => boolean;
+
+        /**
+         * The callback that allows custom handling of the root url based on the response url.
+         */
         rewriteRootURL?: (rootUrl: string, responseURL?: string) => string;
-        loadAssetsAsync: (scene: Scene, data: string, rootUrl: string, onSuccess?: (assets: Nullable<AssetContainer>) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+
+        /**
+         * Load into an asset container.
+         * @param scene The scene to load into
+         * @param data The data to import
+         * @param rootUrl The root url for scene and resources
+         * @param onProgress The callback when the load progresses
+         * @returns The loaded asset container
+         */
+        loadAssetContainerAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
     }
 
     interface IRegisteredPlugin {
@@ -209,7 +298,7 @@
                 let url = rootUrl + sceneFilename;
                 request = Tools.LoadFile(url, dataCallback, onProgress ? event => {
                     onProgress(SceneLoaderProgressEvent.FromProgressEvent(event));
-                }: undefined, database, useArrayBuffer, (request, exception) => {
+                } : undefined, database, useArrayBuffer, (request, exception) => {
                     onError("Failed to load scene." + (exception ? "" : " " + exception.message), exception);
                 });
             };
@@ -272,15 +361,17 @@
         }
 
         /**
-        * Import meshes into a scene
-        * @param meshNames an array of mesh names, a single mesh name, or empty string for all meshes that filter what meshes are imported 
-        * @param rootUrl a string that defines the root url for scene and resources
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
-        * @param scene the instance of BABYLON.Scene to append to
-        * @param onSuccess a callback with a list of imported meshes, particleSystems, and skeletons when import succeeds
-        * @param onProgress a callback with a progress event for each file being loaded
-        * @param onError a callback with the scene, a message, and possibly an exception when import fails
-        */
+         * Import meshes into a scene
+         * @param meshNames an array of mesh names, a single mesh name, or empty string for all meshes that filter what meshes are imported 
+         * @param rootUrl a string that defines the root url for scene and resources
+         * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
+         * @param scene the instance of BABYLON.Scene to append to
+         * @param onSuccess a callback with a list of imported meshes, particleSystems, and skeletons when import succeeds
+         * @param onProgress a callback with a progress event for each file being loaded
+         * @param onError a callback with the scene, a message, and possibly an exception when import fails
+         * @param pluginExtension the extension used to determine the plugin
+         * @returns The loaded plugin
+         */
         public static ImportMesh(meshNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onSuccess: Nullable<(meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void> = null, onProgress: Nullable<(event: SceneLoaderProgressEvent) => void> = null, onError: Nullable<(scene: Scene, message: string, exception?: any) => void> = null, pluginExtension: Nullable<string> = null): Nullable<ISceneLoaderPlugin | ISceneLoaderPluginAsync> {
             if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
                 Tools.Error("Wrong sceneFilename parameter");
@@ -357,15 +448,41 @@
                 }
                 else {
                     var asyncedPlugin = <ISceneLoaderPluginAsync>plugin;
-                    asyncedPlugin.importMeshAsync(meshNames, scene, data, rootUrl, (meshes, particleSystems, skeletons) => {
+                    asyncedPlugin.importMeshAsync(meshNames, scene, data, rootUrl, progressHandler).then(result => {
                         scene.loadingPluginName = plugin.name;
-                        successHandler(meshes, particleSystems, skeletons);
-                    }, progressHandler, errorHandler);
+                        successHandler(result.meshes, result.particleSystems, result.skeletons);
+                    }).catch(error => {
+                        errorHandler(error.message, error);
+                    });
                 }
             }, progressHandler, errorHandler, disposeHandler, pluginExtension);
         }
 
         /**
+        * Import meshes into a scene
+        * @param meshNames an array of mesh names, a single mesh name, or empty string for all meshes that filter what meshes are imported 
+        * @param rootUrl a string that defines the root url for scene and resources
+        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
+        * @param scene the instance of BABYLON.Scene to append to
+        * @param onProgress a callback with a progress event for each file being loaded
+        * @param pluginExtension the extension used to determine the plugin
+        * @returns The loaded list of imported meshes, particleSystems, and skeletons
+        */
+        public static ImportMeshAsync(meshNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onProgress: Nullable<(event: SceneLoaderProgressEvent) => void> = null, pluginExtension: Nullable<string> = null): Promise<{ meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[] }> {
+            return new Promise((resolve, reject) => {
+                SceneLoader.ImportMesh(meshNames, rootUrl, sceneFilename, scene, (meshes, particleSystems, skeletons) => {
+                    resolve({
+                        meshes: meshes,
+                        particleSystems: particleSystems,
+                        skeletons: skeletons
+                    });
+                }, onProgress, (scene, message, exception) => {
+                    reject(exception || new Error(message));
+                });
+            });
+        }
+
+        /**
         * Load a scene
         * @param rootUrl a string that defines the root url for scene and resources
         * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
@@ -373,12 +490,33 @@
         * @param onSuccess a callback with the scene when import succeeds
         * @param onProgress a callback with a progress event for each file being loaded
         * @param onError a callback with the scene, a message, and possibly an exception when import fails
+        * @param pluginExtension the extension used to determine the plugin
+        * @returns The loaded plugin
         */
         public static Load(rootUrl: string, sceneFilename: any, engine: Engine, onSuccess: Nullable<(scene: Scene) => void> = null, onProgress: Nullable<(event: SceneLoaderProgressEvent) => void> = null, onError: Nullable<(scene: Scene, message: string, exception?: any) => void> = null, pluginExtension: Nullable<string> = null): Nullable<ISceneLoaderPlugin | ISceneLoaderPluginAsync> {
             return SceneLoader.Append(rootUrl, sceneFilename, new Scene(engine), onSuccess, onProgress, onError, pluginExtension);
         }
 
         /**
+        * Load a scene
+        * @param rootUrl a string that defines the root url for scene and resources
+        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
+        * @param engine is the instance of BABYLON.Engine to use to create the scene
+        * @param onProgress a callback with a progress event for each file being loaded
+        * @param pluginExtension the extension used to determine the plugin
+        * @returns The loaded scene
+        */
+        public static LoadAsync(rootUrl: string, sceneFilename: any, engine: Engine, onProgress: Nullable<(event: SceneLoaderProgressEvent) => void> = null, pluginExtension: Nullable<string> = null): Promise<Scene> {
+            return new Promise((resolve, reject) => {
+                SceneLoader.Load(rootUrl, sceneFilename, engine, scene => {
+                    resolve(scene);
+                }, onProgress, (scene, message, exception) => {
+                    reject(exception || new Error(message));
+                }, pluginExtension);
+            });
+        }
+
+        /**
         * Append a scene
         * @param rootUrl a string that defines the root url for scene and resources
         * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
@@ -386,6 +524,8 @@
         * @param onSuccess a callback with the scene when import succeeds
         * @param onProgress a callback with a progress event for each file being loaded
         * @param onError a callback with the scene, a message, and possibly an exception when import fails
+        * @param pluginExtension the extension used to determine the plugin
+        * @returns The loaded plugin
         */
         public static Append(rootUrl: string, sceneFilename: any, scene: Scene, onSuccess: Nullable<(scene: Scene) => void> = null, onProgress: Nullable<(event: SceneLoaderProgressEvent) => void> = null, onError: Nullable<(scene: Scene, message: string, exception?: any) => void> = null, pluginExtension: Nullable<string> = null): Nullable<ISceneLoaderPlugin | ISceneLoaderPluginAsync> {
             if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
@@ -454,10 +594,12 @@
                     successHandler();
                 } else {
                     var asyncedPlugin = <ISceneLoaderPluginAsync>plugin;
-                    asyncedPlugin.loadAsync(scene, data, rootUrl, () => {
+                    asyncedPlugin.loadAsync(scene, data, rootUrl, progressHandler).then(() => {
                         scene.loadingPluginName = plugin.name;
                         successHandler();
-                    }, progressHandler, errorHandler);
+                    }).catch(error => {
+                        errorHandler(error.message, error);
+                    });
                 }
 
                 if (SceneLoader.ShowLoadingScreen) {
@@ -467,7 +609,37 @@
                 }
             }, progressHandler, errorHandler, disposeHandler, pluginExtension);
         }
-        
+
+        /**
+        * Append a scene
+        * @param rootUrl a string that defines the root url for scene and resources
+        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
+        * @param scene is the instance of BABYLON.Scene to append to
+        * @param onProgress a callback with a progress event for each file being loaded
+        * @param pluginExtension the extension used to determine the plugin
+        * @returns The given scene
+        */
+        public static AppendAsync(rootUrl: string, sceneFilename: any, scene: Scene, onProgress: Nullable<(event: SceneLoaderProgressEvent) => void> = null, pluginExtension: Nullable<string> = null): Promise<Scene> {
+            return new Promise((resolve, reject) => {
+                SceneLoader.Append(rootUrl, sceneFilename, scene, scene => {
+                    resolve(scene);
+                }, onProgress, (scene, message, exception) => {
+                    reject(exception || new Error(message));
+                }, pluginExtension);
+            });
+        }
+
+        /**
+        * Load a scene into an asset container
+        * @param rootUrl a string that defines the root url for scene and resources
+        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
+        * @param scene is the instance of BABYLON.Scene to append to
+        * @param onSuccess a callback with the scene when import succeeds
+        * @param onProgress a callback with a progress event for each file being loaded
+        * @param onError a callback with the scene, a message, and possibly an exception when import fails
+        * @param pluginExtension the extension used to determine the plugin
+        * @returns The loaded plugin
+        */
         public static LoadAssetContainer(
             rootUrl: string,
             sceneFilename: any,
@@ -524,25 +696,25 @@
             };
 
             return SceneLoader._loadData(rootUrl, sceneFilename, scene, (plugin, data, responseURL) => {
-                if ((<any>plugin).loadAssets) {
+                if ((<any>plugin).loadAssetContainer) {
                     var syncedPlugin = <ISceneLoaderPlugin>plugin;
-                    var assetContainer = syncedPlugin.loadAssets(scene, data, rootUrl, errorHandler);
+                    var assetContainer = syncedPlugin.loadAssetContainer(scene, data, rootUrl, errorHandler);
                     if (!assetContainer) {
                         return;
                     }
 
                     scene.loadingPluginName = plugin.name;
                     successHandler(assetContainer);
-                } else if ((<any>plugin).loadAssetsAsync) {
+                } else if ((<any>plugin).loadAssetContainerAsync) {
                     var asyncedPlugin = <ISceneLoaderPluginAsync>plugin;
-                    asyncedPlugin.loadAssetsAsync(scene, data, rootUrl, (assetContainer) => {
-                        if(assetContainer){
-                            scene.loadingPluginName = plugin.name;
-                            successHandler(assetContainer);
-                        }
-                    }, progressHandler, errorHandler);
-                }else{
-                    errorHandler("LoadAssetContainer is not supported by this plugin. Plugin did not provide a loadAssets or loadAssetsAsync method.")
+                    asyncedPlugin.loadAssetContainerAsync(scene, data, rootUrl, progressHandler).then(assetContainer => {
+                        scene.loadingPluginName = plugin.name;
+                        successHandler(assetContainer);
+                    }).catch(error => {
+                        errorHandler(error.message, error);
+                    });
+                } else {
+                    errorHandler("LoadAssetContainer is not supported by this plugin. Plugin did not provide a loadAssetContainer or loadAssetContainerAsync method.")
                 }
 
                 if (SceneLoader.ShowLoadingScreen) {
@@ -552,5 +724,24 @@
                 }
             }, progressHandler, errorHandler, disposeHandler, pluginExtension);
         }
+
+        /**
+        * Load a scene into an asset container
+        * @param rootUrl a string that defines the root url for scene and resources
+        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
+        * @param scene is the instance of BABYLON.Scene to append to
+        * @param onProgress a callback with a progress event for each file being loaded
+        * @param pluginExtension the extension used to determine the plugin
+        * @returns The loaded asset container
+        */
+        public static LoadAssetContainerAsync(rootUrl: string, sceneFilename: any, scene: Scene, onProgress: Nullable<(event: SceneLoaderProgressEvent) => void> = null, pluginExtension: Nullable<string> = null): Promise<AssetContainer> {
+            return new Promise((resolve, reject) => {
+                SceneLoader.LoadAssetContainer(rootUrl, sceneFilename, scene, assetContainer => {
+                    resolve(assetContainer);
+                }, onProgress, (scene, message, exception) => {
+                    reject(exception || new Error(message));
+                }, pluginExtension);
+            });
+        }
     };
 }

+ 29 - 2
src/Materials/Background/babylon.backgroundMaterial.ts

@@ -95,6 +95,7 @@
         public REFLECTIONMAP_OPPOSITEZ = false;
         public LODINREFLECTIONALPHA = false;
         public GAMMAREFLECTION = false;
+        public EQUIRECTANGULAR_RELFECTION_FOV = false;
 
         // Default BJS.
         public MAINUV1 = false;
@@ -330,6 +331,28 @@
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public enableNoise: boolean = false;
 
+        /**
+         * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
+         * Best used when trying to implement visual zoom effects like fish-eye or binoculars while not adjusting camera fov.
+         * Recommended to be keep at 1.0 except for special cases.
+         */
+        public get fovMultiplier(): number {
+            return this._fovMultiplier;
+        }
+        public set fovMultiplier(value: number) {
+            if (isNaN(value)) {
+                value = 1.0;
+            }
+            this._fovMultiplier = Math.max(0.0, Math.min(2.0, value));
+        }
+        private _fovMultiplier: float = 1.0;
+
+        /**
+         * Enable the FOV adjustment feature controlled by fovMultiplier.
+         * @type {boolean}
+         */
+        public useEquirectangularFOV: boolean = false;
+
         @serialize()
         private _maxSimultaneousLights: int = 4;
         /**
@@ -611,6 +634,7 @@
                         defines.REFLECTIONBLUR = this._reflectionBlur > 0;
                         defines.REFLECTIONMAP_OPPOSITEZ = this.getScene().useRightHandedSystem ? !reflectionTexture.invertZ : reflectionTexture.invertZ;
                         defines.LODINREFLECTIONALPHA = reflectionTexture.lodLevelInAlpha;
+                        defines.EQUIRECTANGULAR_RELFECTION_FOV = this.useEquirectangularFOV;
 
                         if (reflectionTexture.coordinatesMode === Texture.INVCUBIC_MODE) {
                             defines.INVERTCUBICMAP = true;
@@ -756,7 +780,7 @@
                     "vClipPlane", "mBones",
 
                     "vPrimaryColor", "vSecondaryColor", "vTertiaryColor",
-                    "vReflectionInfos", "reflectionMatrix", "vReflectionMicrosurfaceInfos",
+                    "vReflectionInfos", "reflectionMatrix", "vReflectionMicrosurfaceInfos", "fFovMultiplier",
 
                     "shadowLevel", "alpha",
 
@@ -826,6 +850,7 @@
             this._uniformBuffer.addUniform("diffuseMatrix", 16);
             this._uniformBuffer.addUniform("reflectionMatrix", 16);
             this._uniformBuffer.addUniform("vReflectionMicrosurfaceInfos", 3);
+            this._uniformBuffer.addUniform("fFovMultiplier", 1);
             this._uniformBuffer.addUniform("pointSize", 1);
             this._uniformBuffer.addUniform("shadowLevel", 1);
             this._uniformBuffer.addUniform("alpha", 1);
@@ -925,6 +950,8 @@
                     this._uniformBuffer.updateColor4("vTertiaryColor", this._tertiaryColor, this._tertiaryLevel);
                 }
 
+                this._uniformBuffer.updateFloat("fFovMultiplier", this._fovMultiplier);
+
                 // Textures
                 if (scene.texturesEnabled) {
                     if (this._diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
@@ -1039,4 +1066,4 @@
             return SerializationHelper.Parse(() => new BackgroundMaterial(source.name, scene), source, scene, rootUrl);
         }
     }
-}
+}

+ 319 - 266
src/Materials/PBR/babylon.pbrBaseMaterial.ts

@@ -70,6 +70,7 @@
         public REFLECTIONMAP_SPHERICAL = false;
         public REFLECTIONMAP_PLANAR = false;
         public REFLECTIONMAP_CUBIC = false;
+        public USE_LOCAL_REFLECTIONMAP_CUBIC = false;        
         public REFLECTIONMAP_PROJECTION = false;
         public REFLECTIONMAP_SKYBOX = false;
         public REFLECTIONMAP_EXPLICIT = false;
@@ -686,15 +687,296 @@
                 subMesh._materialDefines = new PBRMaterialDefines();
             }
 
-            var scene = this.getScene();
-            var defines = <PBRMaterialDefines>subMesh._materialDefines;
+            const defines = <PBRMaterialDefines>subMesh._materialDefines;
             if (!this.checkReadyOnEveryCall && subMesh.effect) {
-                if (defines._renderId === scene.getRenderId()) {
+                if (defines._renderId === this.getScene().getRenderId()) {
                     return true;
                 }
             }
 
-            var engine = scene.getEngine();
+            const scene = this.getScene();
+            const engine = scene.getEngine();
+
+            if (defines._areTexturesDirty) {
+                if (scene.texturesEnabled) {
+                    if (this._albedoTexture && StandardMaterial.DiffuseTextureEnabled) {
+                        if (!this._albedoTexture.isReadyOrNotBlocking()) {
+                            return false;
+                        }
+                    }
+
+                    if (this._ambientTexture && StandardMaterial.AmbientTextureEnabled) {
+                        if (!this._ambientTexture.isReadyOrNotBlocking()) {
+                            return false;
+                        }
+                    }
+
+                    if (this._opacityTexture && StandardMaterial.OpacityTextureEnabled) {
+                        if (!this._opacityTexture.isReadyOrNotBlocking()) {
+                            return false;
+                        }
+                    }
+
+                    var reflectionTexture = this._getReflectionTexture();
+                    if (reflectionTexture && StandardMaterial.ReflectionTextureEnabled) {
+                        if (!reflectionTexture.isReadyOrNotBlocking()) {
+                            return false;
+                        }
+                    }
+
+                    if (this._lightmapTexture && StandardMaterial.LightmapTextureEnabled) {
+                        if (!this._lightmapTexture.isReadyOrNotBlocking()) {
+                            return false;
+                        }
+                    }
+
+                    if (this._emissiveTexture && StandardMaterial.EmissiveTextureEnabled) {
+                        if (!this._emissiveTexture.isReadyOrNotBlocking()) {
+                            return false;
+                        }
+                    }
+
+                    if (StandardMaterial.SpecularTextureEnabled) {
+                        if (this._metallicTexture) {
+                            if (!this._metallicTexture.isReadyOrNotBlocking()) {
+                                return false;
+                            }
+                        }
+                        else if (this._reflectivityTexture) {
+                            if (!this._reflectivityTexture.isReadyOrNotBlocking()) {
+                                return false;
+                            }
+                        }
+
+                        if (this._microSurfaceTexture) {
+                            if (!this._microSurfaceTexture.isReadyOrNotBlocking()) {
+                                return false;
+                            }
+                        }
+                    }
+
+                    if (engine.getCaps().standardDerivatives && this._bumpTexture && StandardMaterial.BumpTextureEnabled && !this._disableBumpMap) {
+                        // Bump texture cannot be not blocking.
+                        if (!this._bumpTexture.isReady()) {
+                            return false;
+                        }
+                    }
+
+                    var refractionTexture = this._getRefractionTexture();
+                    if (refractionTexture && StandardMaterial.RefractionTextureEnabled) {
+                        if (!refractionTexture.isReadyOrNotBlocking()) {
+                            return false;
+                        }
+                    }
+
+                    if (this._environmentBRDFTexture && StandardMaterial.ReflectionTextureEnabled) {
+                        // This is blocking.
+                        if (!this._environmentBRDFTexture.isReady()) {
+                            return false;
+                        }
+                    }
+                }
+            }
+
+            if (defines._areImageProcessingDirty) {
+                if (!this._imageProcessingConfiguration.isReady()) {
+                    return false;
+                }
+            }
+
+            if (!engine.getCaps().standardDerivatives) {
+                let bufferMesh = null;
+                if (mesh.getClassName() === "InstancedMesh") {
+                    bufferMesh = (mesh as InstancedMesh).sourceMesh;
+                }
+                else if (mesh.getClassName() === "Mesh") {
+                    bufferMesh = mesh as Mesh;
+                }
+
+                if (bufferMesh && bufferMesh.geometry && bufferMesh.geometry.isReady() && !bufferMesh.geometry.isVerticesDataPresent(VertexBuffer.NormalKind)) {
+                    bufferMesh.createNormals(true);
+                    Tools.Warn("PBRMaterial: Normals have been created for the mesh: " + bufferMesh.name);
+                }
+            }
+
+            const effect = this._prepareEffect(mesh, defines, this.onCompiled, this.onError, useInstances);
+            if (effect) {
+                scene.resetCachedMaterial();
+                subMesh.setEffect(effect, defines);
+                this.buildUniformLayout();
+            }
+
+            if (!subMesh.effect || !subMesh.effect.isReady()) {
+                return false;
+            }
+
+            defines._renderId = scene.getRenderId();
+            this._wasPreviouslyReady = true;
+
+            return true;
+        }
+
+        private _prepareEffect(mesh: AbstractMesh, defines: PBRMaterialDefines, onCompiled: Nullable<(effect: Effect) => void> = null, onError: Nullable<(effect: Effect, errors: string) => void> = null, useInstances: Nullable<boolean> = null, useClipPlane: Nullable<boolean> = null): Nullable<Effect> {
+            this._prepareDefines(mesh, defines, useInstances, useClipPlane);
+            if (!defines.isDirty) {
+                return null;
+            }
+
+            defines.markAsProcessed();
+
+            const scene = this.getScene();
+            const engine = scene.getEngine();
+
+            // Fallbacks
+            var fallbacks = new EffectFallbacks();
+            var fallbackRank = 0;
+            if (defines.USESPHERICALINVERTEX) {
+                fallbacks.addFallback(fallbackRank++, "USESPHERICALINVERTEX");
+            }
+
+            if (defines.FOG) {
+                fallbacks.addFallback(fallbackRank, "FOG");
+            }
+            if (defines.POINTSIZE) {
+                fallbacks.addFallback(fallbackRank, "POINTSIZE");
+            }
+            if (defines.LOGARITHMICDEPTH) {
+                fallbacks.addFallback(fallbackRank, "LOGARITHMICDEPTH");
+            }
+            if (defines.PARALLAX) {
+                fallbacks.addFallback(fallbackRank, "PARALLAX");
+            }
+            if (defines.PARALLAXOCCLUSION) {
+                fallbacks.addFallback(fallbackRank++, "PARALLAXOCCLUSION");
+            }
+
+            if (defines.ENVIRONMENTBRDF) {
+                fallbacks.addFallback(fallbackRank++, "ENVIRONMENTBRDF");
+            }
+
+            if (defines.TANGENT) {
+                fallbacks.addFallback(fallbackRank++, "TANGENT");
+            }
+
+            if (defines.BUMP) {
+                fallbacks.addFallback(fallbackRank++, "BUMP");
+            }
+
+            fallbackRank = MaterialHelper.HandleFallbacksForShadows(defines, fallbacks, this._maxSimultaneousLights, fallbackRank++);
+
+            if (defines.SPECULARTERM) {
+                fallbacks.addFallback(fallbackRank++, "SPECULARTERM");
+            }
+
+            if (defines.USESPHERICALFROMREFLECTIONMAP) {
+                fallbacks.addFallback(fallbackRank++, "USESPHERICALFROMREFLECTIONMAP");
+            }
+
+            if (defines.LIGHTMAP) {
+                fallbacks.addFallback(fallbackRank++, "LIGHTMAP");
+            }
+
+            if (defines.NORMAL) {
+                fallbacks.addFallback(fallbackRank++, "NORMAL");
+            }
+
+            if (defines.AMBIENT) {
+                fallbacks.addFallback(fallbackRank++, "AMBIENT");
+            }
+
+            if (defines.EMISSIVE) {
+                fallbacks.addFallback(fallbackRank++, "EMISSIVE");
+            }
+
+            if (defines.VERTEXCOLOR) {
+                fallbacks.addFallback(fallbackRank++, "VERTEXCOLOR");
+            }
+
+            if (defines.NUM_BONE_INFLUENCERS > 0) {
+                fallbacks.addCPUSkinningFallback(fallbackRank++, mesh);
+            }
+
+            if (defines.MORPHTARGETS) {
+                fallbacks.addFallback(fallbackRank++, "MORPHTARGETS");
+            }
+
+            //Attributes
+            var attribs = [VertexBuffer.PositionKind];
+
+            if (defines.NORMAL) {
+                attribs.push(VertexBuffer.NormalKind);
+            }
+
+            if (defines.TANGENT) {
+                attribs.push(VertexBuffer.TangentKind);
+            }
+
+            if (defines.UV1) {
+                attribs.push(VertexBuffer.UVKind);
+            }
+
+            if (defines.UV2) {
+                attribs.push(VertexBuffer.UV2Kind);
+            }
+
+            if (defines.VERTEXCOLOR) {
+                attribs.push(VertexBuffer.ColorKind);
+            }
+
+            MaterialHelper.PrepareAttributesForBones(attribs, mesh, defines, fallbacks);
+            MaterialHelper.PrepareAttributesForInstances(attribs, defines);
+            MaterialHelper.PrepareAttributesForMorphTargets(attribs, mesh, defines);
+
+            var uniforms = ["world", "view", "viewProjection", "vEyePosition", "vLightsType", "vAmbientColor", "vAlbedoColor", "vReflectivityColor", "vEmissiveColor", "vReflectionColor",
+                "vFogInfos", "vFogColor", "pointSize",
+                "vAlbedoInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vReflectionPosition", "vReflectionSize", "vEmissiveInfos", "vReflectivityInfos", 
+                "vMicroSurfaceSamplerInfos", "vBumpInfos", "vLightmapInfos", "vRefractionInfos",
+                "mBones",
+                "vClipPlane", "albedoMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "reflectivityMatrix", "microSurfaceSamplerMatrix", "bumpMatrix", "lightmapMatrix", "refractionMatrix",
+                "vLightingIntensity",
+                "logarithmicDepthConstant",
+                "vSphericalX", "vSphericalY", "vSphericalZ",
+                "vSphericalXX", "vSphericalYY", "vSphericalZZ",
+                "vSphericalXY", "vSphericalYZ", "vSphericalZX",
+                "vReflectionMicrosurfaceInfos", "vRefractionMicrosurfaceInfos",
+                "vTangentSpaceParams"
+            ];
+
+            var samplers = ["albedoSampler", "reflectivitySampler", "ambientSampler", "emissiveSampler",
+                "bumpSampler", "lightmapSampler", "opacitySampler",
+                "refractionSampler", "refractionSamplerLow", "refractionSamplerHigh",
+                "reflectionSampler", "reflectionSamplerLow", "reflectionSamplerHigh",
+                "microSurfaceSampler", "environmentBrdfSampler"];
+            var uniformBuffers = ["Material", "Scene"];
+
+            ImageProcessingConfiguration.PrepareUniforms(uniforms, defines);
+            ImageProcessingConfiguration.PrepareSamplers(samplers, defines);
+
+            MaterialHelper.PrepareUniformsAndSamplersList(<EffectCreationOptions>{
+                uniformsNames: uniforms,
+                uniformBuffersNames: uniformBuffers,
+                samplers: samplers,
+                defines: defines,
+                maxSimultaneousLights: this._maxSimultaneousLights
+            });
+
+            var join = defines.toString();
+            return engine.createEffect("pbr", <EffectCreationOptions>{
+                attributes: attribs,
+                uniformsNames: uniforms,
+                uniformBuffersNames: uniformBuffers,
+                samplers: samplers,
+                defines: join,
+                fallbacks: fallbacks,
+                onCompiled: onCompiled,
+                onError: onError,
+                indexParameters: { maxSimultaneousLights: this._maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS }
+            }, engine);
+        }
+
+        private _prepareDefines(mesh: AbstractMesh, defines: PBRMaterialDefines, useInstances: Nullable<boolean> = null, useClipPlane: Nullable<boolean> = null): void {
+            const scene = this.getScene();
+            const engine = scene.getEngine();
 
             // Lights
             MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, true, this._maxSimultaneousLights, this._disableLighting);
@@ -709,20 +991,12 @@
                     }
 
                     if (this._albedoTexture && StandardMaterial.DiffuseTextureEnabled) {
-                        if (!this._albedoTexture.isReadyOrNotBlocking()) {
-                            return false;
-                        }
-
                         MaterialHelper.PrepareDefinesForMergedUV(this._albedoTexture, defines, "ALBEDO");
                     } else {
                         defines.ALBEDO = false;
                     }
 
                     if (this._ambientTexture && StandardMaterial.AmbientTextureEnabled) {
-                        if (!this._ambientTexture.isReadyOrNotBlocking()) {
-                            return false;
-                        }
-
                         MaterialHelper.PrepareDefinesForMergedUV(this._ambientTexture, defines, "AMBIENT");
                         defines.AMBIENTINGRAYSCALE = this._useAmbientInGrayScale;
                     } else {
@@ -730,10 +1004,6 @@
                     }
 
                     if (this._opacityTexture && StandardMaterial.OpacityTextureEnabled) {
-                        if (!this._opacityTexture.isReadyOrNotBlocking()) {
-                            return false;
-                        }
-
                         MaterialHelper.PrepareDefinesForMergedUV(this._opacityTexture, defines, "OPACITY");
                         defines.OPACITYRGB = this._opacityTexture.getAlphaFromRGB;
                     } else {
@@ -742,10 +1012,6 @@
 
                     var reflectionTexture = this._getReflectionTexture();
                     if (reflectionTexture && StandardMaterial.ReflectionTextureEnabled) {
-                        if (!reflectionTexture.isReadyOrNotBlocking()) {
-                            return false;
-                        }
-
                         defines.REFLECTION = true;
                         defines.GAMMAREFLECTION = reflectionTexture.gammaSpace;
                         defines.REFLECTIONMAP_OPPOSITEZ = this.getScene().useRightHandedSystem ? !reflectionTexture.invertZ : reflectionTexture.invertZ;
@@ -761,6 +1027,7 @@
                             case Texture.CUBIC_MODE:
                             case Texture.INVCUBIC_MODE:
                                 defines.REFLECTIONMAP_CUBIC = true;
+                                defines.USE_LOCAL_REFLECTIONMAP_CUBIC = (<any>reflectionTexture).boundingBoxSize ? true : false;
                                 break;
                             case Texture.EXPLICIT_MODE:
                                 defines.REFLECTIONMAP_EXPLICIT = true;
@@ -805,6 +1072,7 @@
                         defines.REFLECTIONMAP_SPHERICAL = false;
                         defines.REFLECTIONMAP_PLANAR = false;
                         defines.REFLECTIONMAP_CUBIC = false;
+                        defines.USE_LOCAL_REFLECTIONMAP_CUBIC = false;
                         defines.REFLECTIONMAP_PROJECTION = false;
                         defines.REFLECTIONMAP_SKYBOX = false;
                         defines.REFLECTIONMAP_EXPLICIT = false;
@@ -820,10 +1088,6 @@
                     }
 
                     if (this._lightmapTexture && StandardMaterial.LightmapTextureEnabled) {
-                        if (!this._lightmapTexture.isReadyOrNotBlocking()) {
-                            return false;
-                        }
-
                         MaterialHelper.PrepareDefinesForMergedUV(this._lightmapTexture, defines, "LIGHTMAP");
                         defines.USELIGHTMAPASSHADOWMAP = this._useLightmapAsShadowmap;
                     } else {
@@ -831,10 +1095,6 @@
                     }
 
                     if (this._emissiveTexture && StandardMaterial.EmissiveTextureEnabled) {
-                        if (!this._emissiveTexture.isReadyOrNotBlocking()) {
-                            return false;
-                        }
-
                         MaterialHelper.PrepareDefinesForMergedUV(this._emissiveTexture, defines, "EMISSIVE");
                     } else {
                         defines.EMISSIVE = false;
@@ -842,10 +1102,6 @@
 
                     if (StandardMaterial.SpecularTextureEnabled) {
                         if (this._metallicTexture) {
-                            if (!this._metallicTexture.isReadyOrNotBlocking()) {
-                                return false;
-                            }
-
                             MaterialHelper.PrepareDefinesForMergedUV(this._metallicTexture, defines, "REFLECTIVITY");
                             defines.METALLICWORKFLOW = true;
                             defines.ROUGHNESSSTOREINMETALMAPALPHA = this._useRoughnessFromMetallicTextureAlpha;
@@ -854,10 +1110,6 @@
                             defines.AOSTOREINMETALMAPRED = this._useAmbientOcclusionFromMetallicTextureRed;
                         }
                         else if (this._reflectivityTexture) {
-                            if (!this._reflectivityTexture.isReadyOrNotBlocking()) {
-                                return false;
-                            }
-
                             defines.METALLICWORKFLOW = false;
                             MaterialHelper.PrepareDefinesForMergedUV(this._reflectivityTexture, defines, "REFLECTIVITY");
                             defines.MICROSURFACEFROMREFLECTIVITYMAP = this._useMicroSurfaceFromReflectivityMapAlpha;
@@ -868,10 +1120,6 @@
                         }
 
                         if (this._microSurfaceTexture) {
-                            if (!this._microSurfaceTexture.isReadyOrNotBlocking()) {
-                                return false;
-                            }
-
                             MaterialHelper.PrepareDefinesForMergedUV(this._microSurfaceTexture, defines, "MICROSURFACEMAP");
                         } else {
                             defines.MICROSURFACEMAP = false;
@@ -882,11 +1130,6 @@
                     }
 
                     if (scene.getEngine().getCaps().standardDerivatives && this._bumpTexture && StandardMaterial.BumpTextureEnabled && !this._disableBumpMap) {
-                        // Bump texure can not be none blocking.
-                        if (!this._bumpTexture.isReady()) {
-                            return false;
-                        }
-
                         MaterialHelper.PrepareDefinesForMergedUV(this._bumpTexture, defines, "BUMP");
 
                         if (this._useParallax && this._albedoTexture && StandardMaterial.DiffuseTextureEnabled) {
@@ -902,10 +1145,6 @@
 
                     var refractionTexture = this._getRefractionTexture();
                     if (refractionTexture && StandardMaterial.RefractionTextureEnabled) {
-                        if (!refractionTexture.isReadyOrNotBlocking()) {
-                            return false;
-                        }
-
                         defines.REFRACTION = true;
                         defines.REFRACTIONMAP_3D = refractionTexture.isCube;
                         defines.GAMMAREFRACTION = refractionTexture.gammaSpace;
@@ -920,10 +1159,6 @@
                     }
 
                     if (this._environmentBRDFTexture && StandardMaterial.ReflectionTextureEnabled) {
-                        // This is blocking.
-                        if (!this._environmentBRDFTexture.isReady()) {
-                            return false;
-                        }
                         defines.ENVIRONMENTBRDF = true;
                     } else {
                         defines.ENVIRONMENTBRDF = false;
@@ -934,7 +1169,6 @@
                     } else {
                         defines.ALPHAFROMALBEDO = false;
                     }
-
                 }
 
                 defines.SPECULAROVERALPHA = this._useSpecularOverAlpha;
@@ -963,10 +1197,6 @@
             }
 
             if (defines._areImageProcessingDirty) {
-                if (!this._imageProcessingConfiguration.isReady()) {
-                    return false;
-                }
-
                 this._imageProcessingConfiguration.prepareDefines(defines);
             }
 
@@ -980,221 +1210,35 @@
             MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh) || this._forceAlphaTest, defines);
 
             // Values that need to be evaluated on every frame
-            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
+            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, useClipPlane);
 
             // Attribs
-            if (MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true, true, this._transparencyMode !== PBRMaterial.PBRMATERIAL_OPAQUE) && mesh) {
-                let bufferMesh = null;
-                if (mesh instanceof InstancedMesh) {
-                    bufferMesh = (mesh as InstancedMesh).sourceMesh;
-                }
-                else if (mesh instanceof Mesh) {
-                    bufferMesh = mesh as Mesh;
-                }
-
-                if (bufferMesh) {
-                    if (bufferMesh.isVerticesDataPresent(VertexBuffer.NormalKind)) {
-                        // If the first normal's components is the zero vector in one of the submeshes, we have invalid normals
-                        let normalVertexBuffer = bufferMesh.getVertexBuffer(VertexBuffer.NormalKind);
-                        let normals = normalVertexBuffer!.getData();
-                        let vertexBufferOffset = normalVertexBuffer!.getOffset();
-                        let strideSize = normalVertexBuffer!.getStrideSize();
-                        let offset = vertexBufferOffset + subMesh.indexStart * strideSize;
-
-                        if (normals![offset] === 0 && normals![offset + 1] === 0 && normals![offset + 2] === 0) {
-                            defines.NORMAL = false;
-                        }
-                        if (bufferMesh.isVerticesDataPresent(VertexBuffer.TangentKind)) {
-                            // If the first tangent's components is the zero vector in one of the submeshes, we have invalid tangents
-                            let tangentVertexBuffer = bufferMesh.getVertexBuffer(VertexBuffer.TangentKind);
-                            let tangents = tangentVertexBuffer!.getData();
-                            let vertexBufferOffset = tangentVertexBuffer!.getOffset();
-                            let strideSize = tangentVertexBuffer!.getStrideSize();
-                            let offset = vertexBufferOffset + subMesh.indexStart * strideSize;
-
-                            if (tangents![offset] === 0 && tangents![offset + 1] === 0 && tangents![offset + 2] === 0) {
-                                defines.TANGENT = false;
-                            }
-                        }
-                    }
-                    else {
-                        if (!scene.getEngine().getCaps().standardDerivatives) {
-                            bufferMesh.createNormals(true);
-                            Tools.Warn("PBRMaterial: Normals have been created for the mesh: " + bufferMesh.name);
-                        }
-                    }
-                }
-            }
-
-            // Get correct effect
-            if (defines.isDirty) {
-                defines.markAsProcessed();
-                scene.resetCachedMaterial();
-
-                // Fallbacks
-                var fallbacks = new EffectFallbacks();
-                var fallbackRank = 0;
-                if (defines.USESPHERICALINVERTEX) {
-                    fallbacks.addFallback(fallbackRank++, "USESPHERICALINVERTEX");
-                }
-
-                if (defines.FOG) {
-                    fallbacks.addFallback(fallbackRank, "FOG");
-                }
-                if (defines.POINTSIZE) {
-                    fallbacks.addFallback(fallbackRank, "POINTSIZE");
-                }
-                if (defines.LOGARITHMICDEPTH) {
-                    fallbacks.addFallback(fallbackRank, "LOGARITHMICDEPTH");
-                }
-                if (defines.PARALLAX) {
-                    fallbacks.addFallback(fallbackRank, "PARALLAX");
-                }
-                if (defines.PARALLAXOCCLUSION) {
-                    fallbacks.addFallback(fallbackRank++, "PARALLAXOCCLUSION");
-                }
-
-                if (defines.ENVIRONMENTBRDF) {
-                    fallbacks.addFallback(fallbackRank++, "ENVIRONMENTBRDF");
-                }
-
-                if (defines.TANGENT) {
-                    fallbacks.addFallback(fallbackRank++, "TANGENT");
-                }
-
-                if (defines.BUMP) {
-                    fallbacks.addFallback(fallbackRank++, "BUMP");
-                }
-
-                fallbackRank = MaterialHelper.HandleFallbacksForShadows(defines, fallbacks, this._maxSimultaneousLights, fallbackRank++);
-
-                if (defines.SPECULARTERM) {
-                    fallbacks.addFallback(fallbackRank++, "SPECULARTERM");
-                }
-
-                if (defines.USESPHERICALFROMREFLECTIONMAP) {
-                    fallbacks.addFallback(fallbackRank++, "USESPHERICALFROMREFLECTIONMAP");
-                }
-
-                if (defines.LIGHTMAP) {
-                    fallbacks.addFallback(fallbackRank++, "LIGHTMAP");
-                }
-
-                if (defines.NORMAL) {
-                    fallbacks.addFallback(fallbackRank++, "NORMAL");
-                }
-
-                if (defines.AMBIENT) {
-                    fallbacks.addFallback(fallbackRank++, "AMBIENT");
-                }
-
-                if (defines.EMISSIVE) {
-                    fallbacks.addFallback(fallbackRank++, "EMISSIVE");
-                }
-
-                if (defines.VERTEXCOLOR) {
-                    fallbacks.addFallback(fallbackRank++, "VERTEXCOLOR");
-                }
-
-                if (defines.NUM_BONE_INFLUENCERS > 0) {
-                    fallbacks.addCPUSkinningFallback(fallbackRank++, mesh);
-                }
-
-                if (defines.MORPHTARGETS) {
-                    fallbacks.addFallback(fallbackRank++, "MORPHTARGETS");
-                }
-
-                //Attributes
-                var attribs = [VertexBuffer.PositionKind];
-
-                if (defines.NORMAL) {
-                    attribs.push(VertexBuffer.NormalKind);
-                }
-
-                if (defines.TANGENT) {
-                    attribs.push(VertexBuffer.TangentKind);
-                }
-
-                if (defines.UV1) {
-                    attribs.push(VertexBuffer.UVKind);
-                }
+            MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true, true, this._transparencyMode !== PBRMaterial.PBRMATERIAL_OPAQUE);
+        }
 
-                if (defines.UV2) {
-                    attribs.push(VertexBuffer.UV2Kind);
-                }
+        /**
+         * Force shader compilation
+         */
+        public forceCompilation(mesh: AbstractMesh, onCompiled?: (material: Material) => void, options?: Partial<{ clipPlane: boolean }>): void {
+            let localOptions = {
+                clipPlane: false,
+                ...options
+            };
 
-                if (defines.VERTEXCOLOR) {
-                    attribs.push(VertexBuffer.ColorKind);
+            const defines = new PBRMaterialDefines();
+            const effect = this._prepareEffect(mesh, defines, undefined, undefined, undefined, localOptions.clipPlane)!;
+            if (effect.isReady()) {
+                if (onCompiled) {
+                    onCompiled(this);
                 }
-
-                MaterialHelper.PrepareAttributesForBones(attribs, mesh, defines, fallbacks);
-                MaterialHelper.PrepareAttributesForInstances(attribs, defines);
-                MaterialHelper.PrepareAttributesForMorphTargets(attribs, mesh, defines);
-
-                var uniforms = ["world", "view", "viewProjection", "vEyePosition", "vLightsType", "vAmbientColor", "vAlbedoColor", "vReflectivityColor", "vEmissiveColor", "vReflectionColor",
-                    "vFogInfos", "vFogColor", "pointSize",
-                    "vAlbedoInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vEmissiveInfos", "vReflectivityInfos", "vMicroSurfaceSamplerInfos", "vBumpInfos", "vLightmapInfos", "vRefractionInfos",
-                    "mBones",
-                    "vClipPlane", "albedoMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "reflectivityMatrix", "microSurfaceSamplerMatrix", "bumpMatrix", "lightmapMatrix", "refractionMatrix",
-                    "vLightingIntensity",
-                    "logarithmicDepthConstant",
-                    "vSphericalX", "vSphericalY", "vSphericalZ",
-                    "vSphericalXX", "vSphericalYY", "vSphericalZZ",
-                    "vSphericalXY", "vSphericalYZ", "vSphericalZX",
-                    "vReflectionMicrosurfaceInfos", "vRefractionMicrosurfaceInfos",
-                    "vTangentSpaceParams"
-                ];
-
-                var samplers = ["albedoSampler", "reflectivitySampler", "ambientSampler", "emissiveSampler",
-                    "bumpSampler", "lightmapSampler", "opacitySampler",
-                    "refractionSampler", "refractionSamplerLow", "refractionSamplerHigh",
-                    "reflectionSampler", "reflectionSamplerLow", "reflectionSamplerHigh",
-                    "microSurfaceSampler", "environmentBrdfSampler"];
-                var uniformBuffers = ["Material", "Scene"];
-
-                ImageProcessingConfiguration.PrepareUniforms(uniforms, defines);
-                ImageProcessingConfiguration.PrepareSamplers(samplers, defines);
-
-                MaterialHelper.PrepareUniformsAndSamplersList(<EffectCreationOptions>{
-                    uniformsNames: uniforms,
-                    uniformBuffersNames: uniformBuffers,
-                    samplers: samplers,
-                    defines: defines,
-                    maxSimultaneousLights: this._maxSimultaneousLights
-                });
-
-                var onCompiled = (effect: Effect) => {
-                    if (this.onCompiled) {
-                        this.onCompiled(effect);
-                    }
-
-                    this.bindSceneUniformBuffer(effect, scene.getSceneUniformBuffer());
-                };
-
-                var join = defines.toString();
-                subMesh.setEffect(scene.getEngine().createEffect("pbr", <EffectCreationOptions>{
-                    attributes: attribs,
-                    uniformsNames: uniforms,
-                    uniformBuffersNames: uniformBuffers,
-                    samplers: samplers,
-                    defines: join,
-                    fallbacks: fallbacks,
-                    onCompiled: onCompiled,
-                    onError: this.onError,
-                    indexParameters: { maxSimultaneousLights: this._maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS }
-                }, engine), defines);
-
-                this.buildUniformLayout();
             }
-
-            if (!subMesh.effect || !subMesh.effect.isReady()) {
-                return false;
+            else {
+                effect.onCompileObservable.add(() => {
+                    if (onCompiled) {
+                        onCompiled(this);
+                    }
+                });
             }
-
-            defines._renderId = scene.getRenderId();
-            this._wasPreviouslyReady = true;
-
-            return true;
         }
 
         /**
@@ -1211,6 +1255,8 @@
             this._uniformBuffer.addUniform("vMicroSurfaceSamplerInfos", 2);
             this._uniformBuffer.addUniform("vRefractionInfos", 4);
             this._uniformBuffer.addUniform("vReflectionInfos", 2);
+            this._uniformBuffer.addUniform("vReflectionPosition", 3);
+            this._uniformBuffer.addUniform("vReflectionSize", 3);
             this._uniformBuffer.addUniform("vBumpInfos", 3);
             this._uniformBuffer.addUniform("albedoMatrix", 16);
             this._uniformBuffer.addUniform("ambientMatrix", 16);
@@ -1321,6 +1367,13 @@
                             this._uniformBuffer.updateMatrix("reflectionMatrix", reflectionTexture.getReflectionTextureMatrix());
                             this._uniformBuffer.updateFloat2("vReflectionInfos", reflectionTexture.level, 0);
 
+                            if ((<any>reflectionTexture).boundingBoxSize) {
+                                let cubeTexture = <CubeTexture>reflectionTexture;
+
+                                this._uniformBuffer.updateVector3("vReflectionPosition", cubeTexture.boundingBoxPosition);
+                                this._uniformBuffer.updateVector3("vReflectionSize", cubeTexture.boundingBoxSize);
+                            }                            
+
                             var polynomials = reflectionTexture.sphericalPolynomial;
                             if (defines.USESPHERICALFROMREFLECTIONMAP && polynomials) {
                                 this._activeEffect.setFloat3("vSphericalX", polynomials.x.x, polynomials.x.y, polynomials.x.z);

+ 28 - 0
src/Materials/Textures/babylon.cubeTexture.ts

@@ -3,6 +3,34 @@
         public url: string;
         public coordinatesMode = Texture.CUBIC_MODE;
 
+        /**
+         * Gets or sets the center of the bounding box associated with the cube texture
+         * It must define where the camera used to render the texture was set
+         */
+        public boundingBoxPosition = Vector3.Zero();
+
+        private _boundingBoxSize: Vector3;
+
+        /**
+         * Gets or sets the size of the bounding box associated with the cube texture
+         * When defined, the cubemap will switch to local mode
+         * @see https://community.arm.com/graphics/b/blog/posts/reflections-based-on-local-cubemaps-in-unity
+         * @example https://www.babylonjs-playground.com/#RNASML
+         */
+        public set boundingBoxSize(value: Vector3) {
+            if (this._boundingBoxSize && this._boundingBoxSize.equals(value)) {
+                return;
+            }
+            this._boundingBoxSize = value;
+            let scene = this.getScene();
+            if (scene) {
+                scene.markAllMaterialsAsDirty(Material.TextureDirtyFlag);
+            }
+        }
+        public get boundingBoxSize(): Vector3 {
+            return this._boundingBoxSize;
+        }
+
         private _noMipmap: boolean;
         private _files: string[];
         private _extensions: string[];

+ 28 - 0
src/Materials/Textures/babylon.renderTargetTexture.ts

@@ -128,6 +128,34 @@
             }
         }
 
+        /**
+         * Gets or sets the center of the bounding box associated with the texture (when in cube mode)
+         * It must define where the camera used to render the texture is set
+         */
+        public boundingBoxPosition = Vector3.Zero();
+
+        private _boundingBoxSize: Vector3;
+
+        /**
+         * Gets or sets the size of the bounding box associated with the texture (when in cube mode)
+         * When defined, the cubemap will switch to local mode
+         * @see https://community.arm.com/graphics/b/blog/posts/reflections-based-on-local-cubemaps-in-unity
+         * @example https://www.babylonjs-playground.com/#RNASML
+         */        
+        public set boundingBoxSize(value: Vector3) {
+            if (this._boundingBoxSize && this._boundingBoxSize.equals(value)) {
+                return;
+            }
+            this._boundingBoxSize = value;
+            let scene = this.getScene();
+            if (scene) {
+                scene.markAllMaterialsAsDirty(Material.TextureDirtyFlag);
+            }
+        }
+        public get boundingBoxSize(): Vector3 {
+            return this._boundingBoxSize;
+        }
+
         constructor(name: string, size: number | {width: number, height: number} | {ratio: number}, scene: Nullable<Scene>, generateMipMaps?: boolean, doNotChangeAspectRatio: boolean = true, type: number = Engine.TEXTURETYPE_UNSIGNED_INT, public isCube = false, samplingMode = Texture.TRILINEAR_SAMPLINGMODE, generateDepthBuffer = true, generateStencilBuffer = false, isMulti = false) {
             super(null, scene, !generateMipMaps);
             scene = this.getScene();

+ 8 - 10
src/Materials/Textures/babylon.texture.ts

@@ -182,7 +182,7 @@
             if (!scene) {
                 return;
             }
-            
+
             this.delayLoadState = Engine.DELAYLOADSTATE_LOADED;
             this._texture = this._getFromCache(this.url, this._noMipmap, this._samplingMode);
 
@@ -192,19 +192,17 @@
                     delete this._buffer;
                 }
             } else {
-                if (this._texture.isReady) {
-                    Tools.SetImmediate(() => {
-                        if (!this._delayedOnLoad) {
-                            return;
-                        }
-                        this._delayedOnLoad();
-                    });
-                } else {
-                    if (this._delayedOnLoad) {
+                if (this._delayedOnLoad) {
+                    if (this._texture.isReady) {
+                        Tools.SetImmediate(this._delayedOnLoad);
+                    } else {
                         this._texture.onLoadedObservable.add(this._delayedOnLoad);
                     }
                 }
             }
+
+            this._delayedOnLoad = null;
+            this._delayedOnError = null;
         }
 
         public updateSamplingMode(samplingMode: number): void {

+ 4 - 1
src/Materials/Textures/babylon.videoTexture.ts

@@ -92,18 +92,21 @@
             if (typeof src === "object") {
                 return src.toString();
             }
-    
+
             return src;
         };
     
         private _getVideo(src: string | string[] | HTMLVideoElement): HTMLVideoElement {
             if (src instanceof HTMLVideoElement) {
+                Tools.SetCorsBehavior(src.currentSrc, src);
                 return src;
             }
             const video: HTMLVideoElement = document.createElement("video");
             if (typeof src === "string") {
+                Tools.SetCorsBehavior(src, video);
                 video.src = src;
             } else {
+                Tools.SetCorsBehavior(src[0], video);
                 src.forEach(url => {
                     const source = document.createElement("source");
                     source.src = url;

+ 16 - 2
src/Materials/babylon.material.ts

@@ -1020,7 +1020,7 @@
         }
 
         /**
-         * Force shader compilation including textures ready check
+         * Force shader compilation
          * @param mesh - BJS mesh.
          * @param onCompiled - function to execute once the material is compiled.
          * @param options - options to pass to this function.
@@ -1069,7 +1069,7 @@
                     }
                 }
 
-                if (options && options.clipPlane) {
+                if (localOptions.clipPlane) {
                     scene.clipPlane = clipPlaneState;
                 }
             };
@@ -1078,6 +1078,20 @@
         }
 
         /**
+         * Force shader compilation.
+         * @param mesh The mesh that will use this material
+         * @param options Additional options for compiling the shaders
+         * @returns A promise that resolves when the compilation completes
+         */
+        public forceCompilationAsync(mesh: AbstractMesh, options?: Partial<{ clipPlane: boolean }>): Promise<void> {
+            return new Promise(resolve => {
+                this.forceCompilation(mesh, () => {
+                    resolve();
+                }, options);
+            });
+        }
+
+        /**
          * Marks a define in the material to indicate that it needs to be re-computed.
          * @param flag - Material define flag.
          */

+ 8 - 3
src/Materials/babylon.materialHelper.ts

@@ -84,12 +84,17 @@ module BABYLON {
          * @param engine defines the current engine
          * @param defines specifies the list of active defines
          * @param useInstances defines if instances have to be turned on
+         * @param useClipPlane defines if clip plane have to be turned on
          */
-        public static PrepareDefinesForFrameBoundValues(scene: Scene, engine: Engine, defines: any, useInstances: boolean): void {
+        public static PrepareDefinesForFrameBoundValues(scene: Scene, engine: Engine, defines: any, useInstances: boolean, useClipPlane: Nullable<boolean> = null): void {
             var changed = false;
 
-            if (defines["CLIPPLANE"] !== (scene.clipPlane !== undefined && scene.clipPlane !== null)) {
-                defines["CLIPPLANE"] = !defines["CLIPPLANE"];
+            if (useClipPlane == null) {
+                useClipPlane = (scene.clipPlane !== undefined && scene.clipPlane !== null);
+            }
+
+            if (defines["CLIPPLANE"] !== useClipPlane) {
+                defines["CLIPPLANE"] = useClipPlane;
                 changed = true;
             }
 

+ 14 - 0
src/Materials/babylon.standardMaterial.ts

@@ -1,4 +1,5 @@
 module BABYLON {
+    /** @ignore */
     export class StandardMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines {
         public MAINUV1 = false;
         public MAINUV2 = false;
@@ -52,6 +53,7 @@ module BABYLON {
         public REFLECTIONMAP_SPHERICAL = false;
         public REFLECTIONMAP_PLANAR = false;
         public REFLECTIONMAP_CUBIC = false;
+        public USE_LOCAL_REFLECTIONMAP_CUBIC = false;
         public REFLECTIONMAP_PROJECTION = false;
         public REFLECTIONMAP_SKYBOX = false;
         public REFLECTIONMAP_EXPLICIT = false;
@@ -616,6 +618,8 @@ module BABYLON {
                                     defines.setReflectionMode("REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED");
                                     break;
                             }
+
+                            defines.USE_LOCAL_REFLECTIONMAP_CUBIC = (<any>this._reflectionTexture).boundingBoxSize ? true : false;
                         }
                     } else {
                         defines.REFLECTION = false;
@@ -847,6 +851,7 @@ module BABYLON {
                     "mBones",
                     "vClipPlane", "diffuseMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "specularMatrix", "bumpMatrix", "lightmapMatrix", "refractionMatrix",
                     "diffuseLeftColor", "diffuseRightColor", "opacityParts", "reflectionLeftColor", "reflectionRightColor", "emissiveLeftColor", "emissiveRightColor", "refractionLeftColor", "refractionRightColor",
+                    "vReflectionPosition", "vReflectionSize",
                     "logarithmicDepthConstant", "vTangentSpaceParams"
                 ];
 
@@ -911,6 +916,8 @@ module BABYLON {
             this._uniformBuffer.addUniform("vAmbientInfos", 2);
             this._uniformBuffer.addUniform("vOpacityInfos", 2);
             this._uniformBuffer.addUniform("vReflectionInfos", 2);
+            this._uniformBuffer.addUniform("vReflectionPosition", 3);
+            this._uniformBuffer.addUniform("vReflectionSize", 3);
             this._uniformBuffer.addUniform("vEmissiveInfos", 2);
             this._uniformBuffer.addUniform("vLightmapInfos", 2);
             this._uniformBuffer.addUniform("vSpecularInfos", 2);
@@ -1024,6 +1031,13 @@ module BABYLON {
                         if (this._reflectionTexture && StandardMaterial.ReflectionTextureEnabled) {
                             this._uniformBuffer.updateFloat2("vReflectionInfos", this._reflectionTexture.level, this.roughness);
                             this._uniformBuffer.updateMatrix("reflectionMatrix", this._reflectionTexture.getReflectionTextureMatrix());
+
+                            if ((<any>this._reflectionTexture).boundingBoxSize) {
+                                let cubeTexture = <CubeTexture>this._reflectionTexture;
+
+                                this._uniformBuffer.updateVector3("vReflectionPosition", cubeTexture.boundingBoxPosition);
+                                this._uniformBuffer.updateVector3("vReflectionSize", cubeTexture.boundingBoxSize);
+                            }
                         }
 
                         if (this._emissiveTexture && StandardMaterial.EmissiveTextureEnabled) {

+ 0 - 0
src/Mesh/babylon.mesh.ts


Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov