瀏覽代碼

Merge branch 'master' into defaultPipelineDocs

Trevor Baron 7 年之前
父節點
當前提交
0358900248
共有 41 個文件被更改,包括 36461 次插入140739 次删除
  1. 13191 12257
      Playground/babylon.d.txt
  2. 4 2
      Tools/Gulp/config.json
  3. 69 112077
      Viewer/dist/viewer.js
  4. 69 1
      Viewer/dist/viewer.min.js
  5. 11248 10508
      dist/preview release/babylon.d.ts
  6. 48 48
      dist/preview release/babylon.js
  7. 1340 294
      dist/preview release/babylon.max.js
  8. 52 52
      dist/preview release/babylon.worker.js
  9. 5333 4401
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  10. 55 55
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  11. 1413 294
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  12. 1415 296
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  13. 1342 296
      dist/preview release/es6.js
  14. 15 0
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  15. 134 0
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  16. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  17. 15 0
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  18. 134 0
      dist/preview release/loaders/babylon.glTFFileLoader.js
  19. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  20. 125 0
      dist/preview release/loaders/babylonjs.loaders.js
  21. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  22. 15 0
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  23. 3 3
      dist/preview release/serializers/babylon.glTF2Serializer.js
  24. 61 60
      dist/preview release/viewer/babylon.viewer.js
  25. 3 1
      dist/preview release/what's new.md
  26. 119 0
      loaders/src/glTF/2.0/Extensions/KHR_lights.ts
  27. 5 0
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  28. 12 0
      loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts
  29. 13 4
      src/Engine/babylon.engine.ts
  30. 23 4
      src/Lights/babylon.shadowLight.ts
  31. 111 65
      src/Lights/babylon.spotLight.ts
  32. 21 0
      src/Loading/babylon.sceneLoader.ts
  33. 2 1
      src/Materials/babylon.materialHelper.ts
  34. 1 1
      src/Mesh/babylon.mesh.vertexData.ts
  35. 16 2
      src/Mesh/babylon.transformNode.ts
  36. 1 1
      src/Shaders/ShadersInclude/lightFragment.fx
  37. 6 5
      src/Shaders/ShadersInclude/lightsFragmentFunctions.fx
  38. 9 2
      src/Tools/babylon.promise.ts
  39. 24 0
      tests/unit/babylon/promises/babylon.promises.tests.ts
  40. 5 0
      tests/validation/integration.js
  41. 1 1
      tests/validation/validation.js

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


+ 4 - 2
Tools/Gulp/config.json

@@ -1465,7 +1465,8 @@
                     "../../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"
+                    "../../loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts",
+                    "../../loaders/src/glTF/2.0/Extensions/KHR_lights.ts"
                 ],
                 "doNotIncludeInBundle": true,
                 "output": "babylon.glTF2FileLoader.js"
@@ -1484,7 +1485,8 @@
                     "../../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"
+                    "../../loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts",
+                    "../../loaders/src/glTF/2.0/Extensions/KHR_lights.ts"
                 ],
                 "output": "babylon.glTFFileLoader.js"
             }

File diff suppressed because it is too large
+ 69 - 112077
Viewer/dist/viewer.js


File diff suppressed because it is too large
+ 69 - 1
Viewer/dist/viewer.min.js


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


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


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


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


File diff suppressed because it is too large
+ 5333 - 4401
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


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


File diff suppressed because it is too large
+ 1413 - 294
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


File diff suppressed because it is too large
+ 1415 - 296
dist/preview release/customConfigurations/minimalGLTFViewer/es6.js


File diff suppressed because it is too large
+ 1342 - 296
dist/preview release/es6.js


+ 15 - 0
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -521,10 +521,14 @@ declare module BABYLON.GLTF2 {
         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);
@@ -555,3 +559,14 @@ declare module BABYLON.GLTF2.Extensions {
         private _loadSpecularGlossinessProperties(loader, context, material, properties);
     }
 }
+
+
+declare module BABYLON.GLTF2.Extensions {
+    class KHRLights 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;
+    }
+}

+ 134 - 0
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -626,6 +626,8 @@ var BABYLON;
                 GLTFLoader._AssignIndices(this._gltf.scenes);
                 GLTFLoader._AssignIndices(this._gltf.skins);
                 GLTFLoader._AssignIndices(this._gltf.textures);
+                // Handle global extensions as they may add their own data types.
+                GLTF2.GLTFLoaderExtension.LoadRoot(this, "#/", this._gltf);
                 if (data.bin) {
                     var buffers = this._gltf.buffers;
                     if (buffers && buffers[0] && !buffers[0].uri) {
@@ -709,6 +711,7 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadScene = function (context, scene, nodeNames) {
                 var _this = this;
+                GLTF2.GLTFLoaderExtension.LoadScene(this, context, scene);
                 this._rootNode = { babylonMesh: new BABYLON.Mesh("__root__", this._babylonScene) };
                 switch (this.coordinateSystemMode) {
                     case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO: {
@@ -2153,6 +2156,8 @@ var BABYLON;
             }
             GLTFLoaderExtension.prototype._traverseNode = function (loader, context, node, action, parentNode) { return false; };
             GLTFLoaderExtension.prototype._loadNode = function (loader, context, node) { return false; };
+            GLTFLoaderExtension.prototype._loadRoot = function (loader, context, root) { return false; };
+            GLTFLoaderExtension.prototype._loadScene = function (loader, context, scene) { return false; };
             GLTFLoaderExtension.prototype._loadMaterial = function (loader, context, material, assign) { return false; };
             GLTFLoaderExtension.prototype._loadExtension = function (context, property, action) {
                 var _this = this;
@@ -2174,6 +2179,12 @@ var BABYLON;
             GLTFLoaderExtension.TraverseNode = function (loader, context, node, action, parentNode) {
                 return this._ApplyExtensions(function (extension) { return extension._traverseNode(loader, context, node, action, parentNode); });
             };
+            GLTFLoaderExtension.LoadRoot = function (loader, context, root) {
+                return this._ApplyExtensions(function (extension) { return extension._loadRoot(loader, context, root); });
+            };
+            GLTFLoaderExtension.LoadScene = function (loader, context, scene) {
+                return this._ApplyExtensions(function (extension) { return extension._loadScene(loader, context, scene); });
+            };
             GLTFLoaderExtension.LoadNode = function (loader, context, node) {
                 return this._ApplyExtensions(function (extension) { return extension._loadNode(loader, context, node); });
             };
@@ -2419,3 +2430,126 @@ var BABYLON;
 })(BABYLON || (BABYLON = {}));
 
 //# sourceMappingURL=KHR_materials_pbrSpecularGlossiness.js.map
+
+/// <reference path="../../../../../dist/preview release/babylon.d.ts"/>
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+var BABYLON;
+(function (BABYLON) {
+    var GLTF2;
+    (function (GLTF2) {
+        var Extensions;
+        (function (Extensions) {
+            var KHRLights = /** @class */ (function (_super) {
+                __extends(KHRLights, _super);
+                function KHRLights() {
+                    return _super !== null && _super.apply(this, arguments) || this;
+                }
+                Object.defineProperty(KHRLights.prototype, "name", {
+                    get: function () {
+                        return "KHR_lights";
+                    },
+                    enumerable: true,
+                    configurable: true
+                });
+                KHRLights.prototype.applyCommonProperties = function (light, lightInfo) {
+                    if (lightInfo.color) {
+                        light.diffuse.copyFromFloats(lightInfo.color[0], lightInfo.color[1], lightInfo.color[2]);
+                    }
+                    else {
+                        light.diffuse.copyFromFloats(1, 1, 1);
+                    }
+                    if (lightInfo.intensity !== undefined) {
+                        light.intensity = lightInfo.intensity;
+                    }
+                    else {
+                        light.intensity = 1;
+                    }
+                };
+                KHRLights.prototype._loadScene = function (loader, context, scene) {
+                    return this._loadExtension(context, scene, function (context, extension, onComplete) {
+                        if (extension.light >= 0 && loader._gltf.extensions) {
+                            var lightInfo = loader._gltf.extensions.KHR_lights.lights[extension.light];
+                            if (lightInfo.type !== 'ambient') {
+                                return;
+                            }
+                            var lightColor = lightInfo.color ? lightInfo.color : [1, 1, 1];
+                            loader._babylonScene.ambientColor.copyFromFloats(lightColor[0], lightColor[1], lightColor[2]);
+                        }
+                        onComplete();
+                    });
+                };
+                KHRLights.prototype._loadNode = function (loader, context, node) {
+                    var _this = this;
+                    return this._loadExtension(context, node, function (context, extension, onComplete) {
+                        if (extension.light >= 0 && loader._gltf.extensions) {
+                            var lightInfo = loader._gltf.extensions.KHR_lights.lights[extension.light];
+                            var name_1 = node.name || 'Light';
+                            var matrix = void 0;
+                            if (node.matrix) {
+                                matrix = BABYLON.Matrix.FromArray(node.matrix);
+                            }
+                            else {
+                                matrix = BABYLON.Matrix.Identity();
+                            }
+                            var direction = new BABYLON.Vector3(0, 0, 1);
+                            if (lightInfo.type == 'directional' || lightInfo.type == 'spot') {
+                                var rotationMatrix = matrix.getRotationMatrix();
+                                BABYLON.Vector3.TransformCoordinatesToRef(direction, rotationMatrix, direction);
+                            }
+                            var light = void 0;
+                            if (lightInfo.type == 'directional') {
+                                light = new BABYLON.DirectionalLight(name_1, direction, loader._babylonScene);
+                            }
+                            else {
+                                var position = matrix.getTranslation();
+                                if (lightInfo.type == 'spot') {
+                                    var angle = lightInfo.spot && lightInfo.spot.outerConeAngle ? lightInfo.spot.outerConeAngle : Math.PI / 2;
+                                    light = new BABYLON.SpotLight(name_1, position, direction, angle, 2, loader._babylonScene);
+                                }
+                                else {
+                                    light = new BABYLON.PointLight(name_1, position, loader._babylonScene);
+                                }
+                            }
+                            _this.applyCommonProperties(light, lightInfo);
+                            extension.babylonLight = light;
+                            extension.babylonLight.parent = node.parent ? node.parent.babylonMesh : null;
+                            if (node.children) {
+                                for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
+                                    var index = _a[_i];
+                                    var childNode = GLTF2.GLTFLoader._GetProperty(loader._gltf.nodes, index);
+                                    if (!childNode) {
+                                        throw new Error(context + ": Failed to find child node " + index);
+                                    }
+                                    loader._loadNode("#/nodes/" + index, childNode);
+                                }
+                            }
+                        }
+                        onComplete();
+                    });
+                };
+                KHRLights.prototype._loadRoot = function (loader, context, root) {
+                    return this._loadExtension(context, root, function (context, extension, onComplete) {
+                        extension.lights.forEach(function (light, idx) {
+                            light.index = idx;
+                        });
+                        onComplete();
+                    });
+                };
+                return KHRLights;
+            }(GLTF2.GLTFLoaderExtension));
+            Extensions.KHRLights = KHRLights;
+            GLTF2.GLTFLoader.RegisterExtension(new KHRLights());
+        })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
+    })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=KHR_lights.js.map

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


+ 15 - 0
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -1078,10 +1078,14 @@ declare module BABYLON.GLTF2 {
         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);
@@ -1112,3 +1116,14 @@ declare module BABYLON.GLTF2.Extensions {
         private _loadSpecularGlossinessProperties(loader, context, material, properties);
     }
 }
+
+
+declare module BABYLON.GLTF2.Extensions {
+    class KHRLights 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;
+    }
+}

+ 134 - 0
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -2792,6 +2792,8 @@ var BABYLON;
                 GLTFLoader._AssignIndices(this._gltf.scenes);
                 GLTFLoader._AssignIndices(this._gltf.skins);
                 GLTFLoader._AssignIndices(this._gltf.textures);
+                // Handle global extensions as they may add their own data types.
+                GLTF2.GLTFLoaderExtension.LoadRoot(this, "#/", this._gltf);
                 if (data.bin) {
                     var buffers = this._gltf.buffers;
                     if (buffers && buffers[0] && !buffers[0].uri) {
@@ -2875,6 +2877,7 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadScene = function (context, scene, nodeNames) {
                 var _this = this;
+                GLTF2.GLTFLoaderExtension.LoadScene(this, context, scene);
                 this._rootNode = { babylonMesh: new BABYLON.Mesh("__root__", this._babylonScene) };
                 switch (this.coordinateSystemMode) {
                     case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO: {
@@ -4319,6 +4322,8 @@ var BABYLON;
             }
             GLTFLoaderExtension.prototype._traverseNode = function (loader, context, node, action, parentNode) { return false; };
             GLTFLoaderExtension.prototype._loadNode = function (loader, context, node) { return false; };
+            GLTFLoaderExtension.prototype._loadRoot = function (loader, context, root) { return false; };
+            GLTFLoaderExtension.prototype._loadScene = function (loader, context, scene) { return false; };
             GLTFLoaderExtension.prototype._loadMaterial = function (loader, context, material, assign) { return false; };
             GLTFLoaderExtension.prototype._loadExtension = function (context, property, action) {
                 var _this = this;
@@ -4340,6 +4345,12 @@ var BABYLON;
             GLTFLoaderExtension.TraverseNode = function (loader, context, node, action, parentNode) {
                 return this._ApplyExtensions(function (extension) { return extension._traverseNode(loader, context, node, action, parentNode); });
             };
+            GLTFLoaderExtension.LoadRoot = function (loader, context, root) {
+                return this._ApplyExtensions(function (extension) { return extension._loadRoot(loader, context, root); });
+            };
+            GLTFLoaderExtension.LoadScene = function (loader, context, scene) {
+                return this._ApplyExtensions(function (extension) { return extension._loadScene(loader, context, scene); });
+            };
             GLTFLoaderExtension.LoadNode = function (loader, context, node) {
                 return this._ApplyExtensions(function (extension) { return extension._loadNode(loader, context, node); });
             };
@@ -4585,3 +4596,126 @@ var BABYLON;
 })(BABYLON || (BABYLON = {}));
 
 //# sourceMappingURL=KHR_materials_pbrSpecularGlossiness.js.map
+
+/// <reference path="../../../../../dist/preview release/babylon.d.ts"/>
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+var BABYLON;
+(function (BABYLON) {
+    var GLTF2;
+    (function (GLTF2) {
+        var Extensions;
+        (function (Extensions) {
+            var KHRLights = /** @class */ (function (_super) {
+                __extends(KHRLights, _super);
+                function KHRLights() {
+                    return _super !== null && _super.apply(this, arguments) || this;
+                }
+                Object.defineProperty(KHRLights.prototype, "name", {
+                    get: function () {
+                        return "KHR_lights";
+                    },
+                    enumerable: true,
+                    configurable: true
+                });
+                KHRLights.prototype.applyCommonProperties = function (light, lightInfo) {
+                    if (lightInfo.color) {
+                        light.diffuse.copyFromFloats(lightInfo.color[0], lightInfo.color[1], lightInfo.color[2]);
+                    }
+                    else {
+                        light.diffuse.copyFromFloats(1, 1, 1);
+                    }
+                    if (lightInfo.intensity !== undefined) {
+                        light.intensity = lightInfo.intensity;
+                    }
+                    else {
+                        light.intensity = 1;
+                    }
+                };
+                KHRLights.prototype._loadScene = function (loader, context, scene) {
+                    return this._loadExtension(context, scene, function (context, extension, onComplete) {
+                        if (extension.light >= 0 && loader._gltf.extensions) {
+                            var lightInfo = loader._gltf.extensions.KHR_lights.lights[extension.light];
+                            if (lightInfo.type !== 'ambient') {
+                                return;
+                            }
+                            var lightColor = lightInfo.color ? lightInfo.color : [1, 1, 1];
+                            loader._babylonScene.ambientColor.copyFromFloats(lightColor[0], lightColor[1], lightColor[2]);
+                        }
+                        onComplete();
+                    });
+                };
+                KHRLights.prototype._loadNode = function (loader, context, node) {
+                    var _this = this;
+                    return this._loadExtension(context, node, function (context, extension, onComplete) {
+                        if (extension.light >= 0 && loader._gltf.extensions) {
+                            var lightInfo = loader._gltf.extensions.KHR_lights.lights[extension.light];
+                            var name_1 = node.name || 'Light';
+                            var matrix = void 0;
+                            if (node.matrix) {
+                                matrix = BABYLON.Matrix.FromArray(node.matrix);
+                            }
+                            else {
+                                matrix = BABYLON.Matrix.Identity();
+                            }
+                            var direction = new BABYLON.Vector3(0, 0, 1);
+                            if (lightInfo.type == 'directional' || lightInfo.type == 'spot') {
+                                var rotationMatrix = matrix.getRotationMatrix();
+                                BABYLON.Vector3.TransformCoordinatesToRef(direction, rotationMatrix, direction);
+                            }
+                            var light = void 0;
+                            if (lightInfo.type == 'directional') {
+                                light = new BABYLON.DirectionalLight(name_1, direction, loader._babylonScene);
+                            }
+                            else {
+                                var position = matrix.getTranslation();
+                                if (lightInfo.type == 'spot') {
+                                    var angle = lightInfo.spot && lightInfo.spot.outerConeAngle ? lightInfo.spot.outerConeAngle : Math.PI / 2;
+                                    light = new BABYLON.SpotLight(name_1, position, direction, angle, 2, loader._babylonScene);
+                                }
+                                else {
+                                    light = new BABYLON.PointLight(name_1, position, loader._babylonScene);
+                                }
+                            }
+                            _this.applyCommonProperties(light, lightInfo);
+                            extension.babylonLight = light;
+                            extension.babylonLight.parent = node.parent ? node.parent.babylonMesh : null;
+                            if (node.children) {
+                                for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
+                                    var index = _a[_i];
+                                    var childNode = GLTF2.GLTFLoader._GetProperty(loader._gltf.nodes, index);
+                                    if (!childNode) {
+                                        throw new Error(context + ": Failed to find child node " + index);
+                                    }
+                                    loader._loadNode("#/nodes/" + index, childNode);
+                                }
+                            }
+                        }
+                        onComplete();
+                    });
+                };
+                KHRLights.prototype._loadRoot = function (loader, context, root) {
+                    return this._loadExtension(context, root, function (context, extension, onComplete) {
+                        extension.lights.forEach(function (light, idx) {
+                            light.index = idx;
+                        });
+                        onComplete();
+                    });
+                };
+                return KHRLights;
+            }(GLTF2.GLTFLoaderExtension));
+            Extensions.KHRLights = KHRLights;
+            GLTF2.GLTFLoader.RegisterExtension(new KHRLights());
+        })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
+    })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=KHR_lights.js.map

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


+ 125 - 0
dist/preview release/loaders/babylonjs.loaders.js

@@ -3766,6 +3766,8 @@ var BABYLON;
                 GLTFLoader._AssignIndices(this._gltf.scenes);
                 GLTFLoader._AssignIndices(this._gltf.skins);
                 GLTFLoader._AssignIndices(this._gltf.textures);
+                // Handle global extensions as they may add their own data types.
+                GLTF2.GLTFLoaderExtension.LoadRoot(this, "#/", this._gltf);
                 if (data.bin) {
                     var buffers = this._gltf.buffers;
                     if (buffers && buffers[0] && !buffers[0].uri) {
@@ -3849,6 +3851,7 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadScene = function (context, scene, nodeNames) {
                 var _this = this;
+                GLTF2.GLTFLoaderExtension.LoadScene(this, context, scene);
                 this._rootNode = { babylonMesh: new BABYLON.Mesh("__root__", this._babylonScene) };
                 switch (this.coordinateSystemMode) {
                     case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO: {
@@ -5293,6 +5296,8 @@ var BABYLON;
             }
             GLTFLoaderExtension.prototype._traverseNode = function (loader, context, node, action, parentNode) { return false; };
             GLTFLoaderExtension.prototype._loadNode = function (loader, context, node) { return false; };
+            GLTFLoaderExtension.prototype._loadRoot = function (loader, context, root) { return false; };
+            GLTFLoaderExtension.prototype._loadScene = function (loader, context, scene) { return false; };
             GLTFLoaderExtension.prototype._loadMaterial = function (loader, context, material, assign) { return false; };
             GLTFLoaderExtension.prototype._loadExtension = function (context, property, action) {
                 var _this = this;
@@ -5314,6 +5319,12 @@ var BABYLON;
             GLTFLoaderExtension.TraverseNode = function (loader, context, node, action, parentNode) {
                 return this._ApplyExtensions(function (extension) { return extension._traverseNode(loader, context, node, action, parentNode); });
             };
+            GLTFLoaderExtension.LoadRoot = function (loader, context, root) {
+                return this._ApplyExtensions(function (extension) { return extension._loadRoot(loader, context, root); });
+            };
+            GLTFLoaderExtension.LoadScene = function (loader, context, scene) {
+                return this._ApplyExtensions(function (extension) { return extension._loadScene(loader, context, scene); });
+            };
             GLTFLoaderExtension.LoadNode = function (loader, context, node) {
                 return this._ApplyExtensions(function (extension) { return extension._loadNode(loader, context, node); });
             };
@@ -5543,6 +5554,120 @@ var BABYLON;
 //# sourceMappingURL=KHR_materials_pbrSpecularGlossiness.js.map
 
 
+
+var BABYLON;
+(function (BABYLON) {
+    var GLTF2;
+    (function (GLTF2) {
+        var Extensions;
+        (function (Extensions) {
+            var KHRLights = /** @class */ (function (_super) {
+                __extends(KHRLights, _super);
+                function KHRLights() {
+                    return _super !== null && _super.apply(this, arguments) || this;
+                }
+                Object.defineProperty(KHRLights.prototype, "name", {
+                    get: function () {
+                        return "KHR_lights";
+                    },
+                    enumerable: true,
+                    configurable: true
+                });
+                KHRLights.prototype.applyCommonProperties = function (light, lightInfo) {
+                    if (lightInfo.color) {
+                        light.diffuse.copyFromFloats(lightInfo.color[0], lightInfo.color[1], lightInfo.color[2]);
+                    }
+                    else {
+                        light.diffuse.copyFromFloats(1, 1, 1);
+                    }
+                    if (lightInfo.intensity !== undefined) {
+                        light.intensity = lightInfo.intensity;
+                    }
+                    else {
+                        light.intensity = 1;
+                    }
+                };
+                KHRLights.prototype._loadScene = function (loader, context, scene) {
+                    return this._loadExtension(context, scene, function (context, extension, onComplete) {
+                        if (extension.light >= 0 && loader._gltf.extensions) {
+                            var lightInfo = loader._gltf.extensions.KHR_lights.lights[extension.light];
+                            if (lightInfo.type !== 'ambient') {
+                                return;
+                            }
+                            var lightColor = lightInfo.color ? lightInfo.color : [1, 1, 1];
+                            loader._babylonScene.ambientColor.copyFromFloats(lightColor[0], lightColor[1], lightColor[2]);
+                        }
+                        onComplete();
+                    });
+                };
+                KHRLights.prototype._loadNode = function (loader, context, node) {
+                    var _this = this;
+                    return this._loadExtension(context, node, function (context, extension, onComplete) {
+                        if (extension.light >= 0 && loader._gltf.extensions) {
+                            var lightInfo = loader._gltf.extensions.KHR_lights.lights[extension.light];
+                            var name_1 = node.name || 'Light';
+                            var matrix = void 0;
+                            if (node.matrix) {
+                                matrix = BABYLON.Matrix.FromArray(node.matrix);
+                            }
+                            else {
+                                matrix = BABYLON.Matrix.Identity();
+                            }
+                            var direction = new BABYLON.Vector3(0, 0, 1);
+                            if (lightInfo.type == 'directional' || lightInfo.type == 'spot') {
+                                var rotationMatrix = matrix.getRotationMatrix();
+                                BABYLON.Vector3.TransformCoordinatesToRef(direction, rotationMatrix, direction);
+                            }
+                            var light = void 0;
+                            if (lightInfo.type == 'directional') {
+                                light = new BABYLON.DirectionalLight(name_1, direction, loader._babylonScene);
+                            }
+                            else {
+                                var position = matrix.getTranslation();
+                                if (lightInfo.type == 'spot') {
+                                    var angle = lightInfo.spot && lightInfo.spot.outerConeAngle ? lightInfo.spot.outerConeAngle : Math.PI / 2;
+                                    light = new BABYLON.SpotLight(name_1, position, direction, angle, 2, loader._babylonScene);
+                                }
+                                else {
+                                    light = new BABYLON.PointLight(name_1, position, loader._babylonScene);
+                                }
+                            }
+                            _this.applyCommonProperties(light, lightInfo);
+                            extension.babylonLight = light;
+                            extension.babylonLight.parent = node.parent ? node.parent.babylonMesh : null;
+                            if (node.children) {
+                                for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
+                                    var index = _a[_i];
+                                    var childNode = GLTF2.GLTFLoader._GetProperty(loader._gltf.nodes, index);
+                                    if (!childNode) {
+                                        throw new Error(context + ": Failed to find child node " + index);
+                                    }
+                                    loader._loadNode("#/nodes/" + index, childNode);
+                                }
+                            }
+                        }
+                        onComplete();
+                    });
+                };
+                KHRLights.prototype._loadRoot = function (loader, context, root) {
+                    return this._loadExtension(context, root, function (context, extension, onComplete) {
+                        extension.lights.forEach(function (light, idx) {
+                            light.index = idx;
+                        });
+                        onComplete();
+                    });
+                };
+                return KHRLights;
+            }(GLTF2.GLTFLoaderExtension));
+            Extensions.KHRLights = KHRLights;
+            GLTF2.GLTFLoader.RegisterExtension(new KHRLights());
+        })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
+    })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=KHR_lights.js.map
+
+
 (function universalModuleDefinition(root, factory) {
                 var f = factory();
                 if (root && root["BABYLON"]) {

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


+ 15 - 0
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -1179,10 +1179,14 @@ declare module BABYLON.GLTF2 {
         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);
@@ -1213,3 +1217,14 @@ declare module BABYLON.GLTF2.Extensions {
         private _loadSpecularGlossinessProperties(loader, context, material, properties);
     }
 }
+
+
+declare module BABYLON.GLTF2.Extensions {
+    class KHRLights 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;
+    }
+}

+ 3 - 3
dist/preview release/serializers/babylon.glTF2Serializer.js

@@ -50,7 +50,7 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.glTFSerializer.js.map
 
-/// <reference path="../../../../dist/babylon.glTFInterface.d.ts"/>
+/// <reference path="../../../../dist/babylon.glTF2Interface.d.ts"/>
 /**
  * Module for the Babylon glTF 2.0 exporter.  Should ONLY be used internally.
  * @ignore - capitalization of GLTF2 module.
@@ -889,7 +889,7 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.glTFExporter.js.map
 
-/// <reference path="../../../../dist/babylon.glTFInterface.d.ts"/>
+/// <reference path="../../../../dist/babylon.glTF2Interface.d.ts"/>
 var BABYLON;
 (function (BABYLON) {
     /**
@@ -948,7 +948,7 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.glTFData.js.map
 
-/// <reference path="../../../../dist/babylon.glTFInterface.d.ts"/>
+/// <reference path="../../../../dist/babylon.glTF2Interface.d.ts"/>
 var BABYLON;
 (function (BABYLON) {
     var GLTF2;

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


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

@@ -7,7 +7,7 @@
 - `WebVRCamera` now supports GearVR ([brianzinn](https://github.com/brianzinn))
 - 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 (`spotLight.projectedLightTexture`). ([lostink](https://github.com/lostink))
+- Introduced Projection Texture on SpotLight (`spotLight.projectedLightTexture`) ([lostink](https://github.com/lostink))
 
 ## Updates
 - Tons of functions and classes received the code comments they deserved (All the community)
@@ -33,6 +33,7 @@
 - VRHelper will notify now onSelectedMeshUnselected observable to subscribers when the applied ray selection predicate does not produce a hit and a mesh compliant with the meshSelectionPredicate was previously selected
    ([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))
 - 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))
@@ -41,6 +42,7 @@
 - (Viewer) Scene Optimizer intergrated in viewer. ([RaananW](https://github.com/RaananW))
 - (Viewer) The viewer supports custom shaders in the configuration. ([RaananW](https://github.com/RaananW))
 - Documented PostProcessRenderEffect, DefaultRenderingPipeline, BlurPostProcess, DepthOfFieldEffect, PostProcess, PostProcessManager classes ([trevordev](https://github.com/trevordev))
+- SPS internal storage of each solid particle rotation matrix ([jbousquie](https://github.com/jbousquie)) 
 
 ## Bug fixes
 - Texture extension detection in `Engine.CreateTexture` ([sebavan](https://github.com/sebavan))

+ 119 - 0
loaders/src/glTF/2.0/Extensions/KHR_lights.ts

@@ -0,0 +1,119 @@
+/// <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;
+    }
+
+    interface IKHRLights {
+        lights: IGLTFLight[];
+    }
+
+    interface IGLTFLightReference {
+        light: number;
+        // Runtime values
+        babylonLight: Light;
+    }
+
+    export class KHRLights extends GLTFLoaderExtension {
+        public get name(): string {
+            return "KHR_lights";
+        }
+
+        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);
+            }
+
+            if (lightInfo.intensity !== undefined) {
+                light.intensity = lightInfo.intensity;
+            } else {
+                light.intensity = 1;
+            }
+        }
+
+        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;
+                    }
+
+                    const lightColor = lightInfo.color ? lightInfo.color : [1, 1, 1];
+                    loader._babylonScene.ambientColor.copyFromFloats(lightColor[0], lightColor[1], lightColor[2]);
+                }
+                
+                onComplete();
+            });
+        }
+
+        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();
+                    }
+
+                    const direction = new Vector3(0, 0, 1);
+                    if (lightInfo.type == 'directional' || lightInfo.type == 'spot') {
+                        const rotationMatrix = matrix.getRotationMatrix();
+                        Vector3.TransformCoordinatesToRef(direction, rotationMatrix, direction);
+                    }
+
+                    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);
+                        }
+                    }
+                }
+                onComplete();
+            });
+        }
+
+        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();
+            });
+        }
+    }
+
+    GLTFLoader.RegisterExtension(new KHRLights());
+}

+ 5 - 0
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -198,6 +198,9 @@ module BABYLON.GLTF2 {
             GLTFLoader._AssignIndices(this._gltf.skins);
             GLTFLoader._AssignIndices(this._gltf.textures);
 
+            // Handle global extensions as they may add their own data types.
+            GLTFLoaderExtension.LoadRoot(this, "#/", this._gltf);
+
             if (data.bin) {
                 const buffers = this._gltf.buffers;
                 if (buffers && buffers[0] && !buffers[0].uri) {
@@ -290,6 +293,8 @@ module BABYLON.GLTF2 {
         }
 
         private _loadScene(context: string, scene: IGLTFScene, nodeNames: any): void {
+            GLTFLoaderExtension.LoadScene(this, context, scene);
+            
             this._rootNode = { babylonMesh: new Mesh("__root__", this._babylonScene) } as IGLTFNode;
 
             switch (this.coordinateSystemMode) {

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

@@ -10,6 +10,10 @@ module BABYLON.GLTF2 {
 
         protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean { return false; }
 
+        protected _loadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean { return false; }
+
+        protected _loadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean { return false; }
+
         protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean { return false; }
 
         protected _loadExtension<T>(context: string, property: IGLTFProperty, action: (context: string, extension: T, onComplete: () => void) => void): boolean {
@@ -43,6 +47,14 @@ module BABYLON.GLTF2 {
             return this._ApplyExtensions(extension => extension._traverseNode(loader, context, node, action, parentNode));
         }
 
+        public static LoadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean {
+            return this._ApplyExtensions(extension => extension._loadRoot(loader, context, root));
+        }
+
+        public static LoadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean {
+            return this._ApplyExtensions(extension => extension._loadScene(loader, context, scene));
+        }
+
         public static LoadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean {
             return this._ApplyExtensions(extension => extension._loadNode(loader, context, node));
         }

+ 13 - 4
src/Engine/babylon.engine.ts

@@ -283,6 +283,7 @@
             { key: "Chrome/63.0", capture: "63\\.0\\.3239\\.(\\d+)", captureConstraint: 108, targets: ["uniformBuffer"] },
             { key: "Firefox/58", capture: null, captureConstraint: null, targets: ["uniformBuffer"] },
             { key: "Macintosh", capture: null, captureConstraint: null, targets: ["textureBindingOptimization"] },
+            { key: "iPhone", capture: null, captureConstraint: null, targets: ["textureBindingOptimization"] },
         ];
 
         public static Instances = new Array<Engine>();
@@ -1352,10 +1353,14 @@
                 }
                 this._boundTexturesCache[key] = null;
             }
-            this._nextFreeTextureSlots = [];
-            for (let slot = 0; slot < this._maxSimultaneousTextures; slot++) {
-                this._nextFreeTextureSlots.push(slot);
+
+            if (!this.disableTextureBindingOptimization) {
+                this._nextFreeTextureSlots = [];
+                for (let slot = 0; slot < this._maxSimultaneousTextures; slot++) {
+                    this._nextFreeTextureSlots.push(slot);
+                }
             }
+
             this._currentTextureChannel = -1;
         }
 
@@ -4805,6 +4810,10 @@
 
             internalTexture._designatedSlot = -1;
 
+            if (this.disableTextureBindingOptimization) {
+                return -1;
+            }
+            
             // Remove from bound list
             this._linkTrackers(internalTexture.previous, internalTexture.next);
 
@@ -4831,7 +4840,7 @@
             let isTextureForRendering = texture && texture._initialSlot > -1;
 
             if (currentTextureBound !== texture) {
-                if (currentTextureBound && !this.disableTextureBindingOptimization) {
+                if (currentTextureBound) {
                     this._removeDesignatedSlot(currentTextureBound);
                 }
 

+ 23 - 4
src/Lights/babylon.shadowLight.ts

@@ -118,25 +118,44 @@
 
         protected abstract _setDefaultShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>): void;
 
+        protected _position: Vector3;
+        protected _setPosition(value: Vector3) {
+            this._position = value;
+        }
         /**
-         * The position the shdow will be casted from.
+         * Sets the position the shadow will be casted from. Also use as the light position for both 
+         * point and spot lights.
          */
         @serializeAsVector3()
-        public position: Vector3;
+        public get position(): Vector3 {
+            return this._position;
+        }
+        /**
+         * Sets the position the shadow will be casted from. Also use as the light position for both 
+         * point and spot lights.
+         */
+        public set position(value: Vector3) {
+            this._setPosition(value);
+        }
 
         protected _direction: Vector3;
-        @serializeAsVector3()
+        protected _setDirection(value: Vector3) {
+            this._direction = value;
+        }
         /**
          * In 2d mode (needCube being false), gets the direction used to cast the shadow.
+         * Also use as the light direction on spot and directional lights.
          */
+        @serializeAsVector3()
         public get direction(): Vector3 {
             return this._direction;
         }
         /**
          * In 2d mode (needCube being false), sets the direction used to cast the shadow.
+         * Also use as the light direction on spot and directional lights.
          */
         public set direction(value: Vector3) {
-            this._direction = value;
+            this._setDirection(value);
         }
 
         private _shadowMinZ: number;

+ 111 - 65
src/Lights/babylon.spotLight.ts

@@ -13,23 +13,18 @@
             
             Also we have the following rules always holds:
             direction cross up   = right
-            right cross dirction = up
+            right cross direction = up
             up cross right       = forward
 
             light_near and light_far will control the range of the texture projection. If a plane is 
             out of the range in spot light space, there is no texture projection.
-
-            Warning:
-            Change the angle of the Spotlight, direction of the SpotLight will not re-compute the 
-            projection matrix. Need to call computeTextureMatrix() to recompute manually. Add inheritance
-            to the setting function of the 2 attributes will solve the problem.
         */
 
         private _angle: number;
-        @serialize()
         /**
          * Gets the cone angle of the spot light in Radians.
          */
+        @serialize()
         public get angle(): number {
             return this._angle
         }
@@ -38,14 +33,15 @@
          */
         public set angle(value: number) {
             this._angle = value;
+            this._projectionTextureProjectionLightDirty = true;
             this.forceProjectionMatrixCompute();
         }
 
         private _shadowAngleScale: number;
-        @serialize()
         /**
          * Allows scaling the angle of the light for shadow generation only.
          */
+        @serialize()
         public get shadowAngleScale(): number {
             return this._shadowAngleScale
         }
@@ -63,70 +59,89 @@
         @serialize()
         public exponent: number;
 
-        private _textureProjectionMatrix = Matrix.Zero();
-        @serialize()
+        private _projectionTextureMatrix = Matrix.Zero();
         /**
         * Allows reading the projecton texture
         */
-        public get textureMatrix(): Matrix{
-            return this._textureProjectionMatrix;
-        }
-        /**
-        * Allows setting the value of projection texture
-        */
-        public set textureMatrix(value: Matrix) {
-            this._textureProjectionMatrix = value;
+        public get projectionTextureMatrix(): Matrix{
+            return this._projectionTextureMatrix;
         }
 
-        protected _light_near :number;
-        @serialize()
+        protected _projectionTextureLightNear : number = 1e-6;;
         /**
          * Gets the near clip of the Spotlight for texture projection.
          */
-        public get light_near(): number {
-            return this._light_near;
+        @serialize()
+        public get projectionTextureLightNear(): number {
+            return this._projectionTextureLightNear;
         }
         /**
          * Sets the near clip of the Spotlight for texture projection.
          */
-        public set light_near(value: number) {
-            this._light_near = value;
-            this._computeTextureMatrix();
+        public set projectionTextureLightNear(value: number) {
+            this._projectionTextureLightNear = value;
+            this._projectionTextureProjectionLightDirty = true;
         }
 
-        protected _light_far  :number;
+        protected _projectionTextureLightFar : number = 1000.0;
         /**
          * Gets the far clip of the Spotlight for texture projection.
          */
         @serialize()
-        public get light_far(): number {
-            return this._light_far;
+        public get projectionTextureLightFar(): number {
+            return this._projectionTextureLightFar;
         }
         /**
          * Sets the far clip of the Spotlight for texture projection.
          */
-        public set light_far(value: number) {
-            this._light_far = value;
+        public set projectionTextureLightFar(value: number) {
+            this._projectionTextureLightFar = value;
+            this._projectionTextureProjectionLightDirty = true;
+        }
+
+        protected _projectionTextureUpDirection: Vector3 = Vector3.Up();
+        /**
+         * Gets the Up vector of the Spotlight for texture projection.
+         */
+        @serialize()
+        public get projectionTextureUpDirection(): Vector3 {
+            return this._projectionTextureUpDirection;
+        }
+        /**
+         * Sets the Up vector of the Spotlight for texture projection.
+         */
+        public set projectionTextureUpDirection(value: Vector3) {
+            this._projectionTextureUpDirection = value;
+            this._projectionTextureProjectionLightDirty = true;
         }
 
         @serializeAsTexture("projectedLightTexture")
-        private _projectedLightTexture: Nullable<BaseTexture>;;
+        private _projectionTexture: Nullable<BaseTexture>;;
         /** 
          * Gets the projection texture of the light.
         */
-        public get projectedLightTexture(): Nullable<BaseTexture> {
-            return this._projectedLightTexture;
+        public get projectionTexture(): Nullable<BaseTexture> {
+            return this._projectionTexture;
         }
         /**
         * Sets the projection texture of the light.
         */
-        public set projectedLightTexture(value: Nullable<BaseTexture>) {
-            this._projectedLightTexture = value;
-            this._light_far = 1000.0;
-            this._light_near = 1e-6;
-            this._computeTextureMatrix();
+        public set projectionTexture(value: Nullable<BaseTexture>) {
+            this._projectionTexture = value;
+            this._projectionTextureDirty = true;
         }
 
+        private _projectionTextureViewLightDirty = true;
+        private _projectionTextureProjectionLightDirty = true;
+        private _projectionTextureDirty = true;
+        private _projectionTextureViewTargetVector = Vector3.Zero();
+        private _projectionTextureViewLightMatrix = Matrix.Zero();
+        private _projectionTextureProjectionLightMatrix = Matrix.Zero();
+        private _projectionTextureScalingMatrix = Matrix.FromValues(0.5, 0.0, 0.0, 0.0,
+            0.0, 0.5, 0.0, 0.0,
+            0.0, 0.0, 0.5, 0.0,
+            0.5, 0.5, 0.5, 1.0);
+
         /**
          * Creates a SpotLight object in the scene. A spot light is a simply light oriented cone.
          * It can cast shadows.
@@ -164,6 +179,22 @@
         }
 
         /**
+         * Overrides the direction setter to recompute the projection texture view light Matrix.
+         */
+        protected _setDirection(value: Vector3) {
+            super._setDirection(value);
+            this._projectionTextureViewLightDirty = true;
+        }
+
+        /**
+         * Overrides the position setter to recompute the projection texture view light Matrix.
+         */
+        protected _setPosition(value: Vector3) {
+            super._setPosition(value);
+            this._projectionTextureViewLightDirty = true;
+        }
+
+        /**
          * Sets the passed matrix "matrix" as perspective projection matrix for the shadows and the passed view matrix with the fov equal to the SpotLight angle and and aspect ratio of 1.0.  
          * Returns the SpotLight.  
          */
@@ -181,37 +212,43 @@
             this.getDepthMinZ(activeCamera), this.getDepthMaxZ(activeCamera), matrix);
         }
 
-        /**
-         * Main function for light texture projection matrix computing.
-         */
-        protected _computeTextureMatrix(): void {
+        protected _computeProjectionTextureViewLightMatrix(): void {
+            this._projectionTextureViewLightDirty = false;
+            this._projectionTextureDirty = true;
+            
+            this.position.addToRef(this.direction, this._projectionTextureViewTargetVector);
+            Matrix.LookAtLHToRef(this.position, 
+                this._projectionTextureViewTargetVector, 
+                this._projectionTextureUpDirection, 
+                this._projectionTextureViewLightMatrix);
+        }
 
-            var viewLightMatrix = Matrix.Zero();
-            Matrix.LookAtLHToRef(this.position, this.position.add(this.direction), Vector3.Up(), viewLightMatrix);
+        protected _computeProjectionTextureProjectionLightMatrix(): void {
+            this._projectionTextureProjectionLightDirty = false;
+            this._projectionTextureDirty = true;
 
-            var light_far = this.light_far;
-            var light_near = this.light_near;
+            var light_far = this.projectionTextureLightFar;
+            var light_near = this.projectionTextureLightNear;
 
             var P = light_far / (light_far - light_near);
             var Q = - P * light_near;
             var S = 1.0 / Math.tan(this._angle / 2.0);
             var A = 1.0;
-            
-            var projectionLightMatrix = Matrix.Zero();
-            Matrix.FromValuesToRef(S/A, 0.0, 0.0, 0.0,
+
+            Matrix.FromValuesToRef(S / A, 0.0, 0.0, 0.0,
                 0.0, S, 0.0, 0.0,
                 0.0, 0.0, P, 1.0,
-                0.0, 0.0, Q, 0.0, projectionLightMatrix);
-
-            var scaleMatrix = Matrix.Zero();
-            Matrix.FromValuesToRef(0.5, 0.0, 0.0, 0.0,
-                0.0, 0.5, 0.0, 0.0,
-                0.0, 0.0, 0.5, 0.0,
-                0.5, 0.5, 0.5, 1.0, scaleMatrix);
-                
-            this._textureProjectionMatrix.copyFrom(viewLightMatrix);
-            this._textureProjectionMatrix.multiplyToRef(projectionLightMatrix, this._textureProjectionMatrix);
-            this._textureProjectionMatrix.multiplyToRef(scaleMatrix, this._textureProjectionMatrix);
+                0.0, 0.0, Q, 0.0, this._projectionTextureProjectionLightMatrix);
+        }
+
+        /**
+         * Main function for light texture projection matrix computing.
+         */
+        protected _computeProjectionTextureMatrix(): void {
+            this._projectionTextureDirty = false;
+
+            this._projectionTextureViewLightMatrix.multiplyToRef(this._projectionTextureProjectionLightMatrix, this._projectionTextureMatrix);
+            this._projectionTextureMatrix.multiplyToRef(this._projectionTextureScalingMatrix, this._projectionTextureMatrix);
         }
 
         protected _buildUniformLayout(): void {
@@ -260,9 +297,18 @@
                 Math.cos(this.angle * 0.5),
                 lightIndex);
 
-            effect.setMatrix("textureProjectionMatrix" + lightIndex, this._textureProjectionMatrix);
-            if (this.projectedLightTexture){
-                effect.setTexture("projectionLightSampler" + lightIndex, this.projectedLightTexture);
+            if (this.projectionTexture && this.projectionTexture.isReady()) {
+                if (this._projectionTextureViewLightDirty) {
+                    this._computeProjectionTextureViewLightMatrix();
+                }
+                if (this._projectionTextureProjectionLightDirty) {
+                    this._computeProjectionTextureProjectionLightMatrix();
+                }
+                if (this._projectionTextureDirty) {
+                    this._computeProjectionTextureMatrix();
+                }
+                effect.setMatrix("textureProjectionMatrix" + lightIndex, this._projectionTextureMatrix);
+                effect.setTexture("projectionLightSampler" + lightIndex, this.projectionTexture);
             }
             return this;
         }
@@ -272,8 +318,8 @@
          */
         public dispose() : void {
             super.dispose();
-            if (this._projectedLightTexture){
-                this._projectedLightTexture.dispose();
+            if (this._projectionTexture){
+                this._projectionTexture.dispose();
             }
         }
     }

+ 21 - 0
src/Loading/babylon.sceneLoader.ts

@@ -336,6 +336,12 @@
                     rootUrl = plugin.rewriteRootURL(rootUrl, responseURL);
                 }
 
+                if (sceneFilename === "") {
+                    if (sceneFilename === "") {
+                        rootUrl = this._StripFilenameFromRootUrl(rootUrl);
+                    }
+                }
+
                 if ((<any>plugin).importMesh) {
                     var syncedPlugin = <ISceneLoaderPlugin>plugin;
                     var meshes = new Array<AbstractMesh>();
@@ -434,6 +440,10 @@
             };
 
             return SceneLoader._loadData(rootUrl, sceneFilename, scene, (plugin, data, responseURL) => {
+                if (sceneFilename === "") {
+                    rootUrl = this._StripFilenameFromRootUrl(rootUrl);
+                }
+
                 if ((<any>plugin).load) {
                     var syncedPlugin = <ISceneLoaderPlugin>plugin;
                     if (!syncedPlugin.load(scene, data, rootUrl, errorHandler)) {
@@ -457,6 +467,17 @@
                 }
             }, progressHandler, errorHandler, disposeHandler, pluginExtension);
         }
+
+        private static _StripFilenameFromRootUrl(rootUrl: string): string {
+            // We need to strip the filename off from the rootUrl
+            let lastSlash = rootUrl.lastIndexOf("/");
+
+            if (lastSlash > -1) {
+                rootUrl = rootUrl.substr(0, lastSlash + 1);
+            }
+
+            return rootUrl;
+        }
         
         public static LoadAssetContainer(
             rootUrl: string,

+ 2 - 1
src/Materials/babylon.materialHelper.ts

@@ -214,7 +214,8 @@ module BABYLON {
                     var type;
                     if (light.getTypeID() === Light.LIGHTTYPEID_SPOTLIGHT) {
                         type = "SPOTLIGHT" + lightIndex;
-                        defines["PROJECTEDLIGHTTEXTURE" + lightIndex] = (light as SpotLight).projectedLightTexture ? true : false;
+                        let spotLight = light as SpotLight;
+                        defines["PROJECTEDLIGHTTEXTURE" + lightIndex] = spotLight.projectionTexture ? spotLight.projectionTexture.isReady() : false;
                     } else if (light.getTypeID() === Light.LIGHTTYPEID_HEMISPHERICLIGHT) {
                         type = "HEMILIGHT" + lightIndex;
                     } else if (light.getTypeID() === Light.LIGHTTYPEID_POINTLIGHT) {

+ 1 - 1
src/Mesh/babylon.mesh.vertexData.ts

@@ -336,7 +336,7 @@
             }
 
             if (!other) {
-                var padding = new Float32Array(length);
+                var padding = new Float32Array((<FloatArray>source).length);
                 padding.fill(defaultValue);
                 return this._mergeElement(source, padding, length);
             }

+ 16 - 2
src/Mesh/babylon.transformNode.ts

@@ -216,9 +216,12 @@ module BABYLON {
             this._cache.pivotMatrixUpdated = true;
             this._postMultiplyPivotMatrix = postMultiplyPivotMatrix;
 
-            if (this._postMultiplyPivotMatrix) {
-                this._pivotMatrixInverse = Matrix.Invert(matrix);
+            if(!this._pivotMatrixInverse){
+                this._pivotMatrixInverse = Matrix.Invert(this._pivotMatrix);
+            } else {
+                this._pivotMatrix.invertToRef(this._pivotMatrixInverse);
             }
+
             return this;
         }
 
@@ -407,6 +410,13 @@ module BABYLON {
             this._pivotMatrix.m[12] = -point.x;
             this._pivotMatrix.m[13] = -point.y;
             this._pivotMatrix.m[14] = -point.z;
+
+            if(!this._pivotMatrixInverse){
+                this._pivotMatrixInverse = Matrix.Invert(this._pivotMatrix);
+            } else {
+                this._pivotMatrix.invertToRef(this._pivotMatrixInverse);
+            }
+            
             this._cache.pivotMatrixUpdated = true;
             return this;
         }
@@ -825,6 +835,10 @@ module BABYLON {
             // Absolute position
             this._absolutePosition.copyFromFloats(this._worldMatrix.m[12], this._worldMatrix.m[13], this._worldMatrix.m[14]);
 
+            if(this._pivotMatrixInverse){
+                Vector3.TransformCoordinatesToRef(this._absolutePosition, this._pivotMatrixInverse, this._absolutePosition);
+            }
+
             // Callbacks
             this.onAfterWorldMatrixUpdateObservable.notifyObservers(this);
 

+ 1 - 1
src/Shaders/ShadersInclude/lightFragment.fx

@@ -24,7 +24,7 @@
 			#endif
 		#endif
 		#ifdef PROJECTEDLIGHTTEXTURE{X}
-			info = computeProjectionTexture(info,projectionLightSampler{X},textureProjectionMatrix{X});
+			info.diffuse *= computeProjectionTextureDiffuseLighting(projectionLightSampler{X}, textureProjectionMatrix{X});
 		#endif
     #endif
 	#ifdef SHADOW{X}

+ 6 - 5
src/Shaders/ShadersInclude/lightsFragmentFunctions.fx

@@ -109,11 +109,12 @@ lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4
 		return result;
 }
 
-lightingInfo computeProjectionTexture(lightingInfo origin,sampler2D projectionLightSampler, mat4 textureProjectionMatrix){
-	lightingInfo result = origin;
+vec3 computeProjectionTextureDiffuseLighting(sampler2D projectionLightSampler, mat4 textureProjectionMatrix){
 	vec4 strq = textureProjectionMatrix * vec4(vPositionW, 1.0);
 	strq /= strq.w;
-	vec4 textureColor = texture2D(projectionLightSampler, strq.xy);
-	result.diffuse *= vec3(textureColor);
-	return result;
+	vec3 textureColor = texture2D(projectionLightSampler, strq.xy).rgb;
+#ifdef PBR
+	textureColor = toLinearSpace(textureColor);
+#endif
+	return textureColor;
 }

+ 9 - 2
src/Tools/babylon.promise.ts

@@ -135,6 +135,8 @@ module BABYLON {
                         let returnedPromise = returnedValue as InternalPromise<T>;
                         
                         returnedPromise._moveChildren(this._children);
+                    } else {
+                        value = <T>returnedValue;
                     }
                 }
 
@@ -198,10 +200,15 @@ module BABYLON {
             agregator.target = promises.length;
             agregator.rootPromise = newPromise;
 
-            for(var index = 0; index < promises.length; index++) {
-                InternalPromise._RegisterForFulfillment(promises[index], agregator, index);
+            if (promises.length) {
+                for(var index = 0; index < promises.length; index++) {
+                    InternalPromise._RegisterForFulfillment(promises[index], agregator, index);
+                }
+            } else {
+                newPromise._resolve();
             }
 
+
             return newPromise;
         }
     }

+ 24 - 0
tests/unit/babylon/promises/babylon.promises.tests.ts

@@ -175,4 +175,28 @@ describe('Babylon.Promise', () => {
             });
         });
     });     
+
+    describe('#All and then', () => {
+        it('should correctly handle chaining a returning then after a all', (done) => {
+            mocha.timeout(10000);
+            var delayAsync = function (timeout) {
+                return new Promise(function (resolve) {
+                    setTimeout(function () {
+                        resolve(1);
+                    }, timeout);
+                });
+            };
+            
+            var promise = Promise.all([delayAsync(100), delayAsync(200)]).then(function () {
+                return 2;
+            });
+            
+            promise.then(function (value) {
+                value.should.be.equal(2);
+                done();
+            }); 
+        });
+    });      
+
+
 });

+ 5 - 0
tests/validation/integration.js

@@ -21,6 +21,11 @@ xhr.addEventListener("load", function () {
                         var info = engine.getGlInfo();
                         console.log("Webgl Version: " + info.version);
                         console.log("Webgl Vendor: " + info.vendor);
+                        // Reduces error ratio on Embedded Firefox for travis.
+                        if (info.vendor === "VMware, Inc.") {
+                            errorRatio = 5;
+                        }
+
                         console.log("Webgl Renderer: " + info.renderer);
                         done();
                     });

+ 1 - 1
tests/validation/validation.js

@@ -7,7 +7,7 @@ var config;
 var justOnce;
 
 var threshold = 25;
-var errorRatio = 5;
+var errorRatio = 2.5;
 
 // Overload the random to make it deterministic
 var seed = 100000,