浏览代码

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

文件差异内容过多而无法显示
+ 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.glTFLoaderUtils.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts",
                     "../../loaders/src/glTF/2.0/Extensions/MSFT_lod.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,
                 "doNotIncludeInBundle": true,
                 "output": "babylon.glTF2FileLoader.js"
                 "output": "babylon.glTF2FileLoader.js"
@@ -1484,7 +1485,8 @@
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderUtils.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderUtils.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts",
                     "../../loaders/src/glTF/2.0/Extensions/MSFT_lod.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"
                 "output": "babylon.glTFFileLoader.js"
             }
             }

文件差异内容过多而无法显示
+ 69 - 112077
Viewer/dist/viewer.js


文件差异内容过多而无法显示
+ 69 - 1
Viewer/dist/viewer.min.js


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


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


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


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


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


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


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


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


文件差异内容过多而无法显示
+ 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;
         readonly abstract name: string;
         protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
         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 _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 _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;
         protected _loadExtension<T>(context: string, property: IGLTFProperty, action: (context: string, extension: T, onComplete: () => void) => void): boolean;
         static _Extensions: GLTFLoaderExtension[];
         static _Extensions: GLTFLoaderExtension[];
         static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
         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 LoadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
         static LoadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         static LoadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         private static _ApplyExtensions(action);
         private static _ApplyExtensions(action);
@@ -555,3 +559,14 @@ declare module BABYLON.GLTF2.Extensions {
         private _loadSpecularGlossinessProperties(loader, context, material, properties);
         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.scenes);
                 GLTFLoader._AssignIndices(this._gltf.skins);
                 GLTFLoader._AssignIndices(this._gltf.skins);
                 GLTFLoader._AssignIndices(this._gltf.textures);
                 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) {
                 if (data.bin) {
                     var buffers = this._gltf.buffers;
                     var buffers = this._gltf.buffers;
                     if (buffers && buffers[0] && !buffers[0].uri) {
                     if (buffers && buffers[0] && !buffers[0].uri) {
@@ -709,6 +711,7 @@ var BABYLON;
             };
             };
             GLTFLoader.prototype._loadScene = function (context, scene, nodeNames) {
             GLTFLoader.prototype._loadScene = function (context, scene, nodeNames) {
                 var _this = this;
                 var _this = this;
+                GLTF2.GLTFLoaderExtension.LoadScene(this, context, scene);
                 this._rootNode = { babylonMesh: new BABYLON.Mesh("__root__", this._babylonScene) };
                 this._rootNode = { babylonMesh: new BABYLON.Mesh("__root__", this._babylonScene) };
                 switch (this.coordinateSystemMode) {
                 switch (this.coordinateSystemMode) {
                     case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO: {
                     case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO: {
@@ -2153,6 +2156,8 @@ var BABYLON;
             }
             }
             GLTFLoaderExtension.prototype._traverseNode = function (loader, context, node, action, parentNode) { return false; };
             GLTFLoaderExtension.prototype._traverseNode = function (loader, context, node, action, parentNode) { return false; };
             GLTFLoaderExtension.prototype._loadNode = function (loader, context, node) { 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._loadMaterial = function (loader, context, material, assign) { return false; };
             GLTFLoaderExtension.prototype._loadExtension = function (context, property, action) {
             GLTFLoaderExtension.prototype._loadExtension = function (context, property, action) {
                 var _this = this;
                 var _this = this;
@@ -2174,6 +2179,12 @@ var BABYLON;
             GLTFLoaderExtension.TraverseNode = function (loader, context, node, action, parentNode) {
             GLTFLoaderExtension.TraverseNode = function (loader, context, node, action, parentNode) {
                 return this._ApplyExtensions(function (extension) { return extension._traverseNode(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) {
             GLTFLoaderExtension.LoadNode = function (loader, context, node) {
                 return this._ApplyExtensions(function (extension) { return extension._loadNode(loader, context, node); });
                 return this._ApplyExtensions(function (extension) { return extension._loadNode(loader, context, node); });
             };
             };
@@ -2419,3 +2430,126 @@ var BABYLON;
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));
 
 
 //# sourceMappingURL=KHR_materials_pbrSpecularGlossiness.js.map
 //# 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

文件差异内容过多而无法显示
+ 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;
         readonly abstract name: string;
         protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
         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 _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 _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;
         protected _loadExtension<T>(context: string, property: IGLTFProperty, action: (context: string, extension: T, onComplete: () => void) => void): boolean;
         static _Extensions: GLTFLoaderExtension[];
         static _Extensions: GLTFLoaderExtension[];
         static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
         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 LoadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
         static LoadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         static LoadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         private static _ApplyExtensions(action);
         private static _ApplyExtensions(action);
@@ -1112,3 +1116,14 @@ declare module BABYLON.GLTF2.Extensions {
         private _loadSpecularGlossinessProperties(loader, context, material, properties);
         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.scenes);
                 GLTFLoader._AssignIndices(this._gltf.skins);
                 GLTFLoader._AssignIndices(this._gltf.skins);
                 GLTFLoader._AssignIndices(this._gltf.textures);
                 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) {
                 if (data.bin) {
                     var buffers = this._gltf.buffers;
                     var buffers = this._gltf.buffers;
                     if (buffers && buffers[0] && !buffers[0].uri) {
                     if (buffers && buffers[0] && !buffers[0].uri) {
@@ -2875,6 +2877,7 @@ var BABYLON;
             };
             };
             GLTFLoader.prototype._loadScene = function (context, scene, nodeNames) {
             GLTFLoader.prototype._loadScene = function (context, scene, nodeNames) {
                 var _this = this;
                 var _this = this;
+                GLTF2.GLTFLoaderExtension.LoadScene(this, context, scene);
                 this._rootNode = { babylonMesh: new BABYLON.Mesh("__root__", this._babylonScene) };
                 this._rootNode = { babylonMesh: new BABYLON.Mesh("__root__", this._babylonScene) };
                 switch (this.coordinateSystemMode) {
                 switch (this.coordinateSystemMode) {
                     case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO: {
                     case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO: {
@@ -4319,6 +4322,8 @@ var BABYLON;
             }
             }
             GLTFLoaderExtension.prototype._traverseNode = function (loader, context, node, action, parentNode) { return false; };
             GLTFLoaderExtension.prototype._traverseNode = function (loader, context, node, action, parentNode) { return false; };
             GLTFLoaderExtension.prototype._loadNode = function (loader, context, node) { 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._loadMaterial = function (loader, context, material, assign) { return false; };
             GLTFLoaderExtension.prototype._loadExtension = function (context, property, action) {
             GLTFLoaderExtension.prototype._loadExtension = function (context, property, action) {
                 var _this = this;
                 var _this = this;
@@ -4340,6 +4345,12 @@ var BABYLON;
             GLTFLoaderExtension.TraverseNode = function (loader, context, node, action, parentNode) {
             GLTFLoaderExtension.TraverseNode = function (loader, context, node, action, parentNode) {
                 return this._ApplyExtensions(function (extension) { return extension._traverseNode(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) {
             GLTFLoaderExtension.LoadNode = function (loader, context, node) {
                 return this._ApplyExtensions(function (extension) { return extension._loadNode(loader, context, node); });
                 return this._ApplyExtensions(function (extension) { return extension._loadNode(loader, context, node); });
             };
             };
@@ -4585,3 +4596,126 @@ var BABYLON;
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));
 
 
 //# sourceMappingURL=KHR_materials_pbrSpecularGlossiness.js.map
 //# 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

文件差异内容过多而无法显示
+ 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.scenes);
                 GLTFLoader._AssignIndices(this._gltf.skins);
                 GLTFLoader._AssignIndices(this._gltf.skins);
                 GLTFLoader._AssignIndices(this._gltf.textures);
                 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) {
                 if (data.bin) {
                     var buffers = this._gltf.buffers;
                     var buffers = this._gltf.buffers;
                     if (buffers && buffers[0] && !buffers[0].uri) {
                     if (buffers && buffers[0] && !buffers[0].uri) {
@@ -3849,6 +3851,7 @@ var BABYLON;
             };
             };
             GLTFLoader.prototype._loadScene = function (context, scene, nodeNames) {
             GLTFLoader.prototype._loadScene = function (context, scene, nodeNames) {
                 var _this = this;
                 var _this = this;
+                GLTF2.GLTFLoaderExtension.LoadScene(this, context, scene);
                 this._rootNode = { babylonMesh: new BABYLON.Mesh("__root__", this._babylonScene) };
                 this._rootNode = { babylonMesh: new BABYLON.Mesh("__root__", this._babylonScene) };
                 switch (this.coordinateSystemMode) {
                 switch (this.coordinateSystemMode) {
                     case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO: {
                     case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO: {
@@ -5293,6 +5296,8 @@ var BABYLON;
             }
             }
             GLTFLoaderExtension.prototype._traverseNode = function (loader, context, node, action, parentNode) { return false; };
             GLTFLoaderExtension.prototype._traverseNode = function (loader, context, node, action, parentNode) { return false; };
             GLTFLoaderExtension.prototype._loadNode = function (loader, context, node) { 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._loadMaterial = function (loader, context, material, assign) { return false; };
             GLTFLoaderExtension.prototype._loadExtension = function (context, property, action) {
             GLTFLoaderExtension.prototype._loadExtension = function (context, property, action) {
                 var _this = this;
                 var _this = this;
@@ -5314,6 +5319,12 @@ var BABYLON;
             GLTFLoaderExtension.TraverseNode = function (loader, context, node, action, parentNode) {
             GLTFLoaderExtension.TraverseNode = function (loader, context, node, action, parentNode) {
                 return this._ApplyExtensions(function (extension) { return extension._traverseNode(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) {
             GLTFLoaderExtension.LoadNode = function (loader, context, node) {
                 return this._ApplyExtensions(function (extension) { return extension._loadNode(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
 //# 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) {
 (function universalModuleDefinition(root, factory) {
                 var f = factory();
                 var f = factory();
                 if (root && root["BABYLON"]) {
                 if (root && root["BABYLON"]) {

文件差异内容过多而无法显示
+ 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;
         readonly abstract name: string;
         protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
         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 _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 _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;
         protected _loadExtension<T>(context: string, property: IGLTFProperty, action: (context: string, extension: T, onComplete: () => void) => void): boolean;
         static _Extensions: GLTFLoaderExtension[];
         static _Extensions: GLTFLoaderExtension[];
         static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
         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 LoadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
         static LoadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         static LoadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         private static _ApplyExtensions(action);
         private static _ApplyExtensions(action);
@@ -1213,3 +1217,14 @@ declare module BABYLON.GLTF2.Extensions {
         private _loadSpecularGlossinessProperties(loader, context, material, properties);
         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
 //# 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.
  * Module for the Babylon glTF 2.0 exporter.  Should ONLY be used internally.
  * @ignore - capitalization of GLTF2 module.
  * @ignore - capitalization of GLTF2 module.
@@ -889,7 +889,7 @@ var BABYLON;
 
 
 //# sourceMappingURL=babylon.glTFExporter.js.map
 //# sourceMappingURL=babylon.glTFExporter.js.map
 
 
-/// <reference path="../../../../dist/babylon.glTFInterface.d.ts"/>
+/// <reference path="../../../../dist/babylon.glTF2Interface.d.ts"/>
 var BABYLON;
 var BABYLON;
 (function (BABYLON) {
 (function (BABYLON) {
     /**
     /**
@@ -948,7 +948,7 @@ var BABYLON;
 
 
 //# sourceMappingURL=babylon.glTFData.js.map
 //# sourceMappingURL=babylon.glTFData.js.map
 
 
-/// <reference path="../../../../dist/babylon.glTFInterface.d.ts"/>
+/// <reference path="../../../../dist/babylon.glTF2Interface.d.ts"/>
 var BABYLON;
 var BABYLON;
 (function (BABYLON) {
 (function (BABYLON) {
     var GLTF2;
     var GLTF2;

文件差异内容过多而无法显示
+ 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))
 - `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))
 - 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))
 - 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
 ## Updates
 - Tons of functions and classes received the code comments they deserved (All the community)
 - 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
 - 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))
    ([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))
 - (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 default pipeline ([trevordev](https://github.com/trevordev))
 - The observable can now notify observers using promise-based callback chain. ([RaananW](https://github.com/RaananW))
 - 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 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) Scene Optimizer intergrated in viewer. ([RaananW](https://github.com/RaananW))
 - (Viewer) The viewer supports custom shaders in the configuration. ([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))
 - 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
 ## Bug fixes
 - Texture extension detection in `Engine.CreateTexture` ([sebavan](https://github.com/sebavan))
 - 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.skins);
             GLTFLoader._AssignIndices(this._gltf.textures);
             GLTFLoader._AssignIndices(this._gltf.textures);
 
 
+            // Handle global extensions as they may add their own data types.
+            GLTFLoaderExtension.LoadRoot(this, "#/", this._gltf);
+
             if (data.bin) {
             if (data.bin) {
                 const buffers = this._gltf.buffers;
                 const buffers = this._gltf.buffers;
                 if (buffers && buffers[0] && !buffers[0].uri) {
                 if (buffers && buffers[0] && !buffers[0].uri) {
@@ -290,6 +293,8 @@ module BABYLON.GLTF2 {
         }
         }
 
 
         private _loadScene(context: string, scene: IGLTFScene, nodeNames: any): void {
         private _loadScene(context: string, scene: IGLTFScene, nodeNames: any): void {
+            GLTFLoaderExtension.LoadScene(this, context, scene);
+            
             this._rootNode = { babylonMesh: new Mesh("__root__", this._babylonScene) } as IGLTFNode;
             this._rootNode = { babylonMesh: new Mesh("__root__", this._babylonScene) } as IGLTFNode;
 
 
             switch (this.coordinateSystemMode) {
             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 _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 _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 {
         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));
             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 {
         public static LoadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean {
             return this._ApplyExtensions(extension => extension._loadNode(loader, context, node));
             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: "Chrome/63.0", capture: "63\\.0\\.3239\\.(\\d+)", captureConstraint: 108, targets: ["uniformBuffer"] },
             { key: "Firefox/58", capture: null, captureConstraint: null, targets: ["uniformBuffer"] },
             { key: "Firefox/58", capture: null, captureConstraint: null, targets: ["uniformBuffer"] },
             { key: "Macintosh", capture: null, captureConstraint: null, targets: ["textureBindingOptimization"] },
             { key: "Macintosh", capture: null, captureConstraint: null, targets: ["textureBindingOptimization"] },
+            { key: "iPhone", capture: null, captureConstraint: null, targets: ["textureBindingOptimization"] },
         ];
         ];
 
 
         public static Instances = new Array<Engine>();
         public static Instances = new Array<Engine>();
@@ -1352,10 +1353,14 @@
                 }
                 }
                 this._boundTexturesCache[key] = null;
                 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;
             this._currentTextureChannel = -1;
         }
         }
 
 
@@ -4805,6 +4810,10 @@
 
 
             internalTexture._designatedSlot = -1;
             internalTexture._designatedSlot = -1;
 
 
+            if (this.disableTextureBindingOptimization) {
+                return -1;
+            }
+            
             // Remove from bound list
             // Remove from bound list
             this._linkTrackers(internalTexture.previous, internalTexture.next);
             this._linkTrackers(internalTexture.previous, internalTexture.next);
 
 
@@ -4831,7 +4840,7 @@
             let isTextureForRendering = texture && texture._initialSlot > -1;
             let isTextureForRendering = texture && texture._initialSlot > -1;
 
 
             if (currentTextureBound !== texture) {
             if (currentTextureBound !== texture) {
-                if (currentTextureBound && !this.disableTextureBindingOptimization) {
+                if (currentTextureBound) {
                     this._removeDesignatedSlot(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 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()
         @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;
         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.
          * 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 {
         public get direction(): Vector3 {
             return this._direction;
             return this._direction;
         }
         }
         /**
         /**
          * In 2d mode (needCube being false), sets the direction used to cast the shadow.
          * 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) {
         public set direction(value: Vector3) {
-            this._direction = value;
+            this._setDirection(value);
         }
         }
 
 
         private _shadowMinZ: number;
         private _shadowMinZ: number;

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

@@ -13,23 +13,18 @@
             
             
             Also we have the following rules always holds:
             Also we have the following rules always holds:
             direction cross up   = right
             direction cross up   = right
-            right cross dirction = up
+            right cross direction = up
             up cross right       = forward
             up cross right       = forward
 
 
             light_near and light_far will control the range of the texture projection. If a plane is 
             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.
             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;
         private _angle: number;
-        @serialize()
         /**
         /**
          * Gets the cone angle of the spot light in Radians.
          * Gets the cone angle of the spot light in Radians.
          */
          */
+        @serialize()
         public get angle(): number {
         public get angle(): number {
             return this._angle
             return this._angle
         }
         }
@@ -38,14 +33,15 @@
          */
          */
         public set angle(value: number) {
         public set angle(value: number) {
             this._angle = value;
             this._angle = value;
+            this._projectionTextureProjectionLightDirty = true;
             this.forceProjectionMatrixCompute();
             this.forceProjectionMatrixCompute();
         }
         }
 
 
         private _shadowAngleScale: number;
         private _shadowAngleScale: number;
-        @serialize()
         /**
         /**
          * Allows scaling the angle of the light for shadow generation only.
          * Allows scaling the angle of the light for shadow generation only.
          */
          */
+        @serialize()
         public get shadowAngleScale(): number {
         public get shadowAngleScale(): number {
             return this._shadowAngleScale
             return this._shadowAngleScale
         }
         }
@@ -63,70 +59,89 @@
         @serialize()
         @serialize()
         public exponent: number;
         public exponent: number;
 
 
-        private _textureProjectionMatrix = Matrix.Zero();
-        @serialize()
+        private _projectionTextureMatrix = Matrix.Zero();
         /**
         /**
         * Allows reading the projecton texture
         * 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.
          * 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.
          * 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.
          * Gets the far clip of the Spotlight for texture projection.
          */
          */
         @serialize()
         @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.
          * 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")
         @serializeAsTexture("projectedLightTexture")
-        private _projectedLightTexture: Nullable<BaseTexture>;;
+        private _projectionTexture: Nullable<BaseTexture>;;
         /** 
         /** 
          * Gets the projection texture of the light.
          * 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.
         * 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.
          * Creates a SpotLight object in the scene. A spot light is a simply light oriented cone.
          * It can cast shadows.
          * 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.  
          * 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.  
          * Returns the SpotLight.  
          */
          */
@@ -181,37 +212,43 @@
             this.getDepthMinZ(activeCamera), this.getDepthMaxZ(activeCamera), matrix);
             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 P = light_far / (light_far - light_near);
             var Q = - P * light_near;
             var Q = - P * light_near;
             var S = 1.0 / Math.tan(this._angle / 2.0);
             var S = 1.0 / Math.tan(this._angle / 2.0);
             var A = 1.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, S, 0.0, 0.0,
                 0.0, 0.0, P, 1.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 {
         protected _buildUniformLayout(): void {
@@ -260,9 +297,18 @@
                 Math.cos(this.angle * 0.5),
                 Math.cos(this.angle * 0.5),
                 lightIndex);
                 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;
             return this;
         }
         }
@@ -272,8 +318,8 @@
          */
          */
         public dispose() : void {
         public dispose() : void {
             super.dispose();
             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);
                     rootUrl = plugin.rewriteRootURL(rootUrl, responseURL);
                 }
                 }
 
 
+                if (sceneFilename === "") {
+                    if (sceneFilename === "") {
+                        rootUrl = this._StripFilenameFromRootUrl(rootUrl);
+                    }
+                }
+
                 if ((<any>plugin).importMesh) {
                 if ((<any>plugin).importMesh) {
                     var syncedPlugin = <ISceneLoaderPlugin>plugin;
                     var syncedPlugin = <ISceneLoaderPlugin>plugin;
                     var meshes = new Array<AbstractMesh>();
                     var meshes = new Array<AbstractMesh>();
@@ -434,6 +440,10 @@
             };
             };
 
 
             return SceneLoader._loadData(rootUrl, sceneFilename, scene, (plugin, data, responseURL) => {
             return SceneLoader._loadData(rootUrl, sceneFilename, scene, (plugin, data, responseURL) => {
+                if (sceneFilename === "") {
+                    rootUrl = this._StripFilenameFromRootUrl(rootUrl);
+                }
+
                 if ((<any>plugin).load) {
                 if ((<any>plugin).load) {
                     var syncedPlugin = <ISceneLoaderPlugin>plugin;
                     var syncedPlugin = <ISceneLoaderPlugin>plugin;
                     if (!syncedPlugin.load(scene, data, rootUrl, errorHandler)) {
                     if (!syncedPlugin.load(scene, data, rootUrl, errorHandler)) {
@@ -457,6 +467,17 @@
                 }
                 }
             }, progressHandler, errorHandler, disposeHandler, pluginExtension);
             }, 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(
         public static LoadAssetContainer(
             rootUrl: string,
             rootUrl: string,

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

@@ -214,7 +214,8 @@ module BABYLON {
                     var type;
                     var type;
                     if (light.getTypeID() === Light.LIGHTTYPEID_SPOTLIGHT) {
                     if (light.getTypeID() === Light.LIGHTTYPEID_SPOTLIGHT) {
                         type = "SPOTLIGHT" + lightIndex;
                         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) {
                     } else if (light.getTypeID() === Light.LIGHTTYPEID_HEMISPHERICLIGHT) {
                         type = "HEMILIGHT" + lightIndex;
                         type = "HEMILIGHT" + lightIndex;
                     } else if (light.getTypeID() === Light.LIGHTTYPEID_POINTLIGHT) {
                     } else if (light.getTypeID() === Light.LIGHTTYPEID_POINTLIGHT) {

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

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

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

@@ -216,9 +216,12 @@ module BABYLON {
             this._cache.pivotMatrixUpdated = true;
             this._cache.pivotMatrixUpdated = true;
             this._postMultiplyPivotMatrix = postMultiplyPivotMatrix;
             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;
             return this;
         }
         }
 
 
@@ -407,6 +410,13 @@ module BABYLON {
             this._pivotMatrix.m[12] = -point.x;
             this._pivotMatrix.m[12] = -point.x;
             this._pivotMatrix.m[13] = -point.y;
             this._pivotMatrix.m[13] = -point.y;
             this._pivotMatrix.m[14] = -point.z;
             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;
             this._cache.pivotMatrixUpdated = true;
             return this;
             return this;
         }
         }
@@ -825,6 +835,10 @@ module BABYLON {
             // Absolute position
             // Absolute position
             this._absolutePosition.copyFromFloats(this._worldMatrix.m[12], this._worldMatrix.m[13], this._worldMatrix.m[14]);
             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
             // Callbacks
             this.onAfterWorldMatrixUpdateObservable.notifyObservers(this);
             this.onAfterWorldMatrixUpdateObservable.notifyObservers(this);
 
 

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

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

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

@@ -109,11 +109,12 @@ lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4
 		return result;
 		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);
 	vec4 strq = textureProjectionMatrix * vec4(vPositionW, 1.0);
 	strq /= strq.w;
 	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>;
                         let returnedPromise = returnedValue as InternalPromise<T>;
                         
                         
                         returnedPromise._moveChildren(this._children);
                         returnedPromise._moveChildren(this._children);
+                    } else {
+                        value = <T>returnedValue;
                     }
                     }
                 }
                 }
 
 
@@ -198,10 +200,15 @@ module BABYLON {
             agregator.target = promises.length;
             agregator.target = promises.length;
             agregator.rootPromise = newPromise;
             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;
             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();
                         var info = engine.getGlInfo();
                         console.log("Webgl Version: " + info.version);
                         console.log("Webgl Version: " + info.version);
                         console.log("Webgl Vendor: " + info.vendor);
                         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);
                         console.log("Webgl Renderer: " + info.renderer);
                         done();
                         done();
                     });
                     });

+ 1 - 1
tests/validation/validation.js

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