浏览代码

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js into tutorials

Cubees 7 年之前
父节点
当前提交
546c49c042
共有 42 个文件被更改,包括 53332 次插入20892 次删除
  1. 3492 3445
      Playground/babylon.d.txt
  2. 1 1
      Playground/js/index.js
  3. 210 0
      Viewer/assets/pep.min.js
  4. 228 9
      Viewer/dist/viewer.js
  5. 7 3
      Viewer/dist/viewer.min.js
  6. 1 0
      Viewer/src/index.ts
  7. 1 1
      Viewer/src/viewer/defaultViewer.ts
  8. 3837 3795
      dist/preview release/babylon.d.ts
  9. 43 43
      dist/preview release/babylon.js
  10. 509 81
      dist/preview release/babylon.max.js
  11. 20654 0
      dist/preview release/babylon.module.d.ts
  12. 43 43
      dist/preview release/babylon.worker.js
  13. 3063 3001
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  14. 49 48
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  15. 550 89
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  16. 19919 10142
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts
  17. 4 1
      dist/preview release/gui/babylon.gui.js
  18. 1 1
      dist/preview release/gui/babylon.gui.min.js
  19. 1 1
      dist/preview release/gui/package.json
  20. 14 14
      dist/preview release/inspector/babylon.inspector.bundle.js
  21. 1 1
      dist/preview release/inspector/package.json
  22. 1 1
      dist/preview release/loaders/package.json
  23. 1 1
      dist/preview release/materialsLibrary/package.json
  24. 1 1
      dist/preview release/postProcessesLibrary/package.json
  25. 1 1
      dist/preview release/proceduralTexturesLibrary/package.json
  26. 1 1
      dist/preview release/serializers/package.json
  27. 5 1
      gui/src/controls/container.ts
  28. 1 1
      package.json
  29. 454 1
      src/Cameras/VR/babylon.vrExperienceHelper.ts
  30. 1 1
      src/Engine/babylon.engine.ts
  31. 7 6
      src/Helpers/babylon.environmentHelper.ts
  32. 18 0
      src/Materials/PBR/babylon.pbrBaseMaterial.ts
  33. 16 0
      src/Materials/PBR/babylon.pbrMaterial.ts
  34. 0 1
      src/Mesh/babylon.abstractMesh.ts
  35. 10 3
      src/Mesh/babylon.linesMesh.ts
  36. 3 2
      src/Mesh/babylon.mesh.ts
  37. 10 2
      src/Mesh/babylon.mesh.vertexData.ts
  38. 38 15
      src/Mesh/babylon.meshBuilder.ts
  39. 4 0
      src/Shaders/ShadersInclude/backgroundFragmentDeclaration.fx
  40. 15 11
      src/Shaders/pbr.fragment.fx
  41. 12 25
      src/Tools/babylon.tools.ts
  42. 105 99
      src/babylon.scene.ts

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


+ 1 - 1
Playground/js/index.js

@@ -640,7 +640,7 @@
         // Fonts
         // Fonts
         setFontSize = function (size) {
         setFontSize = function (size) {
             fontSize = size;
             fontSize = size;
-            document.querySelector(".view-lines").style.fontSize = size + "px";
+            jsEditor.updateOptions({fontSize: size});
             setToMultipleID("currentFontSize", "innerHTML", "Font: " + size);
             setToMultipleID("currentFontSize", "innerHTML", "Font: " + size);
         };
         };
 
 

文件差异内容过多而无法显示
+ 210 - 0
Viewer/assets/pep.min.js


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


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


+ 1 - 0
Viewer/src/index.ts

@@ -14,6 +14,7 @@ import { AbstractViewer } from './viewer/viewer';
 import 'babylonjs';
 import 'babylonjs';
 import 'babylonjs-loaders';
 import 'babylonjs-loaders';
 import 'babylonjs-materials';
 import 'babylonjs-materials';
+import '../assets/pep.min';
 
 
 import { InitTags } from './initializer';
 import { InitTags } from './initializer';
 
 

+ 1 - 1
Viewer/src/viewer/defaultViewer.ts

@@ -107,7 +107,7 @@ export class DefaultViewer extends AbstractViewer {
                                     let requestFullScreen = viewerElement.requestFullscreen || viewerElement.webkitRequestFullscreen || (<any>viewerElement).msRequestFullscreen || (<any>viewerElement).mozRequestFullScreen;
                                     let requestFullScreen = viewerElement.requestFullscreen || viewerElement.webkitRequestFullscreen || (<any>viewerElement).msRequestFullscreen || (<any>viewerElement).mozRequestFullScreen;
                                     requestFullScreen.call(viewerElement);
                                     requestFullScreen.call(viewerElement);
                                 } else {
                                 } else {
-                                    let exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen
+                                    let exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen || (<any>document).msExitFullscreen || document.mozCancelFullScreen
                                     exitFullscreen.call(document);
                                     exitFullscreen.call(document);
                                 }
                                 }
 
 

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


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


+ 509 - 81
dist/preview release/babylon.max.js

@@ -5781,7 +5781,6 @@ var BABYLON;
     var Tools = /** @class */ (function () {
     var Tools = /** @class */ (function () {
         function Tools() {
         function Tools() {
         }
         }
-        ;
         /**
         /**
          * Interpolates between a and b via alpha
          * Interpolates between a and b via alpha
          * @param a The lower value (returned when alpha = 0)
          * @param a The lower value (returned when alpha = 0)
@@ -6135,10 +6134,7 @@ var BABYLON;
                 database.openAsync(loadFromIndexedDB, noIndexedDB);
                 database.openAsync(loadFromIndexedDB, noIndexedDB);
             }
             }
             else {
             else {
-                if (url.indexOf("file:") !== 0) {
-                    noIndexedDB();
-                }
-                else {
+                if (url.indexOf("file:") !== -1) {
                     var textureName = decodeURIComponent(url.substring(5).toLowerCase());
                     var textureName = decodeURIComponent(url.substring(5).toLowerCase());
                     if (BABYLON.FilesInput.FilesToLoad[textureName]) {
                     if (BABYLON.FilesInput.FilesToLoad[textureName]) {
                         try {
                         try {
@@ -6155,16 +6151,13 @@ var BABYLON;
                         catch (e) {
                         catch (e) {
                             img.src = "";
                             img.src = "";
                         }
                         }
-                    }
-                    else {
-                        Tools.Error("Image: " + textureName + " not found. Did you forget to provide it?");
-                        img.src = Tools.fallbackTexture;
+                        return img;
                     }
                     }
                 }
                 }
+                noIndexedDB();
             }
             }
             return img;
             return img;
         };
         };
-        //ANY
         Tools.LoadFile = function (url, callback, progressCallBack, database, useArrayBuffer, onError) {
         Tools.LoadFile = function (url, callback, progressCallBack, database, useArrayBuffer, onError) {
             url = Tools.CleanUrl(url);
             url = Tools.CleanUrl(url);
             url = Tools.PreprocessUrl(url);
             url = Tools.PreprocessUrl(url);
@@ -6205,30 +6198,20 @@ var BABYLON;
                     database.loadFileFromDB(url, callback, progressCallBack, noIndexedDB, useArrayBuffer);
                     database.loadFileFromDB(url, callback, progressCallBack, noIndexedDB, useArrayBuffer);
                 }
                 }
             };
             };
+            // If file and file input are set
             if (url.indexOf("file:") !== -1) {
             if (url.indexOf("file:") !== -1) {
                 var fileName = decodeURIComponent(url.substring(5).toLowerCase());
                 var fileName = decodeURIComponent(url.substring(5).toLowerCase());
                 if (BABYLON.FilesInput.FilesToLoad[fileName]) {
                 if (BABYLON.FilesInput.FilesToLoad[fileName]) {
                     Tools.ReadFile(BABYLON.FilesInput.FilesToLoad[fileName], callback, progressCallBack, useArrayBuffer);
                     Tools.ReadFile(BABYLON.FilesInput.FilesToLoad[fileName], callback, progressCallBack, useArrayBuffer);
+                    return request;
                 }
                 }
-                else {
-                    var errorMessage = "File: " + fileName + " not found. Did you forget to provide it?";
-                    if (onError) {
-                        var e = new Error(errorMessage);
-                        onError(undefined, e);
-                    }
-                    else {
-                        Tools.Error(errorMessage);
-                    }
-                }
+            }
+            // Caching all files
+            if (database && database.enableSceneOffline) {
+                database.openAsync(loadFromIndexedDB, noIndexedDB);
             }
             }
             else {
             else {
-                // Caching all files
-                if (database && database.enableSceneOffline) {
-                    database.openAsync(loadFromIndexedDB, noIndexedDB);
-                }
-                else {
-                    noIndexedDB();
-                }
+                noIndexedDB();
             }
             }
             return request;
             return request;
         };
         };
@@ -6384,7 +6367,7 @@ var BABYLON;
                 }
                 }
             }
             }
         };
         };
-        Tools.DumpFramebuffer = function (width, height, engine, successCallback, mimeType) {
+        Tools.DumpFramebuffer = function (width, height, engine, successCallback, mimeType, fileName) {
             if (mimeType === void 0) { mimeType = "image/png"; }
             if (mimeType === void 0) { mimeType = "image/png"; }
             // Read the contents of the framebuffer
             // Read the contents of the framebuffer
             var numberOfChannelsByLine = width * 4;
             var numberOfChannelsByLine = width * 4;
@@ -6415,38 +6398,63 @@ var BABYLON;
                 var castData = (imageData.data);
                 var castData = (imageData.data);
                 castData.set(data);
                 castData.set(data);
                 context.putImageData(imageData, 0, 0);
                 context.putImageData(imageData, 0, 0);
-                Tools.EncodeScreenshotCanvasData(successCallback, mimeType);
+                Tools.EncodeScreenshotCanvasData(successCallback, mimeType, fileName);
             }
             }
         };
         };
-        Tools.EncodeScreenshotCanvasData = function (successCallback, mimeType) {
+        Tools.EncodeScreenshotCanvasData = function (successCallback, mimeType, fileName) {
             if (mimeType === void 0) { mimeType = "image/png"; }
             if (mimeType === void 0) { mimeType = "image/png"; }
             var base64Image = screenshotCanvas.toDataURL(mimeType);
             var base64Image = screenshotCanvas.toDataURL(mimeType);
             if (successCallback) {
             if (successCallback) {
                 successCallback(base64Image);
                 successCallback(base64Image);
             }
             }
             else {
             else {
-                //Creating a link if the browser have the download attribute on the a tag, to automatically start download generated image.
-                if (("download" in document.createElement("a"))) {
-                    var a = window.document.createElement("a");
-                    a.href = base64Image;
-                    var date = new Date();
-                    var stringDate = (date.getFullYear() + "-" + (date.getMonth() + 1)).slice(-2) + "-" + date.getDate() + "_" + date.getHours() + "-" + ('0' + date.getMinutes()).slice(-2);
-                    a.setAttribute("download", "screenshot_" + stringDate + ".png");
-                    window.document.body.appendChild(a);
-                    a.addEventListener("click", function () {
-                        if (a.parentElement) {
-                            a.parentElement.removeChild(a);
-                        }
-                    });
-                    a.click();
-                    //Or opening a new tab with the image if it is not possible to automatically start download.
-                }
-                else {
-                    var newWindow = window.open("");
-                    var img = newWindow.document.createElement("img");
-                    img.src = base64Image;
-                    newWindow.document.body.appendChild(img);
+                // We need HTMLCanvasElement.toBlob for HD screenshots
+                if (!screenshotCanvas.toBlob) {
+                    //  low performance polyfill based on toDataURL (https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob)
+                    screenshotCanvas.toBlob = function (callback, type, quality) {
+                        var canvas = this;
+                        setTimeout(function () {
+                            var binStr = atob(canvas.toDataURL(type, quality).split(',')[1]), len = binStr.length, arr = new Uint8Array(len);
+                            for (var i = 0; i < len; i++) {
+                                arr[i] = binStr.charCodeAt(i);
+                            }
+                            callback(new Blob([arr], { type: type || 'image/png' }));
+                        });
+                    };
                 }
                 }
+                screenshotCanvas.toBlob(function (blob) {
+                    var url = URL.createObjectURL(blob);
+                    //Creating a link if the browser have the download attribute on the a tag, to automatically start download generated image.
+                    if (("download" in document.createElement("a"))) {
+                        var a = window.document.createElement("a");
+                        a.href = url;
+                        if (fileName) {
+                            a.setAttribute("download", fileName);
+                        }
+                        else {
+                            var date = new Date();
+                            var stringDate = (date.getFullYear() + "-" + (date.getMonth() + 1)).slice(-2) + "-" + date.getDate() + "_" + date.getHours() + "-" + ('0' + date.getMinutes()).slice(-2);
+                            a.setAttribute("download", "screenshot_" + stringDate + ".png");
+                        }
+                        window.document.body.appendChild(a);
+                        a.addEventListener("click", function () {
+                            if (a.parentElement) {
+                                a.parentElement.removeChild(a);
+                            }
+                        });
+                        a.click();
+                    }
+                    else {
+                        var newWindow = window.open("");
+                        var img = newWindow.document.createElement("img");
+                        img.onload = function () {
+                            // no longer need to read the blob so it's revoked
+                            URL.revokeObjectURL(url);
+                        };
+                        img.src = url;
+                        newWindow.document.body.appendChild(img);
+                    }
+                });
             }
             }
         };
         };
         Tools.CreateScreenshot = function (engine, camera, size, successCallback, mimeType) {
         Tools.CreateScreenshot = function (engine, camera, size, successCallback, mimeType) {
@@ -6499,9 +6507,10 @@ var BABYLON;
             }
             }
             Tools.EncodeScreenshotCanvasData(successCallback, mimeType);
             Tools.EncodeScreenshotCanvasData(successCallback, mimeType);
         };
         };
-        Tools.CreateScreenshotUsingRenderTarget = function (engine, camera, size, successCallback, mimeType, samples) {
+        Tools.CreateScreenshotUsingRenderTarget = function (engine, camera, size, successCallback, mimeType, samples, antialiasing, fileName) {
             if (mimeType === void 0) { mimeType = "image/png"; }
             if (mimeType === void 0) { mimeType = "image/png"; }
             if (samples === void 0) { samples = 1; }
             if (samples === void 0) { samples = 1; }
+            if (antialiasing === void 0) { antialiasing = false; }
             var width;
             var width;
             var height;
             var height;
             //If a precision value is specified
             //If a precision value is specified
@@ -6542,8 +6551,11 @@ var BABYLON;
             var texture = new BABYLON.RenderTargetTexture("screenShot", size, scene, false, false, BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT, false, BABYLON.Texture.NEAREST_SAMPLINGMODE);
             var texture = new BABYLON.RenderTargetTexture("screenShot", size, scene, false, false, BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT, false, BABYLON.Texture.NEAREST_SAMPLINGMODE);
             texture.renderList = null;
             texture.renderList = null;
             texture.samples = samples;
             texture.samples = samples;
+            if (antialiasing) {
+                texture.addPostProcess(new BABYLON.FxaaPostProcess('antialiasing', 1.0, scene.activeCamera));
+            }
             texture.onAfterRenderObservable.add(function () {
             texture.onAfterRenderObservable.add(function () {
-                Tools.DumpFramebuffer(width, height, engine, successCallback, mimeType);
+                Tools.DumpFramebuffer(width, height, engine, successCallback, mimeType, fileName);
             });
             });
             scene.incrementRenderId();
             scene.incrementRenderId();
             scene.resetCachedMaterial();
             scene.resetCachedMaterial();
@@ -8522,7 +8534,7 @@ var BABYLON;
         });
         });
         Object.defineProperty(Engine, "Version", {
         Object.defineProperty(Engine, "Version", {
             get: function () {
             get: function () {
-                return "3.1-beta-4";
+                return "3.1-beta-5";
             },
             },
             enumerable: true,
             enumerable: true,
             configurable: true
             configurable: true
@@ -20477,35 +20489,37 @@ var BABYLON;
                 this.simplificationQueue.executeNext();
                 this.simplificationQueue.executeNext();
             }
             }
             if (this._engine.isDeterministicLockStep()) {
             if (this._engine.isDeterministicLockStep()) {
-                var deltaTime = Math.max(Scene.MinDeltaTime, Math.min(this._engine.getDeltaTime(), Scene.MaxDeltaTime)) / 1000;
-                var defaultTimeStep = (60.0 / 1000.0);
+                var deltaTime = Math.max(Scene.MinDeltaTime, Math.min(this._engine.getDeltaTime(), Scene.MaxDeltaTime)) + this._timeAccumulator;
+                var defaultFPS = (60.0 / 1000.0);
+                var defaultFrameTime = 1000 / 60; // frame time in MS
                 if (this._physicsEngine) {
                 if (this._physicsEngine) {
-                    defaultTimeStep = this._physicsEngine.getTimeStep();
+                    defaultFrameTime = this._physicsEngine.getTimeStep() / 1000; //timestep in physics engine is in seconds
                 }
                 }
+                var stepsTaken = 0;
                 var maxSubSteps = this._engine.getLockstepMaxSteps();
                 var maxSubSteps = this._engine.getLockstepMaxSteps();
-                this._timeAccumulator += deltaTime;
-                // compute the amount of fixed steps we should have taken since the last step
-                var internalSteps = Math.floor(this._timeAccumulator / defaultTimeStep);
+                var internalSteps = Math.floor(deltaTime / (1000 * defaultFPS));
                 internalSteps = Math.min(internalSteps, maxSubSteps);
                 internalSteps = Math.min(internalSteps, maxSubSteps);
-                for (this._currentInternalStep = 0; this._currentInternalStep < internalSteps; this._currentInternalStep++) {
+                do {
                     this.onBeforeStepObservable.notifyObservers(this);
                     this.onBeforeStepObservable.notifyObservers(this);
                     // Animations
                     // Animations
-                    this._animationRatio = defaultTimeStep * (60.0 / 1000.0);
+                    this._animationRatio = defaultFrameTime * defaultFPS;
                     this._animate();
                     this._animate();
                     this.onAfterAnimationsObservable.notifyObservers(this);
                     this.onAfterAnimationsObservable.notifyObservers(this);
                     // Physics
                     // Physics
                     if (this._physicsEngine) {
                     if (this._physicsEngine) {
                         this.onBeforePhysicsObservable.notifyObservers(this);
                         this.onBeforePhysicsObservable.notifyObservers(this);
-                        this._physicsEngine._step(defaultTimeStep);
+                        this._physicsEngine._step(defaultFPS);
                         this.onAfterPhysicsObservable.notifyObservers(this);
                         this.onAfterPhysicsObservable.notifyObservers(this);
                     }
                     }
-                    this._timeAccumulator -= defaultTimeStep;
                     this.onAfterStepObservable.notifyObservers(this);
                     this.onAfterStepObservable.notifyObservers(this);
                     this._currentStepId++;
                     this._currentStepId++;
-                    if ((internalSteps > 1) && (this._currentInternalStep != internalSteps - 1)) {
+                    if ((internalSteps > 1) && (stepsTaken != internalSteps - 1)) {
                         this._evaluateActiveMeshes();
                         this._evaluateActiveMeshes();
                     }
                     }
-                }
+                    stepsTaken++;
+                    deltaTime -= defaultFrameTime;
+                } while (deltaTime > 0 && stepsTaken > maxSubSteps);
+                this._timeAccumulator = deltaTime;
             }
             }
             else {
             else {
                 // Animations
                 // Animations
@@ -29677,11 +29691,17 @@ var BABYLON;
             var indices = [];
             var indices = [];
             var positions = [];
             var positions = [];
             var lines = options.lines;
             var lines = options.lines;
+            var colors = options.colors;
+            var vertexColors = [];
             var idx = 0;
             var idx = 0;
             for (var l = 0; l < lines.length; l++) {
             for (var l = 0; l < lines.length; l++) {
                 var points = lines[l];
                 var points = lines[l];
                 for (var index = 0; index < points.length; index++) {
                 for (var index = 0; index < points.length; index++) {
                     positions.push(points[index].x, points[index].y, points[index].z);
                     positions.push(points[index].x, points[index].y, points[index].z);
+                    if (colors) {
+                        var color = colors[l];
+                        vertexColors.push(color[index].r, color[index].g, color[index].b, color[index].a);
+                    }
                     if (index > 0) {
                     if (index > 0) {
                         indices.push(idx - 1);
                         indices.push(idx - 1);
                         indices.push(idx);
                         indices.push(idx);
@@ -29692,6 +29712,9 @@ var BABYLON;
             var vertexData = new VertexData();
             var vertexData = new VertexData();
             vertexData.indices = indices;
             vertexData.indices = indices;
             vertexData.positions = positions;
             vertexData.positions = positions;
+            if (colors) {
+                vertexData.colors = vertexColors;
+            }
             return vertexData;
             return vertexData;
         };
         };
         /**
         /**
@@ -47198,27 +47221,35 @@ var BABYLON;
 (function (BABYLON) {
 (function (BABYLON) {
     var LinesMesh = /** @class */ (function (_super) {
     var LinesMesh = /** @class */ (function (_super) {
         __extends(LinesMesh, _super);
         __extends(LinesMesh, _super);
-        function LinesMesh(name, scene, parent, source, doNotCloneChildren, useVertexColor) {
+        function LinesMesh(name, scene, parent, source, doNotCloneChildren, useVertexColor, useVertexAlpha) {
             if (scene === void 0) { scene = null; }
             if (scene === void 0) { scene = null; }
             if (parent === void 0) { parent = null; }
             if (parent === void 0) { parent = null; }
             var _this = _super.call(this, name, scene, parent, source, doNotCloneChildren) || this;
             var _this = _super.call(this, name, scene, parent, source, doNotCloneChildren) || this;
             _this.useVertexColor = useVertexColor;
             _this.useVertexColor = useVertexColor;
+            _this.useVertexAlpha = useVertexAlpha;
             _this.color = new BABYLON.Color3(1, 1, 1);
             _this.color = new BABYLON.Color3(1, 1, 1);
             _this.alpha = 1;
             _this.alpha = 1;
             if (source) {
             if (source) {
                 _this.color = source.color.clone();
                 _this.color = source.color.clone();
                 _this.alpha = source.alpha;
                 _this.alpha = source.alpha;
                 _this.useVertexColor = source.useVertexColor;
                 _this.useVertexColor = source.useVertexColor;
+                _this.useVertexAlpha = source.useVertexAlpha;
             }
             }
             _this._intersectionThreshold = 0.1;
             _this._intersectionThreshold = 0.1;
+            var defines = [];
             var options = {
             var options = {
                 attributes: [BABYLON.VertexBuffer.PositionKind],
                 attributes: [BABYLON.VertexBuffer.PositionKind],
                 uniforms: ["world", "viewProjection"],
                 uniforms: ["world", "viewProjection"],
                 needAlphaBlending: false,
                 needAlphaBlending: false,
+                defines: defines
             };
             };
             if (!useVertexColor) {
             if (!useVertexColor) {
                 options.uniforms.push("color");
                 options.uniforms.push("color");
-                options.needAlphaBlending = true;
+            }
+            else {
+                options.needAlphaBlending = (useVertexAlpha) ? true : false;
+                options.defines.push("#define VERTEXCOLOR");
+                options.attributes.push(BABYLON.VertexBuffer.ColorKind);
             }
             }
             _this._colorShader = new BABYLON.ShaderMaterial("colorShader", _this.getScene(), "color", options);
             _this._colorShader = new BABYLON.ShaderMaterial("colorShader", _this.getScene(), "color", options);
             return _this;
             return _this;
@@ -48152,6 +48183,8 @@ var BABYLON;
          * Like every other parametric shape, it is dynamically updatable by passing an existing instance of LineSystem to this static function.
          * Like every other parametric shape, it is dynamically updatable by passing an existing instance of LineSystem to this static function.
          * The parameter `lines` is an array of lines, each line being an array of successive Vector3.
          * The parameter `lines` is an array of lines, each line being an array of successive Vector3.
          * The optional parameter `instance` is an instance of an existing LineSystem object to be updated with the passed `lines` parameter. The way to update it is the same than for
          * The optional parameter `instance` is an instance of an existing LineSystem object to be updated with the passed `lines` parameter. The way to update it is the same than for
+         * The optional parameter `colors` is an array of line colors, each line colors being an array of successive Color4, one per line point.
+         * The optional parameter `useVertexAlpha' is to be set to `true` (default `false`) when the alpha value from the former `Color4` array must be used.
          * updating a simple Line mesh, you just need to update every line in the `lines` array : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#lines-and-dashedlines
          * updating a simple Line mesh, you just need to update every line in the `lines` array : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#lines-and-dashedlines
          * When updating an instance, remember that only line point positions can change, not the number of points, neither the number of lines.
          * When updating an instance, remember that only line point positions can change, not the number of points, neither the number of lines.
          * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.
          * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.
@@ -48159,24 +48192,42 @@ var BABYLON;
         MeshBuilder.CreateLineSystem = function (name, options, scene) {
         MeshBuilder.CreateLineSystem = function (name, options, scene) {
             var instance = options.instance;
             var instance = options.instance;
             var lines = options.lines;
             var lines = options.lines;
+            var colors = options.colors;
             if (instance) {
             if (instance) {
-                var positionFunction = function (positions) {
-                    var i = 0;
-                    for (var l = 0; l < lines.length; l++) {
-                        var points = lines[l];
-                        for (var p = 0; p < points.length; p++) {
-                            positions[i] = points[p].x;
-                            positions[i + 1] = points[p].y;
-                            positions[i + 2] = points[p].z;
-                            i += 3;
+                var positions = instance.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+                var vertexColor;
+                var lineColors;
+                if (colors) {
+                    vertexColor = instance.getVerticesData(BABYLON.VertexBuffer.ColorKind);
+                }
+                var i = 0;
+                var c = 0;
+                for (var l = 0; l < lines.length; l++) {
+                    var points = lines[l];
+                    for (var p = 0; p < points.length; p++) {
+                        positions[i] = points[p].x;
+                        positions[i + 1] = points[p].y;
+                        positions[i + 2] = points[p].z;
+                        if (colors && vertexColor) {
+                            lineColors = colors[l];
+                            vertexColor[c] = lineColors[p].r;
+                            vertexColor[c + 1] = lineColors[p].g;
+                            vertexColor[c + 2] = lineColors[p].b;
+                            vertexColor[c + 3] = lineColors[p].a;
+                            c += 4;
                         }
                         }
+                        i += 3;
                     }
                     }
-                };
-                instance.updateMeshPositions(positionFunction, false);
+                }
+                instance.updateVerticesData(BABYLON.VertexBuffer.PositionKind, positions, false, false);
+                if (colors && vertexColor) {
+                    instance.updateVerticesData(BABYLON.VertexBuffer.ColorKind, vertexColor, false, false);
+                }
                 return instance;
                 return instance;
             }
             }
             // line system creation
             // line system creation
-            var lineSystem = new BABYLON.LinesMesh(name, scene);
+            var useVertexColor = (colors) ? true : false;
+            var lineSystem = new BABYLON.LinesMesh(name, scene, null, undefined, undefined, useVertexColor, options.useVertexAlpha);
             var vertexData = BABYLON.VertexData.CreateLineSystem(options);
             var vertexData = BABYLON.VertexData.CreateLineSystem(options);
             vertexData.applyToMesh(lineSystem, options.updatable);
             vertexData.applyToMesh(lineSystem, options.updatable);
             return lineSystem;
             return lineSystem;
@@ -48188,12 +48239,15 @@ var BABYLON;
          * Like every other parametric shape, it is dynamically updatable by passing an existing instance of LineMesh to this static function.
          * Like every other parametric shape, it is dynamically updatable by passing an existing instance of LineMesh to this static function.
          * The parameter `points` is an array successive Vector3.
          * The parameter `points` is an array successive Vector3.
          * The optional parameter `instance` is an instance of an existing LineMesh object to be updated with the passed `points` parameter : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#lines-and-dashedlines
          * The optional parameter `instance` is an instance of an existing LineMesh object to be updated with the passed `points` parameter : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#lines-and-dashedlines
+         * The optional parameter `colors` is an array of successive Color4, one per line point.
+         * The optional parameter `useVertexAlpha' is to be set to `true` (default `false`) when the alpha value from the former `Color4` array must be used.
          * When updating an instance, remember that only point positions can change, not the number of points.
          * When updating an instance, remember that only point positions can change, not the number of points.
          * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.
          * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.
          */
          */
         MeshBuilder.CreateLines = function (name, options, scene) {
         MeshBuilder.CreateLines = function (name, options, scene) {
             if (scene === void 0) { scene = null; }
             if (scene === void 0) { scene = null; }
-            var lines = MeshBuilder.CreateLineSystem(name, { lines: [options.points], updatable: options.updatable, instance: options.instance }, scene);
+            var colors = (options.colors) ? [options.colors] : null;
+            var lines = MeshBuilder.CreateLineSystem(name, { lines: [options.points], updatable: options.updatable, instance: options.instance, colors: colors, useVertexAlpha: options.useVertexAlpha }, scene);
             return lines;
             return lines;
         };
         };
         /**
         /**
@@ -71211,6 +71265,21 @@ var BABYLON;
             // Are we presenting in the fullscreen fallback?
             // Are we presenting in the fullscreen fallback?
             this._fullscreenVRpresenting = false;
             this._fullscreenVRpresenting = false;
             this._useCustomVRButton = false;
             this._useCustomVRButton = false;
+            this._teleportationRequested = false;
+            this._teleportationEnabledOnLeftController = false;
+            this._teleportationEnabledOnRightController = false;
+            this._leftControllerReady = false;
+            this._rightControllerReady = false;
+            this._teleportationAllowed = false;
+            this._rotationAllowed = true;
+            this._teleportationRequestInitiated = false;
+            this._xboxGamepadTeleportationRequestInitiated = false;
+            this._rotationRightAsked = false;
+            this._rotationLeftAsked = false;
+            this._teleportationFillColor = "#444444";
+            this._teleportationBorderColor = "#FFFFFF";
+            this._rotationAngle = 0;
+            this._haloCenter = new BABYLON.Vector3(0, 0, 0);
             this._scene = scene;
             this._scene = scene;
             if (!this._scene.activeCamera || isNaN(this._scene.activeCamera.position.x)) {
             if (!this._scene.activeCamera || isNaN(this._scene.activeCamera.position.x)) {
                 this._position = new BABYLON.Vector3(0, 2, 0);
                 this._position = new BABYLON.Vector3(0, 2, 0);
@@ -71350,6 +71419,18 @@ var BABYLON;
         });
         });
         // Raised when one of the controller has loaded successfully its associated default mesh
         // Raised when one of the controller has loaded successfully its associated default mesh
         VRExperienceHelper.prototype._onDefaultMeshLoaded = function (webVRController) {
         VRExperienceHelper.prototype._onDefaultMeshLoaded = function (webVRController) {
+            if (webVRController.hand === "left") {
+                this._leftControllerReady = true;
+                if (this._teleportationRequested && !this._teleportationEnabledOnLeftController) {
+                    this._enableTeleportationOnController(webVRController);
+                }
+            }
+            if (webVRController.hand === "right") {
+                this._rightControllerReady = true;
+                if (this._teleportationRequested && !this._teleportationEnabledOnRightController) {
+                    this._enableTeleportationOnController(webVRController);
+                }
+            }
             if (this.onControllerMeshLoaded) {
             if (this.onControllerMeshLoaded) {
                 this.onControllerMeshLoaded(webVRController);
                 this.onControllerMeshLoaded(webVRController);
             }
             }
@@ -71433,6 +71514,7 @@ var BABYLON;
                 if (!this._webVRpresenting) {
                 if (!this._webVRpresenting) {
                     this._webVRCamera.position = this._position;
                     this._webVRCamera.position = this._position;
                     this._scene.activeCamera = this._webVRCamera;
                     this._scene.activeCamera = this._webVRCamera;
+                    this._scene.imageProcessingConfiguration.applyByPostProcess = true;
                 }
                 }
             }
             }
             else {
             else {
@@ -71464,6 +71546,7 @@ var BABYLON;
                 this._scene.activeCamera.attachControl(this._canvas);
                 this._scene.activeCamera.attachControl(this._canvas);
             }
             }
             this.updateButtonVisibility();
             this.updateButtonVisibility();
+            this._scene.imageProcessingConfiguration.applyByPostProcess = false;
         };
         };
         Object.defineProperty(VRExperienceHelper.prototype, "position", {
         Object.defineProperty(VRExperienceHelper.prototype, "position", {
             get: function () {
             get: function () {
@@ -71478,6 +71561,351 @@ var BABYLON;
             enumerable: true,
             enumerable: true,
             configurable: true
             configurable: true
         });
         });
+        VRExperienceHelper.prototype.enableTeleportation = function (vrTeleportationOptions) {
+            var _this = this;
+            if (vrTeleportationOptions === void 0) { vrTeleportationOptions = {}; }
+            this._teleportationRequested = true;
+            if (vrTeleportationOptions) {
+                if (vrTeleportationOptions.floorMeshName) {
+                    this._floorMeshName = vrTeleportationOptions.floorMeshName;
+                }
+            }
+            if (this._leftControllerReady && this._webVRCamera.leftController) {
+                this._enableTeleportationOnController(this._webVRCamera.leftController);
+            }
+            if (this._rightControllerReady && this._webVRCamera.rightController) {
+                this._enableTeleportationOnController(this._webVRCamera.rightController);
+            }
+            this._postProcessMove = new BABYLON.ImageProcessingPostProcess("postProcessMove", 1.0, this._webVRCamera);
+            this._postProcessMove.vignetteWeight = 0;
+            this._postProcessMove.vignetteStretch = 0;
+            this._postProcessMove.vignetteColor = new BABYLON.Color4(0, 0, 0, 0);
+            this._postProcessMove.vignetteEnabled = false;
+            new BABYLON.PassPostProcess("pass", 1.0, this._webVRCamera);
+            this._postProcessMove.imageProcessingConfiguration = new BABYLON.ImageProcessingConfiguration();
+            this._scene.imageProcessingConfiguration.applyByPostProcess = false;
+            this._createTeleportationCircles();
+            this.meshSelectionPredicate = function (mesh) {
+                if (mesh.name.indexOf(_this._floorMeshName) !== -1) {
+                    return true;
+                }
+                return false;
+            };
+            this._scene.registerBeforeRender(function () {
+                _this._castRayAndSelectObject();
+            });
+        };
+        VRExperienceHelper.prototype._enableTeleportationOnController = function (webVRController) {
+            var _this = this;
+            var controllerMesh = webVRController.mesh;
+            if (controllerMesh) {
+                var childMeshes = controllerMesh.getChildMeshes();
+                for (var i = 0; i < childMeshes.length; i++) {
+                    if (childMeshes[i].name === "POINTING_POSE") {
+                        controllerMesh = childMeshes[i];
+                        break;
+                    }
+                }
+                var laserPointer = BABYLON.Mesh.CreateCylinder("laserPointer", 3, 0.004, 0.0001, 20, 1, this._scene, false);
+                var laserPointerMaterial = new BABYLON.StandardMaterial("laserPointerMat", this._scene);
+                laserPointerMaterial.emissiveColor = new BABYLON.Color3(0.7, 0.7, 0.7);
+                laserPointerMaterial.alpha = 0.6;
+                laserPointer.material = laserPointerMaterial;
+                laserPointer.rotation.x = Math.PI / 2;
+                laserPointer.parent = controllerMesh;
+                laserPointer.position.z = -1.5;
+                laserPointer.position.y = 0;
+                laserPointer.isVisible = false;
+                webVRController.onMainButtonStateChangedObservable.add(function (stateObject) {
+                    // Enabling / disabling laserPointer 
+                    if (stateObject.value === 1) {
+                        laserPointer.isVisible = !laserPointer.isVisible;
+                    }
+                });
+                webVRController.onPadValuesChangedObservable.add(function (stateObject) {
+                    // on pressed
+                    if (!_this._teleportationRequestInitiated) {
+                        if (stateObject.y < -0.6) {
+                            laserPointer.isVisible = true;
+                            _this._teleportationRequestInitiated = true;
+                        }
+                    }
+                    else {
+                        if (stateObject.y > -0.4) {
+                            if (_this._teleportationAllowed) {
+                                _this._teleportCamera();
+                            }
+                            _this._teleportationRequestInitiated = false;
+                            laserPointer.isVisible = false;
+                        }
+                    }
+                    if (!_this._rotationLeftAsked) {
+                        if (stateObject.x < -0.6) {
+                            _this._rotationLeftAsked = true;
+                            if (_this._rotationAllowed) {
+                                _this._rotateCamera(false);
+                            }
+                        }
+                    }
+                    else {
+                        if (stateObject.x > -0.4) {
+                            _this._rotationLeftAsked = false;
+                        }
+                    }
+                    if (!_this._rotationRightAsked) {
+                        if (stateObject.x > 0.6) {
+                            _this._rotationRightAsked = true;
+                            if (_this._rotationAllowed) {
+                                _this._rotateCamera(true);
+                            }
+                        }
+                    }
+                    else {
+                        if (stateObject.x < 0.4) {
+                            _this._rotationRightAsked = false;
+                        }
+                    }
+                });
+            }
+        };
+        VRExperienceHelper.prototype._createTeleportationCircles = function () {
+            this._teleportationCircle = BABYLON.Mesh.CreateGround("teleportationCircle", 2, 2, 2, this._scene);
+            var length = 512;
+            var dynamicTexture = new BABYLON.DynamicTexture("DynamicTexture", length, this._scene, true);
+            dynamicTexture.hasAlpha = true;
+            var context = dynamicTexture.getContext();
+            var centerX = length / 2;
+            var centerY = length / 2;
+            var radius = 200;
+            context.beginPath();
+            context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
+            context.fillStyle = this._teleportationFillColor;
+            context.fill();
+            context.lineWidth = 10;
+            context.strokeStyle = this._teleportationBorderColor;
+            context.stroke();
+            context.closePath();
+            dynamicTexture.update();
+            var teleportationCircleMaterial = new BABYLON.StandardMaterial("TextPlaneMaterial", this._scene);
+            teleportationCircleMaterial.diffuseTexture = dynamicTexture;
+            this._teleportationCircle.material = teleportationCircleMaterial;
+            var torus = BABYLON.Mesh.CreateTorus("torus", 0.75, 0.1, 25, this._scene, false);
+            torus.parent = this._teleportationCircle;
+            var animationInnerCircle = new BABYLON.Animation("animationInnerCircle", "position.y", 30, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
+            var keys = [];
+            keys.push({
+                frame: 0,
+                value: 0
+            });
+            keys.push({
+                frame: 30,
+                value: 0.4
+            });
+            keys.push({
+                frame: 60,
+                value: 0
+            });
+            animationInnerCircle.setKeys(keys);
+            var easingFunction = new BABYLON.SineEase();
+            easingFunction.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEINOUT);
+            animationInnerCircle.setEasingFunction(easingFunction);
+            torus.animations = [];
+            torus.animations.push(animationInnerCircle);
+            this._scene.beginAnimation(torus, 0, 60, true);
+            this._hideTeleportationCircle();
+        };
+        VRExperienceHelper.prototype._displayTeleportationCircle = function () {
+            this._teleportationCircle.isVisible = true;
+            this._teleportationCircle.getChildren()[0].isVisible = true;
+        };
+        VRExperienceHelper.prototype._hideTeleportationCircle = function () {
+            this._teleportationCircle.isVisible = false;
+            this._teleportationCircle.getChildren()[0].isVisible = false;
+        };
+        VRExperienceHelper.prototype._rotateCamera = function (right) {
+            var _this = this;
+            if (right) {
+                this._rotationAngle++;
+            }
+            else {
+                this._rotationAngle--;
+            }
+            this.currentVRCamera.animations = [];
+            var target = BABYLON.Quaternion.FromRotationMatrix(BABYLON.Matrix.RotationY(Math.PI / 4 * this._rotationAngle));
+            var animationRotation = new BABYLON.Animation("animationRotation", "rotationQuaternion", 90, BABYLON.Animation.ANIMATIONTYPE_QUATERNION, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
+            var animationRotationKeys = [];
+            animationRotationKeys.push({
+                frame: 0,
+                value: this.currentVRCamera.rotationQuaternion
+            });
+            animationRotationKeys.push({
+                frame: 6,
+                value: target
+            });
+            animationRotation.setKeys(animationRotationKeys);
+            var easingFunction = new BABYLON.CircleEase();
+            easingFunction.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEINOUT);
+            animationRotation.setEasingFunction(easingFunction);
+            this.currentVRCamera.animations.push(animationRotation);
+            this._postProcessMove.animations = [];
+            var animationPP = new BABYLON.Animation("animationPP", "vignetteWeight", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
+            var vignetteWeightKeys = [];
+            vignetteWeightKeys.push({
+                frame: 0,
+                value: 0
+            });
+            vignetteWeightKeys.push({
+                frame: 3,
+                value: 4
+            });
+            vignetteWeightKeys.push({
+                frame: 6,
+                value: 0
+            });
+            animationPP.setKeys(vignetteWeightKeys);
+            animationPP.setEasingFunction(easingFunction);
+            this._postProcessMove.animations.push(animationPP);
+            var animationPP2 = new BABYLON.Animation("animationPP2", "vignetteStretch", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
+            var vignetteStretchKeys = [];
+            vignetteStretchKeys.push({
+                frame: 0,
+                value: 0
+            });
+            vignetteStretchKeys.push({
+                frame: 3,
+                value: 10
+            });
+            vignetteStretchKeys.push({
+                frame: 6,
+                value: 0
+            });
+            animationPP2.setKeys(vignetteStretchKeys);
+            animationPP2.setEasingFunction(easingFunction);
+            this._postProcessMove.animations.push(animationPP2);
+            this._postProcessMove.vignetteWeight = 0;
+            this._postProcessMove.vignetteStretch = 0;
+            this._postProcessMove.vignetteEnabled = true;
+            this._scene.beginAnimation(this._postProcessMove, 0, 6, false, 1, function () {
+                _this._postProcessMove.vignetteEnabled = false;
+            });
+            this._scene.beginAnimation(this.currentVRCamera, 0, 6, false, 1);
+        };
+        VRExperienceHelper.prototype._moveTeleportationSelectorTo = function (coordinates) {
+            this._teleportationAllowed = true;
+            if (this._teleportationRequestInitiated || this._xboxGamepadTeleportationRequestInitiated) {
+                this._displayTeleportationCircle();
+            }
+            else {
+                this._hideTeleportationCircle();
+            }
+            this._haloCenter.copyFrom(coordinates);
+            this._teleportationCircle.position = coordinates;
+            this._teleportationCircle.position.y += 0.001;
+        };
+        VRExperienceHelper.prototype._teleportCamera = function () {
+            var _this = this;
+            this.currentVRCamera.animations = [];
+            var animationCameraTeleportation = new BABYLON.Animation("animationCameraTeleportation", "position.x", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
+            var animationCameraTeleportationKeys = [];
+            animationCameraTeleportationKeys.push({
+                frame: 0,
+                value: this.currentVRCamera.position.x
+            });
+            animationCameraTeleportationKeys.push({
+                frame: 11,
+                value: this._haloCenter.x
+            });
+            animationCameraTeleportation.setKeys(animationCameraTeleportationKeys);
+            var easingFunction = new BABYLON.CircleEase();
+            easingFunction.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEINOUT);
+            animationCameraTeleportation.setEasingFunction(easingFunction);
+            this.currentVRCamera.animations.push(animationCameraTeleportation);
+            var animationZoomIn2 = new BABYLON.Animation("animationZoomIn", "position.z", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
+            var keys2 = [];
+            keys2.push({
+                frame: 0,
+                value: this.currentVRCamera.position.z
+            });
+            keys2.push({
+                frame: 11,
+                value: this._haloCenter.z
+            });
+            animationZoomIn2.setKeys(keys2);
+            animationZoomIn2.setEasingFunction(easingFunction);
+            this.currentVRCamera.animations.push(animationZoomIn2);
+            this._postProcessMove.animations = [];
+            var animationPP = new BABYLON.Animation("animationPP", "vignetteWeight", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
+            var vignetteWeightKeys = [];
+            vignetteWeightKeys.push({
+                frame: 0,
+                value: 0
+            });
+            vignetteWeightKeys.push({
+                frame: 5,
+                value: 8
+            });
+            vignetteWeightKeys.push({
+                frame: 11,
+                value: 0
+            });
+            animationPP.setKeys(vignetteWeightKeys);
+            this._postProcessMove.animations.push(animationPP);
+            var animationPP2 = new BABYLON.Animation("animationPP2", "vignetteStretch", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
+            var vignetteStretchKeys = [];
+            vignetteStretchKeys.push({
+                frame: 0,
+                value: 0
+            });
+            vignetteStretchKeys.push({
+                frame: 5,
+                value: 10
+            });
+            vignetteStretchKeys.push({
+                frame: 11,
+                value: 0
+            });
+            animationPP2.setKeys(vignetteStretchKeys);
+            this._postProcessMove.animations.push(animationPP2);
+            this._postProcessMove.vignetteWeight = 8;
+            this._postProcessMove.vignetteStretch = 10;
+            this._postProcessMove.vignetteEnabled = true;
+            this._scene.beginAnimation(this._postProcessMove, 0, 11, false, 1, function () {
+                _this._postProcessMove.vignetteEnabled = false;
+            });
+            this._scene.beginAnimation(this.currentVRCamera, 0, 11, false, 1);
+        };
+        VRExperienceHelper.prototype._castRayAndSelectObject = function () {
+            var ray;
+            if (!this.currentVRCamera.rightController) {
+                ray = this.currentVRCamera.getForwardRay();
+            }
+            else {
+                ray = this.currentVRCamera.rightController.getForwardRay();
+            }
+            var hit = this._scene.pickWithRay(ray, this.meshSelectionPredicate);
+            if (this._rayHelper) {
+                this._rayHelper.dispose();
+            }
+            if (this.currentVRCamera.rightController) {
+                //if (target) target.isVisible = false;
+                this._rayHelper = BABYLON.RayHelper.CreateAndShow(ray, this._scene, new BABYLON.Color3(0.7, 0.7, 0.7));
+            }
+            if (hit && hit.pickedMesh) {
+                // The object selected is the floor, we're in a teleportation scenario
+                if (hit.pickedMesh.name.indexOf(this._floorMeshName) !== -1 && hit.pickedPoint) {
+                    this._moveTeleportationSelectorTo(hit.pickedPoint);
+                    return;
+                }
+                // If not, we're in a selection scenario
+                this._hideTeleportationCircle();
+                this._teleportationAllowed = false;
+                //currentMeshSelected = hit.pickedMesh;
+            }
+            else {
+                this._teleportationAllowed = false;
+                this._hideTeleportationCircle();
+            }
+        };
         VRExperienceHelper.prototype.dispose = function () {
         VRExperienceHelper.prototype.dispose = function () {
             if (this.isInVRMode()) {
             if (this.isInVRMode()) {
                 this.exitVR();
                 this.exitVR();

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


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


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


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


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


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


+ 4 - 1
dist/preview release/gui/babylon.gui.js

@@ -1993,7 +1993,7 @@ var BABYLON;
                 }
                 }
             };
             };
             Container.prototype._processPicking = function (x, y, type, buttonIndex) {
             Container.prototype._processPicking = function (x, y, type, buttonIndex) {
-                if (!this.isHitTestVisible || !this.isVisible || this.notRenderable) {
+                if (!this.isVisible || this.notRenderable) {
                     return false;
                     return false;
                 }
                 }
                 if (!_super.prototype.contains.call(this, x, y)) {
                 if (!_super.prototype.contains.call(this, x, y)) {
@@ -2006,6 +2006,9 @@ var BABYLON;
                         return true;
                         return true;
                     }
                     }
                 }
                 }
+                if (!this.isHitTestVisible) {
+                    return false;
+                }
                 return this._processObservables(type, x, y, buttonIndex);
                 return this._processObservables(type, x, y, buttonIndex);
             };
             };
             Container.prototype._clipForChildren = function (context) {
             Container.prototype._clipForChildren = function (context) {

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


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

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

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


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

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

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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-loaders",
     "name": "babylonjs-loaders",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
-    "version": "3.1.0-beta3",
+    "version": "3.1.0-beta5",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

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

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

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

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

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

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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-serializers",
     "name": "babylonjs-serializers",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
-    "version": "3.1.0-beta3",
+    "version": "3.1.0-beta5",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 5 - 1
gui/src/controls/container.ts

@@ -175,7 +175,7 @@ module BABYLON.GUI {
         }
         }
 
 
         public _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean {
         public _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean {
-            if (!this.isHitTestVisible || !this.isVisible || this.notRenderable) {
+            if (!this.isVisible || this.notRenderable) {
                 return false;
                 return false;
             }
             }
 
 
@@ -191,6 +191,10 @@ module BABYLON.GUI {
                 }
                 }
             }
             }
 
 
+            if (!this.isHitTestVisible) {
+                return false;
+            }
+
             return this._processObservables(type, x, y, buttonIndex);
             return this._processObservables(type, x, y, buttonIndex);
         }
         }
 
 

+ 1 - 1
package.json

@@ -8,7 +8,7 @@
     ],
     ],
     "name": "babylonjs",
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "3.1.0-beta3",
+    "version": "3.1.0-beta5",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -1,4 +1,8 @@
 module BABYLON {
 module BABYLON {
+    export interface VRTeleportationOptions {
+        floorMeshName?: string; // If you'd like to provide a mesh acting as the floor
+    }
+
     export class VRExperienceHelper {
     export class VRExperienceHelper {
         private _scene: BABYLON.Scene;
         private _scene: BABYLON.Scene;
         private _position: Vector3;
         private _position: Vector3;
@@ -32,6 +36,27 @@ module BABYLON {
         public onControllerMeshLoaded: (controller: WebVRController) => void;
         public onControllerMeshLoaded: (controller: WebVRController) => void;
 
 
         private _useCustomVRButton: boolean = false;
         private _useCustomVRButton: boolean = false;
+        private _teleportationRequested: boolean = false;
+        private _teleportationEnabledOnLeftController: boolean = false;
+        private _teleportationEnabledOnRightController: boolean = false;
+        private _leftControllerReady: boolean = false;
+        private _rightControllerReady: boolean = false;
+        private _floorMeshName: string;
+        private _teleportationAllowed: boolean = false;
+        private _rotationAllowed: boolean = true;
+        private _teleportationRequestInitiated = false;
+        private _xboxGamepadTeleportationRequestInitiated = false;
+        private _rotationRightAsked = false;
+        private _rotationLeftAsked = false;
+        private _teleportationCircle: BABYLON.Mesh;
+        private _postProcessMove: ImageProcessingPostProcess;
+        private _teleportationFillColor: string = "#444444";
+        private _teleportationBorderColor: string = "#FFFFFF";
+        private _rotationAngle: number = 0;
+        private _haloCenter = new BABYLON.Vector3(0, 0, 0);
+        private _rayHelper: RayHelper;
+
+        public meshSelectionPredicate: (mesh: BABYLON.Mesh) => boolean;
 
 
         public get deviceOrientationCamera(): DeviceOrientationCamera {
         public get deviceOrientationCamera(): DeviceOrientationCamera {
             return this._deviceOrientationCamera;
             return this._deviceOrientationCamera;
@@ -171,12 +196,24 @@ module BABYLON {
             this._vrDeviceOrientationCamera = new BABYLON.VRDeviceOrientationFreeCamera("VRDeviceOrientationVRHelper", this._position, this._scene);            
             this._vrDeviceOrientationCamera = new BABYLON.VRDeviceOrientationFreeCamera("VRDeviceOrientationVRHelper", this._position, this._scene);            
             this._webVRCamera = new BABYLON.WebVRFreeCamera("WebVRHelper", this._position, this._scene, webVROptions);
             this._webVRCamera = new BABYLON.WebVRFreeCamera("WebVRHelper", this._position, this._scene, webVROptions);
             this._webVRCamera.onControllerMeshLoadedObservable.add((webVRController) => this._onDefaultMeshLoaded(webVRController));
             this._webVRCamera.onControllerMeshLoadedObservable.add((webVRController) => this._onDefaultMeshLoaded(webVRController));
-            
+        
             this.updateButtonVisibility();
             this.updateButtonVisibility();
         }
         }
 
 
         // Raised when one of the controller has loaded successfully its associated default mesh
         // Raised when one of the controller has loaded successfully its associated default mesh
         private _onDefaultMeshLoaded(webVRController: WebVRController) {
         private _onDefaultMeshLoaded(webVRController: WebVRController) {
+            if (webVRController.hand === "left") {
+                this._leftControllerReady = true;
+                if (this._teleportationRequested && !this._teleportationEnabledOnLeftController) {
+                    this._enableTeleportationOnController(webVRController);
+                }
+            }
+            if (webVRController.hand === "right") {
+                this._rightControllerReady = true;
+                if (this._teleportationRequested && !this._teleportationEnabledOnRightController) {
+                    this._enableTeleportationOnController(webVRController);
+                }
+            }
             if (this.onControllerMeshLoaded) {
             if (this.onControllerMeshLoaded) {
                 this.onControllerMeshLoaded(webVRController);
                 this.onControllerMeshLoaded(webVRController);
             }
             }
@@ -264,6 +301,7 @@ module BABYLON {
                 if (!this._webVRpresenting) {
                 if (!this._webVRpresenting) {
                     this._webVRCamera.position = this._position;
                     this._webVRCamera.position = this._position;
                     this._scene.activeCamera = this._webVRCamera;
                     this._scene.activeCamera = this._webVRCamera;
+                    this._scene.imageProcessingConfiguration.applyByPostProcess = true; 
                 }
                 }
             }
             }
             else {
             else {
@@ -300,6 +338,7 @@ module BABYLON {
             }
             }
 
 
             this.updateButtonVisibility();
             this.updateButtonVisibility();
+            this._scene.imageProcessingConfiguration.applyByPostProcess = false; 
         }
         }
 
 
         public get position(): Vector3 {
         public get position(): Vector3 {
@@ -314,6 +353,420 @@ module BABYLON {
             }
             }
         }
         }
 
 
+        public enableTeleportation(vrTeleportationOptions: VRTeleportationOptions = {}) {
+            this._teleportationRequested = true;
+
+            if (vrTeleportationOptions) {
+                if (vrTeleportationOptions.floorMeshName) {
+                    this._floorMeshName = vrTeleportationOptions.floorMeshName;
+                }
+            }
+
+            if (this._leftControllerReady && this._webVRCamera.leftController) {
+                this._enableTeleportationOnController(this._webVRCamera.leftController)
+            }
+            if (this._rightControllerReady && this._webVRCamera.rightController) {
+                this._enableTeleportationOnController(this._webVRCamera.rightController)
+            }
+
+            this._postProcessMove = new BABYLON.ImageProcessingPostProcess("postProcessMove", 1.0, this._webVRCamera);
+            this._postProcessMove.vignetteWeight = 0;
+            this._postProcessMove.vignetteStretch = 0;
+            this._postProcessMove.vignetteColor = new BABYLON.Color4(0, 0, 0, 0);
+            this._postProcessMove.vignetteEnabled = false;
+            new BABYLON.PassPostProcess("pass", 1.0, this._webVRCamera);
+            this._postProcessMove.imageProcessingConfiguration = new ImageProcessingConfiguration(); 
+            this._scene.imageProcessingConfiguration.applyByPostProcess = false; 
+
+            this._createTeleportationCircles();
+
+            this.meshSelectionPredicate = (mesh) => {
+                if (mesh.name.indexOf(this._floorMeshName) !== -1) {
+                    return true;
+                }
+                return false;
+            }
+
+            this._scene.registerBeforeRender(() => {
+                this._castRayAndSelectObject();
+            });
+        }
+
+        private _enableTeleportationOnController(webVRController: WebVRController) {
+            var controllerMesh = webVRController.mesh;
+            if (controllerMesh) {
+                var childMeshes = controllerMesh.getChildMeshes();
+
+                for (var i = 0; i < childMeshes.length; i++) {
+                    if (childMeshes[i].name === "POINTING_POSE") {
+                        controllerMesh = childMeshes[i];
+                        break;
+                    }
+                }
+                var laserPointer = BABYLON.Mesh.CreateCylinder("laserPointer", 3, 0.004, 0.0001, 20, 1, this._scene, false);
+                var laserPointerMaterial = new BABYLON.StandardMaterial("laserPointerMat", this._scene);
+                laserPointerMaterial.emissiveColor = new BABYLON.Color3(0.7, 0.7, 0.7);
+                laserPointerMaterial.alpha = 0.6;
+                laserPointer.material = laserPointerMaterial;
+                laserPointer.rotation.x = Math.PI / 2;
+                laserPointer.parent = controllerMesh;
+                laserPointer.position.z = -1.5;
+                laserPointer.position.y = 0;
+                laserPointer.isVisible = false;
+                webVRController.onMainButtonStateChangedObservable.add((stateObject) => {
+                    // Enabling / disabling laserPointer 
+                    if (stateObject.value === 1) {
+                        laserPointer.isVisible = !laserPointer.isVisible;
+                    }
+                });
+                webVRController.onPadValuesChangedObservable.add((stateObject) => {
+                    // on pressed
+                    if (!this._teleportationRequestInitiated) {
+                        if (stateObject.y < -0.6) {
+                            laserPointer.isVisible = true;
+                            this._teleportationRequestInitiated = true;
+                        }
+                    }
+                    else {
+                        if (stateObject.y > -0.4) {
+                            if (this._teleportationAllowed) {
+                                this._teleportCamera();
+                            }
+                            this._teleportationRequestInitiated = false;
+                            laserPointer.isVisible = false;
+                        }
+                    }
+                    if (!this._rotationLeftAsked) {
+                        if (stateObject.x < -0.6) {
+                            this._rotationLeftAsked = true;
+                            if (this._rotationAllowed) {
+                                this._rotateCamera(false);
+                            }
+                        }
+                    }
+                    else {
+                        if (stateObject.x > -0.4) {
+                            this._rotationLeftAsked = false;
+                        }
+                    }
+        
+                    if (!this._rotationRightAsked) {
+                        if (stateObject.x > 0.6) {
+                            this._rotationRightAsked = true;
+                            if (this._rotationAllowed) {
+                                this._rotateCamera(true);
+                            }
+                        }
+                    }
+                    else {
+                        if (stateObject.x < 0.4) {
+                            this._rotationRightAsked = false;
+                        }
+                    }
+                });
+            }
+        }
+
+        private _createTeleportationCircles() {
+            this._teleportationCircle = BABYLON.Mesh.CreateGround("teleportationCircle", 2, 2, 2, this._scene);
+            
+            var length = 512;
+            var dynamicTexture = new BABYLON.DynamicTexture("DynamicTexture", length, this._scene, true);
+            dynamicTexture.hasAlpha = true;
+            var context = dynamicTexture.getContext();
+    
+            var centerX = length / 2;
+            var centerY = length / 2;
+            var radius = 200;
+    
+            context.beginPath();
+            context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
+            context.fillStyle = this._teleportationFillColor;
+            context.fill();
+            context.lineWidth = 10;
+            context.strokeStyle = this._teleportationBorderColor;
+            context.stroke();
+            context.closePath();
+            dynamicTexture.update();
+            
+            var teleportationCircleMaterial = new BABYLON.StandardMaterial("TextPlaneMaterial", this._scene);
+            teleportationCircleMaterial.diffuseTexture = dynamicTexture;
+            this._teleportationCircle.material = teleportationCircleMaterial;
+            
+            var torus = BABYLON.Mesh.CreateTorus("torus", 0.75, 0.1, 25, this._scene, false);
+            torus.parent = this._teleportationCircle;
+            
+            var animationInnerCircle = new BABYLON.Animation("animationInnerCircle", "position.y", 30, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
+        
+            var keys = [];
+            keys.push({
+                frame: 0,
+                value: 0
+            });
+            keys.push({
+                frame: 30,
+                value: 0.4
+            });
+            keys.push({
+                frame: 60,
+                value: 0
+            });
+        
+            animationInnerCircle.setKeys(keys);
+        
+            var easingFunction = new BABYLON.SineEase();
+            easingFunction.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEINOUT);
+            animationInnerCircle.setEasingFunction(easingFunction);
+        
+            torus.animations = [];
+            torus.animations.push(animationInnerCircle);
+        
+            this._scene.beginAnimation(torus, 0, 60, true);
+            
+            this._hideTeleportationCircle();
+        }
+
+        private _displayTeleportationCircle() {
+            this._teleportationCircle.isVisible = true;
+            (<Mesh>this._teleportationCircle.getChildren()[0]).isVisible = true;
+        }
+        
+        private _hideTeleportationCircle() {
+            this._teleportationCircle.isVisible = false;
+            (<Mesh>this._teleportationCircle.getChildren()[0]).isVisible = false;
+        }
+
+        private _rotateCamera(right: boolean) {
+            if (right) {
+                this._rotationAngle++;
+            }
+            else {
+                this._rotationAngle--;
+            }
+        
+            this.currentVRCamera.animations = [];
+         
+            var target = BABYLON.Quaternion.FromRotationMatrix(BABYLON.Matrix.RotationY(Math.PI / 4 * this._rotationAngle));
+        
+            var animationRotation = new BABYLON.Animation("animationRotation", "rotationQuaternion", 90, BABYLON.Animation.ANIMATIONTYPE_QUATERNION,
+                BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
+            
+            var animationRotationKeys = [];
+            animationRotationKeys.push({
+                frame: 0,
+                value: this.currentVRCamera.rotationQuaternion
+            });
+            animationRotationKeys.push({
+                frame: 6,
+                value: target
+            });
+        
+            animationRotation.setKeys(animationRotationKeys);
+        
+            var easingFunction = new BABYLON.CircleEase();
+            easingFunction.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEINOUT);
+            animationRotation.setEasingFunction(easingFunction);
+        
+            this.currentVRCamera.animations.push(animationRotation);
+        
+            (<any>this._postProcessMove).animations = [];
+        
+            var animationPP = new BABYLON.Animation("animationPP", "vignetteWeight", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT,
+                BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
+        
+            var vignetteWeightKeys = [];
+            vignetteWeightKeys.push({
+                frame: 0,
+                value: 0
+            });
+            vignetteWeightKeys.push({
+                frame: 3,
+                value: 4
+            });
+            vignetteWeightKeys.push({
+                frame: 6,
+                value: 0
+            });
+        
+            animationPP.setKeys(vignetteWeightKeys);
+            animationPP.setEasingFunction(easingFunction);
+            (<any>this._postProcessMove).animations.push(animationPP);
+        
+            var animationPP2 = new BABYLON.Animation("animationPP2", "vignetteStretch", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT,
+                BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
+        
+            var vignetteStretchKeys = [];
+            vignetteStretchKeys.push({
+                frame: 0,
+                value: 0
+            });
+            vignetteStretchKeys.push({
+                frame: 3,
+                value: 10
+            });
+            vignetteStretchKeys.push({
+                frame: 6,
+                value: 0
+            });
+        
+            animationPP2.setKeys(vignetteStretchKeys);
+            animationPP2.setEasingFunction(easingFunction);
+            (<any>this._postProcessMove).animations.push(animationPP2);
+            
+            this._postProcessMove.vignetteWeight = 0;
+            this._postProcessMove.vignetteStretch = 0;
+            this._postProcessMove.vignetteEnabled = true;
+        
+            this._scene.beginAnimation(this._postProcessMove, 0, 6, false, 1, () => {
+                this._postProcessMove.vignetteEnabled = false;
+            });
+            this._scene.beginAnimation(this.currentVRCamera, 0, 6, false, 1);
+        }
+
+        private _moveTeleportationSelectorTo(coordinates: Vector3) {
+            this._teleportationAllowed = true;
+            if (this._teleportationRequestInitiated || this._xboxGamepadTeleportationRequestInitiated) {
+                this._displayTeleportationCircle();
+            }
+            else {
+                this._hideTeleportationCircle();
+            }
+            this._haloCenter.copyFrom(coordinates);
+            this._teleportationCircle.position = coordinates;
+            this._teleportationCircle.position.y += 0.001;
+        }
+
+        private _teleportCamera() {
+            this.currentVRCamera.animations = [];
+        
+            var animationCameraTeleportation = new BABYLON.Animation("animationCameraTeleportation", "position.x", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT,
+                BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
+        
+            var animationCameraTeleportationKeys = [];
+            animationCameraTeleportationKeys.push({
+                frame: 0,
+                value: this.currentVRCamera.position.x
+            });
+            animationCameraTeleportationKeys.push({
+                frame: 11,
+                value: this._haloCenter.x
+            });
+        
+            animationCameraTeleportation.setKeys(animationCameraTeleportationKeys);
+        
+            var easingFunction = new BABYLON.CircleEase();
+            easingFunction.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEINOUT);
+            animationCameraTeleportation.setEasingFunction(easingFunction);
+        
+            this.currentVRCamera.animations.push(animationCameraTeleportation);
+        
+            var animationZoomIn2 = new BABYLON.Animation("animationZoomIn", "position.z", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT,
+                BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
+        
+            var keys2 = [];
+            keys2.push({
+                frame: 0,
+                value: this.currentVRCamera.position.z
+            });
+            keys2.push({
+                frame: 11,
+                value: this._haloCenter.z
+            });
+        
+            animationZoomIn2.setKeys(keys2);
+        
+            animationZoomIn2.setEasingFunction(easingFunction);
+        
+            this.currentVRCamera.animations.push(animationZoomIn2);
+        
+            (<any>this._postProcessMove).animations = [];
+        
+            var animationPP = new BABYLON.Animation("animationPP", "vignetteWeight", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT,
+                BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
+        
+            var vignetteWeightKeys = [];
+            vignetteWeightKeys.push({
+                frame: 0,
+                value: 0
+            });
+            vignetteWeightKeys.push({
+                frame: 5,
+                value: 8
+            });
+            vignetteWeightKeys.push({
+                frame: 11,
+                value: 0
+            });
+        
+            animationPP.setKeys(vignetteWeightKeys);
+            (<any>this._postProcessMove).animations.push(animationPP);
+        
+            var animationPP2 = new BABYLON.Animation("animationPP2", "vignetteStretch", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT,
+                BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
+        
+            var vignetteStretchKeys = [];
+            vignetteStretchKeys.push({
+                frame: 0,
+                value: 0
+            });
+            vignetteStretchKeys.push({
+                frame: 5,
+                value: 10
+            });
+            vignetteStretchKeys.push({
+                frame: 11,
+                value: 0
+            });
+        
+            animationPP2.setKeys(vignetteStretchKeys);
+            (<any>this._postProcessMove).animations.push(animationPP2);
+        
+            this._postProcessMove.vignetteWeight = 8;
+            this._postProcessMove.vignetteStretch = 10;
+            this._postProcessMove.vignetteEnabled = true;
+         
+            this._scene.beginAnimation(this._postProcessMove, 0, 11, false, 1, () => {
+                this._postProcessMove.vignetteEnabled = false;
+            });
+            this._scene.beginAnimation(this.currentVRCamera, 0, 11, false, 1);
+        }
+
+        private _castRayAndSelectObject () {
+            var ray;
+            if (!(<WebVRFreeCamera>this.currentVRCamera).rightController) {
+                ray = this.currentVRCamera.getForwardRay();
+            } else {
+                ray = (<any>this.currentVRCamera).rightController.getForwardRay();
+            }
+        
+            var hit = this._scene.pickWithRay(ray, this.meshSelectionPredicate);
+        
+            if (this._rayHelper) {
+                this._rayHelper.dispose();
+            }
+        
+            if ((<WebVRFreeCamera>this.currentVRCamera).rightController) {
+                //if (target) target.isVisible = false;
+                this._rayHelper = BABYLON.RayHelper.CreateAndShow(ray, this._scene, new BABYLON.Color3(0.7, 0.7, 0.7));
+            }
+        
+            if (hit && hit.pickedMesh) {
+                // The object selected is the floor, we're in a teleportation scenario
+                if (hit.pickedMesh.name.indexOf(this._floorMeshName) !== -1 && hit.pickedPoint) {
+                    this._moveTeleportationSelectorTo(hit.pickedPoint)
+                    return;
+                }
+                // If not, we're in a selection scenario
+                this._hideTeleportationCircle();
+                this._teleportationAllowed = false;
+                //currentMeshSelected = hit.pickedMesh;
+            }
+            else {
+                this._teleportationAllowed = false;
+                this._hideTeleportationCircle();
+            }
+        }
+
         public dispose() {
         public dispose() {
             if (this.isInVRMode()) {
             if (this.isInVRMode()) {
                 this.exitVR();
                 this.exitVR();

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

@@ -531,7 +531,7 @@
         }
         }
 
 
         public static get Version(): string {
         public static get Version(): string {
-            return "3.1-beta-4";
+            return "3.1-beta-5";
         }
         }
 
 
         // Updatable statics so stick with vars here
         // Updatable statics so stick with vars here

+ 7 - 6
src/Helpers/babylon.environmentHelper.ts

@@ -100,7 +100,7 @@ namespace BABYLON {
          */
          */
         skyboxTexture: string | BaseTexture;
         skyboxTexture: string | BaseTexture;
         /**
         /**
-         * The color mixed in the ground texture by default.
+         * The color mixed in the skybox texture by default.
          * BabylonJS clearColor by default.
          * BabylonJS clearColor by default.
          */
          */
         skyboxColor: Color3;
         skyboxColor: Color3;
@@ -123,7 +123,7 @@ namespace BABYLON {
         rootPosition: Vector3;
         rootPosition: Vector3;
 
 
         /**
         /**
-         * Sets up the inmage processing in the scene.
+         * Sets up the image processing in the scene.
          * true by default.
          * true by default.
          */
          */
         setupImageProcessing: boolean;
         setupImageProcessing: boolean;
@@ -299,8 +299,8 @@ namespace BABYLON {
         /**
         /**
          * Stores the creation options.
          * Stores the creation options.
          */
          */
-        private readonly _options: IEnvironmentHelperOptions;
         private readonly _scene: Scene;
         private readonly _scene: Scene;
+        private _options: IEnvironmentHelperOptions;
 
 
         /**
         /**
          * constructor
          * constructor
@@ -363,12 +363,13 @@ namespace BABYLON {
                 this._groundMirror = null;
                 this._groundMirror = null;
             }
             }
 
 
-            this._setupBackground();
-
             if (this._options.environmentTexture && !newOptions.environmentTexture && this._scene.environmentTexture) {
             if (this._options.environmentTexture && !newOptions.environmentTexture && this._scene.environmentTexture) {
                 this._scene.environmentTexture.dispose();
                 this._scene.environmentTexture.dispose();
             }
             }
 
 
+            this._options = newOptions;
+
+            this._setupBackground();
             this._setupImageProcessing();
             this._setupImageProcessing();
         }
         }
 
 
@@ -436,8 +437,8 @@ namespace BABYLON {
 
 
                 if (this._options.enableGroundMirror) {
                 if (this._options.enableGroundMirror) {
                     this._setupGroundMirrorTexture(sceneSize);
                     this._setupGroundMirrorTexture(sceneSize);
-                    this._setupMirrorInGroundMaterial();
                 }
                 }
+                this._setupMirrorInGroundMaterial();
             }
             }
 
 
             if (this._options.createSkybox) {
             if (this._options.createSkybox) {

+ 18 - 0
src/Materials/PBR/babylon.pbrBaseMaterial.ts

@@ -78,6 +78,8 @@
         public REFLECTIONMAP_OPPOSITEZ = false;
         public REFLECTIONMAP_OPPOSITEZ = false;
         public LODINREFLECTIONALPHA = false;
         public LODINREFLECTIONALPHA = false;
         public GAMMAREFLECTION = false;
         public GAMMAREFLECTION = false;
+        public RADIANCEOCCLUSION = false;
+        public HORIZONOCCLUSION = false;
 
 
         public REFRACTION = false;
         public REFRACTION = false;
         public REFRACTIONMAP_3D = false;
         public REFRACTIONMAP_3D = false;
@@ -267,6 +269,18 @@
         protected _linkRefractionWithTransparency = false;
         protected _linkRefractionWithTransparency = false;
 
 
         protected _useLightmapAsShadowmap = false;
         protected _useLightmapAsShadowmap = false;
+
+        /**
+         * This parameters will enable/disable Horizon occlusion to prevent normal maps to look shiny when the normal
+         * makes the reflect vector face the model (under horizon).
+         */
+        protected _useHorizonOcclusion = false; // USEHORIZONOCCLUSION
+
+        /**
+         * This parameters will enable/disable radiance occlusion by preventing the radiance to lit
+         * too much the area relying on ambient texture to define their ambient occlusion.
+         */
+        protected _useRadianceOcclusion = false;
         
         
         /**
         /**
          * Specifies that the alpha is coming form the albedo channel alpha channel for alpha blending.
          * Specifies that the alpha is coming form the albedo channel alpha channel for alpha blending.
@@ -869,6 +883,10 @@
             }
             }
 
 
             defines.FORCENORMALFORWARD = this._forceNormalForward;
             defines.FORCENORMALFORWARD = this._forceNormalForward;
+            
+            defines.RADIANCEOCCLUSION = this._useRadianceOcclusion;
+            
+            defines.HORIZONOCCLUSION = this._useHorizonOcclusion;
 
 
             // Misc.
             // Misc.
             MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, defines);
             MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, defines);

+ 16 - 0
src/Materials/PBR/babylon.pbrMaterial.ts

@@ -405,6 +405,22 @@
         public forceNormalForward = false;
         public forceNormalForward = false;
 
 
         /**
         /**
+         * This parameters will enable/disable Horizon occlusion to prevent normal maps to look shiny when the normal
+         * makes the reflect vector face the model (under horizon).
+         */
+        @serialize()
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public useHorizonOcclusion = false;
+        
+        /**
+         * This parameters will enable/disable radiance occlusion by preventing the radiance to lit
+         * too much the area relying on ambient texture to define their ambient occlusion.
+         */
+        @serialize()
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public useRadianceOcclusion = false;
+
+        /**
          * Gets the image processing configuration used either in this material.
          * Gets the image processing configuration used either in this material.
          */
          */
         public get imageProcessingConfiguration(): ImageProcessingConfiguration {
         public get imageProcessingConfiguration(): ImageProcessingConfiguration {

+ 0 - 1
src/Mesh/babylon.abstractMesh.ts

@@ -1296,7 +1296,6 @@
 
 
         /**
         /**
          * Disposes the AbstractMesh.  
          * Disposes the AbstractMesh.  
-         * Some internal references are kept for further use.  
          * By default, all the mesh children are also disposed unless the parameter `doNotRecurse` is set to `true`.  
          * By default, all the mesh children are also disposed unless the parameter `doNotRecurse` is set to `true`.  
          * Returns nothing.  
          * Returns nothing.  
          */
          */

+ 10 - 3
src/Mesh/babylon.linesMesh.ts

@@ -32,26 +32,33 @@
         private _intersectionThreshold: number;
         private _intersectionThreshold: number;
         private _colorShader: ShaderMaterial;
         private _colorShader: ShaderMaterial;
 
 
-        constructor(name: string, scene: Nullable<Scene> = null, parent: Nullable<Node> = null, source?: LinesMesh, doNotCloneChildren?: boolean, public useVertexColor?: boolean) {
+        constructor(name: string, scene: Nullable<Scene> = null, parent: Nullable<Node> = null, source?: LinesMesh, doNotCloneChildren?: boolean, public useVertexColor?: boolean, public useVertexAlpha?: boolean) {
             super(name, scene, parent, source, doNotCloneChildren);
             super(name, scene, parent, source, doNotCloneChildren);
 
 
             if (source) {
             if (source) {
                 this.color = source.color.clone();
                 this.color = source.color.clone();
                 this.alpha = source.alpha;
                 this.alpha = source.alpha;
                 this.useVertexColor = source.useVertexColor;
                 this.useVertexColor = source.useVertexColor;
+                this.useVertexAlpha = source.useVertexAlpha;
             }
             }
 
 
             this._intersectionThreshold = 0.1;
             this._intersectionThreshold = 0.1;
 
 
+            var defines: String[] = []; 
             var options = {
             var options = {
                 attributes: [VertexBuffer.PositionKind],
                 attributes: [VertexBuffer.PositionKind],
                 uniforms: ["world", "viewProjection"],
                 uniforms: ["world", "viewProjection"],
                 needAlphaBlending: false,
                 needAlphaBlending: false,
+                defines: defines
             };
             };
-
+            
             if (!useVertexColor) {
             if (!useVertexColor) {
                 options.uniforms.push("color");
                 options.uniforms.push("color");
-                options.needAlphaBlending = true;
+            }
+            else {
+                options.needAlphaBlending = (useVertexAlpha) ? true : false;
+                options.defines.push("#define VERTEXCOLOR");
+                options.attributes.push(VertexBuffer.ColorKind);
             }
             }
 
 
             this._colorShader = new ShaderMaterial("colorShader", this.getScene(), "color", options);
             this._colorShader = new ShaderMaterial("colorShader", this.getScene(), "color", options);

+ 3 - 2
src/Mesh/babylon.mesh.ts

@@ -1582,8 +1582,9 @@
         }
         }
 
 
         /**
         /**
-         * Disposes the mesh.
-         * This also frees the memory allocated under the hood to all the buffers used by WebGL.
+         * Disposes the Mesh.  
+         * By default, all the mesh children are also disposed unless the parameter `doNotRecurse` is set to `true`.  
+         * Returns nothing.  
          */
          */
         public dispose(doNotRecurse?: boolean, disposeMaterialAndTextures: boolean = false): void {
         public dispose(doNotRecurse?: boolean, disposeMaterialAndTextures: boolean = false): void {
             this.morphTargetManager = null;
             this.morphTargetManager = null;

+ 10 - 2
src/Mesh/babylon.mesh.vertexData.ts

@@ -1265,17 +1265,22 @@
         /**
         /**
          * Creates the VertexData of the LineSystem.  
          * Creates the VertexData of the LineSystem.  
          */
          */
-        public static CreateLineSystem(options: { lines: Vector3[][] }): VertexData {
+        public static CreateLineSystem(options: { lines: Vector3[][], colors?: Nullable<Color4[][]> }): VertexData {
             var indices = [];
             var indices = [];
             var positions = [];
             var positions = [];
             var lines = options.lines;
             var lines = options.lines;
+            var colors = options.colors;
+            var vertexColors = [];
             var idx = 0;
             var idx = 0;
 
 
             for (var l = 0; l < lines.length; l++) {
             for (var l = 0; l < lines.length; l++) {
                 var points = lines[l];
                 var points = lines[l];
                 for (var index = 0; index < points.length; index++) {
                 for (var index = 0; index < points.length; index++) {
                     positions.push(points[index].x, points[index].y, points[index].z);
                     positions.push(points[index].x, points[index].y, points[index].z);
-
+                    if (colors) {
+                        var color = colors[l];
+                        vertexColors.push(color[index].r, color[index].g, color[index].b, color[index].a);
+                    }
                     if (index > 0) {
                     if (index > 0) {
                         indices.push(idx - 1);
                         indices.push(idx - 1);
                         indices.push(idx);
                         indices.push(idx);
@@ -1286,6 +1291,9 @@
             var vertexData = new VertexData();
             var vertexData = new VertexData();
             vertexData.indices = indices;
             vertexData.indices = indices;
             vertexData.positions = positions;
             vertexData.positions = positions;
+            if (colors) {
+                vertexData.colors = vertexColors;
+            }
             return vertexData;
             return vertexData;
         }
         }
 
 

+ 38 - 15
src/Mesh/babylon.meshBuilder.ts

@@ -358,33 +358,53 @@
          * Like every other parametric shape, it is dynamically updatable by passing an existing instance of LineSystem to this static function.  
          * Like every other parametric shape, it is dynamically updatable by passing an existing instance of LineSystem to this static function.  
          * The parameter `lines` is an array of lines, each line being an array of successive Vector3.   
          * The parameter `lines` is an array of lines, each line being an array of successive Vector3.   
          * The optional parameter `instance` is an instance of an existing LineSystem object to be updated with the passed `lines` parameter. The way to update it is the same than for 
          * The optional parameter `instance` is an instance of an existing LineSystem object to be updated with the passed `lines` parameter. The way to update it is the same than for 
+         * The optional parameter `colors` is an array of line colors, each line colors being an array of successive Color4, one per line point.  
+         * The optional parameter `useVertexAlpha' is to be set to `true` (default `false`) when the alpha value from the former `Color4` array must be used.  
          * updating a simple Line mesh, you just need to update every line in the `lines` array : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#lines-and-dashedlines   
          * updating a simple Line mesh, you just need to update every line in the `lines` array : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#lines-and-dashedlines   
          * When updating an instance, remember that only line point positions can change, not the number of points, neither the number of lines.      
          * When updating an instance, remember that only line point positions can change, not the number of points, neither the number of lines.      
          * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.  
          * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.  
          */
          */
-        public static CreateLineSystem(name: string, options: { lines: Vector3[][], updatable: boolean, instance: Nullable<LinesMesh> }, scene: Nullable<Scene>): LinesMesh {
+        public static CreateLineSystem(name: string, options: { lines: Vector3[][], updatable: boolean, instance: Nullable<LinesMesh>, colors?: Nullable<Color4[][]>, useVertexAlpha?: boolean }, scene: Nullable<Scene>): LinesMesh {
             var instance = options.instance;
             var instance = options.instance;
             var lines = options.lines;
             var lines = options.lines;
+            var colors = options.colors;
 
 
             if (instance) { // lines update
             if (instance) { // lines update
-                var positionFunction = (positions: FloatArray) => {
-                    var i = 0;
-                    for (var l = 0; l < lines.length; l++) {
-                        var points = lines[l];
-                        for (var p = 0; p < points.length; p++) {
-                            positions[i] = points[p].x;
-                            positions[i + 1] = points[p].y;
-                            positions[i + 2] = points[p].z;
-                            i += 3;
+                var positions = instance.getVerticesData(VertexBuffer.PositionKind)!;
+                var vertexColor;
+                var lineColors;
+                if (colors) {
+                    vertexColor = instance.getVerticesData(VertexBuffer.ColorKind)!;
+                }
+                var i = 0;
+                var c = 0;
+                for (var l = 0; l < lines.length; l++) {
+                    var points = lines[l];
+                    for (var p = 0; p < points.length; p++) {
+                        positions[i] = points[p].x;
+                        positions[i + 1] = points[p].y;
+                        positions[i + 2] = points[p].z;
+                        if (colors && vertexColor) {
+                            lineColors = colors[l];
+                            vertexColor[c] = lineColors[p].r;
+                            vertexColor[c + 1] = lineColors[p].g;
+                            vertexColor[c + 2] = lineColors[p].b;
+                            vertexColor[c + 3] = lineColors[p].a;
+                            c += 4;
                         }
                         }
+                        i += 3;
                     }
                     }
-                };
-                instance.updateMeshPositions(positionFunction, false);
+                }
+                instance.updateVerticesData(VertexBuffer.PositionKind, positions, false, false);
+                if (colors && vertexColor) {
+                    instance.updateVerticesData(VertexBuffer.ColorKind, vertexColor, false, false)
+                }
                 return instance;
                 return instance;
             }
             }
 
 
             // line system creation
             // line system creation
-            var lineSystem = new LinesMesh(name, scene);
+            var useVertexColor = (colors) ? true : false;
+            var lineSystem = new LinesMesh(name, scene, null, undefined, undefined, useVertexColor, options.useVertexAlpha);
             var vertexData = VertexData.CreateLineSystem(options);
             var vertexData = VertexData.CreateLineSystem(options);
             vertexData.applyToMesh(lineSystem, options.updatable);
             vertexData.applyToMesh(lineSystem, options.updatable);
             return lineSystem;
             return lineSystem;
@@ -397,11 +417,14 @@
          * Like every other parametric shape, it is dynamically updatable by passing an existing instance of LineMesh to this static function.  
          * Like every other parametric shape, it is dynamically updatable by passing an existing instance of LineMesh to this static function.  
          * The parameter `points` is an array successive Vector3.   
          * The parameter `points` is an array successive Vector3.   
          * The optional parameter `instance` is an instance of an existing LineMesh object to be updated with the passed `points` parameter : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#lines-and-dashedlines    
          * The optional parameter `instance` is an instance of an existing LineMesh object to be updated with the passed `points` parameter : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#lines-and-dashedlines    
+         * The optional parameter `colors` is an array of successive Color4, one per line point.  
+         * The optional parameter `useVertexAlpha' is to be set to `true` (default `false`) when the alpha value from the former `Color4` array must be used.  
          * When updating an instance, remember that only point positions can change, not the number of points.      
          * When updating an instance, remember that only point positions can change, not the number of points.      
          * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.  
          * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.  
          */
          */
-        public static CreateLines(name: string, options: { points: Vector3[], updatable: boolean, instance: Nullable<LinesMesh> }, scene: Nullable<Scene> = null): LinesMesh {
-            var lines = MeshBuilder.CreateLineSystem(name, { lines: [options.points], updatable: options.updatable, instance: options.instance }, scene);
+        public static CreateLines(name: string, options: { points: Vector3[], updatable: boolean, instance: Nullable<LinesMesh>, colors?: Color4[], useVertexAlpha?: boolean }, scene: Nullable<Scene> = null): LinesMesh {
+            var colors = (options.colors) ? [options.colors] : null;
+            var lines = MeshBuilder.CreateLineSystem(name, { lines: [options.points], updatable: options.updatable, instance: options.instance, colors: colors, useVertexAlpha: options.useVertexAlpha }, scene);
             return lines;
             return lines;
         }
         }
 
 

+ 4 - 0
src/Shaders/ShadersInclude/backgroundFragmentDeclaration.fx

@@ -20,4 +20,8 @@
 
 
 #ifdef REFLECTIONFRESNEL
 #ifdef REFLECTIONFRESNEL
     uniform vec4 vReflectionControl;
     uniform vec4 vReflectionControl;
+#endif
+
+#if defined(REFLECTIONMAP_SPHERICAL) || defined(REFLECTIONMAP_PROJECTION) || defined(REFRACTION)
+uniform mat4 view;
 #endif
 #endif

+ 15 - 11
src/Shaders/pbr.fragment.fx

@@ -616,19 +616,23 @@ void main(void) {
 
 
 	vec3 specularEnvironmentReflectance = specularEnvironmentR0 * environmentBrdf.x + environmentBrdf.y;
 	vec3 specularEnvironmentReflectance = specularEnvironmentR0 * environmentBrdf.x + environmentBrdf.y;
 
 
-	#ifdef AMBIENTINGRAYSCALE
-		float ambientMonochrome = ambientOcclusionColor.r;
-	#else
-		float ambientMonochrome = getLuminance(ambientOcclusionColor);
-	#endif
+	#ifdef RADIANCEOCCLUSION
+		#ifdef AMBIENTINGRAYSCALE
+			float ambientMonochrome = ambientOcclusionColor.r;
+		#else
+			float ambientMonochrome = getLuminance(ambientOcclusionColor);
+		#endif
 
 
-	float seo = environmentRadianceOcclusion(ambientMonochrome, NdotVUnclamped);
-	specularEnvironmentReflectance *= seo;
+		float seo = environmentRadianceOcclusion(ambientMonochrome, NdotVUnclamped);
+		specularEnvironmentReflectance *= seo;
+	#endif
 
 
-	#ifdef BUMP
-		#ifdef REFLECTIONMAP_3D
-			float eho = environmentHorizonOcclusion(reflectionCoords, normalW);
-			specularEnvironmentReflectance *= eho;
+	#ifdef HORIZONOCCLUSION
+		#ifdef BUMP
+			#ifdef REFLECTIONMAP_3D
+				float eho = environmentHorizonOcclusion(reflectionCoords, normalW);
+				specularEnvironmentReflectance *= eho;
+			#endif
 		#endif
 		#endif
 	#endif
 	#endif
 #else
 #else

+ 12 - 25
src/Tools/babylon.tools.ts

@@ -457,10 +457,7 @@
                 database.openAsync(loadFromIndexedDB, noIndexedDB);
                 database.openAsync(loadFromIndexedDB, noIndexedDB);
             }
             }
             else {
             else {
-                if (url.indexOf("file:") !== 0) {
-                    noIndexedDB();
-                }
-                else {
+                if (url.indexOf("file:") !== -1) {
                     var textureName = decodeURIComponent(url.substring(5).toLowerCase());
                     var textureName = decodeURIComponent(url.substring(5).toLowerCase());
                     if (FilesInput.FilesToLoad[textureName]) {
                     if (FilesInput.FilesToLoad[textureName]) {
                         try {
                         try {
@@ -477,18 +474,16 @@
                         catch (e) {
                         catch (e) {
                             img.src = "";
                             img.src = "";
                         }
                         }
-                    }
-                    else {
-                        Tools.Error("Image: " + textureName + " not found. Did you forget to provide it?");
-                        img.src = Tools.fallbackTexture;
+                        return img;
                     }
                     }
                 }
                 }
+
+                noIndexedDB();
             }
             }
 
 
             return img;
             return img;
         }
         }
 
 
-        //ANY
         public static LoadFile(url: string, callback: (data: any, responseURL?: string) => void, progressCallBack?: (data: any) => void, database?: Database, useArrayBuffer?: boolean, onError?: (request?: XMLHttpRequest, exception?: any) => void): Nullable<XMLHttpRequest> {
         public static LoadFile(url: string, callback: (data: any, responseURL?: string) => void, progressCallBack?: (data: any) => void, database?: Database, useArrayBuffer?: boolean, onError?: (request?: XMLHttpRequest, exception?: any) => void): Nullable<XMLHttpRequest> {
             url = Tools.CleanUrl(url);
             url = Tools.CleanUrl(url);
 
 
@@ -537,29 +532,21 @@
                 }
                 }
             };
             };
 
 
+            // If file and file input are set
             if (url.indexOf("file:") !== -1) {
             if (url.indexOf("file:") !== -1) {
                 var fileName = decodeURIComponent(url.substring(5).toLowerCase());
                 var fileName = decodeURIComponent(url.substring(5).toLowerCase());
                 if (FilesInput.FilesToLoad[fileName]) {
                 if (FilesInput.FilesToLoad[fileName]) {
                     Tools.ReadFile(FilesInput.FilesToLoad[fileName], callback, progressCallBack, useArrayBuffer);
                     Tools.ReadFile(FilesInput.FilesToLoad[fileName], callback, progressCallBack, useArrayBuffer);
+                    return request;
                 }
                 }
-                else {
-                    let errorMessage = "File: " + fileName + " not found. Did you forget to provide it?";
-                    if (onError) {
-                        let e = new Error(errorMessage);
-                        onError(undefined, e);
-                    } else {
-                        Tools.Error(errorMessage);
-                    }
-                }
+            }
+
+            // Caching all files
+            if (database && database.enableSceneOffline) {
+                database.openAsync(loadFromIndexedDB, noIndexedDB);
             }
             }
             else {
             else {
-                // Caching all files
-                if (database && database.enableSceneOffline) {
-                    database.openAsync(loadFromIndexedDB, noIndexedDB);
-                }
-                else {
-                    noIndexedDB();
-                }
+                noIndexedDB();
             }
             }
 
 
             return request;
             return request;

+ 105 - 99
src/babylon.scene.ts

@@ -96,7 +96,7 @@
         private static _FOGMODE_EXP2 = 2;
         private static _FOGMODE_EXP2 = 2;
         private static _FOGMODE_LINEAR = 3;
         private static _FOGMODE_LINEAR = 3;
 
 
-        private static _uniqueIdCounter = 0;        
+        private static _uniqueIdCounter = 0;
 
 
         public static MinDeltaTime = 1.0;
         public static MinDeltaTime = 1.0;
         public static MaxDeltaTime = 1000.0;
         public static MaxDeltaTime = 1000.0;
@@ -147,7 +147,7 @@
             if (this._environmentTexture === value) {
             if (this._environmentTexture === value) {
                 return;
                 return;
             }
             }
-            
+
             this._environmentTexture = value;
             this._environmentTexture = value;
             this.markAllMaterialsAsDirty(Material.TextureDirtyFlag);
             this.markAllMaterialsAsDirty(Material.TextureDirtyFlag);
         }
         }
@@ -253,37 +253,37 @@
         * An event triggered before animating the scene
         * An event triggered before animating the scene
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
         */
         */
-        public onBeforeAnimationsObservable = new Observable<Scene>();       
-        
+        public onBeforeAnimationsObservable = new Observable<Scene>();
+
         /**
         /**
         * An event triggered after animations processing
         * An event triggered after animations processing
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
         */
         */
-        public onAfterAnimationsObservable = new Observable<Scene>();               
+        public onAfterAnimationsObservable = new Observable<Scene>();
 
 
         /**
         /**
         * An event triggered before draw calls are ready to be sent
         * An event triggered before draw calls are ready to be sent
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
         */
         */
-        public onBeforeDrawPhaseObservable = new Observable<Scene>();          
+        public onBeforeDrawPhaseObservable = new Observable<Scene>();
 
 
         /**
         /**
         * An event triggered after draw calls have been sent
         * An event triggered after draw calls have been sent
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
         */
         */
-        public onAfterDrawPhaseObservable = new Observable<Scene>();         
-        
+        public onAfterDrawPhaseObservable = new Observable<Scene>();
+
         /**
         /**
         * An event triggered when physic simulation is about to be run
         * An event triggered when physic simulation is about to be run
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
         */
         */
-        public onBeforePhysicsObservable = new Observable<Scene>();          
-        
+        public onBeforePhysicsObservable = new Observable<Scene>();
+
         /**
         /**
         * An event triggered when physic simulation has been done
         * An event triggered when physic simulation has been done
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
         */
         */
-        public onAfterPhysicsObservable = new Observable<Scene>();           
+        public onAfterPhysicsObservable = new Observable<Scene>();
 
 
         /**
         /**
         * An event triggered when the scene is ready
         * An event triggered when the scene is ready
@@ -324,47 +324,47 @@
         * An event triggered when active meshes evaluation is about to start
         * An event triggered when active meshes evaluation is about to start
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
         */
         */
-        public onBeforeActiveMeshesEvaluationObservable = new Observable<Scene>();        
+        public onBeforeActiveMeshesEvaluationObservable = new Observable<Scene>();
 
 
         /**
         /**
         * An event triggered when active meshes evaluation is done
         * An event triggered when active meshes evaluation is done
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
         */
         */
-        public onAfterActiveMeshesEvaluationObservable = new Observable<Scene>();           
+        public onAfterActiveMeshesEvaluationObservable = new Observable<Scene>();
 
 
         /**
         /**
         * An event triggered when particles rendering is about to start
         * An event triggered when particles rendering is about to start
         * Note: This event can be trigger more than once per frame (because particles can be rendered by render target textures as well)
         * Note: This event can be trigger more than once per frame (because particles can be rendered by render target textures as well)
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
         */
         */
-        public onBeforeParticlesRenderingObservable = new Observable<Scene>();        
-        
+        public onBeforeParticlesRenderingObservable = new Observable<Scene>();
+
         /**
         /**
         * An event triggered when particles rendering is done
         * An event triggered when particles rendering is done
         * Note: This event can be trigger more than once per frame (because particles can be rendered by render target textures as well)
         * Note: This event can be trigger more than once per frame (because particles can be rendered by render target textures as well)
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
         */
         */
-        public onAfterParticlesRenderingObservable = new Observable<Scene>();  
+        public onAfterParticlesRenderingObservable = new Observable<Scene>();
 
 
         /**
         /**
         * An event triggered when sprites rendering is about to start
         * An event triggered when sprites rendering is about to start
         * Note: This event can be trigger more than once per frame (because sprites can be rendered by render target textures as well)
         * Note: This event can be trigger more than once per frame (because sprites can be rendered by render target textures as well)
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
         */
         */
-        public onBeforeSpritesRenderingObservable = new Observable<Scene>();        
-        
+        public onBeforeSpritesRenderingObservable = new Observable<Scene>();
+
         /**
         /**
         * An event triggered when sprites rendering is done
         * An event triggered when sprites rendering is done
         * Note: This event can be trigger more than once per frame (because sprites can be rendered by render target textures as well)
         * Note: This event can be trigger more than once per frame (because sprites can be rendered by render target textures as well)
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
         */
         */
-        public onAfterSpritesRenderingObservable = new Observable<Scene>();          
+        public onAfterSpritesRenderingObservable = new Observable<Scene>();
 
 
         /**
         /**
         * An event triggered when SceneLoader.Append or SceneLoader.Load or SceneLoader.ImportMesh were successfully executed
         * An event triggered when SceneLoader.Append or SceneLoader.Load or SceneLoader.ImportMesh were successfully executed
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
         */
         */
-        public onDataLoadedObservable = new Observable<Scene>();            
+        public onDataLoadedObservable = new Observable<Scene>();
 
 
         /**
         /**
         * An event triggered when a camera is created
         * An event triggered when a camera is created
@@ -407,12 +407,12 @@
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
         */
         */
         public onNewTransformNodeAddedObservable = new Observable<TransformNode>();
         public onNewTransformNodeAddedObservable = new Observable<TransformNode>();
-        
+
         /**
         /**
         * An event triggered when a transform node is removed
         * An event triggered when a transform node is removed
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
         */
         */
-        public onTransformNodeRemovedObservable = new Observable<TransformNode>();        
+        public onTransformNodeRemovedObservable = new Observable<TransformNode>();
 
 
         /**
         /**
         * An event triggered when a mesh is created
         * An event triggered when a mesh is created
@@ -432,13 +432,13 @@
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
         */
         */
         public OnBeforeRenderTargetsRenderObservable = new Observable<Scene>();
         public OnBeforeRenderTargetsRenderObservable = new Observable<Scene>();
-        
+
         /**
         /**
         * An event triggered when render targets were rendered.
         * An event triggered when render targets were rendered.
         * Can happen multiple times per frame.
         * Can happen multiple times per frame.
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
         */
         */
-        public OnAfterRenderTargetsRenderObservable = new Observable<Scene>();      
+        public OnAfterRenderTargetsRenderObservable = new Observable<Scene>();
 
 
         /**
         /**
         * An event triggered before calculating deterministic simulation step
         * An event triggered before calculating deterministic simulation step
@@ -553,7 +553,7 @@
          * You have the possibility to skip the process and the call to onKeyboardObservable by setting KeyboardInfoPre.skipOnPointerObservable to true
          * You have the possibility to skip the process and the call to onKeyboardObservable by setting KeyboardInfoPre.skipOnPointerObservable to true
          */
          */
         public onPreKeyboardObservable = new Observable<KeyboardInfoPre>();
         public onPreKeyboardObservable = new Observable<KeyboardInfoPre>();
-        
+
         /**
         /**
          * Observable event triggered each time an keyboard event is received from the hosting window
          * Observable event triggered each time an keyboard event is received from the hosting window
          */
          */
@@ -1116,7 +1116,7 @@
 
 
         public getRenderTargetsDuration(): number {
         public getRenderTargetsDuration(): number {
             Tools.Warn("getRenderTargetsDuration is deprecated. Please use SceneInstrumentation class");
             Tools.Warn("getRenderTargetsDuration is deprecated. Please use SceneInstrumentation class");
-            return 0;            
+            return 0;
         }
         }
 
 
         public getRenderDuration(): number {
         public getRenderDuration(): number {
@@ -1200,7 +1200,7 @@
         }
         }
 
 
         private _processPointerMove(pickResult: Nullable<PickingInfo>, evt: PointerEvent): Scene {
         private _processPointerMove(pickResult: Nullable<PickingInfo>, evt: PointerEvent): Scene {
-            
+
             var canvas = this._engine.getRenderingCanvas();
             var canvas = this._engine.getRenderingCanvas();
 
 
             if (!canvas) {
             if (!canvas) {
@@ -1252,7 +1252,7 @@
                 }
                 }
             }
             }
 
 
-            return this;            
+            return this;
         }
         }
 
 
         /**
         /**
@@ -1263,7 +1263,7 @@
             let evt = new PointerEvent("pointerdown");
             let evt = new PointerEvent("pointerdown");
 
 
             return this._processPointerDown(pickResult, evt);
             return this._processPointerDown(pickResult, evt);
-        }        
+        }
 
 
         private _processPointerDown(pickResult: Nullable<PickingInfo>, evt: PointerEvent): Scene {
         private _processPointerDown(pickResult: Nullable<PickingInfo>, evt: PointerEvent): Scene {
             if (pickResult && pickResult.hit && pickResult.pickedMesh) {
             if (pickResult && pickResult.hit && pickResult.pickedMesh) {
@@ -1330,9 +1330,9 @@
             clickInfo.singleClick = true;
             clickInfo.singleClick = true;
 
 
             return this._processPointerUp(pickResult, evt, clickInfo);
             return this._processPointerUp(pickResult, evt, clickInfo);
-        }    
+        }
 
 
-        private _processPointerUp(pickResult: Nullable<PickingInfo>, evt: PointerEvent, clickInfo: ClickInfo): Scene {            
+        private _processPointerUp(pickResult: Nullable<PickingInfo>, evt: PointerEvent, clickInfo: ClickInfo): Scene {
             if (pickResult && pickResult && pickResult.pickedMesh) {
             if (pickResult && pickResult && pickResult.pickedMesh) {
                 this._pickedUpMesh = pickResult.pickedMesh;
                 this._pickedUpMesh = pickResult.pickedMesh;
                 if (this._pickedDownMesh === this._pickedUpMesh) {
                 if (this._pickedDownMesh === this._pickedUpMesh) {
@@ -1560,7 +1560,7 @@
                 }
                 }
 
 
                 // Meshes
                 // Meshes
-                var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerMovePredicate, false, this.cameraToUseForPointers);             
+                var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerMovePredicate, false, this.cameraToUseForPointers);
 
 
                 this._processPointerMove(pickResult, evt);
                 this._processPointerMove(pickResult, evt);
             };
             };
@@ -1643,7 +1643,7 @@
                 this._pickedUpMesh = null;
                 this._pickedUpMesh = null;
                 this._meshPickProceed = false;
                 this._meshPickProceed = false;
 
 
-                this._updatePointerPosition(evt);      
+                this._updatePointerPosition(evt);
                 this._initClickEvent(this.onPrePointerObservable, this.onPointerObservable, evt, (clickInfo: ClickInfo, pickResult: Nullable<PickingInfo>) => {
                 this._initClickEvent(this.onPrePointerObservable, this.onPointerObservable, evt, (clickInfo: ClickInfo, pickResult: Nullable<PickingInfo>) => {
                     // PreObservable support
                     // PreObservable support
                     if (this.onPrePointerObservable.hasObservers()) {
                     if (this.onPrePointerObservable.hasObservers()) {
@@ -1762,18 +1762,18 @@
             };
             };
 
 
             let engine = this.getEngine();
             let engine = this.getEngine();
-            this._onCanvasFocusObserver = engine.onCanvasFocusObservable.add(()=>{
+            this._onCanvasFocusObserver = engine.onCanvasFocusObservable.add(() => {
                 if (!canvas) {
                 if (!canvas) {
                     return;
                     return;
                 }
                 }
                 canvas.addEventListener("keydown", this._onKeyDown, false);
                 canvas.addEventListener("keydown", this._onKeyDown, false);
-                canvas.addEventListener("keyup", this._onKeyUp, false);   
+                canvas.addEventListener("keyup", this._onKeyUp, false);
             });
             });
 
 
-            this._onCanvasBlurObserver = engine.onCanvasBlurObservable.add(()=>{       
+            this._onCanvasBlurObserver = engine.onCanvasBlurObservable.add(() => {
                 if (!canvas) {
                 if (!canvas) {
                     return;
                     return;
-                }                         
+                }
                 canvas.removeEventListener("keydown", this._onKeyDown);
                 canvas.removeEventListener("keydown", this._onKeyDown);
                 canvas.removeEventListener("keyup", this._onKeyUp);
                 canvas.removeEventListener("keyup", this._onKeyUp);
             });
             });
@@ -1836,7 +1836,7 @@
             this.onKeyboardObservable.clear();
             this.onKeyboardObservable.clear();
             this.onPreKeyboardObservable.clear();
             this.onPreKeyboardObservable.clear();
             this.onPointerObservable.clear();
             this.onPointerObservable.clear();
-            this.onPrePointerObservable.clear();     
+            this.onPrePointerObservable.clear();
         }
         }
 
 
         // Ready
         // Ready
@@ -2082,7 +2082,7 @@
             this._useAlternateCameraConfiguration = active;
             this._useAlternateCameraConfiguration = active;
         }
         }
 
 
-        public getViewMatrix(): Matrix {            
+        public getViewMatrix(): Matrix {
             return this._useAlternateCameraConfiguration ? this._alternateViewMatrix : this._viewMatrix;
             return this._useAlternateCameraConfiguration ? this._alternateViewMatrix : this._viewMatrix;
         }
         }
 
 
@@ -2145,7 +2145,7 @@
             if (!this._alternateSceneUbo) {
             if (!this._alternateSceneUbo) {
                 this._createAlternateUbo();
                 this._createAlternateUbo();
             }
             }
-            
+
             if (this._alternateSceneUbo.useUbo) {
             if (this._alternateSceneUbo.useUbo) {
                 this._alternateSceneUbo.updateMatrix("viewProjection", this._alternateTransformMatrix);
                 this._alternateSceneUbo.updateMatrix("viewProjection", this._alternateTransformMatrix);
                 this._alternateSceneUbo.updateMatrix("view", this._alternateViewMatrix);
                 this._alternateSceneUbo.updateMatrix("view", this._alternateViewMatrix);
@@ -2186,13 +2186,13 @@
             this.onMeshRemovedObservable.notifyObservers(toRemove);
             this.onMeshRemovedObservable.notifyObservers(toRemove);
 
 
             return index;
             return index;
-        }        
+        }
 
 
         public addTransformNode(newTransformNode: TransformNode) {
         public addTransformNode(newTransformNode: TransformNode) {
             this.transformNodes.push(newTransformNode);
             this.transformNodes.push(newTransformNode);
 
 
             this.onNewTransformNodeAddedObservable.notifyObservers(newTransformNode);
             this.onNewTransformNodeAddedObservable.notifyObservers(newTransformNode);
-        }        
+        }
 
 
         public removeTransformNode(toRemove: TransformNode): number {
         public removeTransformNode(toRemove: TransformNode): number {
             var index = this.transformNodes.indexOf(toRemove);
             var index = this.transformNodes.indexOf(toRemove);
@@ -2620,7 +2620,7 @@
             return this.transformNodes.filter(function (m) {
             return this.transformNodes.filter(function (m) {
                 return m.id === id;
                 return m.id === id;
             })
             })
-        }        
+        }
 
 
         /**
         /**
          * Get a mesh with its auto-generated unique id
          * Get a mesh with its auto-generated unique id
@@ -2669,7 +2669,7 @@
                 if (this.transformNodes[index].id === id) {
                 if (this.transformNodes[index].id === id) {
                     return this.transformNodes[index];
                     return this.transformNodes[index];
                 }
                 }
-            }            
+            }
 
 
             for (index = this.cameras.length - 1; index >= 0; index--) {
             for (index = this.cameras.length - 1; index >= 0; index--) {
                 if (this.cameras[index].id === id) {
                 if (this.cameras[index].id === id) {
@@ -2752,7 +2752,7 @@
             }
             }
 
 
             return null;
             return null;
-        }        
+        }
 
 
         public getSoundByName(name: string): Nullable<Sound> {
         public getSoundByName(name: string): Nullable<Sound> {
             var index: number;
             var index: number;
@@ -2923,7 +2923,7 @@
         public _isInIntermediateRendering(): boolean {
         public _isInIntermediateRendering(): boolean {
             return this._intermediateRendering
             return this._intermediateRendering
         }
         }
-        
+
         private _activeMeshesFrozen = false;
         private _activeMeshesFrozen = false;
 
 
         /**
         /**
@@ -2934,7 +2934,7 @@
             this._activeMeshesFrozen = true;
             this._activeMeshesFrozen = true;
             return this;
             return this;
         }
         }
-        
+
         /**
         /**
          * Use this function to restart evaluating active meshes on every frame
          * Use this function to restart evaluating active meshes on every frame
          */
          */
@@ -3010,7 +3010,7 @@
                 if (mesh.alwaysSelectAsActiveMesh || mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) !== 0) && mesh.isInFrustum(this._frustumPlanes)) {
                 if (mesh.alwaysSelectAsActiveMesh || mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) !== 0) && mesh.isInFrustum(this._frustumPlanes)) {
                     this._activeMeshes.push(mesh);
                     this._activeMeshes.push(mesh);
                     this.activeCamera._activeMeshes.push(mesh);
                     this.activeCamera._activeMeshes.push(mesh);
-                        
+
                     mesh._activate(this._renderId);
                     mesh._activate(this._renderId);
                     if (meshLOD !== mesh) {
                     if (meshLOD !== mesh) {
                         meshLOD._activate(this._renderId);
                         meshLOD._activate(this._renderId);
@@ -3057,7 +3057,7 @@
             if (sourceMesh.showBoundingBox || this.forceShowBoundingBoxes) {
             if (sourceMesh.showBoundingBox || this.forceShowBoundingBoxes) {
                 let boundingInfo = sourceMesh.getBoundingInfo();
                 let boundingInfo = sourceMesh.getBoundingInfo();
 
 
-                this.getBoundingBoxRenderer().renderList.push(boundingInfo.boundingBox);    
+                this.getBoundingBoxRenderer().renderList.push(boundingInfo.boundingBox);
             }
             }
 
 
             if (mesh && mesh.subMeshes) {
             if (mesh && mesh.subMeshes) {
@@ -3107,7 +3107,7 @@
                 throw new Error("Active camera not set");
                 throw new Error("Active camera not set");
 
 
             Tools.StartPerformanceCounter("Rendering camera " + this.activeCamera.name);
             Tools.StartPerformanceCounter("Rendering camera " + this.activeCamera.name);
-           
+
             // Viewport
             // Viewport
             engine.setViewport(this.activeCamera.viewport);
             engine.setViewport(this.activeCamera.viewport);
 
 
@@ -3211,7 +3211,7 @@
                 }
                 }
                 engine.setDepthBuffer(true);
                 engine.setDepthBuffer(true);
             }
             }
-        
+
             // Activate HighlightLayer stencil
             // Activate HighlightLayer stencil
             if (renderhighlights) {
             if (renderhighlights) {
                 this._engine.setStencilBuffer(true);
                 this._engine.setStencilBuffer(true);
@@ -3270,7 +3270,7 @@
 
 
             // Finalize frame
             // Finalize frame
             this.postProcessManager._finalizeFrame(camera.isIntermediate);
             this.postProcessManager._finalizeFrame(camera.isIntermediate);
-           
+
             // Reset some special arrays
             // Reset some special arrays
             this._renderTargets.reset();
             this._renderTargets.reset();
 
 
@@ -3291,7 +3291,7 @@
             if (this.activeCamera) {
             if (this.activeCamera) {
                 this.activeCamera.update();
                 this.activeCamera.update();
             }
             }
-            
+
             // rig cameras
             // rig cameras
             for (var index = 0; index < camera._rigCameras.length; index++) {
             for (var index = 0; index < camera._rigCameras.length; index++) {
                 this._renderForCamera(camera._rigCameras[index]);
                 this._renderForCamera(camera._rigCameras[index]);
@@ -3368,60 +3368,66 @@
                 this.simplificationQueue.executeNext();
                 this.simplificationQueue.executeNext();
             }
             }
 
 
-            if(this._engine.isDeterministicLockStep()){
-              var deltaTime = Math.max(Scene.MinDeltaTime, Math.min(this._engine.getDeltaTime(), Scene.MaxDeltaTime)) / 1000;
+            if (this._engine.isDeterministicLockStep()) {
+                var deltaTime = Math.max(Scene.MinDeltaTime, Math.min(this._engine.getDeltaTime(), Scene.MaxDeltaTime)) + this._timeAccumulator;
+
+                var defaultFPS = (60.0 / 1000.0);
+
+                let defaultFrameTime = 1000 / 60; // frame time in MS
+
+                if (this._physicsEngine) {
+                    defaultFrameTime = this._physicsEngine.getTimeStep() / 1000; //timestep in physics engine is in seconds
+                }
+                let stepsTaken = 0;
+
+                var maxSubSteps = this._engine.getLockstepMaxSteps();
+
+                var internalSteps = Math.floor(deltaTime / (1000 * defaultFPS));
+                internalSteps = Math.min(internalSteps, maxSubSteps);
 
 
-              var defaultTimeStep = (60.0 / 1000.0);
-              if (this._physicsEngine) {
-                defaultTimeStep = this._physicsEngine.getTimeStep();
-              }
+                do {
+                    this.onBeforeStepObservable.notifyObservers(this);
 
 
-              var maxSubSteps = this._engine.getLockstepMaxSteps();
+                    // Animations
+                    this._animationRatio = defaultFrameTime * defaultFPS;
+                    this._animate();
+                    this.onAfterAnimationsObservable.notifyObservers(this);
 
 
-              this._timeAccumulator += deltaTime;
+                    // Physics
+                    if (this._physicsEngine) {
+                        this.onBeforePhysicsObservable.notifyObservers(this);
+                        this._physicsEngine._step(defaultFPS);
+                        this.onAfterPhysicsObservable.notifyObservers(this);
+                    }
 
 
-              // compute the amount of fixed steps we should have taken since the last step
-              var internalSteps = Math.floor(this._timeAccumulator / defaultTimeStep);
-              internalSteps = Math.min(internalSteps, maxSubSteps);
+                    this.onAfterStepObservable.notifyObservers(this);
+                    this._currentStepId++;
 
 
-              for(this._currentInternalStep = 0; this._currentInternalStep < internalSteps; this._currentInternalStep++){
+                    if ((internalSteps > 1) && (stepsTaken != internalSteps - 1)) {
+                        this._evaluateActiveMeshes();
+                    }
 
 
-                this.onBeforeStepObservable.notifyObservers(this);
+                    stepsTaken++;
+                    deltaTime -= defaultFrameTime;
 
 
+                } while (deltaTime > 0 && stepsTaken < maxSubSteps);
+
+                this._timeAccumulator = deltaTime;
+
+            }
+            else {
                 // Animations
                 // Animations
-                this._animationRatio = defaultTimeStep * (60.0 / 1000.0);
+                var deltaTime = Math.max(Scene.MinDeltaTime, Math.min(this._engine.getDeltaTime(), Scene.MaxDeltaTime));
+                this._animationRatio = deltaTime * (60.0 / 1000.0);
                 this._animate();
                 this._animate();
                 this.onAfterAnimationsObservable.notifyObservers(this);
                 this.onAfterAnimationsObservable.notifyObservers(this);
 
 
                 // Physics
                 // Physics
                 if (this._physicsEngine) {
                 if (this._physicsEngine) {
-                   this.onBeforePhysicsObservable.notifyObservers(this);
-                   this._physicsEngine._step(defaultTimeStep);
-                   this.onAfterPhysicsObservable.notifyObservers(this);
-                }
-                this._timeAccumulator -= defaultTimeStep;
-
-                this.onAfterStepObservable.notifyObservers(this);
-                this._currentStepId++;
-
-                if((internalSteps > 1) && (this._currentInternalStep != internalSteps - 1)) {
-                    this._evaluateActiveMeshes();
+                    this.onBeforePhysicsObservable.notifyObservers(this);
+                    this._physicsEngine._step(deltaTime / 1000.0);
+                    this.onAfterPhysicsObservable.notifyObservers(this);
                 }
                 }
-              }
-            }
-            else {
-              // Animations
-              var deltaTime = Math.max(Scene.MinDeltaTime, Math.min(this._engine.getDeltaTime(), Scene.MaxDeltaTime));
-              this._animationRatio = deltaTime * (60.0 / 1000.0);
-              this._animate();
-              this.onAfterAnimationsObservable.notifyObservers(this);
-
-              // Physics
-              if (this._physicsEngine) {
-                this.onBeforePhysicsObservable.notifyObservers(this);
-                this._physicsEngine._step(deltaTime / 1000.0);
-                this.onAfterPhysicsObservable.notifyObservers(this);
-              }
             }
             }
 
 
             // Before render
             // Before render
@@ -4001,7 +4007,7 @@
             // Moving coordinates to local viewport world
             // Moving coordinates to local viewport world
             x = x / this._engine.getHardwareScalingLevel() - viewport.x;
             x = x / this._engine.getHardwareScalingLevel() - viewport.x;
             y = y / this._engine.getHardwareScalingLevel() - (this._engine.getRenderHeight() - viewport.y - viewport.height);
             y = y / this._engine.getHardwareScalingLevel() - (this._engine.getRenderHeight() - viewport.y - viewport.height);
-            
+
             result.update(x, y, viewport.width, viewport.height, world ? world : Matrix.Identity(), cameraViewSpace ? Matrix.Identity() : camera.getViewMatrix(), camera.getProjectionMatrix());
             result.update(x, y, viewport.width, viewport.height, world ? world : Matrix.Identity(), cameraViewSpace ? Matrix.Identity() : camera.getViewMatrix(), camera.getProjectionMatrix());
             return this;
             return this;
         }
         }
@@ -4178,7 +4184,7 @@
         public pickSprite(x: number, y: number, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean, camera?: Camera): Nullable<PickingInfo> {
         public pickSprite(x: number, y: number, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean, camera?: Camera): Nullable<PickingInfo> {
             if (!this._tempPickingRay) {
             if (!this._tempPickingRay) {
                 this._tempPickingRay = Ray.Zero();
                 this._tempPickingRay = Ray.Zero();
-            }            
+            }
             this.createPickingRayInCameraSpaceToRef(x, y, this._tempPickingRay, camera);
             this.createPickingRayInCameraSpaceToRef(x, y, this._tempPickingRay, camera);
 
 
             return this._internalPickSprites(this._tempPickingRay, predicate, fastCheck, camera);
             return this._internalPickSprites(this._tempPickingRay, predicate, fastCheck, camera);
@@ -4201,7 +4207,7 @@
                 if (!this._cachedRayForTransform) {
                 if (!this._cachedRayForTransform) {
                     this._cachedRayForTransform = Ray.Zero();
                     this._cachedRayForTransform = Ray.Zero();
                 }
                 }
-                
+
                 Ray.TransformToRef(ray, this._pickWithRayInverseMatrix, this._cachedRayForTransform);
                 Ray.TransformToRef(ray, this._pickWithRayInverseMatrix, this._cachedRayForTransform);
                 return this._cachedRayForTransform;
                 return this._cachedRayForTransform;
             }, predicate, fastCheck);
             }, predicate, fastCheck);
@@ -4233,7 +4239,7 @@
                 if (!this._cachedRayForTransform) {
                 if (!this._cachedRayForTransform) {
                     this._cachedRayForTransform = Ray.Zero();
                     this._cachedRayForTransform = Ray.Zero();
                 }
                 }
-                
+
                 Ray.TransformToRef(ray, this._pickWithRayInverseMatrix, this._cachedRayForTransform);
                 Ray.TransformToRef(ray, this._pickWithRayInverseMatrix, this._cachedRayForTransform);
                 return this._cachedRayForTransform;
                 return this._cachedRayForTransform;
             }, predicate);
             }, predicate);
@@ -4337,7 +4343,7 @@
 
 
             if (this.postProcessManager) {
             if (this.postProcessManager) {
                 this.postProcessManager._rebuild();
                 this.postProcessManager._rebuild();
-            }         
+            }
 
 
             for (var layer of this.layers) {
             for (var layer of this.layers) {
                 layer._rebuild();
                 layer._rebuild();
@@ -4357,7 +4363,7 @@
 
 
             if (this._postProcessRenderPipelineManager) {
             if (this._postProcessRenderPipelineManager) {
                 this._postProcessRenderPipelineManager._rebuild();
                 this._postProcessRenderPipelineManager._rebuild();
-            }            
+            }
         }
         }
 
 
         public _rebuildTextures(): void {
         public _rebuildTextures(): void {