浏览代码

Merge pull request #3347 from BabylonJS/master

nightly
David Catuhe 7 年之前
父节点
当前提交
6694613f0f
共有 56 个文件被更改,包括 19954 次插入19548 次删除
  1. 8 0
      .vscode/launch.json
  2. 7014 6992
      Playground/babylon.d.txt
  3. 二进制
      Playground/scenes/BoomBox.glb
  4. 二进制
      Playground/scenes/BoomBox/BoomBox.bin
  5. 173 0
      Playground/scenes/BoomBox/BoomBox.gltf
  6. 二进制
      Playground/scenes/BoomBox/BoomBox_baseColor.png
  7. 二进制
      Playground/scenes/BoomBox/BoomBox_emissive.png
  8. 二进制
      Playground/scenes/BoomBox/BoomBox_normal.png
  9. 二进制
      Playground/scenes/BoomBox/BoomBox_occlusionRoughnessMetallic.png
  10. 10956 10928
      dist/preview release/babylon.d.ts
  11. 31 31
      dist/preview release/babylon.js
  12. 363 253
      dist/preview release/babylon.max.js
  13. 32 32
      dist/preview release/babylon.worker.js
  14. 33 33
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  15. 402 276
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  16. 1 1
      dist/preview release/gui/babylon.gui.js
  17. 1 1
      dist/preview release/gui/babylon.gui.min.js
  18. 10 3
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  19. 33 23
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  20. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  21. 10 3
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  22. 33 23
      dist/preview release/loaders/babylon.glTFFileLoader.js
  23. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  24. 33 23
      dist/preview release/loaders/babylonjs.loaders.js
  25. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  26. 10 3
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  27. 46 46
      dist/preview release/viewer/babylon.viewer.js
  28. 47 25
      dist/preview release/what's new.md
  29. 1 1
      gui/src/controls/inputText.ts
  30. 6 18
      loaders/readme.md
  31. 0 74
      loaders/src/OBJ/README.md
  32. 38 25
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  33. 7 0
      loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts
  34. 0 182
      loaders/src/glTF/README.md
  35. 106 106
      localDev/index.html
  36. 227 191
      src/Cameras/VR/babylon.vrExperienceHelper.ts
  37. 1 1
      src/Cameras/VR/babylon.webVRCamera.ts
  38. 2 2
      src/Cameras/babylon.arcRotateCamera.ts
  39. 35 31
      src/Cameras/babylon.freeCamera.ts
  40. 70 53
      src/Collisions/babylon.collider.ts
  41. 11 11
      src/Collisions/babylon.collisionCoordinator.ts
  42. 14 14
      src/Collisions/babylon.collisionWorker.ts
  43. 1 1
      src/Engine/babylon.engine.ts
  44. 2 2
      src/Loading/babylon.sceneLoader.ts
  45. 4 2
      src/Materials/Textures/babylon.cubeTexture.ts
  46. 77 77
      src/Materials/babylon.standardMaterial.ts
  47. 8 8
      src/Materials/babylon.uniformBuffer.ts
  48. 27 21
      src/Mesh/babylon.abstractMesh.ts
  49. 13 15
      src/Mesh/babylon.geometry.ts
  50. 4 4
      src/Mesh/babylon.mesh.ts
  51. 1 1
      src/Mesh/babylon.transformNode.ts
  52. 44 0
      src/Physics/Plugins/babylon.cannonJSPlugin.ts
  53. 4 1
      src/babylon.node.ts
  54. 6 2
      src/tsconfig.json
  55. 二进制
      tests/validation/ReferenceImages/charting.png
  56. 1 1
      tests/validation/config.json

+ 8 - 0
.vscode/launch.json

@@ -136,6 +136,14 @@
             "runtimeArgs": [
             "runtimeArgs": [
                 "--enable-unsafe-es3-apis"
                 "--enable-unsafe-es3-apis"
             ]
             ]
+        },
+        {
+            "name": "Launch Build Validation (Firefox)",
+            "type": "firefox",
+            "request": "launch",
+            "reAttach": true,
+            "webRoot": "${workspaceRoot}/",
+            "url": "http://localhost:1338/tests/validation/index.html"
         }
         }
     ]
     ]
 }
 }

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


二进制
Playground/scenes/BoomBox.glb


二进制
Playground/scenes/BoomBox/BoomBox.bin


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

@@ -0,0 +1,173 @@
+{
+  "accessors": [
+    {
+      "bufferView": 0,
+      "componentType": 5126,
+      "count": 3575,
+      "type": "VEC2"
+    },
+    {
+      "bufferView": 1,
+      "componentType": 5126,
+      "count": 3575,
+      "type": "VEC3"
+    },
+    {
+      "bufferView": 2,
+      "componentType": 5126,
+      "count": 3575,
+      "type": "VEC4"
+    },
+    {
+      "bufferView": 3,
+      "componentType": 5126,
+      "count": 3575,
+      "type": "VEC3",
+      "max": [
+        0.009921154,
+        0.00977163,
+        0.0100762453
+      ],
+      "min": [
+        -0.009921154,
+        -0.00977163,
+        -0.0100762453
+      ]
+    },
+    {
+      "bufferView": 4,
+      "componentType": 5123,
+      "count": 18108,
+      "type": "SCALAR"
+    }
+  ],
+  "asset": {
+    "generator": "glTF Tools for Unity",
+    "version": "2.0"
+  },
+  "bufferViews": [
+    {
+      "buffer": 0,
+      "byteLength": 28600
+    },
+    {
+      "buffer": 0,
+      "byteOffset": 28600,
+      "byteLength": 42900
+    },
+    {
+      "buffer": 0,
+      "byteOffset": 71500,
+      "byteLength": 57200
+    },
+    {
+      "buffer": 0,
+      "byteOffset": 128700,
+      "byteLength": 42900
+    },
+    {
+      "buffer": 0,
+      "byteOffset": 171600,
+      "byteLength": 36216
+    }
+  ],
+  "buffers": [
+    {
+      "uri": "BoomBox.bin",
+      "byteLength": 207816
+    }
+  ],
+  "images": [
+    {
+      "uri": "BoomBox_baseColor.png"
+    },
+    {
+      "uri": "BoomBox_occlusionRoughnessMetallic.png"
+    },
+    {
+      "uri": "BoomBox_normal.png"
+    },
+    {
+      "uri": "BoomBox_emissive.png"
+    }
+  ],
+  "meshes": [
+    {
+      "primitives": [
+        {
+          "attributes": {
+            "TEXCOORD_0": 0,
+            "NORMAL": 1,
+            "TANGENT": 2,
+            "POSITION": 3
+          },
+          "indices": 4,
+          "material": 0
+        }
+      ],
+      "name": "BoomBox"
+    }
+  ],
+  "materials": [
+    {
+      "pbrMetallicRoughness": {
+        "baseColorTexture": {
+          "index": 0
+        },
+        "metallicRoughnessTexture": {
+          "index": 1
+        }
+      },
+      "normalTexture": {
+        "index": 2
+      },
+      "occlusionTexture": {
+        "index": 1
+      },
+      "emissiveFactor": [
+        1.0,
+        1.0,
+        1.0
+      ],
+      "emissiveTexture": {
+        "index": 3
+      },
+      "name": "BoomBox_Mat"
+    }
+  ],
+  "nodes": [
+    {
+      "mesh": 0,
+      "rotation": [
+        0.0,
+        1.0,
+        0.0,
+        0.0
+      ],
+      "scale": [ 1, 1, 1 ],
+      "name": "BoomBox"
+    }
+  ],
+  "scene": 0,
+  "scenes": [
+    {
+      "nodes": [
+        0
+      ]
+    }
+  ],
+  "textures": [
+    {
+      "source": 0
+    },
+    {
+      "source": 1
+    },
+    {
+      "source": 2
+    },
+    {
+      "source": 3
+    }
+  ]
+}

二进制
Playground/scenes/BoomBox/BoomBox_baseColor.png


二进制
Playground/scenes/BoomBox/BoomBox_emissive.png


二进制
Playground/scenes/BoomBox/BoomBox_normal.png


二进制
Playground/scenes/BoomBox/BoomBox_occlusionRoughnessMetallic.png


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


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


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


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


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


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


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

@@ -4526,7 +4526,7 @@ var BABYLON;
                                 }
                                 }
                                 this._cursorOffset++;
                                 this._cursorOffset++;
                                 currentSize = context.measureText(text.substr(text.length - this._cursorOffset, this._cursorOffset)).width;
                                 currentSize = context.measureText(text.substr(text.length - this._cursorOffset, this._cursorOffset)).width;
-                            } while (currentSize < absoluteCursorPosition);
+                            } while (currentSize < absoluteCursorPosition && (text.length >= this._cursorOffset));
                             // Find closest move
                             // Find closest move
                             if (Math.abs(absoluteCursorPosition - currentSize) > previousDist) {
                             if (Math.abs(absoluteCursorPosition - currentSize) > previousDist) {
                                 this._cursorOffset--;
                                 this._cursorOffset--;

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


+ 10 - 3
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -306,6 +306,11 @@ declare module BABYLON.GLTF2 {
         minFilter?: ETextureMinFilter;
         minFilter?: ETextureMinFilter;
         wrapS?: ETextureWrapMode;
         wrapS?: ETextureWrapMode;
         wrapT?: ETextureWrapMode;
         wrapT?: ETextureWrapMode;
+        index: number;
+        noMipMaps: boolean;
+        samplingMode: number;
+        wrapU: number;
+        wrapV: number;
     }
     }
     interface IGLTFScene extends IGLTFChildRootProperty {
     interface IGLTFScene extends IGLTFChildRootProperty {
         nodes: number[];
         nodes: number[];
@@ -359,6 +364,7 @@ declare module BABYLON.GLTF2 {
         private _parent;
         private _parent;
         private _rootUrl;
         private _rootUrl;
         private _defaultMaterial;
         private _defaultMaterial;
+        private _defaultSampler;
         private _rootNode;
         private _rootNode;
         private _successCallback;
         private _successCallback;
         private _progressCallback;
         private _progressCallback;
@@ -438,14 +444,15 @@ declare module BABYLON.GLTF2 {
         _loadMaterialBaseProperties(context: string, material: IGLTFMaterial): void;
         _loadMaterialBaseProperties(context: string, material: IGLTFMaterial): void;
         _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
         _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
         _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture;
         _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture;
+        private _loadSampler(context, sampler);
         private _loadImageAsync(context, image, onSuccess);
         private _loadImageAsync(context, image, onSuccess);
         _loadUriAsync(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
         _loadUriAsync(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
         _tryCatchOnError(handler: () => void): void;
         _tryCatchOnError(handler: () => void): void;
         private static _AssignIndices(array?);
         private static _AssignIndices(array?);
         static _GetProperty<T extends IGLTFProperty>(array?: ArrayLike<T>, index?: number): Nullable<T>;
         static _GetProperty<T extends IGLTFProperty>(array?: ArrayLike<T>, index?: number): Nullable<T>;
-        private static _GetTextureWrapMode(mode?);
-        private static _GetTextureSamplingMode(magFilter?, minFilter?);
-        private static _GetNumComponents(type);
+        private static _GetTextureWrapMode(context, mode?);
+        private static _GetTextureSamplingMode(context, magFilter?, minFilter?);
+        private static _GetNumComponents(context, type);
         private _compileMaterialAsync(babylonMaterial, babylonMesh, onSuccess);
         private _compileMaterialAsync(babylonMaterial, babylonMesh, onSuccess);
         private _compileMaterialsAsync(onSuccess);
         private _compileMaterialsAsync(onSuccess);
         private _compileShadowGeneratorsAsync(onSuccess);
         private _compileShadowGeneratorsAsync(onSuccess);

+ 33 - 23
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -367,6 +367,7 @@ var BABYLON;
         var GLTFLoader = /** @class */ (function () {
         var GLTFLoader = /** @class */ (function () {
             function GLTFLoader(parent) {
             function GLTFLoader(parent) {
                 this._disposed = false;
                 this._disposed = false;
+                this._defaultSampler = {};
                 this._renderReady = false;
                 this._renderReady = false;
                 this._requests = new Array();
                 this._requests = new Array();
                 this._renderReadyObservable = new BABYLON.Observable();
                 this._renderReadyObservable = new BABYLON.Observable();
@@ -499,6 +500,7 @@ var BABYLON;
                 GLTFLoader._AssignIndices(this._gltf.materials);
                 GLTFLoader._AssignIndices(this._gltf.materials);
                 GLTFLoader._AssignIndices(this._gltf.meshes);
                 GLTFLoader._AssignIndices(this._gltf.meshes);
                 GLTFLoader._AssignIndices(this._gltf.nodes);
                 GLTFLoader._AssignIndices(this._gltf.nodes);
+                GLTFLoader._AssignIndices(this._gltf.samplers);
                 GLTFLoader._AssignIndices(this._gltf.scenes);
                 GLTFLoader._AssignIndices(this._gltf.scenes);
                 GLTFLoader._AssignIndices(this._gltf.skins);
                 GLTFLoader._AssignIndices(this._gltf.skins);
                 GLTFLoader._AssignIndices(this._gltf.textures);
                 GLTFLoader._AssignIndices(this._gltf.textures);
@@ -506,7 +508,7 @@ var BABYLON;
                     var buffers = this._gltf.buffers;
                     var buffers = this._gltf.buffers;
                     if (buffers && buffers[0] && !buffers[0].uri) {
                     if (buffers && buffers[0] && !buffers[0].uri) {
                         var binaryBuffer = buffers[0];
                         var binaryBuffer = buffers[0];
-                        if (binaryBuffer.byteLength != data.bin.byteLength) {
+                        if (binaryBuffer.byteLength < data.bin.byteLength - 3 || binaryBuffer.byteLength > data.bin.byteLength) {
                             BABYLON.Tools.Warn("Binary buffer length (" + binaryBuffer.byteLength + ") from JSON does not match chunk length (" + data.bin.byteLength + ")");
                             BABYLON.Tools.Warn("Binary buffer length (" + binaryBuffer.byteLength + ") from JSON does not match chunk length (" + data.bin.byteLength + ")");
                         }
                         }
                         binaryBuffer.loadedData = data.bin;
                         binaryBuffer.loadedData = data.bin;
@@ -818,7 +820,7 @@ var BABYLON;
              * @param {IGLTFAccessor} accessor
              * @param {IGLTFAccessor} accessor
              */
              */
             GLTFLoader.prototype._convertToFloat4ColorArray = function (context, data, accessor) {
             GLTFLoader.prototype._convertToFloat4ColorArray = function (context, data, accessor) {
-                var colorComponentCount = GLTFLoader._GetNumComponents(accessor.type);
+                var colorComponentCount = GLTFLoader._GetNumComponents(context, accessor.type);
                 if (colorComponentCount === 4 && accessor.componentType === GLTF2.EComponentType.FLOAT) {
                 if (colorComponentCount === 4 && accessor.componentType === GLTF2.EComponentType.FLOAT) {
                     return data;
                     return data;
                 }
                 }
@@ -913,7 +915,7 @@ var BABYLON;
                                 break;
                                 break;
                             }
                             }
                             default: {
                             default: {
-                                BABYLON.Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                                BABYLON.Tools.Warn(context + ": Ignoring unrecognized attribute '" + attribute + "'");
                                 break;
                                 break;
                             }
                             }
                         }
                         }
@@ -1049,7 +1051,7 @@ var BABYLON;
                                 break;
                                 break;
                             }
                             }
                             default: {
                             default: {
-                                BABYLON.Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                                BABYLON.Tools.Warn(context + ": Ignoring unrecognized attribute '" + attribute + "'");
                                 break;
                                 break;
                             }
                             }
                         }
                         }
@@ -1411,13 +1413,13 @@ var BABYLON;
                     throw new Error(context + ": Failed to find buffer view " + accessor.bufferView);
                     throw new Error(context + ": Failed to find buffer view " + accessor.bufferView);
                 }
                 }
                 this._loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView, function (bufferViewData) {
                 this._loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView, function (bufferViewData) {
-                    var numComponents = GLTFLoader._GetNumComponents(accessor.type);
-                    if (numComponents === 0) {
-                        throw new Error(context + ": Invalid type " + accessor.type);
-                    }
+                    var numComponents = GLTFLoader._GetNumComponents(context, accessor.type);
                     var data;
                     var data;
                     var byteOffset = accessor.byteOffset || 0;
                     var byteOffset = accessor.byteOffset || 0;
                     var byteStride = bufferView.byteStride;
                     var byteStride = bufferView.byteStride;
+                    if (byteStride === 0) {
+                        BABYLON.Tools.Warn(context + ": Byte stride of 0 is not valid");
+                    }
                     try {
                     try {
                         switch (accessor.componentType) {
                         switch (accessor.componentType) {
                             case GLTF2.EComponentType.BYTE: {
                             case GLTF2.EComponentType.BYTE: {
@@ -1458,7 +1460,7 @@ var BABYLON;
             GLTFLoader.prototype._buildArrayBuffer = function (typedArray, data, byteOffset, count, numComponents, byteStride) {
             GLTFLoader.prototype._buildArrayBuffer = function (typedArray, data, byteOffset, count, numComponents, byteStride) {
                 byteOffset += data.byteOffset;
                 byteOffset += data.byteOffset;
                 var targetLength = count * numComponents;
                 var targetLength = count * numComponents;
-                if (byteStride == null || byteStride === numComponents * typedArray.BYTES_PER_ELEMENT) {
+                if (!byteStride || byteStride === numComponents * typedArray.BYTES_PER_ELEMENT) {
                     return new typedArray(data.buffer, byteOffset, targetLength);
                     return new typedArray(data.buffer, byteOffset, targetLength);
                 }
                 }
                 var elementStride = byteStride / typedArray.BYTES_PER_ELEMENT;
                 var elementStride = byteStride / typedArray.BYTES_PER_ELEMENT;
@@ -1667,14 +1669,13 @@ var BABYLON;
             };
             };
             GLTFLoader.prototype._loadTexture = function (context, texture, coordinatesIndex) {
             GLTFLoader.prototype._loadTexture = function (context, texture, coordinatesIndex) {
                 var _this = this;
                 var _this = this;
-                var sampler = (texture.sampler == null ? {} : GLTFLoader._GetProperty(this._gltf.samplers, texture.sampler));
+                var sampler = (texture.sampler == undefined ? this._defaultSampler : GLTFLoader._GetProperty(this._gltf.samplers, texture.sampler));
                 if (!sampler) {
                 if (!sampler) {
                     throw new Error(context + ": Failed to find sampler " + texture.sampler);
                     throw new Error(context + ": Failed to find sampler " + texture.sampler);
                 }
                 }
-                var noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
-                var samplingMode = GLTFLoader._GetTextureSamplingMode(sampler.magFilter, sampler.minFilter);
+                this._loadSampler("#/samplers/" + sampler.index, sampler);
                 this._addPendingData(texture);
                 this._addPendingData(texture);
-                var babylonTexture = new BABYLON.Texture(null, this._babylonScene, noMipMaps, false, samplingMode, function () {
+                var babylonTexture = new BABYLON.Texture(null, this._babylonScene, sampler.noMipMaps, false, sampler.samplingMode, function () {
                     _this._tryCatchOnError(function () {
                     _this._tryCatchOnError(function () {
                         _this._removePendingData(texture);
                         _this._removePendingData(texture);
                     });
                     });
@@ -1707,14 +1708,23 @@ var BABYLON;
                     });
                     });
                 }
                 }
                 babylonTexture.coordinatesIndex = coordinatesIndex || 0;
                 babylonTexture.coordinatesIndex = coordinatesIndex || 0;
-                babylonTexture.wrapU = GLTFLoader._GetTextureWrapMode(sampler.wrapS);
-                babylonTexture.wrapV = GLTFLoader._GetTextureWrapMode(sampler.wrapT);
+                babylonTexture.wrapU = sampler.wrapU;
+                babylonTexture.wrapV = sampler.wrapV;
                 babylonTexture.name = texture.name || "texture" + texture.index;
                 babylonTexture.name = texture.name || "texture" + texture.index;
                 if (this._parent.onTextureLoaded) {
                 if (this._parent.onTextureLoaded) {
                     this._parent.onTextureLoaded(babylonTexture);
                     this._parent.onTextureLoaded(babylonTexture);
                 }
                 }
                 return babylonTexture;
                 return babylonTexture;
             };
             };
+            GLTFLoader.prototype._loadSampler = function (context, sampler) {
+                if (sampler.noMipMaps != undefined) {
+                    return;
+                }
+                sampler.noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
+                sampler.samplingMode = GLTFLoader._GetTextureSamplingMode(context, sampler.magFilter, sampler.minFilter);
+                sampler.wrapU = GLTFLoader._GetTextureWrapMode(context, sampler.wrapS);
+                sampler.wrapV = GLTFLoader._GetTextureWrapMode(context, sampler.wrapT);
+            };
             GLTFLoader.prototype._loadImageAsync = function (context, image, onSuccess) {
             GLTFLoader.prototype._loadImageAsync = function (context, image, onSuccess) {
                 if (image.uri) {
                 if (image.uri) {
                     this._loadUriAsync(context, image.uri, onSuccess);
                     this._loadUriAsync(context, image.uri, onSuccess);
@@ -1787,7 +1797,7 @@ var BABYLON;
                 }
                 }
                 return array[index];
                 return array[index];
             };
             };
-            GLTFLoader._GetTextureWrapMode = function (mode) {
+            GLTFLoader._GetTextureWrapMode = function (context, mode) {
                 // Set defaults if undefined
                 // Set defaults if undefined
                 mode = mode == undefined ? GLTF2.ETextureWrapMode.REPEAT : mode;
                 mode = mode == undefined ? GLTF2.ETextureWrapMode.REPEAT : mode;
                 switch (mode) {
                 switch (mode) {
@@ -1795,11 +1805,11 @@ var BABYLON;
                     case GLTF2.ETextureWrapMode.MIRRORED_REPEAT: return BABYLON.Texture.MIRROR_ADDRESSMODE;
                     case GLTF2.ETextureWrapMode.MIRRORED_REPEAT: return BABYLON.Texture.MIRROR_ADDRESSMODE;
                     case GLTF2.ETextureWrapMode.REPEAT: return BABYLON.Texture.WRAP_ADDRESSMODE;
                     case GLTF2.ETextureWrapMode.REPEAT: return BABYLON.Texture.WRAP_ADDRESSMODE;
                     default:
                     default:
-                        BABYLON.Tools.Warn("Invalid texture wrap mode (" + mode + ")");
+                        BABYLON.Tools.Warn(context + ": Invalid texture wrap mode " + mode);
                         return BABYLON.Texture.WRAP_ADDRESSMODE;
                         return BABYLON.Texture.WRAP_ADDRESSMODE;
                 }
                 }
             };
             };
-            GLTFLoader._GetTextureSamplingMode = function (magFilter, minFilter) {
+            GLTFLoader._GetTextureSamplingMode = function (context, magFilter, minFilter) {
                 // Set defaults if undefined
                 // Set defaults if undefined
                 magFilter = magFilter == undefined ? GLTF2.ETextureMagFilter.LINEAR : magFilter;
                 magFilter = magFilter == undefined ? GLTF2.ETextureMagFilter.LINEAR : magFilter;
                 minFilter = minFilter == undefined ? GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR : minFilter;
                 minFilter = minFilter == undefined ? GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR : minFilter;
@@ -1812,13 +1822,13 @@ var BABYLON;
                         case GLTF2.ETextureMinFilter.NEAREST_MIPMAP_LINEAR: return BABYLON.Texture.LINEAR_NEAREST_MIPLINEAR;
                         case GLTF2.ETextureMinFilter.NEAREST_MIPMAP_LINEAR: return BABYLON.Texture.LINEAR_NEAREST_MIPLINEAR;
                         case GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR: return BABYLON.Texture.LINEAR_LINEAR_MIPLINEAR;
                         case GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR: return BABYLON.Texture.LINEAR_LINEAR_MIPLINEAR;
                         default:
                         default:
-                            BABYLON.Tools.Warn("Invalid texture minification filter (" + minFilter + ")");
+                            BABYLON.Tools.Warn(context + ": Invalid texture minification filter " + minFilter);
                             return BABYLON.Texture.LINEAR_LINEAR_MIPLINEAR;
                             return BABYLON.Texture.LINEAR_LINEAR_MIPLINEAR;
                     }
                     }
                 }
                 }
                 else {
                 else {
                     if (magFilter !== GLTF2.ETextureMagFilter.NEAREST) {
                     if (magFilter !== GLTF2.ETextureMagFilter.NEAREST) {
-                        BABYLON.Tools.Warn("Invalid texture magnification filter (" + magFilter + ")");
+                        BABYLON.Tools.Warn(context + ": Invalid texture magnification filter " + magFilter);
                     }
                     }
                     switch (minFilter) {
                     switch (minFilter) {
                         case GLTF2.ETextureMinFilter.NEAREST: return BABYLON.Texture.NEAREST_NEAREST;
                         case GLTF2.ETextureMinFilter.NEAREST: return BABYLON.Texture.NEAREST_NEAREST;
@@ -1828,12 +1838,12 @@ var BABYLON;
                         case GLTF2.ETextureMinFilter.NEAREST_MIPMAP_LINEAR: return BABYLON.Texture.NEAREST_NEAREST_MIPLINEAR;
                         case GLTF2.ETextureMinFilter.NEAREST_MIPMAP_LINEAR: return BABYLON.Texture.NEAREST_NEAREST_MIPLINEAR;
                         case GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR: return BABYLON.Texture.NEAREST_LINEAR_MIPLINEAR;
                         case GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR: return BABYLON.Texture.NEAREST_LINEAR_MIPLINEAR;
                         default:
                         default:
-                            BABYLON.Tools.Warn("Invalid texture minification filter (" + minFilter + ")");
+                            BABYLON.Tools.Warn(context + ": Invalid texture minification filter " + minFilter);
                             return BABYLON.Texture.NEAREST_NEAREST_MIPNEAREST;
                             return BABYLON.Texture.NEAREST_NEAREST_MIPNEAREST;
                     }
                     }
                 }
                 }
             };
             };
-            GLTFLoader._GetNumComponents = function (type) {
+            GLTFLoader._GetNumComponents = function (context, type) {
                 switch (type) {
                 switch (type) {
                     case "SCALAR": return 1;
                     case "SCALAR": return 1;
                     case "VEC2": return 2;
                     case "VEC2": return 2;
@@ -1843,7 +1853,7 @@ var BABYLON;
                     case "MAT3": return 9;
                     case "MAT3": return 9;
                     case "MAT4": return 16;
                     case "MAT4": return 16;
                 }
                 }
-                return 0;
+                throw new Error(context + ": Invalid type " + type);
             };
             };
             GLTFLoader.prototype._compileMaterialAsync = function (babylonMaterial, babylonMesh, onSuccess) {
             GLTFLoader.prototype._compileMaterialAsync = function (babylonMaterial, babylonMesh, onSuccess) {
                 var _this = this;
                 var _this = this;

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


+ 10 - 3
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -853,6 +853,11 @@ declare module BABYLON.GLTF2 {
         minFilter?: ETextureMinFilter;
         minFilter?: ETextureMinFilter;
         wrapS?: ETextureWrapMode;
         wrapS?: ETextureWrapMode;
         wrapT?: ETextureWrapMode;
         wrapT?: ETextureWrapMode;
+        index: number;
+        noMipMaps: boolean;
+        samplingMode: number;
+        wrapU: number;
+        wrapV: number;
     }
     }
     interface IGLTFScene extends IGLTFChildRootProperty {
     interface IGLTFScene extends IGLTFChildRootProperty {
         nodes: number[];
         nodes: number[];
@@ -906,6 +911,7 @@ declare module BABYLON.GLTF2 {
         private _parent;
         private _parent;
         private _rootUrl;
         private _rootUrl;
         private _defaultMaterial;
         private _defaultMaterial;
+        private _defaultSampler;
         private _rootNode;
         private _rootNode;
         private _successCallback;
         private _successCallback;
         private _progressCallback;
         private _progressCallback;
@@ -985,14 +991,15 @@ declare module BABYLON.GLTF2 {
         _loadMaterialBaseProperties(context: string, material: IGLTFMaterial): void;
         _loadMaterialBaseProperties(context: string, material: IGLTFMaterial): void;
         _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
         _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
         _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture;
         _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture;
+        private _loadSampler(context, sampler);
         private _loadImageAsync(context, image, onSuccess);
         private _loadImageAsync(context, image, onSuccess);
         _loadUriAsync(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
         _loadUriAsync(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
         _tryCatchOnError(handler: () => void): void;
         _tryCatchOnError(handler: () => void): void;
         private static _AssignIndices(array?);
         private static _AssignIndices(array?);
         static _GetProperty<T extends IGLTFProperty>(array?: ArrayLike<T>, index?: number): Nullable<T>;
         static _GetProperty<T extends IGLTFProperty>(array?: ArrayLike<T>, index?: number): Nullable<T>;
-        private static _GetTextureWrapMode(mode?);
-        private static _GetTextureSamplingMode(magFilter?, minFilter?);
-        private static _GetNumComponents(type);
+        private static _GetTextureWrapMode(context, mode?);
+        private static _GetTextureSamplingMode(context, magFilter?, minFilter?);
+        private static _GetNumComponents(context, type);
         private _compileMaterialAsync(babylonMaterial, babylonMesh, onSuccess);
         private _compileMaterialAsync(babylonMaterial, babylonMesh, onSuccess);
         private _compileMaterialsAsync(onSuccess);
         private _compileMaterialsAsync(onSuccess);
         private _compileShadowGeneratorsAsync(onSuccess);
         private _compileShadowGeneratorsAsync(onSuccess);

+ 33 - 23
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -2523,6 +2523,7 @@ var BABYLON;
         var GLTFLoader = /** @class */ (function () {
         var GLTFLoader = /** @class */ (function () {
             function GLTFLoader(parent) {
             function GLTFLoader(parent) {
                 this._disposed = false;
                 this._disposed = false;
+                this._defaultSampler = {};
                 this._renderReady = false;
                 this._renderReady = false;
                 this._requests = new Array();
                 this._requests = new Array();
                 this._renderReadyObservable = new BABYLON.Observable();
                 this._renderReadyObservable = new BABYLON.Observable();
@@ -2655,6 +2656,7 @@ var BABYLON;
                 GLTFLoader._AssignIndices(this._gltf.materials);
                 GLTFLoader._AssignIndices(this._gltf.materials);
                 GLTFLoader._AssignIndices(this._gltf.meshes);
                 GLTFLoader._AssignIndices(this._gltf.meshes);
                 GLTFLoader._AssignIndices(this._gltf.nodes);
                 GLTFLoader._AssignIndices(this._gltf.nodes);
+                GLTFLoader._AssignIndices(this._gltf.samplers);
                 GLTFLoader._AssignIndices(this._gltf.scenes);
                 GLTFLoader._AssignIndices(this._gltf.scenes);
                 GLTFLoader._AssignIndices(this._gltf.skins);
                 GLTFLoader._AssignIndices(this._gltf.skins);
                 GLTFLoader._AssignIndices(this._gltf.textures);
                 GLTFLoader._AssignIndices(this._gltf.textures);
@@ -2662,7 +2664,7 @@ var BABYLON;
                     var buffers = this._gltf.buffers;
                     var buffers = this._gltf.buffers;
                     if (buffers && buffers[0] && !buffers[0].uri) {
                     if (buffers && buffers[0] && !buffers[0].uri) {
                         var binaryBuffer = buffers[0];
                         var binaryBuffer = buffers[0];
-                        if (binaryBuffer.byteLength != data.bin.byteLength) {
+                        if (binaryBuffer.byteLength < data.bin.byteLength - 3 || binaryBuffer.byteLength > data.bin.byteLength) {
                             BABYLON.Tools.Warn("Binary buffer length (" + binaryBuffer.byteLength + ") from JSON does not match chunk length (" + data.bin.byteLength + ")");
                             BABYLON.Tools.Warn("Binary buffer length (" + binaryBuffer.byteLength + ") from JSON does not match chunk length (" + data.bin.byteLength + ")");
                         }
                         }
                         binaryBuffer.loadedData = data.bin;
                         binaryBuffer.loadedData = data.bin;
@@ -2974,7 +2976,7 @@ var BABYLON;
              * @param {IGLTFAccessor} accessor
              * @param {IGLTFAccessor} accessor
              */
              */
             GLTFLoader.prototype._convertToFloat4ColorArray = function (context, data, accessor) {
             GLTFLoader.prototype._convertToFloat4ColorArray = function (context, data, accessor) {
-                var colorComponentCount = GLTFLoader._GetNumComponents(accessor.type);
+                var colorComponentCount = GLTFLoader._GetNumComponents(context, accessor.type);
                 if (colorComponentCount === 4 && accessor.componentType === GLTF2.EComponentType.FLOAT) {
                 if (colorComponentCount === 4 && accessor.componentType === GLTF2.EComponentType.FLOAT) {
                     return data;
                     return data;
                 }
                 }
@@ -3069,7 +3071,7 @@ var BABYLON;
                                 break;
                                 break;
                             }
                             }
                             default: {
                             default: {
-                                BABYLON.Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                                BABYLON.Tools.Warn(context + ": Ignoring unrecognized attribute '" + attribute + "'");
                                 break;
                                 break;
                             }
                             }
                         }
                         }
@@ -3205,7 +3207,7 @@ var BABYLON;
                                 break;
                                 break;
                             }
                             }
                             default: {
                             default: {
-                                BABYLON.Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                                BABYLON.Tools.Warn(context + ": Ignoring unrecognized attribute '" + attribute + "'");
                                 break;
                                 break;
                             }
                             }
                         }
                         }
@@ -3567,13 +3569,13 @@ var BABYLON;
                     throw new Error(context + ": Failed to find buffer view " + accessor.bufferView);
                     throw new Error(context + ": Failed to find buffer view " + accessor.bufferView);
                 }
                 }
                 this._loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView, function (bufferViewData) {
                 this._loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView, function (bufferViewData) {
-                    var numComponents = GLTFLoader._GetNumComponents(accessor.type);
-                    if (numComponents === 0) {
-                        throw new Error(context + ": Invalid type " + accessor.type);
-                    }
+                    var numComponents = GLTFLoader._GetNumComponents(context, accessor.type);
                     var data;
                     var data;
                     var byteOffset = accessor.byteOffset || 0;
                     var byteOffset = accessor.byteOffset || 0;
                     var byteStride = bufferView.byteStride;
                     var byteStride = bufferView.byteStride;
+                    if (byteStride === 0) {
+                        BABYLON.Tools.Warn(context + ": Byte stride of 0 is not valid");
+                    }
                     try {
                     try {
                         switch (accessor.componentType) {
                         switch (accessor.componentType) {
                             case GLTF2.EComponentType.BYTE: {
                             case GLTF2.EComponentType.BYTE: {
@@ -3614,7 +3616,7 @@ var BABYLON;
             GLTFLoader.prototype._buildArrayBuffer = function (typedArray, data, byteOffset, count, numComponents, byteStride) {
             GLTFLoader.prototype._buildArrayBuffer = function (typedArray, data, byteOffset, count, numComponents, byteStride) {
                 byteOffset += data.byteOffset;
                 byteOffset += data.byteOffset;
                 var targetLength = count * numComponents;
                 var targetLength = count * numComponents;
-                if (byteStride == null || byteStride === numComponents * typedArray.BYTES_PER_ELEMENT) {
+                if (!byteStride || byteStride === numComponents * typedArray.BYTES_PER_ELEMENT) {
                     return new typedArray(data.buffer, byteOffset, targetLength);
                     return new typedArray(data.buffer, byteOffset, targetLength);
                 }
                 }
                 var elementStride = byteStride / typedArray.BYTES_PER_ELEMENT;
                 var elementStride = byteStride / typedArray.BYTES_PER_ELEMENT;
@@ -3823,14 +3825,13 @@ var BABYLON;
             };
             };
             GLTFLoader.prototype._loadTexture = function (context, texture, coordinatesIndex) {
             GLTFLoader.prototype._loadTexture = function (context, texture, coordinatesIndex) {
                 var _this = this;
                 var _this = this;
-                var sampler = (texture.sampler == null ? {} : GLTFLoader._GetProperty(this._gltf.samplers, texture.sampler));
+                var sampler = (texture.sampler == undefined ? this._defaultSampler : GLTFLoader._GetProperty(this._gltf.samplers, texture.sampler));
                 if (!sampler) {
                 if (!sampler) {
                     throw new Error(context + ": Failed to find sampler " + texture.sampler);
                     throw new Error(context + ": Failed to find sampler " + texture.sampler);
                 }
                 }
-                var noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
-                var samplingMode = GLTFLoader._GetTextureSamplingMode(sampler.magFilter, sampler.minFilter);
+                this._loadSampler("#/samplers/" + sampler.index, sampler);
                 this._addPendingData(texture);
                 this._addPendingData(texture);
-                var babylonTexture = new BABYLON.Texture(null, this._babylonScene, noMipMaps, false, samplingMode, function () {
+                var babylonTexture = new BABYLON.Texture(null, this._babylonScene, sampler.noMipMaps, false, sampler.samplingMode, function () {
                     _this._tryCatchOnError(function () {
                     _this._tryCatchOnError(function () {
                         _this._removePendingData(texture);
                         _this._removePendingData(texture);
                     });
                     });
@@ -3863,14 +3864,23 @@ var BABYLON;
                     });
                     });
                 }
                 }
                 babylonTexture.coordinatesIndex = coordinatesIndex || 0;
                 babylonTexture.coordinatesIndex = coordinatesIndex || 0;
-                babylonTexture.wrapU = GLTFLoader._GetTextureWrapMode(sampler.wrapS);
-                babylonTexture.wrapV = GLTFLoader._GetTextureWrapMode(sampler.wrapT);
+                babylonTexture.wrapU = sampler.wrapU;
+                babylonTexture.wrapV = sampler.wrapV;
                 babylonTexture.name = texture.name || "texture" + texture.index;
                 babylonTexture.name = texture.name || "texture" + texture.index;
                 if (this._parent.onTextureLoaded) {
                 if (this._parent.onTextureLoaded) {
                     this._parent.onTextureLoaded(babylonTexture);
                     this._parent.onTextureLoaded(babylonTexture);
                 }
                 }
                 return babylonTexture;
                 return babylonTexture;
             };
             };
+            GLTFLoader.prototype._loadSampler = function (context, sampler) {
+                if (sampler.noMipMaps != undefined) {
+                    return;
+                }
+                sampler.noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
+                sampler.samplingMode = GLTFLoader._GetTextureSamplingMode(context, sampler.magFilter, sampler.minFilter);
+                sampler.wrapU = GLTFLoader._GetTextureWrapMode(context, sampler.wrapS);
+                sampler.wrapV = GLTFLoader._GetTextureWrapMode(context, sampler.wrapT);
+            };
             GLTFLoader.prototype._loadImageAsync = function (context, image, onSuccess) {
             GLTFLoader.prototype._loadImageAsync = function (context, image, onSuccess) {
                 if (image.uri) {
                 if (image.uri) {
                     this._loadUriAsync(context, image.uri, onSuccess);
                     this._loadUriAsync(context, image.uri, onSuccess);
@@ -3943,7 +3953,7 @@ var BABYLON;
                 }
                 }
                 return array[index];
                 return array[index];
             };
             };
-            GLTFLoader._GetTextureWrapMode = function (mode) {
+            GLTFLoader._GetTextureWrapMode = function (context, mode) {
                 // Set defaults if undefined
                 // Set defaults if undefined
                 mode = mode == undefined ? GLTF2.ETextureWrapMode.REPEAT : mode;
                 mode = mode == undefined ? GLTF2.ETextureWrapMode.REPEAT : mode;
                 switch (mode) {
                 switch (mode) {
@@ -3951,11 +3961,11 @@ var BABYLON;
                     case GLTF2.ETextureWrapMode.MIRRORED_REPEAT: return BABYLON.Texture.MIRROR_ADDRESSMODE;
                     case GLTF2.ETextureWrapMode.MIRRORED_REPEAT: return BABYLON.Texture.MIRROR_ADDRESSMODE;
                     case GLTF2.ETextureWrapMode.REPEAT: return BABYLON.Texture.WRAP_ADDRESSMODE;
                     case GLTF2.ETextureWrapMode.REPEAT: return BABYLON.Texture.WRAP_ADDRESSMODE;
                     default:
                     default:
-                        BABYLON.Tools.Warn("Invalid texture wrap mode (" + mode + ")");
+                        BABYLON.Tools.Warn(context + ": Invalid texture wrap mode " + mode);
                         return BABYLON.Texture.WRAP_ADDRESSMODE;
                         return BABYLON.Texture.WRAP_ADDRESSMODE;
                 }
                 }
             };
             };
-            GLTFLoader._GetTextureSamplingMode = function (magFilter, minFilter) {
+            GLTFLoader._GetTextureSamplingMode = function (context, magFilter, minFilter) {
                 // Set defaults if undefined
                 // Set defaults if undefined
                 magFilter = magFilter == undefined ? GLTF2.ETextureMagFilter.LINEAR : magFilter;
                 magFilter = magFilter == undefined ? GLTF2.ETextureMagFilter.LINEAR : magFilter;
                 minFilter = minFilter == undefined ? GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR : minFilter;
                 minFilter = minFilter == undefined ? GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR : minFilter;
@@ -3968,13 +3978,13 @@ var BABYLON;
                         case GLTF2.ETextureMinFilter.NEAREST_MIPMAP_LINEAR: return BABYLON.Texture.LINEAR_NEAREST_MIPLINEAR;
                         case GLTF2.ETextureMinFilter.NEAREST_MIPMAP_LINEAR: return BABYLON.Texture.LINEAR_NEAREST_MIPLINEAR;
                         case GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR: return BABYLON.Texture.LINEAR_LINEAR_MIPLINEAR;
                         case GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR: return BABYLON.Texture.LINEAR_LINEAR_MIPLINEAR;
                         default:
                         default:
-                            BABYLON.Tools.Warn("Invalid texture minification filter (" + minFilter + ")");
+                            BABYLON.Tools.Warn(context + ": Invalid texture minification filter " + minFilter);
                             return BABYLON.Texture.LINEAR_LINEAR_MIPLINEAR;
                             return BABYLON.Texture.LINEAR_LINEAR_MIPLINEAR;
                     }
                     }
                 }
                 }
                 else {
                 else {
                     if (magFilter !== GLTF2.ETextureMagFilter.NEAREST) {
                     if (magFilter !== GLTF2.ETextureMagFilter.NEAREST) {
-                        BABYLON.Tools.Warn("Invalid texture magnification filter (" + magFilter + ")");
+                        BABYLON.Tools.Warn(context + ": Invalid texture magnification filter " + magFilter);
                     }
                     }
                     switch (minFilter) {
                     switch (minFilter) {
                         case GLTF2.ETextureMinFilter.NEAREST: return BABYLON.Texture.NEAREST_NEAREST;
                         case GLTF2.ETextureMinFilter.NEAREST: return BABYLON.Texture.NEAREST_NEAREST;
@@ -3984,12 +3994,12 @@ var BABYLON;
                         case GLTF2.ETextureMinFilter.NEAREST_MIPMAP_LINEAR: return BABYLON.Texture.NEAREST_NEAREST_MIPLINEAR;
                         case GLTF2.ETextureMinFilter.NEAREST_MIPMAP_LINEAR: return BABYLON.Texture.NEAREST_NEAREST_MIPLINEAR;
                         case GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR: return BABYLON.Texture.NEAREST_LINEAR_MIPLINEAR;
                         case GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR: return BABYLON.Texture.NEAREST_LINEAR_MIPLINEAR;
                         default:
                         default:
-                            BABYLON.Tools.Warn("Invalid texture minification filter (" + minFilter + ")");
+                            BABYLON.Tools.Warn(context + ": Invalid texture minification filter " + minFilter);
                             return BABYLON.Texture.NEAREST_NEAREST_MIPNEAREST;
                             return BABYLON.Texture.NEAREST_NEAREST_MIPNEAREST;
                     }
                     }
                 }
                 }
             };
             };
-            GLTFLoader._GetNumComponents = function (type) {
+            GLTFLoader._GetNumComponents = function (context, type) {
                 switch (type) {
                 switch (type) {
                     case "SCALAR": return 1;
                     case "SCALAR": return 1;
                     case "VEC2": return 2;
                     case "VEC2": return 2;
@@ -3999,7 +4009,7 @@ var BABYLON;
                     case "MAT3": return 9;
                     case "MAT3": return 9;
                     case "MAT4": return 16;
                     case "MAT4": return 16;
                 }
                 }
-                return 0;
+                throw new Error(context + ": Invalid type " + type);
             };
             };
             GLTFLoader.prototype._compileMaterialAsync = function (babylonMaterial, babylonMesh, onSuccess) {
             GLTFLoader.prototype._compileMaterialAsync = function (babylonMaterial, babylonMesh, onSuccess) {
                 var _this = this;
                 var _this = this;

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


+ 33 - 23
dist/preview release/loaders/babylonjs.loaders.js

@@ -3479,6 +3479,7 @@ var BABYLON;
         var GLTFLoader = /** @class */ (function () {
         var GLTFLoader = /** @class */ (function () {
             function GLTFLoader(parent) {
             function GLTFLoader(parent) {
                 this._disposed = false;
                 this._disposed = false;
+                this._defaultSampler = {};
                 this._renderReady = false;
                 this._renderReady = false;
                 this._requests = new Array();
                 this._requests = new Array();
                 this._renderReadyObservable = new BABYLON.Observable();
                 this._renderReadyObservable = new BABYLON.Observable();
@@ -3611,6 +3612,7 @@ var BABYLON;
                 GLTFLoader._AssignIndices(this._gltf.materials);
                 GLTFLoader._AssignIndices(this._gltf.materials);
                 GLTFLoader._AssignIndices(this._gltf.meshes);
                 GLTFLoader._AssignIndices(this._gltf.meshes);
                 GLTFLoader._AssignIndices(this._gltf.nodes);
                 GLTFLoader._AssignIndices(this._gltf.nodes);
+                GLTFLoader._AssignIndices(this._gltf.samplers);
                 GLTFLoader._AssignIndices(this._gltf.scenes);
                 GLTFLoader._AssignIndices(this._gltf.scenes);
                 GLTFLoader._AssignIndices(this._gltf.skins);
                 GLTFLoader._AssignIndices(this._gltf.skins);
                 GLTFLoader._AssignIndices(this._gltf.textures);
                 GLTFLoader._AssignIndices(this._gltf.textures);
@@ -3618,7 +3620,7 @@ var BABYLON;
                     var buffers = this._gltf.buffers;
                     var buffers = this._gltf.buffers;
                     if (buffers && buffers[0] && !buffers[0].uri) {
                     if (buffers && buffers[0] && !buffers[0].uri) {
                         var binaryBuffer = buffers[0];
                         var binaryBuffer = buffers[0];
-                        if (binaryBuffer.byteLength != data.bin.byteLength) {
+                        if (binaryBuffer.byteLength < data.bin.byteLength - 3 || binaryBuffer.byteLength > data.bin.byteLength) {
                             BABYLON.Tools.Warn("Binary buffer length (" + binaryBuffer.byteLength + ") from JSON does not match chunk length (" + data.bin.byteLength + ")");
                             BABYLON.Tools.Warn("Binary buffer length (" + binaryBuffer.byteLength + ") from JSON does not match chunk length (" + data.bin.byteLength + ")");
                         }
                         }
                         binaryBuffer.loadedData = data.bin;
                         binaryBuffer.loadedData = data.bin;
@@ -3930,7 +3932,7 @@ var BABYLON;
              * @param {IGLTFAccessor} accessor
              * @param {IGLTFAccessor} accessor
              */
              */
             GLTFLoader.prototype._convertToFloat4ColorArray = function (context, data, accessor) {
             GLTFLoader.prototype._convertToFloat4ColorArray = function (context, data, accessor) {
-                var colorComponentCount = GLTFLoader._GetNumComponents(accessor.type);
+                var colorComponentCount = GLTFLoader._GetNumComponents(context, accessor.type);
                 if (colorComponentCount === 4 && accessor.componentType === GLTF2.EComponentType.FLOAT) {
                 if (colorComponentCount === 4 && accessor.componentType === GLTF2.EComponentType.FLOAT) {
                     return data;
                     return data;
                 }
                 }
@@ -4025,7 +4027,7 @@ var BABYLON;
                                 break;
                                 break;
                             }
                             }
                             default: {
                             default: {
-                                BABYLON.Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                                BABYLON.Tools.Warn(context + ": Ignoring unrecognized attribute '" + attribute + "'");
                                 break;
                                 break;
                             }
                             }
                         }
                         }
@@ -4161,7 +4163,7 @@ var BABYLON;
                                 break;
                                 break;
                             }
                             }
                             default: {
                             default: {
-                                BABYLON.Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                                BABYLON.Tools.Warn(context + ": Ignoring unrecognized attribute '" + attribute + "'");
                                 break;
                                 break;
                             }
                             }
                         }
                         }
@@ -4523,13 +4525,13 @@ var BABYLON;
                     throw new Error(context + ": Failed to find buffer view " + accessor.bufferView);
                     throw new Error(context + ": Failed to find buffer view " + accessor.bufferView);
                 }
                 }
                 this._loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView, function (bufferViewData) {
                 this._loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView, function (bufferViewData) {
-                    var numComponents = GLTFLoader._GetNumComponents(accessor.type);
-                    if (numComponents === 0) {
-                        throw new Error(context + ": Invalid type " + accessor.type);
-                    }
+                    var numComponents = GLTFLoader._GetNumComponents(context, accessor.type);
                     var data;
                     var data;
                     var byteOffset = accessor.byteOffset || 0;
                     var byteOffset = accessor.byteOffset || 0;
                     var byteStride = bufferView.byteStride;
                     var byteStride = bufferView.byteStride;
+                    if (byteStride === 0) {
+                        BABYLON.Tools.Warn(context + ": Byte stride of 0 is not valid");
+                    }
                     try {
                     try {
                         switch (accessor.componentType) {
                         switch (accessor.componentType) {
                             case GLTF2.EComponentType.BYTE: {
                             case GLTF2.EComponentType.BYTE: {
@@ -4570,7 +4572,7 @@ var BABYLON;
             GLTFLoader.prototype._buildArrayBuffer = function (typedArray, data, byteOffset, count, numComponents, byteStride) {
             GLTFLoader.prototype._buildArrayBuffer = function (typedArray, data, byteOffset, count, numComponents, byteStride) {
                 byteOffset += data.byteOffset;
                 byteOffset += data.byteOffset;
                 var targetLength = count * numComponents;
                 var targetLength = count * numComponents;
-                if (byteStride == null || byteStride === numComponents * typedArray.BYTES_PER_ELEMENT) {
+                if (!byteStride || byteStride === numComponents * typedArray.BYTES_PER_ELEMENT) {
                     return new typedArray(data.buffer, byteOffset, targetLength);
                     return new typedArray(data.buffer, byteOffset, targetLength);
                 }
                 }
                 var elementStride = byteStride / typedArray.BYTES_PER_ELEMENT;
                 var elementStride = byteStride / typedArray.BYTES_PER_ELEMENT;
@@ -4779,14 +4781,13 @@ var BABYLON;
             };
             };
             GLTFLoader.prototype._loadTexture = function (context, texture, coordinatesIndex) {
             GLTFLoader.prototype._loadTexture = function (context, texture, coordinatesIndex) {
                 var _this = this;
                 var _this = this;
-                var sampler = (texture.sampler == null ? {} : GLTFLoader._GetProperty(this._gltf.samplers, texture.sampler));
+                var sampler = (texture.sampler == undefined ? this._defaultSampler : GLTFLoader._GetProperty(this._gltf.samplers, texture.sampler));
                 if (!sampler) {
                 if (!sampler) {
                     throw new Error(context + ": Failed to find sampler " + texture.sampler);
                     throw new Error(context + ": Failed to find sampler " + texture.sampler);
                 }
                 }
-                var noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
-                var samplingMode = GLTFLoader._GetTextureSamplingMode(sampler.magFilter, sampler.minFilter);
+                this._loadSampler("#/samplers/" + sampler.index, sampler);
                 this._addPendingData(texture);
                 this._addPendingData(texture);
-                var babylonTexture = new BABYLON.Texture(null, this._babylonScene, noMipMaps, false, samplingMode, function () {
+                var babylonTexture = new BABYLON.Texture(null, this._babylonScene, sampler.noMipMaps, false, sampler.samplingMode, function () {
                     _this._tryCatchOnError(function () {
                     _this._tryCatchOnError(function () {
                         _this._removePendingData(texture);
                         _this._removePendingData(texture);
                     });
                     });
@@ -4819,14 +4820,23 @@ var BABYLON;
                     });
                     });
                 }
                 }
                 babylonTexture.coordinatesIndex = coordinatesIndex || 0;
                 babylonTexture.coordinatesIndex = coordinatesIndex || 0;
-                babylonTexture.wrapU = GLTFLoader._GetTextureWrapMode(sampler.wrapS);
-                babylonTexture.wrapV = GLTFLoader._GetTextureWrapMode(sampler.wrapT);
+                babylonTexture.wrapU = sampler.wrapU;
+                babylonTexture.wrapV = sampler.wrapV;
                 babylonTexture.name = texture.name || "texture" + texture.index;
                 babylonTexture.name = texture.name || "texture" + texture.index;
                 if (this._parent.onTextureLoaded) {
                 if (this._parent.onTextureLoaded) {
                     this._parent.onTextureLoaded(babylonTexture);
                     this._parent.onTextureLoaded(babylonTexture);
                 }
                 }
                 return babylonTexture;
                 return babylonTexture;
             };
             };
+            GLTFLoader.prototype._loadSampler = function (context, sampler) {
+                if (sampler.noMipMaps != undefined) {
+                    return;
+                }
+                sampler.noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
+                sampler.samplingMode = GLTFLoader._GetTextureSamplingMode(context, sampler.magFilter, sampler.minFilter);
+                sampler.wrapU = GLTFLoader._GetTextureWrapMode(context, sampler.wrapS);
+                sampler.wrapV = GLTFLoader._GetTextureWrapMode(context, sampler.wrapT);
+            };
             GLTFLoader.prototype._loadImageAsync = function (context, image, onSuccess) {
             GLTFLoader.prototype._loadImageAsync = function (context, image, onSuccess) {
                 if (image.uri) {
                 if (image.uri) {
                     this._loadUriAsync(context, image.uri, onSuccess);
                     this._loadUriAsync(context, image.uri, onSuccess);
@@ -4899,7 +4909,7 @@ var BABYLON;
                 }
                 }
                 return array[index];
                 return array[index];
             };
             };
-            GLTFLoader._GetTextureWrapMode = function (mode) {
+            GLTFLoader._GetTextureWrapMode = function (context, mode) {
                 // Set defaults if undefined
                 // Set defaults if undefined
                 mode = mode == undefined ? GLTF2.ETextureWrapMode.REPEAT : mode;
                 mode = mode == undefined ? GLTF2.ETextureWrapMode.REPEAT : mode;
                 switch (mode) {
                 switch (mode) {
@@ -4907,11 +4917,11 @@ var BABYLON;
                     case GLTF2.ETextureWrapMode.MIRRORED_REPEAT: return BABYLON.Texture.MIRROR_ADDRESSMODE;
                     case GLTF2.ETextureWrapMode.MIRRORED_REPEAT: return BABYLON.Texture.MIRROR_ADDRESSMODE;
                     case GLTF2.ETextureWrapMode.REPEAT: return BABYLON.Texture.WRAP_ADDRESSMODE;
                     case GLTF2.ETextureWrapMode.REPEAT: return BABYLON.Texture.WRAP_ADDRESSMODE;
                     default:
                     default:
-                        BABYLON.Tools.Warn("Invalid texture wrap mode (" + mode + ")");
+                        BABYLON.Tools.Warn(context + ": Invalid texture wrap mode " + mode);
                         return BABYLON.Texture.WRAP_ADDRESSMODE;
                         return BABYLON.Texture.WRAP_ADDRESSMODE;
                 }
                 }
             };
             };
-            GLTFLoader._GetTextureSamplingMode = function (magFilter, minFilter) {
+            GLTFLoader._GetTextureSamplingMode = function (context, magFilter, minFilter) {
                 // Set defaults if undefined
                 // Set defaults if undefined
                 magFilter = magFilter == undefined ? GLTF2.ETextureMagFilter.LINEAR : magFilter;
                 magFilter = magFilter == undefined ? GLTF2.ETextureMagFilter.LINEAR : magFilter;
                 minFilter = minFilter == undefined ? GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR : minFilter;
                 minFilter = minFilter == undefined ? GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR : minFilter;
@@ -4924,13 +4934,13 @@ var BABYLON;
                         case GLTF2.ETextureMinFilter.NEAREST_MIPMAP_LINEAR: return BABYLON.Texture.LINEAR_NEAREST_MIPLINEAR;
                         case GLTF2.ETextureMinFilter.NEAREST_MIPMAP_LINEAR: return BABYLON.Texture.LINEAR_NEAREST_MIPLINEAR;
                         case GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR: return BABYLON.Texture.LINEAR_LINEAR_MIPLINEAR;
                         case GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR: return BABYLON.Texture.LINEAR_LINEAR_MIPLINEAR;
                         default:
                         default:
-                            BABYLON.Tools.Warn("Invalid texture minification filter (" + minFilter + ")");
+                            BABYLON.Tools.Warn(context + ": Invalid texture minification filter " + minFilter);
                             return BABYLON.Texture.LINEAR_LINEAR_MIPLINEAR;
                             return BABYLON.Texture.LINEAR_LINEAR_MIPLINEAR;
                     }
                     }
                 }
                 }
                 else {
                 else {
                     if (magFilter !== GLTF2.ETextureMagFilter.NEAREST) {
                     if (magFilter !== GLTF2.ETextureMagFilter.NEAREST) {
-                        BABYLON.Tools.Warn("Invalid texture magnification filter (" + magFilter + ")");
+                        BABYLON.Tools.Warn(context + ": Invalid texture magnification filter " + magFilter);
                     }
                     }
                     switch (minFilter) {
                     switch (minFilter) {
                         case GLTF2.ETextureMinFilter.NEAREST: return BABYLON.Texture.NEAREST_NEAREST;
                         case GLTF2.ETextureMinFilter.NEAREST: return BABYLON.Texture.NEAREST_NEAREST;
@@ -4940,12 +4950,12 @@ var BABYLON;
                         case GLTF2.ETextureMinFilter.NEAREST_MIPMAP_LINEAR: return BABYLON.Texture.NEAREST_NEAREST_MIPLINEAR;
                         case GLTF2.ETextureMinFilter.NEAREST_MIPMAP_LINEAR: return BABYLON.Texture.NEAREST_NEAREST_MIPLINEAR;
                         case GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR: return BABYLON.Texture.NEAREST_LINEAR_MIPLINEAR;
                         case GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR: return BABYLON.Texture.NEAREST_LINEAR_MIPLINEAR;
                         default:
                         default:
-                            BABYLON.Tools.Warn("Invalid texture minification filter (" + minFilter + ")");
+                            BABYLON.Tools.Warn(context + ": Invalid texture minification filter " + minFilter);
                             return BABYLON.Texture.NEAREST_NEAREST_MIPNEAREST;
                             return BABYLON.Texture.NEAREST_NEAREST_MIPNEAREST;
                     }
                     }
                 }
                 }
             };
             };
-            GLTFLoader._GetNumComponents = function (type) {
+            GLTFLoader._GetNumComponents = function (context, type) {
                 switch (type) {
                 switch (type) {
                     case "SCALAR": return 1;
                     case "SCALAR": return 1;
                     case "VEC2": return 2;
                     case "VEC2": return 2;
@@ -4955,7 +4965,7 @@ var BABYLON;
                     case "MAT3": return 9;
                     case "MAT3": return 9;
                     case "MAT4": return 16;
                     case "MAT4": return 16;
                 }
                 }
-                return 0;
+                throw new Error(context + ": Invalid type " + type);
             };
             };
             GLTFLoader.prototype._compileMaterialAsync = function (babylonMaterial, babylonMesh, onSuccess) {
             GLTFLoader.prototype._compileMaterialAsync = function (babylonMaterial, babylonMesh, onSuccess) {
                 var _this = this;
                 var _this = this;

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


+ 10 - 3
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -951,6 +951,11 @@ declare module BABYLON.GLTF2 {
         minFilter?: ETextureMinFilter;
         minFilter?: ETextureMinFilter;
         wrapS?: ETextureWrapMode;
         wrapS?: ETextureWrapMode;
         wrapT?: ETextureWrapMode;
         wrapT?: ETextureWrapMode;
+        index: number;
+        noMipMaps: boolean;
+        samplingMode: number;
+        wrapU: number;
+        wrapV: number;
     }
     }
     interface IGLTFScene extends IGLTFChildRootProperty {
     interface IGLTFScene extends IGLTFChildRootProperty {
         nodes: number[];
         nodes: number[];
@@ -1004,6 +1009,7 @@ declare module BABYLON.GLTF2 {
         private _parent;
         private _parent;
         private _rootUrl;
         private _rootUrl;
         private _defaultMaterial;
         private _defaultMaterial;
+        private _defaultSampler;
         private _rootNode;
         private _rootNode;
         private _successCallback;
         private _successCallback;
         private _progressCallback;
         private _progressCallback;
@@ -1083,14 +1089,15 @@ declare module BABYLON.GLTF2 {
         _loadMaterialBaseProperties(context: string, material: IGLTFMaterial): void;
         _loadMaterialBaseProperties(context: string, material: IGLTFMaterial): void;
         _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
         _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
         _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture;
         _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture;
+        private _loadSampler(context, sampler);
         private _loadImageAsync(context, image, onSuccess);
         private _loadImageAsync(context, image, onSuccess);
         _loadUriAsync(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
         _loadUriAsync(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
         _tryCatchOnError(handler: () => void): void;
         _tryCatchOnError(handler: () => void): void;
         private static _AssignIndices(array?);
         private static _AssignIndices(array?);
         static _GetProperty<T extends IGLTFProperty>(array?: ArrayLike<T>, index?: number): Nullable<T>;
         static _GetProperty<T extends IGLTFProperty>(array?: ArrayLike<T>, index?: number): Nullable<T>;
-        private static _GetTextureWrapMode(mode?);
-        private static _GetTextureSamplingMode(magFilter?, minFilter?);
-        private static _GetNumComponents(type);
+        private static _GetTextureWrapMode(context, mode?);
+        private static _GetTextureSamplingMode(context, magFilter?, minFilter?);
+        private static _GetNumComponents(context, type);
         private _compileMaterialAsync(babylonMaterial, babylonMesh, onSuccess);
         private _compileMaterialAsync(babylonMaterial, babylonMesh, onSuccess);
         private _compileMaterialsAsync(onSuccess);
         private _compileMaterialsAsync(onSuccess);
         private _compileShadowGeneratorsAsync(onSuccess);
         private _compileShadowGeneratorsAsync(onSuccess);

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


+ 47 - 25
dist/preview release/what's new.md

@@ -1,43 +1,47 @@
-# 3.1.0:
+# 3.1.0
 
 
 ## Major updates
 ## Major updates
-- Added VRExperienceHelper to create WebVR experience with 2 lines of code. [Doc here](http://doc.babylonjs.com/how_to/webvr_helper) ([davrous](https://github.com/davrous), [TrevorDev](https://github.com/TrevorDev))
-- Viewer (TODO)
-- Added BackgroundMaterial [Doc here](https://doc.babylonjs.com/how_to/backgroundmaterial)
-- Added EnvironmentHelper [Doc here](https://doc.babylonjs.com/babylon101/environment#skybox-and-ground)
-- Added support for webgl context lost and restored events. [Doc here](http://doc.babylonjs.com/tutorials/optimizing_your_scene#handling-webgl-context-lost) ([deltakosh](https://github.com/deltakosh))
+
+- Added VRExperienceHelper to create WebVR experience with 2 lines of code. [Documentation](http://doc.babylonjs.com/how_to/webvr_helper) ([davrous](https://github.com/davrous), [TrevorDev](https://github.com/TrevorDev))
+- Added BackgroundMaterial. [Documentation](https://doc.babylonjs.com/how_to/backgroundmaterial) ([sebavan](https://github.com/sebavan))
+- Added EnvironmentHelper. [Documentation](https://doc.babylonjs.com/babylon101/environment#skybox-and-ground) ([sebavan](https://github.com/sebavan))
+- Added support for webgl context lost and restored events. [Documentation](http://doc.babylonjs.com/tutorials/optimizing_your_scene#handling-webgl-context-lost) ([deltakosh](https://github.com/deltakosh))
 - Added support for non-pow2 textures when in WebGL2 mode ([deltakosh](https://github.com/deltakosh))
 - Added support for non-pow2 textures when in WebGL2 mode ([deltakosh](https://github.com/deltakosh))
 - Engine can now be initialized with an existing webgl context ([deltakosh](https://github.com/deltakosh))
 - Engine can now be initialized with an existing webgl context ([deltakosh](https://github.com/deltakosh))
-- Introduced behaviors. [Doc here](http://doc.babylonjs.com/overviews/behaviors) ([deltakosh](https://github.com/deltakosh))
-- Added support for WebGL Occlusion queries. [Doc here](http://doc.babylonjs.com/overviews/occlusionquery) ([Ibraheem Osama](https://github.com/IbraheemOsama))
-- New behaviors for ArcRotateCamera [Doc here](http://doc.babylonjs.com/overviews/behaviors): 
+- Introduced behaviors. [Documentation](http://doc.babylonjs.com/overviews/behaviors) ([deltakosh](https://github.com/deltakosh))
+- Added support for WebGL Occlusion queries. [Documentation](http://doc.babylonjs.com/overviews/occlusionquery) ([Ibraheem Osama](https://github.com/IbraheemOsama))
+- New behaviors for ArcRotateCamera. [Documentation](http://doc.babylonjs.com/overviews/behaviors) 
   - AutoRotation ([deltakosh](https://github.com/deltakosh))
   - AutoRotation ([deltakosh](https://github.com/deltakosh))
   - Framing ([deltakosh](https://github.com/deltakosh))
   - Framing ([deltakosh](https://github.com/deltakosh))
   - Bouncing ([deltakosh](https://github.com/deltakosh))
   - Bouncing ([deltakosh](https://github.com/deltakosh))
-- New InputText for Babylon.GUI. [Doc here](http://doc.babylonjs.com/overviews/gui#inputtext) ([deltakosh](https://github.com/deltakosh))
-- New VirtualKeyboard for Babylon.GUI. [Doc here](http://doc.babylonjs.com/overviews/gui#virtualkeyboard) ([deltakosh](https://github.com/deltakosh) / [adam](https://github.com/abow))
-- Added support for depth pre-pass rendering. [Doc here](http://doc.babylonjs.com/tutorials/transparency_and_how_meshes_are_rendered#depth-pre-pass-meshes) ([deltakosh](https://github.com/deltakosh))
-- Added support for `material.separateCullingPass`. [Doc here](http://doc.babylonjs.com/tutorials/transparency_and_how_meshes_are_rendered#things-to-do-and-not-to-do) ([sebavan](https://github.com/sebavan))
+- New InputText for Babylon.GUI. [Documentation](http://doc.babylonjs.com/overviews/gui#inputtext) ([deltakosh](https://github.com/deltakosh))
+- New VirtualKeyboard for Babylon.GUI. [Documentation](http://doc.babylonjs.com/overviews/gui#virtualkeyboard) ([deltakosh](https://github.com/deltakosh) / [adam](https://github.com/abow))
+- Added support for depth pre-pass rendering. [Documentation](http://doc.babylonjs.com/tutorials/transparency_and_how_meshes_are_rendered#depth-pre-pass-meshes) ([deltakosh](https://github.com/deltakosh))
+- Added support for `material.separateCullingPass`. [Documentation](http://doc.babylonjs.com/tutorials/transparency_and_how_meshes_are_rendered#things-to-do-and-not-to-do) ([sebavan](https://github.com/sebavan))
 - Added support for Windows Motion Controllers ([Lewis Weaver](https://github.com/leweaver))
 - Added support for Windows Motion Controllers ([Lewis Weaver](https://github.com/leweaver))
-- Added support for Particle animation in ParticleSystem. [Doc here](http://doc.babylonjs.com/tutorials/particles#particle-animation) ([Ibraheem Osama](https://github.com/IbraheemOsama))
-- More robust TypeScript code with *strictNullChecks*, *noImplicitAny*, *noImplicitThis* and *noImplicitReturns* compiler options ([deltakosh](https://github.com/deltakosh))
-- Introduced `NullEngine` which can be used to use Babylon.js in headless mode. [Doc here](http://doc.babylonjs.com/generals/nullengine) ([deltakosh](https://github.com/deltakosh))
-- New instrumentations tools. [Doc here](http://doc.babylonjs.com/how_to/optimizing_your_scene#instrumentation) ([deltakosh](https://github.com/deltakosh))
-- Complete rework of Unity3D exporter. [Doc here](http://doc.babylonjs.com/resources/intro) ([MackeyK24](https://github.com/MackeyK24))
+- Added support for Particle animation in ParticleSystem. [Documentation](http://doc.babylonjs.com/tutorials/particles#particle-animation) ([Ibraheem Osama](https://github.com/IbraheemOsama))
+- More robust TypeScript code with *strictNullChecks*, *noImplicitAny*, *noImplicitThis* and *noImplicitReturns* compiler options ([deltakosh](https://github.com/deltakosh) and [RaananW](https://github.com/RaananW))
+- Introduced `NullEngine` which can be used to use Babylon.js in headless mode. [Documentation](http://doc.babylonjs.com/generals/nullengine) ([deltakosh](https://github.com/deltakosh))
+- New instrumentations tools. [Documentation](http://doc.babylonjs.com/how_to/optimizing_your_scene#instrumentation) ([deltakosh](https://github.com/deltakosh))
+- Complete rework of Unity3D exporter. [Documentation](http://doc.babylonjs.com/resources/intro) ([MackeyK24](https://github.com/MackeyK24))
+- Introducing the BabylonJS viewer, an HTML-based 3D/model viewer, with Babylon at its core. [Documentation](http://doc.babylonjs.com/extensions/the_babylon_viewer) ([RaananW](https://github.com/RaananW))
+- Full NPM support for BabylonJS and its modules, based on UMD and including Typings. [BabylonJS on npm](https://www.npmjs.com/~babylonjs) ([RaananW](https://github.com/RaananW))
 
 
 ## Updates
 ## Updates
+
 - Introduced `TransformNode` class as a parent of `AbstractMesh`. This class was extensively asked by the community to hold only tranformation for a node ([deltakosh](https://github.com/deltakosh))
 - Introduced `TransformNode` class as a parent of `AbstractMesh`. This class was extensively asked by the community to hold only tranformation for a node ([deltakosh](https://github.com/deltakosh))
+- Collider object is now exposed on meshes. It can be used to get precise information about mesh to mesh collisions (used with mesh.moveWithCollisions function) ([deltakosh](https://github.com/deltakosh))
 - Added `boundingInfo.centerOn` to recreate the bounding info to be centered around a specific point given a specific extend ([deltakosh](https://github.com/deltakosh))
 - Added `boundingInfo.centerOn` to recreate the bounding info to be centered around a specific point given a specific extend ([deltakosh](https://github.com/deltakosh))
 - Added `mesh.normalizeToUnitCube` to uniformly scales the mesh to fit inside of a unit cube (1 X 1 X 1 units) ([deltakosh](https://github.com/deltakosh))
 - Added `mesh.normalizeToUnitCube` to uniformly scales the mesh to fit inside of a unit cube (1 X 1 X 1 units) ([deltakosh](https://github.com/deltakosh))
 - Added `scene.onDataLoadedObservable` which is raised when SceneLoader.Append or SceneLoader.Load or SceneLoader.ImportMesh were successfully executed ([deltakosh](https://github.com/deltakosh))
 - Added `scene.onDataLoadedObservable` which is raised when SceneLoader.Append or SceneLoader.Load or SceneLoader.ImportMesh were successfully executed ([deltakosh](https://github.com/deltakosh))
 - Support for adaptiveKernelBlur on MirrorTexture ([deltakosh](https://github.com/deltakosh))
 - Support for adaptiveKernelBlur on MirrorTexture ([deltakosh](https://github.com/deltakosh))
 - Support for non uniform scaling. Normals are now correctly computed ([deltakosh](https://github.com/deltakosh))
 - Support for non uniform scaling. Normals are now correctly computed ([deltakosh](https://github.com/deltakosh))
-- Added `MultiObserver`. [Doc here](http://doc.babylonjs.com/overviews/observables#multiobserver) ([deltakosh](https://github.com/deltakosh))
+- Added `MultiObserver`. [Documentation](http://doc.babylonjs.com/overviews/observables#multiobserver) ([deltakosh](https://github.com/deltakosh))
 - Added `shadowGenerator.addShadowCaster` and `shadowGenerator.removeShadowCaster` helper functions ([deltakosh](https://github.com/deltakosh))
 - Added `shadowGenerator.addShadowCaster` and `shadowGenerator.removeShadowCaster` helper functions ([deltakosh](https://github.com/deltakosh))
 - Several inspector improvements ([temechon](https://github.com/temechon))
 - Several inspector improvements ([temechon](https://github.com/temechon))
 - New observables for actions: `onBeforeExecuteObservable` for all actions and `onInterpolationDoneObservable` for `InterpolateValueAction` ([deltakosh](https://github.com/deltakosh))
 - New observables for actions: `onBeforeExecuteObservable` for all actions and `onInterpolationDoneObservable` for `InterpolateValueAction` ([deltakosh](https://github.com/deltakosh))
 - New observables for gamepads: `onButtonDownObservable`, `onButtonUpObservable`, `onPadDownObservable`, `onPadUpObservable` ([deltakosh](https://github.com/deltakosh))
 - New observables for gamepads: `onButtonDownObservable`, `onButtonUpObservable`, `onPadDownObservable`, `onPadUpObservable` ([deltakosh](https://github.com/deltakosh))
-- New `camera.storeState()` and `camera.restoreState()` functions to store / restore cameras position / rotation / fov. (Doc here)[http://doc.babylonjs.com/tutorials/cameras#state] ([deltakosh](https://github.com/deltakosh))
+- New `camera.storeState()` and `camera.restoreState()` functions to store / restore cameras position / rotation / fov. [Documentation](http://doc.babylonjs.com/tutorials/cameras#state) ([deltakosh](https://github.com/deltakosh))
 - POW2 textures rescale is now done by shaders (It was previously done using canvas) ([deltakosh](https://github.com/deltakosh))
 - POW2 textures rescale is now done by shaders (It was previously done using canvas) ([deltakosh](https://github.com/deltakosh))
 - Added `SceneLoader.CleanBoneMatrixWeights` to force the loader to normalize matrix weights when loading bones (off by default) ([deltakosh](https://github.com/deltakosh)) 
 - Added `SceneLoader.CleanBoneMatrixWeights` to force the loader to normalize matrix weights when loading bones (off by default) ([deltakosh](https://github.com/deltakosh)) 
 - Added `camera.onViewMatrixChangedObservable` and `camera.onProjectionMatrixChangedObservable` ([deltakosh](https://github.com/deltakosh))
 - Added `camera.onViewMatrixChangedObservable` and `camera.onProjectionMatrixChangedObservable` ([deltakosh](https://github.com/deltakosh))
@@ -47,17 +51,35 @@
 - GUI: Added support for pointer move events on projected UI ([deltakosh](https://github.com/deltakosh))
 - GUI: Added support for pointer move events on projected UI ([deltakosh](https://github.com/deltakosh))
 - Normals are generated automatically by StandardMaterial if meshes do not have normals ([deltakosh](https://github.com/deltakosh))
 - Normals are generated automatically by StandardMaterial if meshes do not have normals ([deltakosh](https://github.com/deltakosh))
 - Added `mesh.onMaterialChangedObservable` to notify when a new material is set ([deltakosh](https://github.com/deltakosh))
 - Added `mesh.onMaterialChangedObservable` to notify when a new material is set ([deltakosh](https://github.com/deltakosh))
-- Improved the SPS perfs for dead or invisible solid particles ([jerome](https://github.com/jbousquie))  
-- Added `enableDepthSort` parameter to the SPS in order to sort the particles from the camera position ([jerome](https://github.com/jbousquie)) 
-- Added `pivot` property to the SPS solid particles ([jerome](https://github.com/jbousquie)) 
-- Added the mesh facet depth sort to FacetData  ([jerome](https://github.com/jbousquie)) 
-- Added `LineSystem` and `LineMesh` per point colors ([jerome](https://github.com/jbousquie))  
+- Improved the SPS perfs for dead or invisible solid particles ([jerome](https://github.com/jbousquie))
+- Added `enableDepthSort` parameter to the SPS in order to sort the particles from the camera position ([jerome](https://github.com/jbousquie))
+- Added `pivot` property to the SPS solid particles ([jerome](https://github.com/jbousquie))
+- Added the mesh facet depth sort to FacetData  ([jerome](https://github.com/jbousquie))
+- Added `LineSystem` and `LineMesh` per point colors ([jerome](https://github.com/jbousquie))
 - Added `AdvancedDynamicTexture.renderScale` to allow users to render at higher DPI ([deltakosh](https://github.com/deltakosh))
 - Added `AdvancedDynamicTexture.renderScale` to allow users to render at higher DPI ([deltakosh](https://github.com/deltakosh))
+- WaterMaterial works on VR ([RaananW](https://github.com/RaananW))
+- Playground has an optional createEngine function to replace the default engine. [Example](https://www.babylonjs-playground.com/#5CAP01#5) ([RaananW](https://github.com/RaananW))
+- Error handling in the Assets Manager was revamped and now also includes a message and an exception (if provided). [Documentation](http://doc.babylonjs.com/how_to/how_to_use_assetsmanager#task-state-and-error-handling) ([RaananW](https://github.com/RaananW))
+- Asset Task has a state (INIT, RUNNING, DONE and ERROR). [Documentation](http://doc.babylonjs.com/how_to/how_to_use_assetsmanager#task-state-and-error-handling) ([RaananW](https://github.com/RaananW))
+- Added new options to the physics impostor constructor - ignoreParent and diableBidirectionalTransformation. [Documentation](http://doc.babylonjs.com/how_to/using_the_physics_engine#impostors) ([RaananW](https://github.com/RaananW))
+- It is now possible to define which loader to use when loading assets using the SceneLoader. [Commit](https://github.com/BabylonJS/Babylon.js/commit/91bffeaafc668980be0f9cf83df69b8eb2e2ba5f) ([RaananW](https://github.com/RaananW))
 
 
 ## Bug fixes
 ## Bug fixes
+
+- Fixed a bug with ellipsoid offset not being taking in account on cameras ([deltakosh](https://github.com/deltakosh))
+- Fixed a bug with ellipsoid offset badly taking in account on meshes ([deltakosh](https://github.com/deltakosh))
 - Fixed a bug with PBR on iOS ([sebavan](https://github.com/sebavan))
 - Fixed a bug with PBR on iOS ([sebavan](https://github.com/sebavan))
+- MTLLoader didn't parse values correctly ([RaananW](https://github.com/RaananW))
+- Fixed an error with child positions of parents in the physics engine ([RaananW](https://github.com/RaananW))
+- Fixed a bug with error while executing onSuccess callbacks in the Assets manager. ([RaananW](https://github.com/RaananW))
+- Fixed a bug with the Heightmap impostor when the heightmap is scaled or rotated. [Commit](https://github.com/BabylonJS/Babylon.js/commit/e898c4f26512a5466b5b594aecf4711f1dfd50e0) ([RaananW](https://github.com/RaananW))
+- Fixed an error with deterministic step. ([RaananW](https://github.com/RaananW))
+- Fixed a bug with controller jitter when in VR. ([RaananW](https://github.com/RaananW))
+- Fixed a bug with impostor jitter when in VR. ([RaananW](https://github.com/RaananW))
 
 
 ## Breaking changes
 ## Breaking changes
+
 - `Gamepads` was removed in favor of `scene.gamepadManager`
 - `Gamepads` was removed in favor of `scene.gamepadManager`
 - `DynamicFloatArray`, `MapTexture` and `RectPakingMap` were removed because there were not used anymore
 - `DynamicFloatArray`, `MapTexture` and `RectPakingMap` were removed because there were not used anymore
 - `IAssetTask` was removed in favor of `AbstractAssetTask` class
 - `IAssetTask` was removed in favor of `AbstractAssetTask` class
+- WebVR 1.0 support removed.

+ 1 - 1
gui/src/controls/inputText.ts

@@ -380,7 +380,7 @@ module BABYLON.GUI {
                             this._cursorOffset++;
                             this._cursorOffset++;
                             currentSize = context.measureText(text.substr(text.length - this._cursorOffset, this._cursorOffset)).width;
                             currentSize = context.measureText(text.substr(text.length - this._cursorOffset, this._cursorOffset)).width;
 
 
-                        } while (currentSize < absoluteCursorPosition);
+                        } while (currentSize < absoluteCursorPosition && (text.length >= this._cursorOffset));
 
 
                         // Find closest move
                         // Find closest move
                         if (Math.abs(absoluteCursorPosition - currentSize) > previousDist) {
                         if (Math.abs(absoluteCursorPosition - currentSize) > previousDist) {

+ 6 - 18
loaders/readme.md

@@ -1,24 +1,12 @@
 ## Babylon.js loaders
 ## Babylon.js loaders
 
 
-You will find here all loading plugin that you can use to load different formats than .babylon
-
-To use then you just have to reference the loader file:
-
-```
-<script src="Babylon.js"></script>
-<script src="babylon.stlFileLoader.js"></script>
-```
-
-And then the SceneLoader will know how to load the new extension:
-```
-BABYLON.SceneLoader.Load("/Files/", "ch9.stl", engine, function (newScene) { 
-   newScene.activeCamera.attachControl(canvas, false);
-   engine.runRenderLoop(function () { 
-       newScene.render(); 
-   }); 
-});
-```
+### Usage
+See documentation links:
+- https://doc.babylonjs.com/how_to/obj
+- https://doc.babylonjs.com/how_to/stl
+- https://doc.babylonjs.com/how_to/gltf
 
 
+### Build
 To compile, from the tools/gulp folder:
 To compile, from the tools/gulp folder:
 
 
 ```
 ```

+ 0 - 74
loaders/src/OBJ/README.md

@@ -1,74 +0,0 @@
-# Babylon.js .obj File Loader
-
-#[Demo](http://www.babylonjs-playground.com/#28YUR5)
-To use it, you just have to reference the loader file:
-
-```
-<script src="babylon.2.1.js"></script>
-<script src="babylon.objFileLoader.js"></script>
-```
-
-Babylon.js will know how to load the obj file and its mtl file automatically: 
-```
-BABYLON.SceneLoader.Load("/assets/", "batman.obj", engine, function (newScene) { 
-   // ...
-});
-```
-```
-var loader = new BABYLON.AssetsManager(scene);
-var batman = loader.addMeshTask("batman", "", "assets/", "batman.obj");
-```
-```
-BABYLON.SceneLoader.ImportMesh("batmanface", "", "batman.obj", scene, function (meshes) { 
-   // ...
-});
-```
-
-## Good things to know
-* Your model doesn't have to be triangulated, as this loader will do it automatically.
-* A Babylon.Mesh will be created for each object/group
-* The obj model should be exported with -Z axis forward, and Y axis upward to be compatible with Babylon.js
-
-![Axis](http://geomorph.sourceforge.net/preview/axes.jpg)
-
-* By default, due to optimization in the code for loading time, UVs problems can appear, like this :
-
-![Batman UVs problem](http://i.imgur.com/vjWKNRK.png)
-
-If you meet this problem, set the variable 
-```
-BABYLON.OBJFileLoader.OPTIMIZE_WITH_UV = true;
-```
-Then, you'll have a better texture, but with a longer loading.
-
-![Batman UVs ok](http://i.imgur.com/Dajwlvq.png)
-
-## Supported
-* Object/group
-* Faces
-    * triangles
-    * quads
-    * polygons
-* Colors
-    * diffuseColor
-    * ambientColor
-    * specularColor
-    * specularPower
-    * alpha
-* Textures
-    * ambientTexture
-    * diffuseTexture
-    * specularTexture
-    * bumpTexture
-    * opacityTexture
-* Multimaterial
-	* For each material defined in the same mesh, it creates a new BABYLON.Mesh.
-	* The name of the created BABYLON.Mesh follows this syntax: meshName_mmX 
-	* X is the nth BABYLON.Mesh created with this method
-
-    
-## Not supported currently
-* Smoothing groups (s parameter in OBJ file)
-* Illumination (illum parameter in MTL file)
-* The differents options for loading textures in MTL file.
-* A good description about MTL file and his options could be found here: http://paulbourke.net/dataformats/mtl/

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

@@ -52,6 +52,7 @@ module BABYLON.GLTF2 {
         private _parent: GLTFFileLoader;
         private _parent: GLTFFileLoader;
         private _rootUrl: string;
         private _rootUrl: string;
         private _defaultMaterial: PBRMaterial;
         private _defaultMaterial: PBRMaterial;
+        private _defaultSampler = {} as IGLTFSampler;
         private _rootNode: IGLTFNode;
         private _rootNode: IGLTFNode;
         private _successCallback: () => void;
         private _successCallback: () => void;
         private _progressCallback: (event: ProgressEvent) => void;
         private _progressCallback: (event: ProgressEvent) => void;
@@ -219,6 +220,7 @@ module BABYLON.GLTF2 {
             GLTFLoader._AssignIndices(this._gltf.materials);
             GLTFLoader._AssignIndices(this._gltf.materials);
             GLTFLoader._AssignIndices(this._gltf.meshes);
             GLTFLoader._AssignIndices(this._gltf.meshes);
             GLTFLoader._AssignIndices(this._gltf.nodes);
             GLTFLoader._AssignIndices(this._gltf.nodes);
+            GLTFLoader._AssignIndices(this._gltf.samplers);
             GLTFLoader._AssignIndices(this._gltf.scenes);
             GLTFLoader._AssignIndices(this._gltf.scenes);
             GLTFLoader._AssignIndices(this._gltf.skins);
             GLTFLoader._AssignIndices(this._gltf.skins);
             GLTFLoader._AssignIndices(this._gltf.textures);
             GLTFLoader._AssignIndices(this._gltf.textures);
@@ -227,7 +229,7 @@ module BABYLON.GLTF2 {
                 const buffers = this._gltf.buffers;
                 const buffers = this._gltf.buffers;
                 if (buffers && buffers[0] && !buffers[0].uri) {
                 if (buffers && buffers[0] && !buffers[0].uri) {
                     const binaryBuffer = buffers[0];
                     const binaryBuffer = buffers[0];
-                    if (binaryBuffer.byteLength != data.bin.byteLength) {
+                    if (binaryBuffer.byteLength < data.bin.byteLength - 3 || binaryBuffer.byteLength > data.bin.byteLength) {
                         Tools.Warn("Binary buffer length (" + binaryBuffer.byteLength + ") from JSON does not match chunk length (" + data.bin.byteLength + ")");
                         Tools.Warn("Binary buffer length (" + binaryBuffer.byteLength + ") from JSON does not match chunk length (" + data.bin.byteLength + ")");
                     }
                     }
 
 
@@ -576,7 +578,7 @@ module BABYLON.GLTF2 {
          * @param {IGLTFAccessor} accessor 
          * @param {IGLTFAccessor} accessor 
          */
          */
         private _convertToFloat4ColorArray(context: string, data: ArrayBufferView, accessor: IGLTFAccessor): Float32Array {
         private _convertToFloat4ColorArray(context: string, data: ArrayBufferView, accessor: IGLTFAccessor): Float32Array {
-            const colorComponentCount = GLTFLoader._GetNumComponents(accessor.type);
+            const colorComponentCount = GLTFLoader._GetNumComponents(context, accessor.type);
             if (colorComponentCount === 4 && accessor.componentType === EComponentType.FLOAT) {
             if (colorComponentCount === 4 && accessor.componentType === EComponentType.FLOAT) {
                 return data as Float32Array;
                 return data as Float32Array;
             }
             }
@@ -679,7 +681,7 @@ module BABYLON.GLTF2 {
                             break;
                             break;
                         }
                         }
                         default: {
                         default: {
-                            Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                            Tools.Warn(context + ": Ignoring unrecognized attribute '" + attribute + "'");
                             break;
                             break;
                         }
                         }
                     }
                     }
@@ -816,7 +818,7 @@ module BABYLON.GLTF2 {
                             break;
                             break;
                         }
                         }
                         default: {
                         default: {
-                            Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                            Tools.Warn(context + ": Ignoring unrecognized attribute '" + attribute + "'");
                             break;
                             break;
                         }
                         }
                     }
                     }
@@ -1223,14 +1225,15 @@ module BABYLON.GLTF2 {
             }
             }
 
 
             this._loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView, bufferViewData => {
             this._loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView, bufferViewData => {
-                const numComponents = GLTFLoader._GetNumComponents(accessor.type);
-                if (numComponents === 0) {
-                    throw new Error(context + ": Invalid type " + accessor.type);
-                }
+                const numComponents = GLTFLoader._GetNumComponents(context, accessor.type);
 
 
                 let data: ArrayBufferView;
                 let data: ArrayBufferView;
-                let byteOffset = accessor.byteOffset || 0;
-                let byteStride = bufferView.byteStride;
+                const byteOffset = accessor.byteOffset || 0;
+                const byteStride = bufferView.byteStride;
+
+                if (byteStride === 0) {
+                    Tools.Warn(context + ": Byte stride of 0 is not valid");
+                }
 
 
                 try {
                 try {
                     switch (accessor.componentType) {
                     switch (accessor.componentType) {
@@ -1276,7 +1279,7 @@ module BABYLON.GLTF2 {
 
 
             const targetLength = count * numComponents;
             const targetLength = count * numComponents;
 
 
-            if (byteStride == null || byteStride === numComponents * typedArray.BYTES_PER_ELEMENT) {
+            if (!byteStride || byteStride === numComponents * typedArray.BYTES_PER_ELEMENT) {
                 return new typedArray(data.buffer, byteOffset, targetLength);
                 return new typedArray(data.buffer, byteOffset, targetLength);
             }
             }
 
 
@@ -1528,16 +1531,15 @@ module BABYLON.GLTF2 {
         }
         }
 
 
         public _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture {
         public _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture {
-            const sampler = (texture.sampler == null ? <IGLTFSampler>{} : GLTFLoader._GetProperty(this._gltf.samplers, texture.sampler));
+            const sampler = (texture.sampler == undefined ? this._defaultSampler : GLTFLoader._GetProperty(this._gltf.samplers, texture.sampler));
             if (!sampler) {
             if (!sampler) {
                 throw new Error(context + ": Failed to find sampler " + texture.sampler);
                 throw new Error(context + ": Failed to find sampler " + texture.sampler);
             }
             }
 
 
-            const noMipMaps = (sampler.minFilter === ETextureMinFilter.NEAREST || sampler.minFilter === ETextureMinFilter.LINEAR);
-            const samplingMode = GLTFLoader._GetTextureSamplingMode(sampler.magFilter, sampler.minFilter);
+            this._loadSampler("#/samplers/" + sampler.index, sampler);
 
 
             this._addPendingData(texture);
             this._addPendingData(texture);
-            const babylonTexture = new Texture(null, this._babylonScene, noMipMaps, false, samplingMode, () => {
+            const babylonTexture = new Texture(null, this._babylonScene, sampler.noMipMaps, false, sampler.samplingMode, () => {
                 this._tryCatchOnError(() => {
                 this._tryCatchOnError(() => {
                     this._removePendingData(texture);
                     this._removePendingData(texture);
                 });
                 });
@@ -1574,8 +1576,8 @@ module BABYLON.GLTF2 {
             }
             }
 
 
             babylonTexture.coordinatesIndex = coordinatesIndex || 0;
             babylonTexture.coordinatesIndex = coordinatesIndex || 0;
-            babylonTexture.wrapU = GLTFLoader._GetTextureWrapMode(sampler.wrapS);
-            babylonTexture.wrapV = GLTFLoader._GetTextureWrapMode(sampler.wrapT);
+            babylonTexture.wrapU = sampler.wrapU;
+            babylonTexture.wrapV = sampler.wrapV;
             babylonTexture.name = texture.name || "texture" + texture.index;
             babylonTexture.name = texture.name || "texture" + texture.index;
 
 
             if (this._parent.onTextureLoaded) {
             if (this._parent.onTextureLoaded) {
@@ -1585,6 +1587,17 @@ module BABYLON.GLTF2 {
             return babylonTexture;
             return babylonTexture;
         }
         }
 
 
+        private _loadSampler(context: string, sampler: IGLTFSampler): void {
+            if (sampler.noMipMaps != undefined) {
+                return;
+            }
+
+            sampler.noMipMaps = (sampler.minFilter === ETextureMinFilter.NEAREST || sampler.minFilter === ETextureMinFilter.LINEAR);
+            sampler.samplingMode = GLTFLoader._GetTextureSamplingMode(context, sampler.magFilter, sampler.minFilter);
+            sampler.wrapU = GLTFLoader._GetTextureWrapMode(context, sampler.wrapS);
+            sampler.wrapV = GLTFLoader._GetTextureWrapMode(context, sampler.wrapT);
+        }
+
         private _loadImageAsync(context: string, image: IGLTFImage, onSuccess: (data: ArrayBufferView) => void): void {
         private _loadImageAsync(context: string, image: IGLTFImage, onSuccess: (data: ArrayBufferView) => void): void {
             if (image.uri) {
             if (image.uri) {
                 this._loadUriAsync(context, image.uri, onSuccess);
                 this._loadUriAsync(context, image.uri, onSuccess);
@@ -1669,7 +1682,7 @@ module BABYLON.GLTF2 {
             return array[index];
             return array[index];
         }
         }
 
 
-        private static _GetTextureWrapMode(mode?: ETextureWrapMode): number {
+        private static _GetTextureWrapMode(context: string, mode?: ETextureWrapMode): number {
             // Set defaults if undefined
             // Set defaults if undefined
             mode = mode == undefined ? ETextureWrapMode.REPEAT : mode;
             mode = mode == undefined ? ETextureWrapMode.REPEAT : mode;
 
 
@@ -1678,12 +1691,12 @@ module BABYLON.GLTF2 {
                 case ETextureWrapMode.MIRRORED_REPEAT: return Texture.MIRROR_ADDRESSMODE;
                 case ETextureWrapMode.MIRRORED_REPEAT: return Texture.MIRROR_ADDRESSMODE;
                 case ETextureWrapMode.REPEAT: return Texture.WRAP_ADDRESSMODE;
                 case ETextureWrapMode.REPEAT: return Texture.WRAP_ADDRESSMODE;
                 default:
                 default:
-                    Tools.Warn("Invalid texture wrap mode (" + mode + ")");
+                    Tools.Warn(context + ": Invalid texture wrap mode " + mode);
                     return Texture.WRAP_ADDRESSMODE;
                     return Texture.WRAP_ADDRESSMODE;
             }
             }
         }
         }
 
 
-        private static _GetTextureSamplingMode(magFilter?: ETextureMagFilter, minFilter?: ETextureMinFilter): number {
+        private static _GetTextureSamplingMode(context: string, magFilter?: ETextureMagFilter, minFilter?: ETextureMinFilter): number {
             // Set defaults if undefined
             // Set defaults if undefined
             magFilter = magFilter == undefined ? ETextureMagFilter.LINEAR : magFilter;
             magFilter = magFilter == undefined ? ETextureMagFilter.LINEAR : magFilter;
             minFilter = minFilter == undefined ? ETextureMinFilter.LINEAR_MIPMAP_LINEAR : minFilter;
             minFilter = minFilter == undefined ? ETextureMinFilter.LINEAR_MIPMAP_LINEAR : minFilter;
@@ -1697,13 +1710,13 @@ module BABYLON.GLTF2 {
                     case ETextureMinFilter.NEAREST_MIPMAP_LINEAR: return Texture.LINEAR_NEAREST_MIPLINEAR;
                     case ETextureMinFilter.NEAREST_MIPMAP_LINEAR: return Texture.LINEAR_NEAREST_MIPLINEAR;
                     case ETextureMinFilter.LINEAR_MIPMAP_LINEAR: return Texture.LINEAR_LINEAR_MIPLINEAR;
                     case ETextureMinFilter.LINEAR_MIPMAP_LINEAR: return Texture.LINEAR_LINEAR_MIPLINEAR;
                     default:
                     default:
-                        Tools.Warn("Invalid texture minification filter (" + minFilter + ")");
+                        Tools.Warn(context + ": Invalid texture minification filter " + minFilter);
                         return Texture.LINEAR_LINEAR_MIPLINEAR;
                         return Texture.LINEAR_LINEAR_MIPLINEAR;
                 }
                 }
             }
             }
             else {
             else {
                 if (magFilter !== ETextureMagFilter.NEAREST) {
                 if (magFilter !== ETextureMagFilter.NEAREST) {
-                    Tools.Warn("Invalid texture magnification filter (" + magFilter + ")");
+                    Tools.Warn(context + ": Invalid texture magnification filter " + magFilter);
                 }
                 }
 
 
                 switch (minFilter) {
                 switch (minFilter) {
@@ -1714,13 +1727,13 @@ module BABYLON.GLTF2 {
                     case ETextureMinFilter.NEAREST_MIPMAP_LINEAR: return Texture.NEAREST_NEAREST_MIPLINEAR;
                     case ETextureMinFilter.NEAREST_MIPMAP_LINEAR: return Texture.NEAREST_NEAREST_MIPLINEAR;
                     case ETextureMinFilter.LINEAR_MIPMAP_LINEAR: return Texture.NEAREST_LINEAR_MIPLINEAR;
                     case ETextureMinFilter.LINEAR_MIPMAP_LINEAR: return Texture.NEAREST_LINEAR_MIPLINEAR;
                     default:
                     default:
-                        Tools.Warn("Invalid texture minification filter (" + minFilter + ")");
+                        Tools.Warn(context + ": Invalid texture minification filter " + minFilter);
                         return Texture.NEAREST_NEAREST_MIPNEAREST;
                         return Texture.NEAREST_NEAREST_MIPNEAREST;
                 }
                 }
             }
             }
         }
         }
 
 
-        private static _GetNumComponents(type: string): number {
+        private static _GetNumComponents(context: string, type: string): number {
             switch (type) {
             switch (type) {
                 case "SCALAR": return 1;
                 case "SCALAR": return 1;
                 case "VEC2": return 2;
                 case "VEC2": return 2;
@@ -1731,7 +1744,7 @@ module BABYLON.GLTF2 {
                 case "MAT4": return 16;
                 case "MAT4": return 16;
             }
             }
 
 
-            return 0;
+            throw new Error(context + ": Invalid type " + type);
         }
         }
 
 
         private _compileMaterialAsync(babylonMaterial: Material, babylonMesh: AbstractMesh, onSuccess: () => void): void {
         private _compileMaterialAsync(babylonMaterial: Material, babylonMesh: AbstractMesh, onSuccess: () => void): void {

+ 7 - 0
loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts

@@ -242,6 +242,13 @@ module BABYLON.GLTF2 {
         minFilter?: ETextureMinFilter;
         minFilter?: ETextureMinFilter;
         wrapS?: ETextureWrapMode;
         wrapS?: ETextureWrapMode;
         wrapT?: ETextureWrapMode;
         wrapT?: ETextureWrapMode;
+
+        // Runtime values
+        index: number;
+        noMipMaps: boolean;
+        samplingMode: number;
+        wrapU: number;
+        wrapV: number;
     }
     }
 
 
     export interface IGLTFScene extends IGLTFChildRootProperty {
     export interface IGLTFScene extends IGLTFChildRootProperty {

+ 0 - 182
loaders/src/glTF/README.md

@@ -1,182 +0,0 @@
-# Babylon.js glTF File Loader
-
-The glTF file loader is a SceneLoader plugin.
-
-[Simple Playground Example](http://www.babylonjs-playground.com/#2IK4U7)
-
-## Setup
-
-**Full Version**
-
-This loader supports both glTF 1.0 and 2.0 and will use the correct loader based on the glTF version string.
-
-```HTML
-<script src="babylon.js"></script>
-<script src="babylon.glTFFileLoader.js"></script>
-```
-
-**Version 1 Only**
-
-This loader supports only glTF 1.0 and will fail to load glTF 2.0.
-
-```HTML
-<script src="babylon.js"></script>
-<script src="babylon.glTF1FileLoader.js"></script>
-```
-
-**Version 2 Only**
-
-This loader supports only glTF 2.0 and will fail to load glTF 1.0.
-
-```HTML
-<script src="babylon.js"></script>
-<script src="babylon.glTF2FileLoader.js"></script>
-```
-
-## Loading the Scene
-The Load function loads a glTF asset into a new scene.
-```JavaScript
-BABYLON.SceneLoader.Load("./", "duck.gltf", engine, function (scene) {
-    // do something with the scene
-});
-```
-
-The Append function appends a glTF file to an existing scene.
-```JavaScript
-BABYLON.SceneLoader.Append("./", "duck.gltf", scene, function (scene) {
-    // do something with the scene
-});
-```
-
-The ImportMesh function imports specific meshes from a glTF asset to an existing scene and returns the imported meshes and skeletons.
-```JavaScript
-// The first parameter can be set to null to load all meshes and skeletons
-BABYLON.SceneLoader.ImportMesh(["myMesh1", "myMesh2"], "./", "duck.gltf", scene, function (meshes, particleSystems, skeletons) {
-    // do something with the meshes and skeletons
-    // particleSystems are always null for glTF assets
-});
-```
-
-## Advanced
-
-The SceneLoader returns the glTF loader instance to enable setting properties per instance.
-
-```JavaScript
-var loader = BABYLON.SceneLoader.Load("./", "duck.gltf", engine, function (scene) {
-    // do something with the scene
-});
-
-// do something with the loader
-// loader.<option1> = <...>
-// loader.<option2> = <...>
-// loader.dispose();
-```
-
-#### onParsed
-Raised when the asset has been parsed. The `data.json` property stores the glTF JSON. The `data.bin` property stores the BIN chunk from a glTF binary or null if the input is not a glTF binary.
-
-```JavaScript
-loader.onParsed = function (data) {
-    // do something with the data
-};
-```
-
-### Version 1 Only
-
-#### IncrementalLoading
-Set this property to false to disable incremental loading which delays the loader from calling the success callback until after loading the meshes and shaders. Textures always loads asynchronously. For example, the success callback can compute the bounding information of the loaded meshes when incremental loading is disabled. Defaults to true.
-
-```JavaScript
-BABYLON.GLTFFileLoader.IncrementalLoading = false;
-```
-
-#### HomogeneousCoordinates
-Set this property to true in order to work with homogeneous coordinates, available with some converters and exporters. Defaults to false.
-
-```JavaScript
-BABYLON.GLTFFileLoader.HomogeneousCoordinates = true;
-```
-
-### Version 2 Only
-
-#### coordinateSystemMode
-The coordinate system mode (AUTO, FORCE_RIGHT_HANDED). Defaults to AUTO.
-
-```JavaScript
-loader.coordinateSystemMode = BABYLON.GLTFLoaderCoordinateSystemMode.FORCE_RIGHT_HANDED;
-```
-
-#### animationStartMode
-The animation start mode (NONE, FIRST, ALL). Defaults to FIRST.
-
-```JavaScript
-loader.animationStartMode = BABYLON.GLTFLoaderAnimationStartMode.NONE;
-```
-
-#### compileMaterials
-Set to true to compile materials before raising the success callback. Defaults to false.
-
-```JavaScript
-loader.compileMaterials = true;
-```
-
-#### useClipPlane
-Set to true to also compile materials with clip planes. Defaults to false.
-
-```JavaScript
-loader.useClipPlane = true;
-```
-
-#### compileShadowGenerators
-Set to true to compile shadow generators before raising the success callback. Defaults to false.
-
-```JavaScript
-loader.compileShadowGenerators = true;
-```
-
-#### onMeshLoaded
-Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
-
-```JavaScript
-loader.onMeshLoaded = function (mesh) {
-    // do something with the mesh
-};
-```
-
-#### onTextureLoaded
-Raised when the loader creates a texture 
-after parsing the glTF properties of the texture.
-
-```JavaScript
-loader.onTextureLoaded = function (texture) {
-    // do something with the texture
-};
-```
-
-#### onMaterialLoaded
-Raised when the loader creates a material after parsing the glTF properties of the material.
-
-```JavaScript
-loader.onMaterialLoaded = function (material) {
-    // do something with the material
-};
-```
-
-#### onComplete
-Raised when the asset is completely loaded, immediately before the loader is disposed.
-For assets with LODs, raised when all of the LODs are complete.
-For assets without LODs, raised when the model is complete, immediately after onSuccess.
-
-```JavaScript
-loader.onComplete = function () {
-    // do something when loading is complete
-};
-```
-
-#### dispose
-Disposes the loader, releases resources during load, and cancels any outstanding requests.
-
-```JavaScript
-// Cancel loading of the current glTF asset.
-loader.dispose();
-```

+ 106 - 106
localDev/index.html

@@ -1,120 +1,120 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
 <html xmlns="http://www.w3.org/1999/xhtml">
 <html xmlns="http://www.w3.org/1999/xhtml">
 
 
-    <head>
-        <title>Local Development</title>
-
-        <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-        <script src="https://preview.babylonjs.com/cannon.js"></script>
-        <script src="https://preview.babylonjs.com/Oimo.js"></script>
-        <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
-        <script src="../Tools/DevLoader/BabylonLoader.js"></script>
-        <script src="src/webgl-debug.js"></script>
-
-        <style>
-            html,
-            body {
-                width: 100%;
-                height: 100%;
-                padding: 0;
-                margin: 0;
-                overflow: hidden;
-            }
-
-            #renderCanvas {
-                width: 100%;
-                height: 100%;
-            }
-
-            #fps {
-                position: absolute;
-                background-color: black;
-                border: 2px solid red;
-                text-align: center;
-                font-size: 16px;
-                color: white;
-                top: 15px;
-                right: 10px;
-                width: 60px;
-                height: 20px;
-            }
-        </style>
-    </head>
-
-    <body>
-        <div id="fps">0</div>
-        <canvas id="renderCanvas" touch-action="none"></canvas>
-
-        <script>
-            var canvas = document.getElementById("renderCanvas");
-            //	canvas = WebGLDebugUtils.makeLostContextSimulatingCanvas(canvas);
-            var divFps = document.getElementById("fps");
-
-            // Global to simulate PG.
-            var engine = null;
-
-            // Allow querystring to navigate easily in debug in local samples.
-            var indexjs = 'src/index';
-            var sampleSearch = /sample=([0-9]+)/i;
-            var matches = null;
-            if ((matches = sampleSearch.exec(window.location)) !== null) {
-                indexjs += '.';
-                indexjs += matches[1];
-            }
-            indexjs += '.js';
-
-            // Load the scripts + map file to allow vscode debug.
-            BABYLONDEVTOOLS.Loader
-                .require(indexjs)
-                .load(function () {
-                    if (BABYLON.Engine.isSupported()) {
-                        if (typeof createEngine !== "undefined") {
-                            engine = createEngine();
-                        } else {
-                            engine = new BABYLON.Engine(canvas, true, { stencil: true, disableWebGL2Support: false, preserveDrawingBuffer: true });
-                        }
-
-                        BABYLONDEVTOOLS.Loader.debugShortcut(engine);
-
-                        // call the scene creation from the js.
-                        if (typeof delayCreateScene !== "undefined") {
-                            var scene = delayCreateScene();
+<head>
+    <title>Local Development</title>
+
+    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+    <script src="https://preview.babylonjs.com/cannon.js"></script>
+    <script src="https://preview.babylonjs.com/Oimo.js"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
+    <script src="../Tools/DevLoader/BabylonLoader.js"></script>
+    <script src="src/webgl-debug.js"></script>
+
+    <style>
+        html,
+        body {
+            width: 100%;
+            height: 100%;
+            padding: 0;
+            margin: 0;
+            overflow: hidden;
+        }
+
+        #renderCanvas {
+            width: 100%;
+            height: 100%;
+        }
+
+        #fps {
+            position: absolute;
+            background-color: black;
+            border: 2px solid red;
+            text-align: center;
+            font-size: 16px;
+            color: white;
+            top: 15px;
+            right: 10px;
+            width: 60px;
+            height: 20px;
+        }
+    </style>
+</head>
+
+<body>
+    <div id="fps">0</div>
+    <canvas id="renderCanvas" touch-action="none"></canvas>
+
+    <script>
+        var canvas = document.getElementById("renderCanvas");
+        //	canvas = WebGLDebugUtils.makeLostContextSimulatingCanvas(canvas);
+        var divFps = document.getElementById("fps");
+
+        // Global to simulate PG.
+        var engine = null;
+
+        // Allow querystring to navigate easily in debug in local samples.
+        var indexjs = 'src/index';
+        var sampleSearch = /sample=([0-9]+)/i;
+        var matches = null;
+        if ((matches = sampleSearch.exec(window.location)) !== null) {
+            indexjs += '.';
+            indexjs += matches[1];
+        }
+        indexjs += '.js';
+
+        // Load the scripts + map file to allow vscode debug.
+        BABYLONDEVTOOLS.Loader
+            .require(indexjs)
+            .load(function () {
+                if (BABYLON.Engine.isSupported()) {
+                    if (typeof createEngine !== "undefined") {
+                        engine = createEngine();
+                    } else {
+                        engine = new BABYLON.Engine(canvas, true, { stencil: true, disableWebGL2Support: false, preserveDrawingBuffer: true });
+                    }
 
 
-                            if (scene) {
-                                // Register a render loop to repeatedly render the scene
+                    BABYLONDEVTOOLS.Loader.debugShortcut(engine);
 
 
-                                engine.runRenderLoop(function () {
-                                    if (scene.activeCamera) {
-                                        scene.render();
-                                    }
-                                    divFps.innerHTML = engine.getFps().toFixed() + " fps";
-                                });
-                            }
-                        }
-                        else {
-                            var scene = createScene();
+                    // call the scene creation from the js.
+                    if (typeof delayCreateScene !== "undefined") {
+                        var scene = delayCreateScene();
 
 
-                            if (scene) {
-                                // Register a render loop to repeatedly render the scene
+                        if (scene) {
+                            // Register a render loop to repeatedly render the scene
 
 
-                                engine.runRenderLoop(function () {
+                            engine.runRenderLoop(function () {
+                                if (scene.activeCamera) {
                                     scene.render();
                                     scene.render();
-                                    divFps.innerHTML = engine.getFps().toFixed() + " fps";
-                                });
-                            }
+                                }
+                                divFps.innerHTML = engine.getFps().toFixed() + " fps";
+                            });
                         }
                         }
-
-                        // Resize
-                        window.addEventListener("resize", function () {
-                            engine.resize();
-                        });
-
                     }
                     }
                     else {
                     else {
-                        alert('BabylonJS is not supported.')
+                        var scene = createScene();
+
+                        if (scene) {
+                            // Register a render loop to repeatedly render the scene
+
+                            engine.runRenderLoop(function () {
+                                scene.render();
+                                divFps.innerHTML = engine.getFps().toFixed() + " fps";
+                            });
+                        }
                     }
                     }
-                });
-        </script>
-    </body>
+
+                    // Resize
+                    window.addEventListener("resize", function () {
+                        engine.resize();
+                    });
+
+                }
+                else {
+                    alert('BabylonJS is not supported.')
+                }
+            });
+    </script>
+</body>
 
 
 </html>
 </html>

+ 227 - 191
src/Cameras/VR/babylon.vrExperienceHelper.ts

@@ -57,6 +57,8 @@ module BABYLON {
         private _teleportationAllowed: boolean = false;
         private _teleportationAllowed: boolean = false;
         private _rotationAllowed: boolean = true;
         private _rotationAllowed: boolean = true;
         private _teleportationRequestInitiated = false;
         private _teleportationRequestInitiated = false;
+        private _teleportationBackRequestInitiated = false;
+        private teleportBackwardsVector = new Vector3(0, -1, -1);
         private _rotationRightAsked = false;
         private _rotationRightAsked = false;
         private _rotationLeftAsked = false;
         private _rotationLeftAsked = false;
         private _teleportationCircle: Mesh;
         private _teleportationCircle: Mesh;
@@ -122,6 +124,14 @@ module BABYLON {
                     this._leftLaserPointer.isVisible = false;
                     this._leftLaserPointer.isVisible = false;
                 }
                 }
             }
             }
+            else {
+                if(this._rightLaserPointer) {
+                    this._rightLaserPointer.isVisible = true;
+                }
+                else if (this._leftLaserPointer) {
+                    this._leftLaserPointer.isVisible = true;
+                }
+            }
         }
         }
 
 
         public get deviceOrientationCamera(): Nullable<DeviceOrientationCamera> {
         public get deviceOrientationCamera(): Nullable<DeviceOrientationCamera> {
@@ -150,24 +160,37 @@ module BABYLON {
             this._scene = scene;
             this._scene = scene;
             this._canvas = scene.getEngine().getRenderingCanvas();
             this._canvas = scene.getEngine().getRenderingCanvas();
 
 
-            this._defaultHeight = webVROptions.defaultHeight || 1.7;
-
+            // Parse options
             if (webVROptions.createFallbackVRDeviceOrientationFreeCamera === undefined) {
             if (webVROptions.createFallbackVRDeviceOrientationFreeCamera === undefined) {
                 webVROptions.createFallbackVRDeviceOrientationFreeCamera = true;
                 webVROptions.createFallbackVRDeviceOrientationFreeCamera = true;
             }
             }
-
             if (webVROptions.createDeviceOrientationCamera === undefined) {
             if (webVROptions.createDeviceOrientationCamera === undefined) {
                 webVROptions.createDeviceOrientationCamera = true;
                 webVROptions.createDeviceOrientationCamera = true;
             }
             }
-
-            if (!this._scene.activeCamera || webVROptions.createDeviceOrientationCamera) {
-                if (!this._scene.activeCamera || isNaN(this._scene.activeCamera.position.x)) {
-                    this._position = new BABYLON.Vector3(0, this._defaultHeight, 0);
-                    this._deviceOrientationCamera = new BABYLON.DeviceOrientationCamera("deviceOrientationVRHelper", this._position.clone(), scene);
+            if (webVROptions.useCustomVRButton) {
+                this._useCustomVRButton = true;
+                if (webVROptions.customVRButton) {
+                    this._btnVR = webVROptions.customVRButton;
                 }
                 }
-                else {
-                    this._position = this._scene.activeCamera.position.clone();
-                    this._deviceOrientationCamera = new BABYLON.DeviceOrientationCamera("deviceOrientationVRHelper", this._position.clone(), scene);
+            }
+            if (webVROptions.rayLength) {
+                this._rayLength = webVROptions.rayLength
+            }
+            this._defaultHeight = webVROptions.defaultHeight || 1.7;
+
+            // Set position
+            if(this._scene.activeCamera){
+                this._position = this._scene.activeCamera.position.clone();
+            }else{
+                this._position = new BABYLON.Vector3(0, this._defaultHeight, 0);
+            }
+
+            // Set non-vr camera
+            if(webVROptions.createDeviceOrientationCamera || !this._scene.activeCamera){
+                this._deviceOrientationCamera = new BABYLON.DeviceOrientationCamera("deviceOrientationVRHelper", this._position.clone(), scene);
+                
+                // Copy data from existing camera
+                if(this._scene.activeCamera){
                     this._deviceOrientationCamera.minZ = this._scene.activeCamera.minZ;
                     this._deviceOrientationCamera.minZ = this._scene.activeCamera.minZ;
                     this._deviceOrientationCamera.maxZ = this._scene.activeCamera.maxZ;
                     this._deviceOrientationCamera.maxZ = this._scene.activeCamera.maxZ;
                     // Set rotation from previous camera
                     // Set rotation from previous camera
@@ -181,29 +204,22 @@ module BABYLON {
                         this._deviceOrientationCamera.rotation = targetCamera.rotation.clone();
                         this._deviceOrientationCamera.rotation = targetCamera.rotation.clone();
                     }
                     }
                 }
                 }
+
                 this._scene.activeCamera = this._deviceOrientationCamera;
                 this._scene.activeCamera = this._deviceOrientationCamera;
                 if (this._canvas) {
                 if (this._canvas) {
                     this._scene.activeCamera.attachControl(this._canvas);
                     this._scene.activeCamera.attachControl(this._canvas);
                 }
                 }
-            }
-            else {
+            }else{
                 this._existingCamera = this._scene.activeCamera;
                 this._existingCamera = this._scene.activeCamera;
-                this._position = this._scene.activeCamera.position.clone();
             }
             }
 
 
-            if (webVROptions) {
-                if (webVROptions.useCustomVRButton) {
-                    this._useCustomVRButton = true;
-                    if (webVROptions.customVRButton) {
-                        this._btnVR = webVROptions.customVRButton;
-                    }
-                }
-
-                if (webVROptions.rayLength) {
-                    this._rayLength = webVROptions.rayLength
-                }
+            // Create VR cameras
+            if (webVROptions.createFallbackVRDeviceOrientationFreeCamera) {
+            this._vrDeviceOrientationCamera = new BABYLON.VRDeviceOrientationFreeCamera("VRDeviceOrientationVRHelper", this._position, this._scene);
             }
             }
+            this._webVRCamera = new BABYLON.WebVRFreeCamera("WebVRHelper", this._position, this._scene, webVROptions);
 
 
+            // Create default button
             if (!this._useCustomVRButton) {
             if (!this._useCustomVRButton) {
                 this._btnVR = <HTMLButtonElement>document.createElement("BUTTON");
                 this._btnVR = <HTMLButtonElement>document.createElement("BUTTON");
                 this._btnVR.className = "babylonVRicon";
                 this._btnVR.className = "babylonVRicon";
@@ -219,50 +235,42 @@ module BABYLON {
                 var style = document.createElement('style');
                 var style = document.createElement('style');
                 style.appendChild(document.createTextNode(css));
                 style.appendChild(document.createTextNode(css));
                 document.getElementsByTagName('head')[0].appendChild(style);
                 document.getElementsByTagName('head')[0].appendChild(style);
-            }
-
-            if (this._canvas) {
-                if (!this._useCustomVRButton) {
-                    this._btnVR.style.top = this._canvas.offsetTop + this._canvas.offsetHeight - 70 + "px";
-                    this._btnVR.style.left = this._canvas.offsetLeft + this._canvas.offsetWidth - 100 + "px";
-                }
-                if (this._btnVR) {
-                    this._btnVR.addEventListener("click", () => {
-                        if(!this.isInVRMode){
-                            this.enterVR();
-                        }else{
-                            this.exitVR();
-                        }
-                    });
-                }
 
 
-                window.addEventListener("resize", () => {
-                    if (this._canvas && !this._useCustomVRButton) {
-                        this._btnVR.style.top = this._canvas.offsetTop + this._canvas.offsetHeight - 70 + "px";
-                        this._btnVR.style.left = this._canvas.offsetLeft + this._canvas.offsetWidth - 100 + "px";
-                    }
+                this.moveButtonToBottomRight();
+            }
 
 
-                    if (this._fullscreenVRpresenting && this._webVRready) {
+            // VR button click event
+            if (this._btnVR) {
+                this._btnVR.addEventListener("click", () => {
+                    if (!this.isInVRMode) {
+                        this.enterVR();
+                    } else {
                         this.exitVR();
                         this.exitVR();
                     }
                     }
                 });
                 });
             }
             }
 
 
+            // Window events
+            window.addEventListener("resize", () => {
+                this.moveButtonToBottomRight();
+                if (this._fullscreenVRpresenting && this._webVRready) {
+                    this.exitVR();
+                }
+            });
             document.addEventListener("fullscreenchange", () => { this._onFullscreenChange() }, false);
             document.addEventListener("fullscreenchange", () => { this._onFullscreenChange() }, false);
             document.addEventListener("mozfullscreenchange", () => { this._onFullscreenChange() }, false);
             document.addEventListener("mozfullscreenchange", () => { this._onFullscreenChange() }, false);
             document.addEventListener("webkitfullscreenchange", () => { this._onFullscreenChange() }, false);
             document.addEventListener("webkitfullscreenchange", () => { this._onFullscreenChange() }, false);
             document.addEventListener("msfullscreenchange", () => { this._onFullscreenChange() }, false);
             document.addEventListener("msfullscreenchange", () => { this._onFullscreenChange() }, false);
 
 
-            this._scene.getEngine().onVRDisplayChangedObservable.add((e) => {
-                if (!this._useCustomVRButton && !this._btnVRDisplayed && e.vrDisplay) {
-                    document.body.appendChild(this._btnVR);
-                    this._btnVRDisplayed = true;
-                }
-            })
-
-            if (!this._useCustomVRButton && !this._btnVRDisplayed && webVROptions.createFallbackVRDeviceOrientationFreeCamera) {
-                document.body.appendChild(this._btnVR);
-                this._btnVRDisplayed = true;
+            // Display vr button when headset is connected
+            if (webVROptions.createFallbackVRDeviceOrientationFreeCamera) {
+                this.displayVRButton();
+            }else{
+                this._scene.getEngine().onVRDisplayChangedObservable.add((e) => {
+                    if (e.vrDisplay) {
+                        this.displayVRButton();
+                    }
+                })
             }
             }
 
 
             // Exiting VR mode using 'ESC' key on desktop
             // Exiting VR mode using 'ESC' key on desktop
@@ -294,17 +302,12 @@ module BABYLON {
                 this._webVRrequesting = false;
                 this._webVRrequesting = false;
                 this.updateButtonVisibility();
                 this.updateButtonVisibility();
             };
             };
-
             scene.getEngine().onVRDisplayChangedObservable.add(this._onVRDisplayChanged);
             scene.getEngine().onVRDisplayChangedObservable.add(this._onVRDisplayChanged);
             scene.getEngine().onVRRequestPresentStart.add(this._onVRRequestPresentStart);
             scene.getEngine().onVRRequestPresentStart.add(this._onVRRequestPresentStart);
             scene.getEngine().onVRRequestPresentComplete.add(this._onVRRequestPresentComplete);
             scene.getEngine().onVRRequestPresentComplete.add(this._onVRRequestPresentComplete);
             window.addEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
             window.addEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
 
 
-            // Create the cameras
-            if (webVROptions.createFallbackVRDeviceOrientationFreeCamera) {
-                this._vrDeviceOrientationCamera = new BABYLON.VRDeviceOrientationFreeCamera("VRDeviceOrientationVRHelper", this._position, this._scene);
-            }
-            this._webVRCamera = new BABYLON.WebVRFreeCamera("WebVRHelper", this._position, this._scene, webVROptions);
+            // Gamepad connection events
             this._webVRCamera.onControllerMeshLoadedObservable.add((webVRController) => this._onDefaultMeshLoaded(webVRController));
             this._webVRCamera.onControllerMeshLoadedObservable.add((webVRController) => this._onDefaultMeshLoaded(webVRController));
             this._scene.gamepadManager.onGamepadConnectedObservable.add((pad) => this._onNewGamepadConnected(pad));
             this._scene.gamepadManager.onGamepadConnectedObservable.add((pad) => this._onNewGamepadConnected(pad));
             this._scene.gamepadManager.onGamepadDisconnectedObservable.add((pad) => this._onNewGamepadDisconnected(pad));
             this._scene.gamepadManager.onGamepadDisconnectedObservable.add((pad) => this._onNewGamepadDisconnected(pad));
@@ -395,6 +398,20 @@ module BABYLON {
             this.updateButtonVisibility();
             this.updateButtonVisibility();
         }
         }
 
 
+        private moveButtonToBottomRight(){
+            if (this._canvas && !this._useCustomVRButton) {
+                this._btnVR.style.top = this._canvas.offsetTop + this._canvas.offsetHeight - 70 + "px";
+                this._btnVR.style.left = this._canvas.offsetLeft + this._canvas.offsetWidth - 100 + "px";
+            }
+        }
+
+        private displayVRButton(){
+            if (!this._useCustomVRButton && !this._btnVRDisplayed) {
+                document.body.appendChild(this._btnVR);
+                this._btnVRDisplayed = true;
+            }
+        }
+
         private updateButtonVisibility() {
         private updateButtonVisibility() {
             if (!this._btnVR || this._useCustomVRButton) {
             if (!this._btnVR || this._useCustomVRButton) {
                 return;
                 return;
@@ -414,10 +431,6 @@ module BABYLON {
          * Otherwise, will use the fullscreen API.
          * Otherwise, will use the fullscreen API.
          */
          */
         public enterVR() {
         public enterVR() {
-            if (this._scene.activeCamera) {
-                this._position = this._scene.activeCamera.position.clone();
-            }
-
             if (this.onEnteringVR) {
             if (this.onEnteringVR) {
                 try {
                 try {
                     this.onEnteringVR.notifyObservers(this);
                     this.onEnteringVR.notifyObservers(this);
@@ -426,6 +439,11 @@ module BABYLON {
                     Tools.Warn("Error in your custom logic onEnteringVR: " + err);
                     Tools.Warn("Error in your custom logic onEnteringVR: " + err);
                 }
                 }
             }
             }
+
+            if (this._scene.activeCamera) {
+                this._position = this._scene.activeCamera.position.clone();
+            }
+
             if (this._webVRrequesting)
             if (this._webVRrequesting)
                 return;
                 return;
 
 
@@ -617,23 +635,12 @@ module BABYLON {
                 if (gamepad.leftStick) {
                 if (gamepad.leftStick) {
                     gamepad.onleftstickchanged((stickValues) => {
                     gamepad.onleftstickchanged((stickValues) => {
                         if (this._teleportationEnabled) {
                         if (this._teleportationEnabled) {
+                            this._checkTeleportBackwards(stickValues);
                             // Listening to classic/xbox gamepad only if no VR controller is active
                             // Listening to classic/xbox gamepad only if no VR controller is active
                             if ((!this._leftLaserPointer && !this._rightLaserPointer) ||
                             if ((!this._leftLaserPointer && !this._rightLaserPointer) ||
                                 ((this._leftLaserPointer && !this._leftLaserPointer.isVisible) &&
                                 ((this._leftLaserPointer && !this._leftLaserPointer.isVisible) &&
                                     (this._rightLaserPointer && !this._rightLaserPointer.isVisible))) {
                                     (this._rightLaserPointer && !this._rightLaserPointer.isVisible))) {
-                                if (!this._teleportationRequestInitiated) {
-                                    if (stickValues.y < -this._padSensibilityUp) {
-                                        this._teleportationRequestInitiated = true;
-                                    }
-                                }
-                                else {
-                                    if (stickValues.y > -this._padSensibilityDown) {
-                                        if (this._teleportationAllowed) {
-                                            this._teleportCamera();
-                                        }
-                                        this._teleportationRequestInitiated = false;
-                                    }
-                                }
+                                this._checkTeleportWithRay(stickValues);
                             }
                             }
                         }
                         }
                     });
                     });
@@ -641,50 +648,19 @@ module BABYLON {
                 if (gamepad.rightStick) {
                 if (gamepad.rightStick) {
                     gamepad.onrightstickchanged((stickValues) => {
                     gamepad.onrightstickchanged((stickValues) => {
                         if (this._teleportationEnabled) {
                         if (this._teleportationEnabled) {
-                            if (!this._rotationLeftAsked) {
-                                if (stickValues.x < -this._padSensibilityUp) {
-                                    this._rotationLeftAsked = true;
-                                    if (this._rotationAllowed) {
-                                        this._rotateCamera(false);
-                                    }
-                                }
-                            }
-                            else {
-                                if (stickValues.x > -this._padSensibilityDown) {
-                                    this._rotationLeftAsked = false;
-                                }
-                            }
-                            if (!this._rotationRightAsked) {
-                                if (stickValues.x > this._padSensibilityUp) {
-                                    this._rotationRightAsked = true;
-                                    if (this._rotationAllowed) {
-                                        this._rotateCamera(true);
-                                    }
-                                }
-                            }
-                            else {
-                                if (stickValues.x < this._padSensibilityDown) {
-                                    this._rotationRightAsked = false;
-                                }
-                            }
+                            this._checkRotate(stickValues);
                         }
                         }
                     });
                     });
                 }
                 }
                 if (gamepad.type === BABYLON.Gamepad.XBOX) {
                 if (gamepad.type === BABYLON.Gamepad.XBOX) {
                     (<Xbox360Pad>gamepad).onbuttondown((buttonPressed: Xbox360Button) => {
                     (<Xbox360Pad>gamepad).onbuttondown((buttonPressed: Xbox360Button) => {
                         if (this._interactionsEnabled && buttonPressed === Xbox360Button.A) {
                         if (this._interactionsEnabled && buttonPressed === Xbox360Button.A) {
-                            this._pointerDownOnMeshAsked = true;
-                            if (this._currentMeshSelected && this._currentHit) {
-                                this._scene.simulatePointerDown(this._currentHit);
-                            }
+                            this._selectionPointerDown();
                         }
                         }
                     });
                     });
                     (<Xbox360Pad>gamepad).onbuttonup((buttonPressed: Xbox360Button) => {
                     (<Xbox360Pad>gamepad).onbuttonup((buttonPressed: Xbox360Button) => {
                         if (this._interactionsEnabled && buttonPressed === Xbox360Button.A) {
                         if (this._interactionsEnabled && buttonPressed === Xbox360Button.A) {
-                            if (this._currentMeshSelected && this._currentHit) {
-                                this._scene.simulatePointerUp(this._currentHit);
-                            }
-                            this._pointerDownOnMeshAsked = false;
+                            this._selectionPointerUp();
                         }
                         }
                     });
                     });
                 }
                 }
@@ -763,21 +739,130 @@ module BABYLON {
                 webVRController.onTriggerStateChangedObservable.add((stateObject) => {
                 webVRController.onTriggerStateChangedObservable.add((stateObject) => {
                     if (!this._pointerDownOnMeshAsked) {
                     if (!this._pointerDownOnMeshAsked) {
                         if (stateObject.value > this._padSensibilityUp) {
                         if (stateObject.value > this._padSensibilityUp) {
-                            this._pointerDownOnMeshAsked = true;
-                            if (this._currentMeshSelected && this._currentHit) {
-                                this._scene.simulatePointerDown(this._currentHit);
+                            this._selectionPointerDown();
+                        }
+                    } else if (stateObject.value < this._padSensibilityDown) {
+                        this._selectionPointerUp();
+                    }
+                });
+            }
+        }
+
+        private _checkTeleportWithRay(stateObject: StickValues, webVRController:Nullable<WebVRController> = null){
+            if (!this._teleportationRequestInitiated) {
+                if (stateObject.y < -this._padSensibilityUp) {
+                    if(webVRController){
+                        // If laser pointer wasn't enabled yet
+                        if (this._displayLaserPointer && webVRController.hand === "left" && this._leftLaserPointer) {
+                            this._leftLaserPointer.isVisible = true;
+                            if (this._rightLaserPointer) {
+                                this._rightLaserPointer.isVisible = false;
+                            }
+                        } else if (this._displayLaserPointer && this._rightLaserPointer) {
+                            this._rightLaserPointer.isVisible = true;
+                            if (this._leftLaserPointer) {
+                                this._leftLaserPointer.isVisible = false;
                             }
                             }
                         }
                         }
                     }
                     }
-                    else if (stateObject.value < this._padSensibilityDown) {
-                        if (this._currentMeshSelected && this._currentHit) {
-                            this._scene.simulatePointerUp(this._currentHit);
+                    this._teleportationRequestInitiated = true;
+                }
+            } else {
+                // Listening to the proper controller values changes to confirm teleportation
+                if (webVRController == null 
+                    ||(webVRController.hand === "left" && this._leftLaserPointer && this._leftLaserPointer.isVisible)
+                    || (webVRController.hand === "right" && this._rightLaserPointer && this._rightLaserPointer.isVisible)) {
+                    if (stateObject.y > -this._padSensibilityDown) {
+                        if (this._teleportationAllowed) {
+                            this._teleportationAllowed = false;
+                            this._teleportCamera();
                         }
                         }
-                        this._pointerDownOnMeshAsked = false;
+                        this._teleportationRequestInitiated = false;
                     }
                     }
-                });
+                }
+            }
+        }
+        private _selectionPointerDown(){
+            this._pointerDownOnMeshAsked = true;
+            if (this._currentMeshSelected && this._currentHit) {
+                this._scene.simulatePointerDown(this._currentHit);
+            }
+        }
+        private _selectionPointerUp(){
+            if (this._currentMeshSelected && this._currentHit) {
+                this._scene.simulatePointerUp(this._currentHit);
+            }
+            this._pointerDownOnMeshAsked = false;
+        }
+        private _checkRotate(stateObject: StickValues){
+            if (!this._rotationLeftAsked) {
+                if (stateObject.x < -this._padSensibilityUp) {
+                    this._rotationLeftAsked = true;
+                    if (this._rotationAllowed) {
+                        this._rotateCamera(false);
+                    }
+                }
+            } else {
+                if (stateObject.x > -this._padSensibilityDown) {
+                    this._rotationLeftAsked = false;
+                }
+            }
+
+            if (!this._rotationRightAsked) {
+                if (stateObject.x > this._padSensibilityUp) {
+                    this._rotationRightAsked = true;
+                    if (this._rotationAllowed) {
+                        this._rotateCamera(true);
+                    }
+                }
+            } else {
+                if (stateObject.x < this._padSensibilityDown) {
+                    this._rotationRightAsked = false;
+                }
             }
             }
         }
         }
+        private _checkTeleportBackwards(stateObject: StickValues){
+            // Teleport backwards
+            if(stateObject.y > this._padSensibilityUp) {
+                if(!this._teleportationBackRequestInitiated){
+                    if(!this.currentVRCamera){
+                        return;
+                    }
+
+                    // Get rotation and position of the current camera
+                    var rotation = Quaternion.FromRotationMatrix(this.currentVRCamera.getWorldMatrix().getRotationMatrix());
+                    var position = this.currentVRCamera.position;
+
+                    // If the camera has device position, use that instead
+                    if((<WebVRFreeCamera>this.currentVRCamera).devicePosition && (<WebVRFreeCamera>this.currentVRCamera).deviceRotationQuaternion){
+                        rotation = (<WebVRFreeCamera>this.currentVRCamera).deviceRotationQuaternion;
+                        position = (<WebVRFreeCamera>this.currentVRCamera).devicePosition;
+                    }
+
+                    // Get matrix with only the y rotation of the device rotation
+                    rotation.toEulerAnglesToRef(this._workingVector);
+                    this._workingVector.z = 0;
+                    this._workingVector.x = 0;
+                    Quaternion.RotationYawPitchRollToRef(this._workingVector.y, this._workingVector.x, this._workingVector.z, this._workingQuaternion);
+                    this._workingQuaternion.toRotationMatrix(this._workingMatrix);
+
+                    // Rotate backwards ray by device rotation to cast at the ground behind the user
+                    Vector3.TransformCoordinatesToRef(this.teleportBackwardsVector, this._workingMatrix, this._workingVector);
+                    
+                    // Teleport if ray hit the ground and is not to far away eg. backwards off a cliff
+                    var ray = new BABYLON.Ray(position, this._workingVector);
+                    var hit = this._scene.pickWithRay(ray, this._raySelectionPredicate);
+                    if(hit && hit.pickedPoint && hit.pickedMesh &&this._isTeleportationFloor(hit.pickedMesh) && hit.distance < 5){
+                        this._teleportCamera(hit.pickedPoint);
+                    }
+                    
+                    this._teleportationBackRequestInitiated = true;
+                }
+            }else{
+                this._teleportationBackRequestInitiated = false;
+            }
+            
+        }
 
 
         private _enableTeleportationOnController(webVRController: WebVRController) {
         private _enableTeleportationOnController(webVRController: WebVRController) {
             var controllerMesh = webVRController.mesh;
             var controllerMesh = webVRController.mesh;
@@ -795,64 +880,9 @@ module BABYLON {
                     this._teleportationEnabledOnRightController = true;
                     this._teleportationEnabledOnRightController = true;
                 }
                 }
                 webVRController.onPadValuesChangedObservable.add((stateObject) => {
                 webVRController.onPadValuesChangedObservable.add((stateObject) => {
-                    if (!this._teleportationRequestInitiated) {
-                        if (stateObject.y < -this._padSensibilityUp) {
-                            // If laser pointer wasn't enabled yet
-                            if (this._displayLaserPointer && webVRController.hand === "left" && this._leftLaserPointer) {
-                                this._leftLaserPointer.isVisible = true;
-                                if (this._rightLaserPointer) {
-                                    this._rightLaserPointer.isVisible = false;
-                                }
-                            }
-                            else if (this._displayLaserPointer && this._rightLaserPointer) {
-                                this._rightLaserPointer.isVisible = true;
-                                if (this._leftLaserPointer) {
-                                    this._leftLaserPointer.isVisible = false;
-                                }
-                            }
-                            this._teleportationRequestInitiated = true;
-                        }
-                    }
-                    else {
-                        // Listening to the proper controller values changes to confirm teleportation
-                        if ((webVRController.hand === "left" && this._leftLaserPointer && this._leftLaserPointer.isVisible)
-                            || (webVRController.hand === "right" && this._rightLaserPointer && this._rightLaserPointer.isVisible)) {
-                            if (stateObject.y > -this._padSensibilityDown) {
-                                if (this._teleportationAllowed) {
-                                    this._teleportationAllowed = false;
-                                    this._teleportCamera();
-                                }
-                                this._teleportationRequestInitiated = false;
-                            }
-                        }
-                    }
-                    if (!this._rotationLeftAsked) {
-                        if (stateObject.x < -this._padSensibilityUp) {
-                            this._rotationLeftAsked = true;
-                            if (this._rotationAllowed) {
-                                this._rotateCamera(false);
-                            }
-                        }
-                    }
-                    else {
-                        if (stateObject.x > -this._padSensibilityDown) {
-                            this._rotationLeftAsked = false;
-                        }
-                    }
-
-                    if (!this._rotationRightAsked) {
-                        if (stateObject.x > this._padSensibilityUp) {
-                            this._rotationRightAsked = true;
-                            if (this._rotationAllowed) {
-                                this._rotateCamera(true);
-                            }
-                        }
-                    }
-                    else {
-                        if (stateObject.x < this._padSensibilityDown) {
-                            this._rotationRightAsked = false;
-                        }
-                    }
+                    this._checkTeleportBackwards(stateObject);
+                    this._checkTeleportWithRay(stateObject, webVRController);
+                    this._checkRotate(stateObject)
                 });
                 });
             }
             }
         }
         }
@@ -1056,21 +1086,27 @@ module BABYLON {
             }
             }
         }
         }
         private _workingVector = Vector3.Zero();
         private _workingVector = Vector3.Zero();
-        private _teleportCamera() {
+        private _workingQuaternion = Quaternion.Identity();
+        private _workingMatrix = Matrix.Identity();
+        private _teleportCamera(location:Nullable<Vector3> = null) {
             if (!(this.currentVRCamera instanceof FreeCamera)) {
             if (!(this.currentVRCamera instanceof FreeCamera)) {
                 return;
                 return;
             }
             }
 
 
-            // Teleport the hmd to where the user is looking by moving the anchor to where they are looking minus the
-            // offset of the headset from the anchor. Then add the helper's position to account for user's height offset
-            if (this.webVRCamera.leftCamera) {
-                this._workingVector.copyFrom(this.webVRCamera.leftCamera.globalPosition);
-                this._workingVector.subtractInPlace(this.webVRCamera.position);
-                this._haloCenter.subtractToRef(this._workingVector, this._workingVector);
-            } else {
-                this._workingVector.copyFrom(this._haloCenter);
+            if(!location){
+                // Teleport the hmd to where the user is looking by moving the anchor to where they are looking minus the
+                // offset of the headset from the anchor.
+                if (this.webVRCamera.leftCamera) {
+                    this._workingVector.copyFrom(this.webVRCamera.leftCamera.globalPosition);
+                    this._workingVector.subtractInPlace(this.webVRCamera.position);
+                    this._haloCenter.subtractToRef(this._workingVector, this._workingVector);
+                } else {
+                    this._workingVector.copyFrom(this._haloCenter);
+                }
+                location = this._workingVector;
             }
             }
-            this._workingVector.y += this._defaultHeight;
+            // Add height to account for user's height offset
+            location.y += this._defaultHeight;
 
 
             // Create animation from the camera's position to the new location
             // Create animation from the camera's position to the new location
             this.currentVRCamera.animations = [];
             this.currentVRCamera.animations = [];
@@ -1081,7 +1117,7 @@ module BABYLON {
             },
             },
             {
             {
                 frame: 11,
                 frame: 11,
-                value: this._workingVector
+                value: location
             }
             }
             ];
             ];
 
 

+ 1 - 1
src/Cameras/VR/babylon.webVRCamera.ts

@@ -324,7 +324,7 @@ module BABYLON {
             
             
             // Get current device rotation in babylon world
             // Get current device rotation in babylon world
             Matrix.FromQuaternionToRef(this._deviceRoomRotationQuaternion, this._workingMatrix);
             Matrix.FromQuaternionToRef(this._deviceRoomRotationQuaternion, this._workingMatrix);
-            this._deviceToWorld.multiplyToRef(this._workingMatrix, this._workingMatrix);
+            this._workingMatrix.multiplyToRef(this._deviceToWorld, this._workingMatrix)
             Quaternion.FromRotationMatrixToRef(this._workingMatrix, this.deviceRotationQuaternion);
             Quaternion.FromRotationMatrixToRef(this._workingMatrix, this.deviceRotationQuaternion);
 
 
             super.update();
             super.update();

+ 2 - 2
src/Cameras/babylon.arcRotateCamera.ts

@@ -657,7 +657,7 @@
                 if (!this._collider) {
                 if (!this._collider) {
                     this._collider = new Collider();
                     this._collider = new Collider();
                 }
                 }
-                this._collider.radius = this.collisionRadius;
+                this._collider._radius = this.collisionRadius;
                 this._newPosition.subtractToRef(this.position, this._collisionVelocity);
                 this._newPosition.subtractToRef(this.position, this._collisionVelocity);
                 this._collisionTriggered = true;
                 this._collisionTriggered = true;
                 this.getScene().collisionCoordinator.getNewPosition(this.position, this._collisionVelocity, this._collider, 3, null, this._onCollisionPositionChange, this.uniqueId);
                 this.getScene().collisionCoordinator.getNewPosition(this.position, this._collisionVelocity, this._collider, 3, null, this._onCollisionPositionChange, this.uniqueId);
@@ -685,7 +685,7 @@
         protected _onCollisionPositionChange = (collisionId: number, newPosition: Vector3, collidedMesh: Nullable<AbstractMesh> = null) => {
         protected _onCollisionPositionChange = (collisionId: number, newPosition: Vector3, collidedMesh: Nullable<AbstractMesh> = null) => {
 
 
             if (this.getScene().workerCollisions && this.checkCollisions) {
             if (this.getScene().workerCollisions && this.checkCollisions) {
-                newPosition.multiplyInPlace(this._collider.radius);
+                newPosition.multiplyInPlace(this._collider._radius);
             }
             }
 
 
             if (!collidedMesh) {
             if (!collidedMesh) {

+ 35 - 31
src/Cameras/babylon.freeCamera.ts

@@ -1,16 +1,19 @@
 module BABYLON {
 module BABYLON {
-    export class FreeCamera extends TargetCamera {        
+    export class FreeCamera extends TargetCamera {
         @serializeAsVector3()
         @serializeAsVector3()
         public ellipsoid = new Vector3(0.5, 1, 0.5);
         public ellipsoid = new Vector3(0.5, 1, 0.5);
 
 
+        @serializeAsVector3()
+        public ellipsoidOffset = new Vector3(0, 0, 0);
+
         @serialize()
         @serialize()
         public checkCollisions = false;
         public checkCollisions = false;
 
 
         @serialize()
         @serialize()
         public applyGravity = false;
         public applyGravity = false;
-                
-        public inputs : FreeCameraInputsManager;
-        
+
+        public inputs: FreeCameraInputsManager;
+
         //-- begin properties for backward compatibility for inputs
         //-- begin properties for backward compatibility for inputs
         public get angularSensibility(): number {
         public get angularSensibility(): number {
             var mouse = <FreeCameraMouseInput>this.inputs.attached["mouse"];
             var mouse = <FreeCameraMouseInput>this.inputs.attached["mouse"];
@@ -19,13 +22,13 @@
 
 
             return 0;
             return 0;
         }
         }
-        
+
         public set angularSensibility(value: number) {
         public set angularSensibility(value: number) {
             var mouse = <FreeCameraMouseInput>this.inputs.attached["mouse"];
             var mouse = <FreeCameraMouseInput>this.inputs.attached["mouse"];
             if (mouse)
             if (mouse)
                 mouse.angularSensibility = value;
                 mouse.angularSensibility = value;
         }
         }
-        
+
         public get keysUp(): number[] {
         public get keysUp(): number[] {
             var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
             var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
             if (keyboard)
             if (keyboard)
@@ -33,13 +36,13 @@
 
 
             return [];
             return [];
         }
         }
-        
+
         public set keysUp(value: number[]) {
         public set keysUp(value: number[]) {
             var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
             var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
             if (keyboard)
             if (keyboard)
                 keyboard.keysUp = value;
                 keyboard.keysUp = value;
         }
         }
-        
+
         public get keysDown(): number[] {
         public get keysDown(): number[] {
             var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
             var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
             if (keyboard)
             if (keyboard)
@@ -47,13 +50,13 @@
 
 
             return [];
             return [];
         }
         }
-        
+
         public set keysDown(value: number[]) {
         public set keysDown(value: number[]) {
             var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
             var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
             if (keyboard)
             if (keyboard)
                 keyboard.keysDown = value;
                 keyboard.keysDown = value;
         }
         }
-        
+
         public get keysLeft(): number[] {
         public get keysLeft(): number[] {
             var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
             var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
             if (keyboard)
             if (keyboard)
@@ -61,13 +64,13 @@
 
 
             return [];
             return [];
         }
         }
-        
+
         public set keysLeft(value: number[]) {
         public set keysLeft(value: number[]) {
             var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
             var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
             if (keyboard)
             if (keyboard)
                 keyboard.keysLeft = value;
                 keyboard.keysLeft = value;
         }
         }
-        
+
         public get keysRight(): number[] {
         public get keysRight(): number[] {
             var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
             var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
             if (keyboard)
             if (keyboard)
@@ -75,55 +78,55 @@
 
 
             return [];
             return [];
         }
         }
-        
+
         public set keysRight(value: number[]) {
         public set keysRight(value: number[]) {
             var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
             var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
             if (keyboard)
             if (keyboard)
                 keyboard.keysRight = value;
                 keyboard.keysRight = value;
         }
         }
-        
+
         //-- end properties for backward compatibility for inputs
         //-- end properties for backward compatibility for inputs
-        
+
         public onCollide: (collidedMesh: AbstractMesh) => void;
         public onCollide: (collidedMesh: AbstractMesh) => void;
-        
+
         private _collider: Collider;
         private _collider: Collider;
         private _needMoveForGravity = false;
         private _needMoveForGravity = false;
         private _oldPosition = Vector3.Zero();
         private _oldPosition = Vector3.Zero();
         private _diffPosition = Vector3.Zero();
         private _diffPosition = Vector3.Zero();
         private _newPosition = Vector3.Zero();
         private _newPosition = Vector3.Zero();
-        
+
         public _localDirection: Vector3;
         public _localDirection: Vector3;
-        public _transformedDirection: Vector3;        
-        
+        public _transformedDirection: Vector3;
+
         constructor(name: string, position: Vector3, scene: Scene) {
         constructor(name: string, position: Vector3, scene: Scene) {
             super(name, position, scene);
             super(name, position, scene);
             this.inputs = new FreeCameraInputsManager(this);
             this.inputs = new FreeCameraInputsManager(this);
             this.inputs.addKeyboard().addMouse();
             this.inputs.addKeyboard().addMouse();
-        }     
+        }
 
 
         // Controls
         // Controls
         public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
         public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
             this.inputs.attachElement(element, noPreventDefault);
             this.inputs.attachElement(element, noPreventDefault);
-        }        
+        }
 
 
         public detachControl(element: HTMLElement): void {
         public detachControl(element: HTMLElement): void {
             this.inputs.detachElement(element);
             this.inputs.detachElement(element);
-            
+
             this.cameraDirection = new Vector3(0, 0, 0);
             this.cameraDirection = new Vector3(0, 0, 0);
             this.cameraRotation = new Vector2(0, 0);
             this.cameraRotation = new Vector2(0, 0);
         }
         }
 
 
         // Collisions
         // Collisions
         private _collisionMask = -1;
         private _collisionMask = -1;
-        
+
         public get collisionMask(): number {
         public get collisionMask(): number {
             return this._collisionMask;
             return this._collisionMask;
         }
         }
-        
+
         public set collisionMask(mask: number) {
         public set collisionMask(mask: number) {
             this._collisionMask = !isNaN(mask) ? mask : -1;
             this._collisionMask = !isNaN(mask) ? mask : -1;
         }
         }
-	 
+
         public _collideWithWorld(displacement: Vector3): void {
         public _collideWithWorld(displacement: Vector3): void {
             var globalPosition: Vector3;
             var globalPosition: Vector3;
 
 
@@ -134,17 +137,18 @@
             }
             }
 
 
             globalPosition.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPosition);
             globalPosition.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPosition);
+            this._oldPosition.addInPlace(this.ellipsoidOffset);
 
 
             if (!this._collider) {
             if (!this._collider) {
                 this._collider = new Collider();
                 this._collider = new Collider();
             }
             }
 
 
-            this._collider.radius = this.ellipsoid;
+            this._collider._radius = this.ellipsoid;
             this._collider.collisionMask = this._collisionMask;
             this._collider.collisionMask = this._collisionMask;
-		
+
             //no need for clone, as long as gravity is not on.
             //no need for clone, as long as gravity is not on.
             var actualDisplacement = displacement;
             var actualDisplacement = displacement;
-			
+
             //add gravity to the direction to prevent the dual-collision checking
             //add gravity to the direction to prevent the dual-collision checking
             if (this.applyGravity) {
             if (this.applyGravity) {
                 //this prevents mending with cameraDirection, a global variable of the free camera class.
                 //this prevents mending with cameraDirection, a global variable of the free camera class.
@@ -158,7 +162,7 @@
         private _onCollisionPositionChange = (collisionId: number, newPosition: Vector3, collidedMesh: Nullable<AbstractMesh> = null) => {
         private _onCollisionPositionChange = (collisionId: number, newPosition: Vector3, collidedMesh: Nullable<AbstractMesh> = null) => {
             //TODO move this to the collision coordinator!
             //TODO move this to the collision coordinator!
             if (this.getScene().workerCollisions)
             if (this.getScene().workerCollisions)
-                newPosition.multiplyInPlace(this._collider.radius);
+                newPosition.multiplyInPlace(this._collider._radius);
 
 
             var updatePosition = (newPos: Vector3) => {
             var updatePosition = (newPos: Vector3) => {
                 this._newPosition.copyFrom(newPos);
                 this._newPosition.copyFrom(newPos);
@@ -203,9 +207,9 @@
             this.inputs.clear();
             this.inputs.clear();
             super.dispose();
             super.dispose();
         }
         }
-        
+
         public getClassName(): string {
         public getClassName(): string {
             return "FreeCamera";
             return "FreeCamera";
         }
         }
-    }    
+    }
 } 
 } 

+ 70 - 53
src/Collisions/babylon.collider.ts

@@ -55,23 +55,20 @@
                 return result;
                 return result;
             }
             }
         }
         }
-    )();
+        )();
 
 
     export class Collider {
     export class Collider {
-        public radius = Vector3.One();
-        public retry = 0;
-        public velocity: Vector3;
-        public basePoint: Vector3;
-        public epsilon: number;
+        /** Define if a collision was found */
         public collisionFound: boolean;
         public collisionFound: boolean;
-        public velocityWorldLength: number;
-        public basePointWorld = Vector3.Zero();
-        public velocityWorld = Vector3.Zero();
-        public normalizedVelocity = Vector3.Zero();
-        public initialVelocity: Vector3;
-        public initialPosition: Vector3;
-        public nearestDistance: number;
+
+        /**
+         * Define last intersection point in local space
+         */
         public intersectionPoint: Vector3;
         public intersectionPoint: Vector3;
+
+        /**
+         * Define last collided mesh
+         */
         public collidedMesh: Nullable<AbstractMesh>;
         public collidedMesh: Nullable<AbstractMesh>;
 
 
         private _collisionPoint = Vector3.Zero();
         private _collisionPoint = Vector3.Zero();
@@ -86,28 +83,48 @@
         private _slidePlaneNormal = Vector3.Zero();
         private _slidePlaneNormal = Vector3.Zero();
         private _displacementVector = Vector3.Zero();
         private _displacementVector = Vector3.Zero();
 
 
+        public _radius = Vector3.One();
+        public _retry = 0;
+        private _velocity: Vector3;
+        private _basePoint: Vector3;
+        private _epsilon: number;
+        public _velocityWorldLength: number;
+        public _basePointWorld = Vector3.Zero();
+        private _velocityWorld = Vector3.Zero();
+        private _normalizedVelocity = Vector3.Zero();
+        public _initialVelocity: Vector3;
+        public _initialPosition: Vector3;
+        private _nearestDistance: number;
+
         private _collisionMask = -1;
         private _collisionMask = -1;
-        
+
         public get collisionMask(): number {
         public get collisionMask(): number {
             return this._collisionMask;
             return this._collisionMask;
         }
         }
-        
+
         public set collisionMask(mask: number) {
         public set collisionMask(mask: number) {
             this._collisionMask = !isNaN(mask) ? mask : -1;
             this._collisionMask = !isNaN(mask) ? mask : -1;
         }
         }
 
 
+        /**
+         * Gets the plane normal used to compute the sliding response (in local space)
+         */
+        public get slidePlaneNormal(): Vector3 {
+            return this._slidePlaneNormal;
+        }
+
         // Methods
         // Methods
         public _initialize(source: Vector3, dir: Vector3, e: number): void {
         public _initialize(source: Vector3, dir: Vector3, e: number): void {
-            this.velocity = dir;
-            Vector3.NormalizeToRef(dir, this.normalizedVelocity);
-            this.basePoint = source;
+            this._velocity = dir;
+            Vector3.NormalizeToRef(dir, this._normalizedVelocity);
+            this._basePoint = source;
 
 
-            source.multiplyToRef(this.radius, this.basePointWorld);
-            dir.multiplyToRef(this.radius, this.velocityWorld);
+            source.multiplyToRef(this._radius, this._basePointWorld);
+            dir.multiplyToRef(this._radius, this._velocityWorld);
 
 
-            this.velocityWorldLength = this.velocityWorld.length();
+            this._velocityWorldLength = this._velocityWorld.length();
 
 
-            this.epsilon = e;
+            this._epsilon = e;
             this.collisionFound = false;
             this.collisionFound = false;
         }
         }
 
 
@@ -132,15 +149,15 @@
         }
         }
 
 
         public _canDoCollision(sphereCenter: Vector3, sphereRadius: number, vecMin: Vector3, vecMax: Vector3): boolean {
         public _canDoCollision(sphereCenter: Vector3, sphereRadius: number, vecMin: Vector3, vecMax: Vector3): boolean {
-            var distance = Vector3.Distance(this.basePointWorld, sphereCenter);
+            var distance = Vector3.Distance(this._basePointWorld, sphereCenter);
 
 
-            var max = Math.max(this.radius.x, this.radius.y, this.radius.z);
+            var max = Math.max(this._radius.x, this._radius.y, this._radius.z);
 
 
-            if (distance > this.velocityWorldLength + max + sphereRadius) {
+            if (distance > this._velocityWorldLength + max + sphereRadius) {
                 return false;
                 return false;
             }
             }
 
 
-            if (!intersectBoxAASphere(vecMin, vecMax, this.basePointWorld, this.velocityWorldLength + max))
+            if (!intersectBoxAASphere(vecMin, vecMax, this._basePointWorld, this._velocityWorldLength + max))
                 return false;
                 return false;
 
 
             return true;
             return true;
@@ -162,11 +179,11 @@
 
 
             var trianglePlane = trianglePlaneArray[faceIndex];
             var trianglePlane = trianglePlaneArray[faceIndex];
 
 
-            if ((!hasMaterial) && !trianglePlane.isFrontFacingTo(this.normalizedVelocity, 0))
+            if ((!hasMaterial) && !trianglePlane.isFrontFacingTo(this._normalizedVelocity, 0))
                 return;
                 return;
 
 
-            var signedDistToTrianglePlane = trianglePlane.signedDistanceTo(this.basePoint);
-            var normalDotVelocity = Vector3.Dot(trianglePlane.normal, this.velocity);
+            var signedDistToTrianglePlane = trianglePlane.signedDistanceTo(this._basePoint);
+            var normalDotVelocity = Vector3.Dot(trianglePlane.normal, this._velocity);
 
 
             if (normalDotVelocity == 0) {
             if (normalDotVelocity == 0) {
                 if (Math.abs(signedDistToTrianglePlane) >= 1.0)
                 if (Math.abs(signedDistToTrianglePlane) >= 1.0)
@@ -199,8 +216,8 @@
             var t = 1.0;
             var t = 1.0;
 
 
             if (!embeddedInPlane) {
             if (!embeddedInPlane) {
-                this.basePoint.subtractToRef(trianglePlane.normal, this._planeIntersectionPoint);
-                this.velocity.scaleToRef(t0, this._tempVector);
+                this._basePoint.subtractToRef(trianglePlane.normal, this._planeIntersectionPoint);
+                this._velocity.scaleToRef(t0, this._tempVector);
                 this._planeIntersectionPoint.addInPlace(this._tempVector);
                 this._planeIntersectionPoint.addInPlace(this._tempVector);
 
 
                 if (this._checkPointInTriangle(this._planeIntersectionPoint, p1, p2, p3, trianglePlane.normal)) {
                 if (this._checkPointInTriangle(this._planeIntersectionPoint, p1, p2, p3, trianglePlane.normal)) {
@@ -211,12 +228,12 @@
             }
             }
 
 
             if (!found) {
             if (!found) {
-                var velocitySquaredLength = this.velocity.lengthSquared();
+                var velocitySquaredLength = this._velocity.lengthSquared();
 
 
                 var a = velocitySquaredLength;
                 var a = velocitySquaredLength;
 
 
-                this.basePoint.subtractToRef(p1, this._tempVector);
-                var b = 2.0 * (Vector3.Dot(this.velocity, this._tempVector));
+                this._basePoint.subtractToRef(p1, this._tempVector);
+                var b = 2.0 * (Vector3.Dot(this._velocity, this._tempVector));
                 var c = this._tempVector.lengthSquared() - 1.0;
                 var c = this._tempVector.lengthSquared() - 1.0;
 
 
                 var lowestRoot = getLowestRoot(a, b, c, t);
                 var lowestRoot = getLowestRoot(a, b, c, t);
@@ -226,8 +243,8 @@
                     this._collisionPoint.copyFrom(p1);
                     this._collisionPoint.copyFrom(p1);
                 }
                 }
 
 
-                this.basePoint.subtractToRef(p2, this._tempVector);
-                b = 2.0 * (Vector3.Dot(this.velocity, this._tempVector));
+                this._basePoint.subtractToRef(p2, this._tempVector);
+                b = 2.0 * (Vector3.Dot(this._velocity, this._tempVector));
                 c = this._tempVector.lengthSquared() - 1.0;
                 c = this._tempVector.lengthSquared() - 1.0;
 
 
                 lowestRoot = getLowestRoot(a, b, c, t);
                 lowestRoot = getLowestRoot(a, b, c, t);
@@ -237,8 +254,8 @@
                     this._collisionPoint.copyFrom(p2);
                     this._collisionPoint.copyFrom(p2);
                 }
                 }
 
 
-                this.basePoint.subtractToRef(p3, this._tempVector);
-                b = 2.0 * (Vector3.Dot(this.velocity, this._tempVector));
+                this._basePoint.subtractToRef(p3, this._tempVector);
+                b = 2.0 * (Vector3.Dot(this._velocity, this._tempVector));
                 c = this._tempVector.lengthSquared() - 1.0;
                 c = this._tempVector.lengthSquared() - 1.0;
 
 
                 lowestRoot = getLowestRoot(a, b, c, t);
                 lowestRoot = getLowestRoot(a, b, c, t);
@@ -249,13 +266,13 @@
                 }
                 }
 
 
                 p2.subtractToRef(p1, this._edge);
                 p2.subtractToRef(p1, this._edge);
-                p1.subtractToRef(this.basePoint, this._baseToVertex);
+                p1.subtractToRef(this._basePoint, this._baseToVertex);
                 var edgeSquaredLength = this._edge.lengthSquared();
                 var edgeSquaredLength = this._edge.lengthSquared();
-                var edgeDotVelocity = Vector3.Dot(this._edge, this.velocity);
+                var edgeDotVelocity = Vector3.Dot(this._edge, this._velocity);
                 var edgeDotBaseToVertex = Vector3.Dot(this._edge, this._baseToVertex);
                 var edgeDotBaseToVertex = Vector3.Dot(this._edge, this._baseToVertex);
 
 
                 a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
                 a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
-                b = edgeSquaredLength * (2.0 * Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
+                b = edgeSquaredLength * (2.0 * Vector3.Dot(this._velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
                 c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
                 c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
 
 
                 lowestRoot = getLowestRoot(a, b, c, t);
                 lowestRoot = getLowestRoot(a, b, c, t);
@@ -271,13 +288,13 @@
                 }
                 }
 
 
                 p3.subtractToRef(p2, this._edge);
                 p3.subtractToRef(p2, this._edge);
-                p2.subtractToRef(this.basePoint, this._baseToVertex);
+                p2.subtractToRef(this._basePoint, this._baseToVertex);
                 edgeSquaredLength = this._edge.lengthSquared();
                 edgeSquaredLength = this._edge.lengthSquared();
-                edgeDotVelocity = Vector3.Dot(this._edge, this.velocity);
+                edgeDotVelocity = Vector3.Dot(this._edge, this._velocity);
                 edgeDotBaseToVertex = Vector3.Dot(this._edge, this._baseToVertex);
                 edgeDotBaseToVertex = Vector3.Dot(this._edge, this._baseToVertex);
 
 
                 a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
                 a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
-                b = edgeSquaredLength * (2.0 * Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
+                b = edgeSquaredLength * (2.0 * Vector3.Dot(this._velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
                 c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
                 c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
                 lowestRoot = getLowestRoot(a, b, c, t);
                 lowestRoot = getLowestRoot(a, b, c, t);
                 if (lowestRoot.found) {
                 if (lowestRoot.found) {
@@ -292,13 +309,13 @@
                 }
                 }
 
 
                 p1.subtractToRef(p3, this._edge);
                 p1.subtractToRef(p3, this._edge);
-                p3.subtractToRef(this.basePoint, this._baseToVertex);
+                p3.subtractToRef(this._basePoint, this._baseToVertex);
                 edgeSquaredLength = this._edge.lengthSquared();
                 edgeSquaredLength = this._edge.lengthSquared();
-                edgeDotVelocity = Vector3.Dot(this._edge, this.velocity);
+                edgeDotVelocity = Vector3.Dot(this._edge, this._velocity);
                 edgeDotBaseToVertex = Vector3.Dot(this._edge, this._baseToVertex);
                 edgeDotBaseToVertex = Vector3.Dot(this._edge, this._baseToVertex);
 
 
                 a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
                 a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
-                b = edgeSquaredLength * (2.0 * Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
+                b = edgeSquaredLength * (2.0 * Vector3.Dot(this._velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
                 c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
                 c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
 
 
                 lowestRoot = getLowestRoot(a, b, c, t);
                 lowestRoot = getLowestRoot(a, b, c, t);
@@ -315,15 +332,15 @@
             }
             }
 
 
             if (found) {
             if (found) {
-                var distToCollision = t * this.velocity.length();
+                var distToCollision = t * this._velocity.length();
 
 
-                if (!this.collisionFound || distToCollision < this.nearestDistance) {
+                if (!this.collisionFound || distToCollision < this._nearestDistance) {
                     if (!this.intersectionPoint) {
                     if (!this.intersectionPoint) {
                         this.intersectionPoint = this._collisionPoint.clone();
                         this.intersectionPoint = this._collisionPoint.clone();
                     } else {
                     } else {
                         this.intersectionPoint.copyFrom(this._collisionPoint);
                         this.intersectionPoint.copyFrom(this._collisionPoint);
                     }
                     }
-                    this.nearestDistance = distToCollision;
+                    this._nearestDistance = distToCollision;
                     this.collisionFound = true;
                     this.collisionFound = true;
                 }
                 }
             }
             }
@@ -341,12 +358,12 @@
 
 
         public _getResponse(pos: Vector3, vel: Vector3): void {
         public _getResponse(pos: Vector3, vel: Vector3): void {
             pos.addToRef(vel, this._destinationPoint);
             pos.addToRef(vel, this._destinationPoint);
-            vel.scaleInPlace((this.nearestDistance / vel.length()));
+            vel.scaleInPlace((this._nearestDistance / vel.length()));
 
 
-            this.basePoint.addToRef(vel, pos);
+            this._basePoint.addToRef(vel, pos);
             pos.subtractToRef(this.intersectionPoint, this._slidePlaneNormal);
             pos.subtractToRef(this.intersectionPoint, this._slidePlaneNormal);
             this._slidePlaneNormal.normalize();
             this._slidePlaneNormal.normalize();
-            this._slidePlaneNormal.scaleToRef(this.epsilon, this._displacementVector);
+            this._slidePlaneNormal.scaleToRef(this._epsilon, this._displacementVector);
 
 
             pos.addInPlace(this._displacementVector);
             pos.addInPlace(this._displacementVector);
             this.intersectionPoint.addInPlace(this._displacementVector);
             this.intersectionPoint.addInPlace(this._displacementVector);

+ 11 - 11
src/Collisions/babylon.collisionCoordinator.ts

@@ -194,8 +194,8 @@ module BABYLON {
             if (!this._init) return;
             if (!this._init) return;
             if (this._collisionsCallbackArray[collisionIndex] || this._collisionsCallbackArray[collisionIndex + 100000]) return;
             if (this._collisionsCallbackArray[collisionIndex] || this._collisionsCallbackArray[collisionIndex + 100000]) return;
 
 
-            position.divideToRef(collider.radius, this._scaledPosition);
-            displacement.divideToRef(collider.radius, this._scaledVelocity);
+            position.divideToRef(collider._radius, this._scaledPosition);
+            displacement.divideToRef(collider._radius, this._scaledVelocity);
 
 
             this._collisionsCallbackArray[collisionIndex] = onNewPosition;
             this._collisionsCallbackArray[collisionIndex] = onNewPosition;
 
 
@@ -203,7 +203,7 @@ module BABYLON {
                 collider: {
                 collider: {
                     position: this._scaledPosition.asArray(),
                     position: this._scaledPosition.asArray(),
                     velocity: this._scaledVelocity.asArray(),
                     velocity: this._scaledVelocity.asArray(),
-                    radius: collider.radius.asArray()
+                    radius: collider._radius.asArray()
                 },
                 },
                 collisionId: collisionIndex,
                 collisionId: collisionIndex,
                 excludedMeshUniqueId: excludedMesh ? excludedMesh.uniqueId : null,
                 excludedMeshUniqueId: excludedMesh ? excludedMesh.uniqueId : null,
@@ -360,15 +360,15 @@ module BABYLON {
         private _finalPosition = Vector3.Zero();
         private _finalPosition = Vector3.Zero();
 
 
         public getNewPosition(position: Vector3, displacement: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh: Nullable<AbstractMesh>) => void, collisionIndex: number): void {
         public getNewPosition(position: Vector3, displacement: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh: Nullable<AbstractMesh>) => void, collisionIndex: number): void {
-            position.divideToRef(collider.radius, this._scaledPosition);
-            displacement.divideToRef(collider.radius, this._scaledVelocity);
+            position.divideToRef(collider._radius, this._scaledPosition);
+            displacement.divideToRef(collider._radius, this._scaledVelocity);
             collider.collidedMesh = null;
             collider.collidedMesh = null;
-            collider.retry = 0;
-            collider.initialVelocity = this._scaledVelocity;
-            collider.initialPosition = this._scaledPosition;
+            collider._retry = 0;
+            collider._initialVelocity = this._scaledVelocity;
+            collider._initialPosition = this._scaledPosition;
             this._collideWithWorld(this._scaledPosition, this._scaledVelocity, collider, maximumRetry, this._finalPosition, excludedMesh);
             this._collideWithWorld(this._scaledPosition, this._scaledVelocity, collider, maximumRetry, this._finalPosition, excludedMesh);
 
 
-            this._finalPosition.multiplyInPlace(collider.radius);
+            this._finalPosition.multiplyInPlace(collider._radius);
             //run the callback
             //run the callback
             onNewPosition(collisionIndex, this._finalPosition, collider.collidedMesh);
             onNewPosition(collisionIndex, this._finalPosition, collider.collidedMesh);
         }
         }
@@ -392,7 +392,7 @@ module BABYLON {
         private _collideWithWorld(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, finalPosition: Vector3, excludedMesh: Nullable<AbstractMesh> = null): void {
         private _collideWithWorld(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, finalPosition: Vector3, excludedMesh: Nullable<AbstractMesh> = null): void {
             var closeDistance = Engine.CollisionsEpsilon * 10.0;
             var closeDistance = Engine.CollisionsEpsilon * 10.0;
 
 
-            if (collider.retry >= maximumRetry) {
+            if (collider._retry >= maximumRetry) {
                 finalPosition.copyFrom(position);
                 finalPosition.copyFrom(position);
                 return;
                 return;
             }
             }
@@ -424,7 +424,7 @@ module BABYLON {
                 return;
                 return;
             }
             }
 
 
-            collider.retry++;
+            collider._retry++;
             this._collideWithWorld(position, velocity, collider, maximumRetry, finalPosition, excludedMesh);
             this._collideWithWorld(position, velocity, collider, maximumRetry, finalPosition, excludedMesh);
         }
         }
     }
     }

+ 14 - 14
src/Collisions/babylon.collisionWorker.ts

@@ -55,7 +55,7 @@ module BABYLON {
 
 
             //TODO CollisionsEpsilon should be defined here and not in the engine.
             //TODO CollisionsEpsilon should be defined here and not in the engine.
             const closeDistance = 0.01; //is initializing here correct? A quick look - looks like it is fine.
             const closeDistance = 0.01; //is initializing here correct? A quick look - looks like it is fine.
-            if (this.collider.retry >= maximumRetry) {
+            if (this.collider._retry >= maximumRetry) {
                 this.finalPosition.copyFrom(position);
                 this.finalPosition.copyFrom(position);
                 return;
                 return;
             }
             }
@@ -91,7 +91,7 @@ module BABYLON {
                 return;
                 return;
             }
             }
 
 
-            this.collider.retry++;
+            this.collider._retry++;
             this.collideWithWorld(position, velocity, maximumRetry, excludedMeshUniqueId);
             this.collideWithWorld(position, velocity, maximumRetry, excludedMeshUniqueId);
         }
         }
 
 
@@ -102,7 +102,7 @@ module BABYLON {
             };
             };
 
 
             // Transformation matrix
             // Transformation matrix
-            Matrix.ScalingToRef(1.0 / this.collider.radius.x, 1.0 / this.collider.radius.y, 1.0 / this.collider.radius.z, this.collisionsScalingMatrix);
+            Matrix.ScalingToRef(1.0 / this.collider._radius.x, 1.0 / this.collider._radius.y, 1.0 / this.collider._radius.z, this.collisionsScalingMatrix);
             var worldFromCache = Matrix.FromArray(mesh.worldMatrixFromCache);
             var worldFromCache = Matrix.FromArray(mesh.worldMatrixFromCache);
             worldFromCache.multiplyToRef(this.collisionsScalingMatrix, this.collisionTranformationMatrix);
             worldFromCache.multiplyToRef(this.collisionsScalingMatrix, this.collisionTranformationMatrix);
 
 
@@ -165,7 +165,7 @@ module BABYLON {
                 for (var i = start; i < end; i++) {
                 for (var i = start; i < end; i++) {
                     (<any>subMesh)['_lastColliderWorldVertices'].push(Vector3.TransformCoordinates((<any>meshGeometry)['positionsArray'][i], transformMatrix));
                     (<any>subMesh)['_lastColliderWorldVertices'].push(Vector3.TransformCoordinates((<any>meshGeometry)['positionsArray'][i], transformMatrix));
                 }
                 }
-            }        
+            }
 
 
             // Collide
             // Collide
             this.collider._collide((<any>subMesh)['_trianglePlanes'], (<any>subMesh)['_lastColliderWorldVertices'], <any>meshGeometry.indices, subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart, subMesh.hasMaterial);
             this.collider._collide((<any>subMesh)['_trianglePlanes'], (<any>subMesh)['_lastColliderWorldVertices'], <any>meshGeometry.indices, subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart, subMesh.hasMaterial);
@@ -233,7 +233,7 @@ module BABYLON {
             var finalPosition = Vector3.Zero();
             var finalPosition = Vector3.Zero();
             //create a new collider
             //create a new collider
             var collider = new Collider();
             var collider = new Collider();
-            collider.radius = Vector3.FromArray(payload.collider.radius);
+            collider._radius = Vector3.FromArray(payload.collider.radius);
 
 
             var colliderWorker = new CollideWorker(collider, this._collisionCache, finalPosition);
             var colliderWorker = new CollideWorker(collider, this._collisionCache, finalPosition);
             colliderWorker.collideWithWorld(Vector3.FromArray(payload.collider.position), Vector3.FromArray(payload.collider.velocity), payload.maximumRetry, payload.excludedMeshUniqueId);
             colliderWorker.collideWithWorld(Vector3.FromArray(payload.collider.position), Vector3.FromArray(payload.collider.velocity), payload.maximumRetry, payload.excludedMeshUniqueId);
@@ -273,15 +273,15 @@ module BABYLON {
             var onNewMessage = (event: MessageEvent) => {
             var onNewMessage = (event: MessageEvent) => {
                 var message = <BabylonMessage>event.data;
                 var message = <BabylonMessage>event.data;
                 switch (message.taskType) {
                 switch (message.taskType) {
-                case WorkerTaskType.INIT:
-                    collisionDetector.onInit(<InitPayload>message.payload);
-                    break;
-                case WorkerTaskType.COLLIDE:
-                    collisionDetector.onCollision(<CollidePayload>message.payload);
-                    break;
-                case WorkerTaskType.UPDATE:
-                    collisionDetector.onUpdate(<UpdatePayload>message.payload);
-                    break;
+                    case WorkerTaskType.INIT:
+                        collisionDetector.onInit(<InitPayload>message.payload);
+                        break;
+                    case WorkerTaskType.COLLIDE:
+                        collisionDetector.onCollision(<CollidePayload>message.payload);
+                        break;
+                    case WorkerTaskType.UPDATE:
+                        collisionDetector.onUpdate(<UpdatePayload>message.payload);
+                        break;
                 }
                 }
             }
             }
 
 

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

@@ -564,7 +564,7 @@
         }
         }
 
 
         public static get Version(): string {
         public static get Version(): string {
-            return "3.1-rc-0";
+            return "3.1-rc-1";
         }
         }
 
 
         // Updatable statics so stick with vars here
         // Updatable statics so stick with vars here

+ 2 - 2
src/Loading/babylon.sceneLoader.ts

@@ -104,7 +104,7 @@
             if (registeredPlugin) {
             if (registeredPlugin) {
                 return registeredPlugin;
                 return registeredPlugin;
             }
             }
-
+            Tools.Warn("Unable to find a plugin to load " + extension + " files. Trying to use .babylon default plugin.");
             return SceneLoader._getDefaultPlugin();
             return SceneLoader._getDefaultPlugin();
         }
         }
 
 
@@ -126,7 +126,7 @@
             }
             }
 
 
             var queryStringPosition = sceneFilename.indexOf("?");
             var queryStringPosition = sceneFilename.indexOf("?");
-            
+
             if (queryStringPosition !== -1) {
             if (queryStringPosition !== -1) {
                 sceneFilename = sceneFilename.substring(0, queryStringPosition);
                 sceneFilename = sceneFilename.substring(0, queryStringPosition);
             }
             }

+ 4 - 2
src/Materials/Textures/babylon.cubeTexture.ts

@@ -52,13 +52,15 @@
                 files = [];
                 files = [];
 
 
                 if (extensions) {
                 if (extensions) {
-                    
+
                     for (var index = 0; index < extensions.length; index++) {
                     for (var index = 0; index < extensions.length; index++) {
                         files.push(rootUrl + extensions[index]);
                         files.push(rootUrl + extensions[index]);
                     }
                     }
                 }
                 }
             }
             }
 
 
+            this._files = files;
+
             if (!this._texture) {
             if (!this._texture) {
                 if (!scene.useDelayedTextureLoading) {
                 if (!scene.useDelayedTextureLoading) {
                     if (prefiltered) {
                     if (prefiltered) {
@@ -131,7 +133,7 @@
         public clone(): CubeTexture {
         public clone(): CubeTexture {
             return SerializationHelper.Clone(() => {
             return SerializationHelper.Clone(() => {
                 let scene = this.getScene();
                 let scene = this.getScene();
-                
+
                 if (!scene) {
                 if (!scene) {
                     return this;
                     return this;
                 }
                 }

+ 77 - 77
src/Materials/babylon.standardMaterial.ts

@@ -1,5 +1,5 @@
 module BABYLON {
 module BABYLON {
-   export class StandardMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines {
+    export class StandardMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines {
         public MAINUV1 = false;
         public MAINUV1 = false;
         public MAINUV2 = false;
         public MAINUV2 = false;
         public DIFFUSE = false;
         public DIFFUSE = false;
@@ -93,11 +93,11 @@ module BABYLON {
 
 
         public setReflectionMode(modeToEnable: string) {
         public setReflectionMode(modeToEnable: string) {
             var modes = [
             var modes = [
-                            "REFLECTIONMAP_CUBIC", "REFLECTIONMAP_EXPLICIT", "REFLECTIONMAP_PLANAR",
-                            "REFLECTIONMAP_PROJECTION", "REFLECTIONMAP_PROJECTION", "REFLECTIONMAP_SKYBOX",
-                            "REFLECTIONMAP_SPHERICAL", "REFLECTIONMAP_EQUIRECTANGULAR", "REFLECTIONMAP_EQUIRECTANGULAR_FIXED",
-                            "REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED"
-                        ];
+                "REFLECTIONMAP_CUBIC", "REFLECTIONMAP_EXPLICIT", "REFLECTIONMAP_PLANAR",
+                "REFLECTIONMAP_PROJECTION", "REFLECTIONMAP_PROJECTION", "REFLECTIONMAP_SKYBOX",
+                "REFLECTIONMAP_SPHERICAL", "REFLECTIONMAP_EQUIRECTANGULAR", "REFLECTIONMAP_EQUIRECTANGULAR_FIXED",
+                "REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED"
+            ];
 
 
             for (var mode of modes) {
             for (var mode of modes) {
                 (<any>this)[mode] = (mode === modeToEnable);
                 (<any>this)[mode] = (mode === modeToEnable);
@@ -117,39 +117,39 @@ module BABYLON {
         public ambientTexture: Nullable<BaseTexture>;;
         public ambientTexture: Nullable<BaseTexture>;;
 
 
         @serializeAsTexture("opacityTexture")
         @serializeAsTexture("opacityTexture")
-        private _opacityTexture: Nullable<BaseTexture>;;        
+        private _opacityTexture: Nullable<BaseTexture>;;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
-        public opacityTexture: Nullable<BaseTexture>;;    
+        public opacityTexture: Nullable<BaseTexture>;;
 
 
         @serializeAsTexture("reflectionTexture")
         @serializeAsTexture("reflectionTexture")
         private _reflectionTexture: Nullable<BaseTexture>;;
         private _reflectionTexture: Nullable<BaseTexture>;;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
-        public reflectionTexture: Nullable<BaseTexture>;        
+        public reflectionTexture: Nullable<BaseTexture>;
 
 
         @serializeAsTexture("emissiveTexture")
         @serializeAsTexture("emissiveTexture")
         private _emissiveTexture: Nullable<BaseTexture>;;
         private _emissiveTexture: Nullable<BaseTexture>;;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
-        public emissiveTexture: Nullable<BaseTexture>;;     
+        public emissiveTexture: Nullable<BaseTexture>;;
 
 
         @serializeAsTexture("specularTexture")
         @serializeAsTexture("specularTexture")
         private _specularTexture: Nullable<BaseTexture>;;
         private _specularTexture: Nullable<BaseTexture>;;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
-        public specularTexture: Nullable<BaseTexture>;;             
+        public specularTexture: Nullable<BaseTexture>;;
 
 
         @serializeAsTexture("bumpTexture")
         @serializeAsTexture("bumpTexture")
         private _bumpTexture: Nullable<BaseTexture>;;
         private _bumpTexture: Nullable<BaseTexture>;;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
-        public bumpTexture: Nullable<BaseTexture>;;         
+        public bumpTexture: Nullable<BaseTexture>;;
 
 
         @serializeAsTexture("lightmapTexture")
         @serializeAsTexture("lightmapTexture")
         private _lightmapTexture: Nullable<BaseTexture>;;
         private _lightmapTexture: Nullable<BaseTexture>;;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
-        public lightmapTexture: Nullable<BaseTexture>;;            
+        public lightmapTexture: Nullable<BaseTexture>;;
 
 
         @serializeAsTexture("refractionTexture")
         @serializeAsTexture("refractionTexture")
         private _refractionTexture: Nullable<BaseTexture>;;
         private _refractionTexture: Nullable<BaseTexture>;;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
-        public refractionTexture: Nullable<BaseTexture>;;   
+        public refractionTexture: Nullable<BaseTexture>;;
 
 
         @serializeAsColor3("ambient")
         @serializeAsColor3("ambient")
         public ambientColor = new Color3(0, 0, 0);
         public ambientColor = new Color3(0, 0, 0);
@@ -169,27 +169,27 @@ module BABYLON {
         @serialize("useAlphaFromDiffuseTexture")
         @serialize("useAlphaFromDiffuseTexture")
         private _useAlphaFromDiffuseTexture = false;
         private _useAlphaFromDiffuseTexture = false;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
-        public useAlphaFromDiffuseTexture: boolean;      
+        public useAlphaFromDiffuseTexture: boolean;
 
 
         @serialize("useEmissiveAsIllumination")
         @serialize("useEmissiveAsIllumination")
         private _useEmissiveAsIllumination = false;
         private _useEmissiveAsIllumination = false;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
-        public useEmissiveAsIllumination: boolean;           
-      
+        public useEmissiveAsIllumination: boolean;
+
         @serialize("linkEmissiveWithDiffuse")
         @serialize("linkEmissiveWithDiffuse")
         private _linkEmissiveWithDiffuse = false;
         private _linkEmissiveWithDiffuse = false;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
-        public linkEmissiveWithDiffuse: boolean;                    
+        public linkEmissiveWithDiffuse: boolean;
 
 
         @serialize("useSpecularOverAlpha")
         @serialize("useSpecularOverAlpha")
         private _useSpecularOverAlpha = false;
         private _useSpecularOverAlpha = false;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
-        public useSpecularOverAlpha: boolean;               
+        public useSpecularOverAlpha: boolean;
 
 
         @serialize("useReflectionOverAlpha")
         @serialize("useReflectionOverAlpha")
         private _useReflectionOverAlpha = false;
         private _useReflectionOverAlpha = false;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
-        public useReflectionOverAlpha: boolean;               
+        public useReflectionOverAlpha: boolean;
 
 
         @serialize("disableLighting")
         @serialize("disableLighting")
         private _disableLighting = false;
         private _disableLighting = false;
@@ -199,12 +199,12 @@ module BABYLON {
         @serialize("useParallax")
         @serialize("useParallax")
         private _useParallax = false;
         private _useParallax = false;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
-        public useParallax: boolean;            
+        public useParallax: boolean;
 
 
         @serialize("useParallaxOcclusion")
         @serialize("useParallaxOcclusion")
         private _useParallaxOcclusion = false;
         private _useParallaxOcclusion = false;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
-        public useParallaxOcclusion: boolean;                  
+        public useParallaxOcclusion: boolean;
 
 
         @serialize()
         @serialize()
         public parallaxScaleBias = 0.05;
         public parallaxScaleBias = 0.05;
@@ -212,7 +212,7 @@ module BABYLON {
         @serialize("roughness")
         @serialize("roughness")
         private _roughness = 0;
         private _roughness = 0;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
-        public roughness: number;            
+        public roughness: number;
 
 
         @serialize()
         @serialize()
         public indexOfRefraction = 0.98;
         public indexOfRefraction = 0.98;
@@ -223,49 +223,49 @@ module BABYLON {
         @serialize("useLightmapAsShadowmap")
         @serialize("useLightmapAsShadowmap")
         private _useLightmapAsShadowmap = false;
         private _useLightmapAsShadowmap = false;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
-        public useLightmapAsShadowmap: boolean;             
+        public useLightmapAsShadowmap: boolean;
 
 
         // Fresnel
         // Fresnel
         @serializeAsFresnelParameters("diffuseFresnelParameters")
         @serializeAsFresnelParameters("diffuseFresnelParameters")
         private _diffuseFresnelParameters: FresnelParameters;
         private _diffuseFresnelParameters: FresnelParameters;
         @expandToProperty("_markAllSubMeshesAsFresnelDirty")
         @expandToProperty("_markAllSubMeshesAsFresnelDirty")
-        public diffuseFresnelParameters: FresnelParameters;            
+        public diffuseFresnelParameters: FresnelParameters;
 
 
         @serializeAsFresnelParameters("opacityFresnelParameters")
         @serializeAsFresnelParameters("opacityFresnelParameters")
         private _opacityFresnelParameters: FresnelParameters;
         private _opacityFresnelParameters: FresnelParameters;
         @expandToProperty("_markAllSubMeshesAsFresnelDirty")
         @expandToProperty("_markAllSubMeshesAsFresnelDirty")
-        public opacityFresnelParameters: FresnelParameters;            
-           
+        public opacityFresnelParameters: FresnelParameters;
+
 
 
         @serializeAsFresnelParameters("reflectionFresnelParameters")
         @serializeAsFresnelParameters("reflectionFresnelParameters")
         private _reflectionFresnelParameters: FresnelParameters;
         private _reflectionFresnelParameters: FresnelParameters;
         @expandToProperty("_markAllSubMeshesAsFresnelDirty")
         @expandToProperty("_markAllSubMeshesAsFresnelDirty")
-        public reflectionFresnelParameters: FresnelParameters;             
+        public reflectionFresnelParameters: FresnelParameters;
 
 
         @serializeAsFresnelParameters("refractionFresnelParameters")
         @serializeAsFresnelParameters("refractionFresnelParameters")
         private _refractionFresnelParameters: FresnelParameters;
         private _refractionFresnelParameters: FresnelParameters;
         @expandToProperty("_markAllSubMeshesAsFresnelDirty")
         @expandToProperty("_markAllSubMeshesAsFresnelDirty")
-        public refractionFresnelParameters: FresnelParameters;           
+        public refractionFresnelParameters: FresnelParameters;
 
 
         @serializeAsFresnelParameters("emissiveFresnelParameters")
         @serializeAsFresnelParameters("emissiveFresnelParameters")
         private _emissiveFresnelParameters: FresnelParameters;
         private _emissiveFresnelParameters: FresnelParameters;
         @expandToProperty("_markAllSubMeshesAsFresnelDirty")
         @expandToProperty("_markAllSubMeshesAsFresnelDirty")
-        public emissiveFresnelParameters: FresnelParameters;            
+        public emissiveFresnelParameters: FresnelParameters;
 
 
         @serialize("useReflectionFresnelFromSpecular")
         @serialize("useReflectionFresnelFromSpecular")
-        private _useReflectionFresnelFromSpecular = false;    
+        private _useReflectionFresnelFromSpecular = false;
         @expandToProperty("_markAllSubMeshesAsFresnelDirty")
         @expandToProperty("_markAllSubMeshesAsFresnelDirty")
-        public useReflectionFresnelFromSpecular: boolean;                 
+        public useReflectionFresnelFromSpecular: boolean;
 
 
         @serialize("useGlossinessFromSpecularMapAlpha")
         @serialize("useGlossinessFromSpecularMapAlpha")
         private _useGlossinessFromSpecularMapAlpha = false;
         private _useGlossinessFromSpecularMapAlpha = false;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
-        public useGlossinessFromSpecularMapAlpha: boolean;           
-  
+        public useGlossinessFromSpecularMapAlpha: boolean;
+
         @serialize("maxSimultaneousLights")
         @serialize("maxSimultaneousLights")
         private _maxSimultaneousLights = 4;
         private _maxSimultaneousLights = 4;
         @expandToProperty("_markAllSubMeshesAsLightsDirty")
         @expandToProperty("_markAllSubMeshesAsLightsDirty")
-        public maxSimultaneousLights: number;                   
+        public maxSimultaneousLights: number;
 
 
         /**
         /**
          * If sets to true, x component of normal map value will invert (x = 1.0 - x).
          * If sets to true, x component of normal map value will invert (x = 1.0 - x).
@@ -289,7 +289,7 @@ module BABYLON {
         @serialize("twoSidedLighting")
         @serialize("twoSidedLighting")
         private _twoSidedLighting = false;
         private _twoSidedLighting = false;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
-        public twoSidedLighting: boolean;     
+        public twoSidedLighting: boolean;
 
 
         /**
         /**
          * Default configuration related to image processing available in the standard Material.
          * Default configuration related to image processing available in the standard Material.
@@ -403,7 +403,7 @@ module BABYLON {
         public set cameraExposure(value: number) {
         public set cameraExposure(value: number) {
             this._imageProcessingConfiguration.exposure = value;
             this._imageProcessingConfiguration.exposure = value;
         };
         };
-        
+
         /**
         /**
          * Gets The camera contrast used on this material.
          * Gets The camera contrast used on this material.
          */
          */
@@ -417,7 +417,7 @@ module BABYLON {
         public set cameraContrast(value: number) {
         public set cameraContrast(value: number) {
             this._imageProcessingConfiguration.contrast = value;
             this._imageProcessingConfiguration.contrast = value;
         }
         }
-        
+
         /**
         /**
          * Gets the Color Grading 2D Lookup Texture.
          * Gets the Color Grading 2D Lookup Texture.
          */
          */
@@ -427,7 +427,7 @@ module BABYLON {
         /**
         /**
          * Sets the Color Grading 2D Lookup Texture.
          * Sets the Color Grading 2D Lookup Texture.
          */
          */
-        public set cameraColorGradingTexture(value: Nullable<BaseTexture> ) {
+        public set cameraColorGradingTexture(value: Nullable<BaseTexture>) {
             this._imageProcessingConfiguration.colorGradingTexture = value;
             this._imageProcessingConfiguration.colorGradingTexture = value;
         }
         }
 
 
@@ -448,7 +448,7 @@ module BABYLON {
          */
          */
         public set cameraColorCurves(value: Nullable<ColorCurves>) {
         public set cameraColorCurves(value: Nullable<ColorCurves>) {
             this._imageProcessingConfiguration.colorCurves = value;
             this._imageProcessingConfiguration.colorCurves = value;
-        }        
+        }
 
 
         public customShaderNameResolve: (shaderName: string, uniforms: string[], uniformBuffers: string[], samplers: string[], defines: StandardMaterialDefines) => string;
         public customShaderNameResolve: (shaderName: string, uniforms: string[], uniformBuffers: string[], samplers: string[], defines: StandardMaterialDefines) => string;
 
 
@@ -481,7 +481,7 @@ module BABYLON {
 
 
         public getClassName(): string {
         public getClassName(): string {
             return "StandardMaterial";
             return "StandardMaterial";
-        }        
+        }
 
 
         @serialize()
         @serialize()
         public get useLogarithmicDepth(): boolean {
         public get useLogarithmicDepth(): boolean {
@@ -513,7 +513,7 @@ module BABYLON {
         /**
         /**
          * Child classes can use it to update shaders
          * Child classes can use it to update shaders
          */
          */
-        public isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances: boolean = false): boolean {            
+        public isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances: boolean = false): boolean {
             if (subMesh.effect && this.isFrozen) {
             if (subMesh.effect && this.isFrozen) {
                 if (this._wasPreviouslyReady && subMesh.effect) {
                 if (this._wasPreviouslyReady && subMesh.effect) {
                     return true;
                     return true;
@@ -696,7 +696,7 @@ module BABYLON {
 
 
                 defines.EMISSIVEASILLUMINATION = this._useEmissiveAsIllumination;
                 defines.EMISSIVEASILLUMINATION = this._useEmissiveAsIllumination;
 
 
-                defines.LINKEMISSIVEWITHDIFFUSE = this._linkEmissiveWithDiffuse;       
+                defines.LINKEMISSIVEWITHDIFFUSE = this._linkEmissiveWithDiffuse;
 
 
                 defines.SPECULAROVERALPHA = this._useSpecularOverAlpha;
                 defines.SPECULAROVERALPHA = this._useSpecularOverAlpha;
 
 
@@ -726,9 +726,9 @@ module BABYLON {
 
 
                         defines.REFLECTIONFRESNELFROMSPECULAR = this._useReflectionFresnelFromSpecular;
                         defines.REFLECTIONFRESNELFROMSPECULAR = this._useReflectionFresnelFromSpecular;
 
 
-                        defines.REFRACTIONFRESNEL = (this._refractionFresnelParameters && this._refractionFresnelParameters.isEnabled) ;
+                        defines.REFRACTIONFRESNEL = (this._refractionFresnelParameters && this._refractionFresnelParameters.isEnabled);
 
 
-                        defines.EMISSIVEFRESNEL = (this._emissiveFresnelParameters && this._emissiveFresnelParameters.isEnabled) ;
+                        defines.EMISSIVEFRESNEL = (this._emissiveFresnelParameters && this._emissiveFresnelParameters.isEnabled);
 
 
                         defines._needNormals = true;
                         defines._needNormals = true;
                         defines.FRESNEL = true;
                         defines.FRESNEL = true;
@@ -838,9 +838,9 @@ module BABYLON {
                 MaterialHelper.PrepareAttributesForBones(attribs, mesh, defines, fallbacks);
                 MaterialHelper.PrepareAttributesForBones(attribs, mesh, defines, fallbacks);
                 MaterialHelper.PrepareAttributesForInstances(attribs, defines);
                 MaterialHelper.PrepareAttributesForInstances(attribs, defines);
                 MaterialHelper.PrepareAttributesForMorphTargets(attribs, mesh, defines);
                 MaterialHelper.PrepareAttributesForMorphTargets(attribs, mesh, defines);
-                
+
                 var shaderName = "default";
                 var shaderName = "default";
-                
+
                 var uniforms = ["world", "view", "viewProjection", "vEyePosition", "vLightsType", "vAmbientColor", "vDiffuseColor", "vSpecularColor", "vEmissiveColor",
                 var uniforms = ["world", "view", "viewProjection", "vEyePosition", "vLightsType", "vAmbientColor", "vDiffuseColor", "vSpecularColor", "vEmissiveColor",
                     "vFogInfos", "vFogColor", "pointSize",
                     "vFogInfos", "vFogColor", "pointSize",
                     "vDiffuseInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vEmissiveInfos", "vSpecularInfos", "vBumpInfos", "vLightmapInfos", "vRefractionInfos",
                     "vDiffuseInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vEmissiveInfos", "vSpecularInfos", "vBumpInfos", "vLightmapInfos", "vRefractionInfos",
@@ -858,10 +858,10 @@ module BABYLON {
                 ImageProcessingConfiguration.PrepareSamplers(samplers, defines);
                 ImageProcessingConfiguration.PrepareSamplers(samplers, defines);
 
 
                 MaterialHelper.PrepareUniformsAndSamplersList(<EffectCreationOptions>{
                 MaterialHelper.PrepareUniformsAndSamplersList(<EffectCreationOptions>{
-                    uniformsNames: uniforms, 
+                    uniformsNames: uniforms,
                     uniformBuffersNames: uniformBuffers,
                     uniformBuffersNames: uniformBuffers,
-                    samplers: samplers, 
-                    defines: defines, 
+                    samplers: samplers,
+                    defines: defines,
                     maxSimultaneousLights: this._maxSimultaneousLights
                     maxSimultaneousLights: this._maxSimultaneousLights
                 });
                 });
 
 
@@ -881,7 +881,7 @@ module BABYLON {
                     onError: this.onError,
                     onError: this.onError,
                     indexParameters: { maxSimultaneousLights: this._maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS }
                     indexParameters: { maxSimultaneousLights: this._maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS }
                 }, engine), defines);
                 }, engine), defines);
-                
+
                 this.buildUniformLayout();
                 this.buildUniformLayout();
             }
             }
 
 
@@ -967,13 +967,13 @@ module BABYLON {
             this.bindOnlyWorldMatrix(world);
             this.bindOnlyWorldMatrix(world);
 
 
             let mustRebind = this._mustRebind(scene, effect, mesh.visibility);
             let mustRebind = this._mustRebind(scene, effect, mesh.visibility);
-            
+
             // Bones
             // Bones
             MaterialHelper.BindBonesParameters(mesh, effect);
             MaterialHelper.BindBonesParameters(mesh, effect);
-            
+
             if (mustRebind) {
             if (mustRebind) {
                 this._uniformBuffer.bindToEffect(effect, "Material");
                 this._uniformBuffer.bindToEffect(effect, "Material");
-                
+
                 this.bindViewProjection(effect);
                 this.bindViewProjection(effect);
                 if (!this._uniformBuffer.useUbo || !this.isFrozen || !this._uniformBuffer.isSync) {
                 if (!this._uniformBuffer.useUbo || !this.isFrozen || !this._uniformBuffer.isSync) {
 
 
@@ -1062,7 +1062,7 @@ module BABYLON {
                                 }
                                 }
                             }
                             }
                             this._uniformBuffer.updateFloat4("vRefractionInfos", this._refractionTexture.level, this.indexOfRefraction, depth, this.invertRefractionY ? -1 : 1);
                             this._uniformBuffer.updateFloat4("vRefractionInfos", this._refractionTexture.level, this.indexOfRefraction, depth, this.invertRefractionY ? -1 : 1);
-                        }                    
+                        }
                     }
                     }
 
 
                     // Point size
                     // Point size
@@ -1078,7 +1078,7 @@ module BABYLON {
                     // Diffuse
                     // Diffuse
                     this._uniformBuffer.updateColor4("vDiffuseColor", this.diffuseColor, this.alpha * mesh.visibility);
                     this._uniformBuffer.updateColor4("vDiffuseColor", this.diffuseColor, this.alpha * mesh.visibility);
                 }
                 }
-                
+
                 // Textures     
                 // Textures     
                 if (scene.texturesEnabled) {
                 if (scene.texturesEnabled) {
                     if (this._diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
                     if (this._diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
@@ -1147,7 +1147,7 @@ module BABYLON {
                 if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE || this._reflectionTexture || this._refractionTexture) {
                 if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE || this._reflectionTexture || this._refractionTexture) {
                     this.bindView(effect);
                     this.bindView(effect);
                 }
                 }
-                
+
                 // Fog
                 // Fog
                 MaterialHelper.BindFogParameters(scene, mesh, effect);
                 MaterialHelper.BindFogParameters(scene, mesh, effect);
 
 
@@ -1264,38 +1264,38 @@ module BABYLON {
 
 
             if (this._ambientTexture === texture) {
             if (this._ambientTexture === texture) {
                 return true;
                 return true;
-            }     
+            }
 
 
             if (this._opacityTexture === texture) {
             if (this._opacityTexture === texture) {
                 return true;
                 return true;
-            }    
+            }
 
 
             if (this._reflectionTexture === texture) {
             if (this._reflectionTexture === texture) {
                 return true;
                 return true;
-            }  
+            }
 
 
             if (this._emissiveTexture === texture) {
             if (this._emissiveTexture === texture) {
                 return true;
                 return true;
-            }           
+            }
 
 
             if (this._specularTexture === texture) {
             if (this._specularTexture === texture) {
                 return true;
                 return true;
-            }                  
+            }
 
 
             if (this._bumpTexture === texture) {
             if (this._bumpTexture === texture) {
                 return true;
                 return true;
-            }                  
+            }
 
 
             if (this._lightmapTexture === texture) {
             if (this._lightmapTexture === texture) {
                 return true;
                 return true;
-            }                  
+            }
 
 
             if (this._refractionTexture === texture) {
             if (this._refractionTexture === texture) {
                 return true;
                 return true;
-            }                  
+            }
 
 
-            return false;    
-        }        
+            return false;
+        }
 
 
         public dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean): void {
         public dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean): void {
             if (forceDisposeTextures) {
             if (forceDisposeTextures) {
@@ -1413,8 +1413,8 @@ module BABYLON {
 
 
             StandardMaterial._ReflectionTextureEnabled = value;
             StandardMaterial._ReflectionTextureEnabled = value;
             Engine.MarkAllMaterialsAsDirty(Material.TextureDirtyFlag);
             Engine.MarkAllMaterialsAsDirty(Material.TextureDirtyFlag);
-        }        
-        
+        }
+
         static _EmissiveTextureEnabled = true;
         static _EmissiveTextureEnabled = true;
         public static get EmissiveTextureEnabled(): boolean {
         public static get EmissiveTextureEnabled(): boolean {
             return StandardMaterial._EmissiveTextureEnabled;
             return StandardMaterial._EmissiveTextureEnabled;
@@ -1426,7 +1426,7 @@ module BABYLON {
 
 
             StandardMaterial._EmissiveTextureEnabled = value;
             StandardMaterial._EmissiveTextureEnabled = value;
             Engine.MarkAllMaterialsAsDirty(Material.TextureDirtyFlag);
             Engine.MarkAllMaterialsAsDirty(Material.TextureDirtyFlag);
-        }       
+        }
 
 
         static _SpecularTextureEnabled = true;
         static _SpecularTextureEnabled = true;
         public static get SpecularTextureEnabled(): boolean {
         public static get SpecularTextureEnabled(): boolean {
@@ -1439,7 +1439,7 @@ module BABYLON {
 
 
             StandardMaterial._SpecularTextureEnabled = value;
             StandardMaterial._SpecularTextureEnabled = value;
             Engine.MarkAllMaterialsAsDirty(Material.TextureDirtyFlag);
             Engine.MarkAllMaterialsAsDirty(Material.TextureDirtyFlag);
-        }     
+        }
 
 
         static _BumpTextureEnabled = true;
         static _BumpTextureEnabled = true;
         public static get BumpTextureEnabled(): boolean {
         public static get BumpTextureEnabled(): boolean {
@@ -1452,7 +1452,7 @@ module BABYLON {
 
 
             StandardMaterial._BumpTextureEnabled = value;
             StandardMaterial._BumpTextureEnabled = value;
             Engine.MarkAllMaterialsAsDirty(Material.TextureDirtyFlag);
             Engine.MarkAllMaterialsAsDirty(Material.TextureDirtyFlag);
-        }         
+        }
 
 
         static _LightmapTextureEnabled = true;
         static _LightmapTextureEnabled = true;
         public static get LightmapTextureEnabled(): boolean {
         public static get LightmapTextureEnabled(): boolean {
@@ -1465,9 +1465,9 @@ module BABYLON {
 
 
             StandardMaterial._LightmapTextureEnabled = value;
             StandardMaterial._LightmapTextureEnabled = value;
             Engine.MarkAllMaterialsAsDirty(Material.TextureDirtyFlag);
             Engine.MarkAllMaterialsAsDirty(Material.TextureDirtyFlag);
-        }           
+        }
 
 
-        static _RefractionTextureEnabled = true;    
+        static _RefractionTextureEnabled = true;
         public static get RefractionTextureEnabled(): boolean {
         public static get RefractionTextureEnabled(): boolean {
             return StandardMaterial._RefractionTextureEnabled;
             return StandardMaterial._RefractionTextureEnabled;
         }
         }
@@ -1478,7 +1478,7 @@ module BABYLON {
 
 
             StandardMaterial._RefractionTextureEnabled = value;
             StandardMaterial._RefractionTextureEnabled = value;
             Engine.MarkAllMaterialsAsDirty(Material.TextureDirtyFlag);
             Engine.MarkAllMaterialsAsDirty(Material.TextureDirtyFlag);
-        }    
+        }
 
 
         static _ColorGradingTextureEnabled = true;
         static _ColorGradingTextureEnabled = true;
         public static get ColorGradingTextureEnabled(): boolean {
         public static get ColorGradingTextureEnabled(): boolean {
@@ -1491,7 +1491,7 @@ module BABYLON {
 
 
             StandardMaterial._ColorGradingTextureEnabled = value;
             StandardMaterial._ColorGradingTextureEnabled = value;
             Engine.MarkAllMaterialsAsDirty(Material.TextureDirtyFlag);
             Engine.MarkAllMaterialsAsDirty(Material.TextureDirtyFlag);
-        }           
+        }
 
 
         static _FresnelEnabled = true;
         static _FresnelEnabled = true;
         public static get FresnelEnabled(): boolean {
         public static get FresnelEnabled(): boolean {
@@ -1504,6 +1504,6 @@ module BABYLON {
 
 
             StandardMaterial._FresnelEnabled = value;
             StandardMaterial._FresnelEnabled = value;
             Engine.MarkAllMaterialsAsDirty(Material.FresnelDirtyFlag);
             Engine.MarkAllMaterialsAsDirty(Material.FresnelDirtyFlag);
-        }          
+        }
     }
     }
 } 
 } 

+ 8 - 8
src/Materials/babylon.uniformBuffer.ts

@@ -6,8 +6,8 @@ module BABYLON {
         private _data: number[];
         private _data: number[];
         private _bufferData: Float32Array;
         private _bufferData: Float32Array;
         private _dynamic?: boolean;
         private _dynamic?: boolean;
-        private _uniformLocations: { [key:string]:number; };
-        private _uniformSizes: { [key:string]:number; };
+        private _uniformLocations: { [key: string]: number; };
+        private _uniformSizes: { [key: string]: number; };
         private _uniformLocationPointer: number;
         private _uniformLocationPointer: number;
         private _needSync: boolean;
         private _needSync: boolean;
         private _noUBO: boolean;
         private _noUBO: boolean;
@@ -143,7 +143,7 @@ module BABYLON {
                 this.updateColor4 = this._updateColor4ForEffect;
                 this.updateColor4 = this._updateColor4ForEffect;
             } else {
             } else {
                 this._engine._uniformBuffers.push(this);
                 this._engine._uniformBuffers.push(this);
-                
+
                 this.updateMatrix3x3 = this._updateMatrix3x3ForUniform;
                 this.updateMatrix3x3 = this._updateMatrix3x3ForUniform;
                 this.updateMatrix2x2 = this._updateMatrix2x2ForUniform;
                 this.updateMatrix2x2 = this._updateMatrix2x2ForUniform;
                 this.updateFloat = this._updateFloatForUniform;
                 this.updateFloat = this._updateFloatForUniform;
@@ -167,7 +167,7 @@ module BABYLON {
         public get useUbo(): boolean {
         public get useUbo(): boolean {
             return !this._noUBO;
             return !this._noUBO;
         }
         }
-        
+
         /**
         /**
          * Indicates if the WebGL underlying uniform buffer is in sync
          * Indicates if the WebGL underlying uniform buffer is in sync
          * with the javascript cache data.
          * with the javascript cache data.
@@ -222,7 +222,7 @@ module BABYLON {
                 var diff = this._uniformLocationPointer - oldPointer;
                 var diff = this._uniformLocationPointer - oldPointer;
 
 
                 for (var i = 0; i < diff; i++) {
                 for (var i = 0; i < diff; i++) {
-                      this._data.push(0); 
+                    this._data.push(0);
                 }
                 }
             }
             }
         }
         }
@@ -375,7 +375,7 @@ module BABYLON {
 
 
             this._needSync = true;
             this._needSync = true;
         }
         }
-        
+
         public _rebuild(): void {
         public _rebuild(): void {
             if (this._noUBO) {
             if (this._noUBO) {
                 return;
                 return;
@@ -501,7 +501,7 @@ module BABYLON {
             UniformBuffer._tempBuffer[0] = x;
             UniformBuffer._tempBuffer[0] = x;
             UniformBuffer._tempBuffer[1] = y;
             UniformBuffer._tempBuffer[1] = y;
             this.updateUniform(name, UniformBuffer._tempBuffer, 2);
             this.updateUniform(name, UniformBuffer._tempBuffer, 2);
-        }        
+        }
 
 
         private _updateFloat3ForEffect(name: string, x: number, y: number, z: number, suffix = "") {
         private _updateFloat3ForEffect(name: string, x: number, y: number, z: number, suffix = "") {
             this._currentEffect.setFloat3(name + suffix, x, y, z);
             this._currentEffect.setFloat3(name + suffix, x, y, z);
@@ -603,7 +603,7 @@ module BABYLON {
             if (this._noUBO || !this._buffer) {
             if (this._noUBO || !this._buffer) {
                 return;
                 return;
             }
             }
-            
+
             effect.bindUniformBuffer(this._buffer, name);
             effect.bindUniformBuffer(this._buffer, name);
         }
         }
 
 

+ 27 - 21
src/Mesh/babylon.abstractMesh.ts

@@ -42,12 +42,12 @@
             Y: 1,
             Y: 1,
             Z: 1
             Z: 1
         };
         };
-      
+
         private _facetDepthSort: boolean = false;                           // is the facet depth sort to be computed
         private _facetDepthSort: boolean = false;                           // is the facet depth sort to be computed
         private _facetDepthSortEnabled: boolean = false;                    // is the facet depth sort initialized
         private _facetDepthSortEnabled: boolean = false;                    // is the facet depth sort initialized
         private _depthSortedIndices: IndicesArray;                          // copy of the indices array to store them once sorted
         private _depthSortedIndices: IndicesArray;                          // copy of the indices array to store them once sorted
-        private _depthSortedFacets: {ind: number, sqDistance: number}[];    // array of depth sorted facets
-        private _facetDepthSortFunction: (f1: {ind: number, sqDistance: number}, f2: {ind: number, sqDistance: number}) => number;  // facet depth sort function
+        private _depthSortedFacets: { ind: number, sqDistance: number }[];    // array of depth sorted facets
+        private _facetDepthSortFunction: (f1: { ind: number, sqDistance: number }, f2: { ind: number, sqDistance: number }) => number;  // facet depth sort function
         private _facetDepthSortFrom: Vector3;                               // location where to depth sort from
         private _facetDepthSortFrom: Vector3;                               // location where to depth sort from
         private _facetDepthSortOrigin: Vector3;                             // same as facetDepthSortFrom but expressed in the mesh local space
         private _facetDepthSortOrigin: Vector3;                             // same as facetDepthSortFrom but expressed in the mesh local space
         private _invertedMatrix: Matrix;                                    // Mesh inverted World Matrix
         private _invertedMatrix: Matrix;                                    // Mesh inverted World Matrix
@@ -1064,17 +1064,23 @@
             }
             }
         }
         }
 
 
+        /**
+         * Gets Collider object used to compute collisions (not physics)
+         */
+        public get collider(): Collider {
+            return this._collider;
+        }
+
         public moveWithCollisions(displacement: Vector3): AbstractMesh {
         public moveWithCollisions(displacement: Vector3): AbstractMesh {
             var globalPosition = this.getAbsolutePosition();
             var globalPosition = this.getAbsolutePosition();
 
 
-            globalPosition.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPositionForCollisions);
-            this._oldPositionForCollisions.addInPlace(this.ellipsoidOffset);
+            globalPosition.addToRef(this.ellipsoidOffset, this._oldPositionForCollisions);
 
 
             if (!this._collider) {
             if (!this._collider) {
                 this._collider = new Collider();
                 this._collider = new Collider();
             }
             }
 
 
-            this._collider.radius = this.ellipsoid;
+            this._collider._radius = this.ellipsoid;
 
 
             this.getScene().collisionCoordinator.getNewPosition(this._oldPositionForCollisions, displacement, this._collider, 3, this, this._onCollisionPositionChange, this.uniqueId);
             this.getScene().collisionCoordinator.getNewPosition(this._oldPositionForCollisions, displacement, this._collider, 3, this, this._onCollisionPositionChange, this.uniqueId);
             return this;
             return this;
@@ -1083,7 +1089,7 @@
         private _onCollisionPositionChange = (collisionId: number, newPosition: Vector3, collidedMesh: Nullable<AbstractMesh> = null) => {
         private _onCollisionPositionChange = (collisionId: number, newPosition: Vector3, collidedMesh: Nullable<AbstractMesh> = null) => {
             //TODO move this to the collision coordinator!
             //TODO move this to the collision coordinator!
             if (this.getScene().workerCollisions)
             if (this.getScene().workerCollisions)
-                newPosition.multiplyInPlace(this._collider.radius);
+                newPosition.multiplyInPlace(this._collider._radius);
 
 
             newPosition.subtractToRef(this._oldPositionForCollisions, this._diffPositionForCollisions);
             newPosition.subtractToRef(this._oldPositionForCollisions, this._diffPositionForCollisions);
 
 
@@ -1154,8 +1160,8 @@
 
 
             // Octrees
             // Octrees
             if (this._submeshesOctree && this.useOctreeForCollisions) {
             if (this._submeshesOctree && this.useOctreeForCollisions) {
-                var radius = collider.velocityWorldLength + Math.max(collider.radius.x, collider.radius.y, collider.radius.z);
-                var intersections = this._submeshesOctree.intersects(collider.basePointWorld, radius);
+                var radius = collider._velocityWorldLength + Math.max(collider._radius.x, collider._radius.y, collider._radius.z);
+                var intersections = this._submeshesOctree.intersects(collider._basePointWorld, radius);
 
 
                 len = intersections.length;
                 len = intersections.length;
                 subMeshes = intersections.data;
                 subMeshes = intersections.data;
@@ -1182,7 +1188,7 @@
                 return this;
                 return this;
 
 
             // Transformation matrix
             // Transformation matrix
-            Matrix.ScalingToRef(1.0 / collider.radius.x, 1.0 / collider.radius.y, 1.0 / collider.radius.z, this._collisionsScalingMatrix);
+            Matrix.ScalingToRef(1.0 / collider._radius.x, 1.0 / collider._radius.y, 1.0 / collider._radius.z, this._collisionsScalingMatrix);
             this.worldMatrixFromCache.multiplyToRef(this._collisionsScalingMatrix, this._collisionsTransformMatrix);
             this.worldMatrixFromCache.multiplyToRef(this._collisionsScalingMatrix, this._collisionsTransformMatrix);
             this._processCollisionsForSubMeshes(collider, this._collisionsTransformMatrix);
             this._processCollisionsForSubMeshes(collider, this._collisionsTransformMatrix);
             return this;
             return this;
@@ -1489,7 +1495,7 @@
                 }
                 }
                 else if (indices instanceof Uint32Array) {
                 else if (indices instanceof Uint32Array) {
                     this._depthSortedIndices = new Uint32Array(indices!);
                     this._depthSortedIndices = new Uint32Array(indices!);
-                } 
+                }
                 else {
                 else {
                     var needs32bits = false;
                     var needs32bits = false;
                     for (var i = 0; i < indices!.length; i++) {
                     for (var i = 0; i < indices!.length; i++) {
@@ -1500,12 +1506,12 @@
                     }
                     }
                     if (needs32bits) {
                     if (needs32bits) {
                         this._depthSortedIndices = new Uint32Array(indices!);
                         this._depthSortedIndices = new Uint32Array(indices!);
-                    } 
+                    }
                     else {
                     else {
                         this._depthSortedIndices = new Uint16Array(indices!);
                         this._depthSortedIndices = new Uint16Array(indices!);
                     }
                     }
-                }               
-                this._facetDepthSortFunction = function(f1, f2) {
+                }
+                this._facetDepthSortFunction = function (f1, f2) {
                     return (f2.sqDistance - f1.sqDistance);
                     return (f2.sqDistance - f1.sqDistance);
                 };
                 };
                 if (!this._facetDepthSortFrom) {
                 if (!this._facetDepthSortFrom) {
@@ -1553,7 +1559,7 @@
 
 
             if (this._facetDepthSort && this._facetDepthSortEnabled) {
             if (this._facetDepthSort && this._facetDepthSortEnabled) {
                 this._depthSortedFacets.sort(this._facetDepthSortFunction);
                 this._depthSortedFacets.sort(this._facetDepthSortFunction);
-                var l = (this._depthSortedIndices.length / 3)|0;
+                var l = (this._depthSortedIndices.length / 3) | 0;
                 for (var f = 0; f < l; f++) {
                 for (var f = 0; f < l; f++) {
                     var sind = this._depthSortedFacets[f].ind;
                     var sind = this._depthSortedFacets[f].ind;
                     this._depthSortedIndices[f * 3] = indices![sind];
                     this._depthSortedIndices[f * 3] = indices![sind];
@@ -1782,19 +1788,19 @@
          * Align the mesh with a normal.
          * Align the mesh with a normal.
          * Returns the mesh.  
          * Returns the mesh.  
          */
          */
-        public alignWithNormal(normal:BABYLON.Vector3, upDirection?:BABYLON.Vector3):AbstractMesh{       
-            if(!upDirection){
+        public alignWithNormal(normal: BABYLON.Vector3, upDirection?: BABYLON.Vector3): AbstractMesh {
+            if (!upDirection) {
                 upDirection = BABYLON.Axis.Y;
                 upDirection = BABYLON.Axis.Y;
             }
             }
-            
+
             var axisX = Tmp.Vector3[0];
             var axisX = Tmp.Vector3[0];
             var axisZ = Tmp.Vector3[1];
             var axisZ = Tmp.Vector3[1];
             Vector3.CrossToRef(upDirection, normal, axisZ);
             Vector3.CrossToRef(upDirection, normal, axisZ);
             Vector3.CrossToRef(normal, axisZ, axisX);
             Vector3.CrossToRef(normal, axisZ, axisX);
-            
-            if(this.rotationQuaternion){
+
+            if (this.rotationQuaternion) {
                 Quaternion.RotationQuaternionFromAxisToRef(axisX, normal, axisZ, this.rotationQuaternion);
                 Quaternion.RotationQuaternionFromAxisToRef(axisX, normal, axisZ, this.rotationQuaternion);
-            }else{
+            } else {
                 Vector3.RotationFromAxisToRef(axisX, normal, axisZ, this.rotation);
                 Vector3.RotationFromAxisToRef(axisX, normal, axisZ, this.rotation);
             }
             }
             return this;
             return this;

+ 13 - 15
src/Mesh/babylon.geometry.ts

@@ -48,7 +48,7 @@
 
 
         public static CreateGeometryForMesh(mesh: Mesh): Geometry {
         public static CreateGeometryForMesh(mesh: Mesh): Geometry {
             let geometry = new Geometry(Geometry.RandomId(), mesh.getScene());
             let geometry = new Geometry(Geometry.RandomId(), mesh.getScene());
-            
+
             geometry.applyToMesh(mesh);
             geometry.applyToMesh(mesh);
 
 
             return geometry;
             return geometry;
@@ -80,7 +80,7 @@
             // applyToMesh
             // applyToMesh
             if (mesh) {
             if (mesh) {
                 if (mesh.getClassName() === "LinesMesh") {
                 if (mesh.getClassName() === "LinesMesh") {
-                    this.boundingBias = new Vector2(0, (<LinesMesh> mesh).intersectionThreshold);
+                    this.boundingBias = new Vector2(0, (<LinesMesh>mesh).intersectionThreshold);
                     this.updateExtend();
                     this.updateExtend();
                 }
                 }
 
 
@@ -307,7 +307,7 @@
          * - BABYLON.VertexBuffer.MatricesIndicesExtraKind
          * - BABYLON.VertexBuffer.MatricesIndicesExtraKind
          * - BABYLON.VertexBuffer.MatricesWeightsKind
          * - BABYLON.VertexBuffer.MatricesWeightsKind
          * - BABYLON.VertexBuffer.MatricesWeightsExtraKind
          * - BABYLON.VertexBuffer.MatricesWeightsExtraKind
-         */        
+         */
         public isVertexBufferUpdatable(kind: string): boolean {
         public isVertexBufferUpdatable(kind: string): boolean {
             let vb = this._vertexBuffers[kind];
             let vb = this._vertexBuffers[kind];
 
 
@@ -482,7 +482,7 @@
             }
             }
         }
         }
 
 
-        private updateExtend(data: Nullable<FloatArray> = null, stride? : number) {
+        private updateExtend(data: Nullable<FloatArray> = null, stride?: number) {
             if (!data) {
             if (!data) {
                 data = <FloatArray>this._vertexBuffers[VertexBuffer.PositionKind].getData();
                 data = <FloatArray>this._vertexBuffers[VertexBuffer.PositionKind].getData();
             }
             }
@@ -617,13 +617,11 @@
         }
         }
 
 
         // Cache
         // Cache
-        public _resetPointsArrayCache(): void
-        {
+        public _resetPointsArrayCache(): void {
             this._positions = null;
             this._positions = null;
         }
         }
 
 
-        public _generatePointsArray(): boolean
-        {
+        public _generatePointsArray(): boolean {
             if (this._positions)
             if (this._positions)
                 return true;
                 return true;
 
 
@@ -753,7 +751,7 @@
             return serializationObject;
             return serializationObject;
         }
         }
 
 
-        private toNumberArray(origin: Nullable<Float32Array | IndicesArray>) : number[] {
+        private toNumberArray(origin: Nullable<Float32Array | IndicesArray>): number[] {
             if (Array.isArray(origin)) {
             if (Array.isArray(origin)) {
                 return origin;
                 return origin;
             } else {
             } else {
@@ -933,7 +931,7 @@
                 }
                 }
 
 
                 if (binaryInfo.matricesWeightsAttrDesc && binaryInfo.matricesWeightsAttrDesc.count > 0) {
                 if (binaryInfo.matricesWeightsAttrDesc && binaryInfo.matricesWeightsAttrDesc.count > 0) {
-                    var matricesWeightsData = new Float32Array(parsedGeometry, binaryInfo.matricesWeightsAttrDesc.offset, binaryInfo.matricesWeightsAttrDesc.count);                    
+                    var matricesWeightsData = new Float32Array(parsedGeometry, binaryInfo.matricesWeightsAttrDesc.offset, binaryInfo.matricesWeightsAttrDesc.count);
                     mesh.setVerticesData(VertexBuffer.MatricesWeightsKind, matricesWeightsData, false);
                     mesh.setVerticesData(VertexBuffer.MatricesWeightsKind, matricesWeightsData, false);
                 }
                 }
 
 
@@ -1034,7 +1032,7 @@
                     mesh.setVerticesData(VertexBuffer.MatricesWeightsKind, parsedGeometry.matricesWeights, parsedGeometry.matricesWeights._updatable);
                     mesh.setVerticesData(VertexBuffer.MatricesWeightsKind, parsedGeometry.matricesWeights, parsedGeometry.matricesWeights._updatable);
                 }
                 }
 
 
-                if (parsedGeometry.matricesWeightsExtra) {       
+                if (parsedGeometry.matricesWeightsExtra) {
                     mesh.setVerticesData(VertexBuffer.MatricesWeightsExtraKind, parsedGeometry.matricesWeightsExtra, parsedGeometry.matricesWeights._updatable);
                     mesh.setVerticesData(VertexBuffer.MatricesWeightsExtraKind, parsedGeometry.matricesWeightsExtra, parsedGeometry.matricesWeights._updatable);
                 }
                 }
 
 
@@ -1066,7 +1064,7 @@
             }
             }
         }
         }
 
 
-        private static _CleanMatricesWeights(parsedGeometry:any, mesh:Mesh): void {
+        private static _CleanMatricesWeights(parsedGeometry: any, mesh: Mesh): void {
             const epsilon: number = 1e-3;
             const epsilon: number = 1e-3;
             if (!SceneLoader.CleanBoneMatrixWeights) {
             if (!SceneLoader.CleanBoneMatrixWeights) {
                 return;
                 return;
@@ -1108,7 +1106,7 @@
                         }
                         }
                     }
                     }
                 }
                 }
-                if (firstZeroWeight < 0  || firstZeroWeight > (influencers - 1)) {
+                if (firstZeroWeight < 0 || firstZeroWeight > (influencers - 1)) {
                     firstZeroWeight = influencers - 1;
                     firstZeroWeight = influencers - 1;
                 }
                 }
                 if (weight > epsilon) {
                 if (weight > epsilon) {
@@ -1119,7 +1117,7 @@
                     if (matricesWeightsExtra) {
                     if (matricesWeightsExtra) {
                         for (var j = 0; j < 4; j++) {
                         for (var j = 0; j < 4; j++) {
                             matricesWeightsExtra[i + j] *= mweight;
                             matricesWeightsExtra[i + j] *= mweight;
-                        }    
+                        }
                     }
                     }
                 } else {
                 } else {
                     if (firstZeroWeight >= 4) {
                     if (firstZeroWeight >= 4) {
@@ -1133,7 +1131,7 @@
             }
             }
 
 
             mesh.setVerticesData(VertexBuffer.MatricesIndicesKind, matricesIndices);
             mesh.setVerticesData(VertexBuffer.MatricesIndicesKind, matricesIndices);
-            if (parsedGeometry.matricesWeightsExtra) {       
+            if (parsedGeometry.matricesWeightsExtra) {
                 mesh.setVerticesData(VertexBuffer.MatricesIndicesExtraKind, matricesIndicesExtra);
                 mesh.setVerticesData(VertexBuffer.MatricesIndicesExtraKind, matricesIndicesExtra);
             }
             }
         }
         }

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

@@ -1439,13 +1439,13 @@
             else if (this.delayLoadState === Engine.DELAYLOADSTATE_NOTLOADED) {
             else if (this.delayLoadState === Engine.DELAYLOADSTATE_NOTLOADED) {
                 this.delayLoadState = Engine.DELAYLOADSTATE_LOADING;
                 this.delayLoadState = Engine.DELAYLOADSTATE_LOADING;
 
 
-                this._queueLoad(this, scene);
+                this._queueLoad(scene);
             }
             }
             return this;
             return this;
         }
         }
 
 
-        private _queueLoad(mesh: Mesh, scene: Scene): Mesh {
-            scene._addPendingData(mesh);
+        private _queueLoad(scene: Scene): Mesh {
+            scene._addPendingData(this);
 
 
             var getBinaryData = (this.delayLoadingFile.indexOf(".babylonbinarymeshdata") !== -1);
             var getBinaryData = (this.delayLoadingFile.indexOf(".babylonbinarymeshdata") !== -1);
 
 
@@ -1582,7 +1582,7 @@
          * Modifies the mesh geometry according to its own current World Matrix.  
          * Modifies the mesh geometry according to its own current World Matrix.  
          * The mesh World Matrix is then reset.
          * The mesh World Matrix is then reset.
          * This method returns nothing but really modifies the mesh even if it's originally not set as updatable.
          * This method returns nothing but really modifies the mesh even if it's originally not set as updatable.
-         * tuto : tuto : http://doc.babylonjs.com/tutorials/How_Rotations_and_Translations_Work#baking-transform 
+         * tuto : tuto : http://doc.babylonjs.com/resources/baking_transformations
          * Note that, under the hood, this method sets a new VertexBuffer each call.   
          * Note that, under the hood, this method sets a new VertexBuffer each call.   
          * Returns the Mesh.  
          * Returns the Mesh.  
          */
          */

+ 1 - 1
src/Mesh/babylon.transformNode.ts

@@ -948,7 +948,7 @@ module BABYLON {
             // Remove from scene
             // Remove from scene
             this.getScene().removeTransformNode(this);
             this.getScene().removeTransformNode(this);
 
 
-            this._cache = null;
+            this._cache = {};
 
 
             if (!doNotRecurse) {
             if (!doNotRecurse) {
                 // Children
                 // Children

+ 44 - 0
src/Physics/Plugins/babylon.cannonJSPlugin.ts

@@ -18,6 +18,9 @@
                 Tools.Error("CannonJS is not available. Please make sure you included the js file.");
                 Tools.Error("CannonJS is not available. Please make sure you included the js file.");
                 return;
                 return;
             }
             }
+
+            this._extendNamespace();
+
             this.world = new this.BJSCANNON.World();
             this.world = new this.BJSCANNON.World();
             this.world.broadphase = new this.BJSCANNON.NaiveBroadphase();
             this.world.broadphase = new this.BJSCANNON.NaiveBroadphase();
             this.world.solver.iterations = iterations;
             this.world.solver.iterations = iterations;
@@ -590,5 +593,46 @@
         public dispose() {
         public dispose() {
 
 
         }
         }
+
+        private _extendNamespace() {
+
+            //this will force cannon to execute at least one step when using interpolation
+            let step_tmp1 = new this.BJSCANNON.Vec3();
+            let Engine = this.BJSCANNON;
+            this.BJSCANNON.World.prototype.step = function (dt: number, timeSinceLastCalled: number, maxSubSteps: number) {
+                maxSubSteps = maxSubSteps || 10;
+                timeSinceLastCalled = timeSinceLastCalled || 0;
+                if (timeSinceLastCalled === 0) {
+                    this.internalStep(dt);
+                    this.time += dt;
+                } else {
+                    var internalSteps = Math.floor((this.time + timeSinceLastCalled) / dt) - Math.floor(this.time / dt);
+                    internalSteps = Math.min(internalSteps, maxSubSteps) || 1;
+                    var t0 = performance.now();
+                    for (var i = 0; i !== internalSteps; i++) {
+                        this.internalStep(dt);
+                        if (performance.now() - t0 > dt * 1000) {
+                            break;
+                        }
+                    }
+                    this.time += timeSinceLastCalled;
+                    var h = this.time % dt;
+                    var h_div_dt = h / dt;
+                    var interpvelo = step_tmp1;
+                    var bodies = this.bodies;
+                    for (var j = 0; j !== bodies.length; j++) {
+                        var b = bodies[j];
+                        if (b.type !== Engine.Body.STATIC && b.sleepState !== Engine.Body.SLEEPING) {
+                            b.position.vsub(b.previousPosition, interpvelo);
+                            interpvelo.scale(h_div_dt, interpvelo);
+                            b.position.vadd(interpvelo, b.interpolatedPosition);
+                        } else {
+                            b.interpolatedPosition.copy(b.position);
+                            b.interpolatedQuaternion.copy(b.quaternion);
+                        }
+                    }
+                }
+            };
+        }
     }
     }
 }
 }

+ 4 - 1
src/babylon.node.ts

@@ -119,7 +119,10 @@
                 // We defer the attach when the scene will be loaded
                 // We defer the attach when the scene will be loaded
                 var observer = this._scene.onDataLoadedObservable.add(() => {
                 var observer = this._scene.onDataLoadedObservable.add(() => {
                     behavior.attach(this);
                     behavior.attach(this);
-                    this._scene.onDataLoadedObservable.remove(observer);
+                    setTimeout(() => {
+                        // Need to use a timeout to avoid removing an observer while iterating the list of observers
+                        this._scene.onDataLoadedObservable.remove(observer);
+                    }, 0);
                 });
                 });
             } else {
             } else {
                 behavior.attach(this);
                 behavior.attach(this);

+ 6 - 2
src/tsconfig.json

@@ -6,10 +6,14 @@
     "target": "es5",
     "target": "es5",
     "sourceMap": true,
     "sourceMap": true,
     "noImplicitAny": true,
     "noImplicitAny": true,
-    "lib": ["dom", "es2015.promise", "es5"],
+    "lib": [
+      "dom",
+      "es2015.promise",
+      "es5"
+    ],
     "noImplicitReturns": true,
     "noImplicitReturns": true,
     "noImplicitThis": true,
     "noImplicitThis": true,
-    "noUnusedLocals": true,    
+    "noUnusedLocals": true,
     "strictNullChecks": true,
     "strictNullChecks": true,
     "strictFunctionTypes": true
     "strictFunctionTypes": true
   }
   }

二进制
tests/validation/ReferenceImages/charting.png


+ 1 - 1
tests/validation/config.json

@@ -76,7 +76,7 @@
     },
     },
     {
     {
       "title": "Charting",
       "title": "Charting",
-      "renderCount": 3,
+      "renderCount": 20,
       "scriptToRun": "/Demos/Charting/charting.js",
       "scriptToRun": "/Demos/Charting/charting.js",
       "functionToCall": "CreateChartingTestScene",
       "functionToCall": "CreateChartingTestScene",
       "referenceImage": "charting.png"
       "referenceImage": "charting.png"