فهرست منبع

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. BIN
      Playground/scenes/BoomBox.glb
  4. BIN
      Playground/scenes/BoomBox/BoomBox.bin
  5. 173 0
      Playground/scenes/BoomBox/BoomBox.gltf
  6. BIN
      Playground/scenes/BoomBox/BoomBox_baseColor.png
  7. BIN
      Playground/scenes/BoomBox/BoomBox_emissive.png
  8. BIN
      Playground/scenes/BoomBox/BoomBox_normal.png
  9. BIN
      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. BIN
      tests/validation/ReferenceImages/charting.png
  56. 1 1
      tests/validation/config.json

+ 8 - 0
.vscode/launch.json

@@ -136,6 +136,14 @@
             "runtimeArgs": [
                 "--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


BIN
Playground/scenes/BoomBox.glb


BIN
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
+    }
+  ]
+}

BIN
Playground/scenes/BoomBox/BoomBox_baseColor.png


BIN
Playground/scenes/BoomBox/BoomBox_emissive.png


BIN
Playground/scenes/BoomBox/BoomBox_normal.png


BIN
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++;
                                 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
                             if (Math.abs(absoluteCursorPosition - currentSize) > previousDist) {
                                 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;
         wrapS?: ETextureWrapMode;
         wrapT?: ETextureWrapMode;
+        index: number;
+        noMipMaps: boolean;
+        samplingMode: number;
+        wrapU: number;
+        wrapV: number;
     }
     interface IGLTFScene extends IGLTFChildRootProperty {
         nodes: number[];
@@ -359,6 +364,7 @@ declare module BABYLON.GLTF2 {
         private _parent;
         private _rootUrl;
         private _defaultMaterial;
+        private _defaultSampler;
         private _rootNode;
         private _successCallback;
         private _progressCallback;
@@ -438,14 +444,15 @@ declare module BABYLON.GLTF2 {
         _loadMaterialBaseProperties(context: string, material: IGLTFMaterial): void;
         _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
         _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture;
+        private _loadSampler(context, sampler);
         private _loadImageAsync(context, image, onSuccess);
         _loadUriAsync(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
         _tryCatchOnError(handler: () => void): void;
         private static _AssignIndices(array?);
         static _GetProperty<T extends IGLTFProperty>(array?: ArrayLike<T>, index?: number): Nullable<T>;
-        private static _GetTextureWrapMode(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 _compileMaterialsAsync(onSuccess);
         private _compileShadowGeneratorsAsync(onSuccess);

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

@@ -367,6 +367,7 @@ var BABYLON;
         var GLTFLoader = /** @class */ (function () {
             function GLTFLoader(parent) {
                 this._disposed = false;
+                this._defaultSampler = {};
                 this._renderReady = false;
                 this._requests = new Array();
                 this._renderReadyObservable = new BABYLON.Observable();
@@ -499,6 +500,7 @@ var BABYLON;
                 GLTFLoader._AssignIndices(this._gltf.materials);
                 GLTFLoader._AssignIndices(this._gltf.meshes);
                 GLTFLoader._AssignIndices(this._gltf.nodes);
+                GLTFLoader._AssignIndices(this._gltf.samplers);
                 GLTFLoader._AssignIndices(this._gltf.scenes);
                 GLTFLoader._AssignIndices(this._gltf.skins);
                 GLTFLoader._AssignIndices(this._gltf.textures);
@@ -506,7 +508,7 @@ var BABYLON;
                     var buffers = this._gltf.buffers;
                     if (buffers && buffers[0] && !buffers[0].uri) {
                         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 + ")");
                         }
                         binaryBuffer.loadedData = data.bin;
@@ -818,7 +820,7 @@ var BABYLON;
              * @param {IGLTFAccessor} 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) {
                     return data;
                 }
@@ -913,7 +915,7 @@ var BABYLON;
                                 break;
                             }
                             default: {
-                                BABYLON.Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                                BABYLON.Tools.Warn(context + ": Ignoring unrecognized attribute '" + attribute + "'");
                                 break;
                             }
                         }
@@ -1049,7 +1051,7 @@ var BABYLON;
                                 break;
                             }
                             default: {
-                                BABYLON.Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                                BABYLON.Tools.Warn(context + ": Ignoring unrecognized attribute '" + attribute + "'");
                                 break;
                             }
                         }
@@ -1411,13 +1413,13 @@ var BABYLON;
                     throw new Error(context + ": Failed to find buffer view " + accessor.bufferView);
                 }
                 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 byteOffset = accessor.byteOffset || 0;
                     var byteStride = bufferView.byteStride;
+                    if (byteStride === 0) {
+                        BABYLON.Tools.Warn(context + ": Byte stride of 0 is not valid");
+                    }
                     try {
                         switch (accessor.componentType) {
                             case GLTF2.EComponentType.BYTE: {
@@ -1458,7 +1460,7 @@ var BABYLON;
             GLTFLoader.prototype._buildArrayBuffer = function (typedArray, data, byteOffset, count, numComponents, byteStride) {
                 byteOffset += data.byteOffset;
                 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);
                 }
                 var elementStride = byteStride / typedArray.BYTES_PER_ELEMENT;
@@ -1667,14 +1669,13 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadTexture = function (context, texture, coordinatesIndex) {
                 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) {
                     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);
-                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._removePendingData(texture);
                     });
@@ -1707,14 +1708,23 @@ var BABYLON;
                     });
                 }
                 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;
                 if (this._parent.onTextureLoaded) {
                     this._parent.onTextureLoaded(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) {
                 if (image.uri) {
                     this._loadUriAsync(context, image.uri, onSuccess);
@@ -1787,7 +1797,7 @@ var BABYLON;
                 }
                 return array[index];
             };
-            GLTFLoader._GetTextureWrapMode = function (mode) {
+            GLTFLoader._GetTextureWrapMode = function (context, mode) {
                 // Set defaults if undefined
                 mode = mode == undefined ? GLTF2.ETextureWrapMode.REPEAT : mode;
                 switch (mode) {
@@ -1795,11 +1805,11 @@ var BABYLON;
                     case GLTF2.ETextureWrapMode.MIRRORED_REPEAT: return BABYLON.Texture.MIRROR_ADDRESSMODE;
                     case GLTF2.ETextureWrapMode.REPEAT: return BABYLON.Texture.WRAP_ADDRESSMODE;
                     default:
-                        BABYLON.Tools.Warn("Invalid texture wrap mode (" + mode + ")");
+                        BABYLON.Tools.Warn(context + ": Invalid texture wrap mode " + mode);
                         return BABYLON.Texture.WRAP_ADDRESSMODE;
                 }
             };
-            GLTFLoader._GetTextureSamplingMode = function (magFilter, minFilter) {
+            GLTFLoader._GetTextureSamplingMode = function (context, magFilter, minFilter) {
                 // Set defaults if undefined
                 magFilter = magFilter == undefined ? GLTF2.ETextureMagFilter.LINEAR : magFilter;
                 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.LINEAR_MIPMAP_LINEAR: return BABYLON.Texture.LINEAR_LINEAR_MIPLINEAR;
                         default:
-                            BABYLON.Tools.Warn("Invalid texture minification filter (" + minFilter + ")");
+                            BABYLON.Tools.Warn(context + ": Invalid texture minification filter " + minFilter);
                             return BABYLON.Texture.LINEAR_LINEAR_MIPLINEAR;
                     }
                 }
                 else {
                     if (magFilter !== GLTF2.ETextureMagFilter.NEAREST) {
-                        BABYLON.Tools.Warn("Invalid texture magnification filter (" + magFilter + ")");
+                        BABYLON.Tools.Warn(context + ": Invalid texture magnification filter " + magFilter);
                     }
                     switch (minFilter) {
                         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.LINEAR_MIPMAP_LINEAR: return BABYLON.Texture.NEAREST_LINEAR_MIPLINEAR;
                         default:
-                            BABYLON.Tools.Warn("Invalid texture minification filter (" + minFilter + ")");
+                            BABYLON.Tools.Warn(context + ": Invalid texture minification filter " + minFilter);
                             return BABYLON.Texture.NEAREST_NEAREST_MIPNEAREST;
                     }
                 }
             };
-            GLTFLoader._GetNumComponents = function (type) {
+            GLTFLoader._GetNumComponents = function (context, type) {
                 switch (type) {
                     case "SCALAR": return 1;
                     case "VEC2": return 2;
@@ -1843,7 +1853,7 @@ var BABYLON;
                     case "MAT3": return 9;
                     case "MAT4": return 16;
                 }
-                return 0;
+                throw new Error(context + ": Invalid type " + type);
             };
             GLTFLoader.prototype._compileMaterialAsync = function (babylonMaterial, babylonMesh, onSuccess) {
                 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;
         wrapS?: ETextureWrapMode;
         wrapT?: ETextureWrapMode;
+        index: number;
+        noMipMaps: boolean;
+        samplingMode: number;
+        wrapU: number;
+        wrapV: number;
     }
     interface IGLTFScene extends IGLTFChildRootProperty {
         nodes: number[];
@@ -906,6 +911,7 @@ declare module BABYLON.GLTF2 {
         private _parent;
         private _rootUrl;
         private _defaultMaterial;
+        private _defaultSampler;
         private _rootNode;
         private _successCallback;
         private _progressCallback;
@@ -985,14 +991,15 @@ declare module BABYLON.GLTF2 {
         _loadMaterialBaseProperties(context: string, material: IGLTFMaterial): void;
         _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
         _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture;
+        private _loadSampler(context, sampler);
         private _loadImageAsync(context, image, onSuccess);
         _loadUriAsync(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
         _tryCatchOnError(handler: () => void): void;
         private static _AssignIndices(array?);
         static _GetProperty<T extends IGLTFProperty>(array?: ArrayLike<T>, index?: number): Nullable<T>;
-        private static _GetTextureWrapMode(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 _compileMaterialsAsync(onSuccess);
         private _compileShadowGeneratorsAsync(onSuccess);

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

@@ -2523,6 +2523,7 @@ var BABYLON;
         var GLTFLoader = /** @class */ (function () {
             function GLTFLoader(parent) {
                 this._disposed = false;
+                this._defaultSampler = {};
                 this._renderReady = false;
                 this._requests = new Array();
                 this._renderReadyObservable = new BABYLON.Observable();
@@ -2655,6 +2656,7 @@ var BABYLON;
                 GLTFLoader._AssignIndices(this._gltf.materials);
                 GLTFLoader._AssignIndices(this._gltf.meshes);
                 GLTFLoader._AssignIndices(this._gltf.nodes);
+                GLTFLoader._AssignIndices(this._gltf.samplers);
                 GLTFLoader._AssignIndices(this._gltf.scenes);
                 GLTFLoader._AssignIndices(this._gltf.skins);
                 GLTFLoader._AssignIndices(this._gltf.textures);
@@ -2662,7 +2664,7 @@ var BABYLON;
                     var buffers = this._gltf.buffers;
                     if (buffers && buffers[0] && !buffers[0].uri) {
                         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 + ")");
                         }
                         binaryBuffer.loadedData = data.bin;
@@ -2974,7 +2976,7 @@ var BABYLON;
              * @param {IGLTFAccessor} 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) {
                     return data;
                 }
@@ -3069,7 +3071,7 @@ var BABYLON;
                                 break;
                             }
                             default: {
-                                BABYLON.Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                                BABYLON.Tools.Warn(context + ": Ignoring unrecognized attribute '" + attribute + "'");
                                 break;
                             }
                         }
@@ -3205,7 +3207,7 @@ var BABYLON;
                                 break;
                             }
                             default: {
-                                BABYLON.Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                                BABYLON.Tools.Warn(context + ": Ignoring unrecognized attribute '" + attribute + "'");
                                 break;
                             }
                         }
@@ -3567,13 +3569,13 @@ var BABYLON;
                     throw new Error(context + ": Failed to find buffer view " + accessor.bufferView);
                 }
                 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 byteOffset = accessor.byteOffset || 0;
                     var byteStride = bufferView.byteStride;
+                    if (byteStride === 0) {
+                        BABYLON.Tools.Warn(context + ": Byte stride of 0 is not valid");
+                    }
                     try {
                         switch (accessor.componentType) {
                             case GLTF2.EComponentType.BYTE: {
@@ -3614,7 +3616,7 @@ var BABYLON;
             GLTFLoader.prototype._buildArrayBuffer = function (typedArray, data, byteOffset, count, numComponents, byteStride) {
                 byteOffset += data.byteOffset;
                 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);
                 }
                 var elementStride = byteStride / typedArray.BYTES_PER_ELEMENT;
@@ -3823,14 +3825,13 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadTexture = function (context, texture, coordinatesIndex) {
                 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) {
                     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);
-                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._removePendingData(texture);
                     });
@@ -3863,14 +3864,23 @@ var BABYLON;
                     });
                 }
                 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;
                 if (this._parent.onTextureLoaded) {
                     this._parent.onTextureLoaded(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) {
                 if (image.uri) {
                     this._loadUriAsync(context, image.uri, onSuccess);
@@ -3943,7 +3953,7 @@ var BABYLON;
                 }
                 return array[index];
             };
-            GLTFLoader._GetTextureWrapMode = function (mode) {
+            GLTFLoader._GetTextureWrapMode = function (context, mode) {
                 // Set defaults if undefined
                 mode = mode == undefined ? GLTF2.ETextureWrapMode.REPEAT : mode;
                 switch (mode) {
@@ -3951,11 +3961,11 @@ var BABYLON;
                     case GLTF2.ETextureWrapMode.MIRRORED_REPEAT: return BABYLON.Texture.MIRROR_ADDRESSMODE;
                     case GLTF2.ETextureWrapMode.REPEAT: return BABYLON.Texture.WRAP_ADDRESSMODE;
                     default:
-                        BABYLON.Tools.Warn("Invalid texture wrap mode (" + mode + ")");
+                        BABYLON.Tools.Warn(context + ": Invalid texture wrap mode " + mode);
                         return BABYLON.Texture.WRAP_ADDRESSMODE;
                 }
             };
-            GLTFLoader._GetTextureSamplingMode = function (magFilter, minFilter) {
+            GLTFLoader._GetTextureSamplingMode = function (context, magFilter, minFilter) {
                 // Set defaults if undefined
                 magFilter = magFilter == undefined ? GLTF2.ETextureMagFilter.LINEAR : magFilter;
                 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.LINEAR_MIPMAP_LINEAR: return BABYLON.Texture.LINEAR_LINEAR_MIPLINEAR;
                         default:
-                            BABYLON.Tools.Warn("Invalid texture minification filter (" + minFilter + ")");
+                            BABYLON.Tools.Warn(context + ": Invalid texture minification filter " + minFilter);
                             return BABYLON.Texture.LINEAR_LINEAR_MIPLINEAR;
                     }
                 }
                 else {
                     if (magFilter !== GLTF2.ETextureMagFilter.NEAREST) {
-                        BABYLON.Tools.Warn("Invalid texture magnification filter (" + magFilter + ")");
+                        BABYLON.Tools.Warn(context + ": Invalid texture magnification filter " + magFilter);
                     }
                     switch (minFilter) {
                         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.LINEAR_MIPMAP_LINEAR: return BABYLON.Texture.NEAREST_LINEAR_MIPLINEAR;
                         default:
-                            BABYLON.Tools.Warn("Invalid texture minification filter (" + minFilter + ")");
+                            BABYLON.Tools.Warn(context + ": Invalid texture minification filter " + minFilter);
                             return BABYLON.Texture.NEAREST_NEAREST_MIPNEAREST;
                     }
                 }
             };
-            GLTFLoader._GetNumComponents = function (type) {
+            GLTFLoader._GetNumComponents = function (context, type) {
                 switch (type) {
                     case "SCALAR": return 1;
                     case "VEC2": return 2;
@@ -3999,7 +4009,7 @@ var BABYLON;
                     case "MAT3": return 9;
                     case "MAT4": return 16;
                 }
-                return 0;
+                throw new Error(context + ": Invalid type " + type);
             };
             GLTFLoader.prototype._compileMaterialAsync = function (babylonMaterial, babylonMesh, onSuccess) {
                 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 () {
             function GLTFLoader(parent) {
                 this._disposed = false;
+                this._defaultSampler = {};
                 this._renderReady = false;
                 this._requests = new Array();
                 this._renderReadyObservable = new BABYLON.Observable();
@@ -3611,6 +3612,7 @@ var BABYLON;
                 GLTFLoader._AssignIndices(this._gltf.materials);
                 GLTFLoader._AssignIndices(this._gltf.meshes);
                 GLTFLoader._AssignIndices(this._gltf.nodes);
+                GLTFLoader._AssignIndices(this._gltf.samplers);
                 GLTFLoader._AssignIndices(this._gltf.scenes);
                 GLTFLoader._AssignIndices(this._gltf.skins);
                 GLTFLoader._AssignIndices(this._gltf.textures);
@@ -3618,7 +3620,7 @@ var BABYLON;
                     var buffers = this._gltf.buffers;
                     if (buffers && buffers[0] && !buffers[0].uri) {
                         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 + ")");
                         }
                         binaryBuffer.loadedData = data.bin;
@@ -3930,7 +3932,7 @@ var BABYLON;
              * @param {IGLTFAccessor} 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) {
                     return data;
                 }
@@ -4025,7 +4027,7 @@ var BABYLON;
                                 break;
                             }
                             default: {
-                                BABYLON.Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                                BABYLON.Tools.Warn(context + ": Ignoring unrecognized attribute '" + attribute + "'");
                                 break;
                             }
                         }
@@ -4161,7 +4163,7 @@ var BABYLON;
                                 break;
                             }
                             default: {
-                                BABYLON.Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                                BABYLON.Tools.Warn(context + ": Ignoring unrecognized attribute '" + attribute + "'");
                                 break;
                             }
                         }
@@ -4523,13 +4525,13 @@ var BABYLON;
                     throw new Error(context + ": Failed to find buffer view " + accessor.bufferView);
                 }
                 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 byteOffset = accessor.byteOffset || 0;
                     var byteStride = bufferView.byteStride;
+                    if (byteStride === 0) {
+                        BABYLON.Tools.Warn(context + ": Byte stride of 0 is not valid");
+                    }
                     try {
                         switch (accessor.componentType) {
                             case GLTF2.EComponentType.BYTE: {
@@ -4570,7 +4572,7 @@ var BABYLON;
             GLTFLoader.prototype._buildArrayBuffer = function (typedArray, data, byteOffset, count, numComponents, byteStride) {
                 byteOffset += data.byteOffset;
                 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);
                 }
                 var elementStride = byteStride / typedArray.BYTES_PER_ELEMENT;
@@ -4779,14 +4781,13 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadTexture = function (context, texture, coordinatesIndex) {
                 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) {
                     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);
-                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._removePendingData(texture);
                     });
@@ -4819,14 +4820,23 @@ var BABYLON;
                     });
                 }
                 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;
                 if (this._parent.onTextureLoaded) {
                     this._parent.onTextureLoaded(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) {
                 if (image.uri) {
                     this._loadUriAsync(context, image.uri, onSuccess);
@@ -4899,7 +4909,7 @@ var BABYLON;
                 }
                 return array[index];
             };
-            GLTFLoader._GetTextureWrapMode = function (mode) {
+            GLTFLoader._GetTextureWrapMode = function (context, mode) {
                 // Set defaults if undefined
                 mode = mode == undefined ? GLTF2.ETextureWrapMode.REPEAT : mode;
                 switch (mode) {
@@ -4907,11 +4917,11 @@ var BABYLON;
                     case GLTF2.ETextureWrapMode.MIRRORED_REPEAT: return BABYLON.Texture.MIRROR_ADDRESSMODE;
                     case GLTF2.ETextureWrapMode.REPEAT: return BABYLON.Texture.WRAP_ADDRESSMODE;
                     default:
-                        BABYLON.Tools.Warn("Invalid texture wrap mode (" + mode + ")");
+                        BABYLON.Tools.Warn(context + ": Invalid texture wrap mode " + mode);
                         return BABYLON.Texture.WRAP_ADDRESSMODE;
                 }
             };
-            GLTFLoader._GetTextureSamplingMode = function (magFilter, minFilter) {
+            GLTFLoader._GetTextureSamplingMode = function (context, magFilter, minFilter) {
                 // Set defaults if undefined
                 magFilter = magFilter == undefined ? GLTF2.ETextureMagFilter.LINEAR : magFilter;
                 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.LINEAR_MIPMAP_LINEAR: return BABYLON.Texture.LINEAR_LINEAR_MIPLINEAR;
                         default:
-                            BABYLON.Tools.Warn("Invalid texture minification filter (" + minFilter + ")");
+                            BABYLON.Tools.Warn(context + ": Invalid texture minification filter " + minFilter);
                             return BABYLON.Texture.LINEAR_LINEAR_MIPLINEAR;
                     }
                 }
                 else {
                     if (magFilter !== GLTF2.ETextureMagFilter.NEAREST) {
-                        BABYLON.Tools.Warn("Invalid texture magnification filter (" + magFilter + ")");
+                        BABYLON.Tools.Warn(context + ": Invalid texture magnification filter " + magFilter);
                     }
                     switch (minFilter) {
                         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.LINEAR_MIPMAP_LINEAR: return BABYLON.Texture.NEAREST_LINEAR_MIPLINEAR;
                         default:
-                            BABYLON.Tools.Warn("Invalid texture minification filter (" + minFilter + ")");
+                            BABYLON.Tools.Warn(context + ": Invalid texture minification filter " + minFilter);
                             return BABYLON.Texture.NEAREST_NEAREST_MIPNEAREST;
                     }
                 }
             };
-            GLTFLoader._GetNumComponents = function (type) {
+            GLTFLoader._GetNumComponents = function (context, type) {
                 switch (type) {
                     case "SCALAR": return 1;
                     case "VEC2": return 2;
@@ -4955,7 +4965,7 @@ var BABYLON;
                     case "MAT3": return 9;
                     case "MAT4": return 16;
                 }
-                return 0;
+                throw new Error(context + ": Invalid type " + type);
             };
             GLTFLoader.prototype._compileMaterialAsync = function (babylonMaterial, babylonMesh, onSuccess) {
                 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;
         wrapS?: ETextureWrapMode;
         wrapT?: ETextureWrapMode;
+        index: number;
+        noMipMaps: boolean;
+        samplingMode: number;
+        wrapU: number;
+        wrapV: number;
     }
     interface IGLTFScene extends IGLTFChildRootProperty {
         nodes: number[];
@@ -1004,6 +1009,7 @@ declare module BABYLON.GLTF2 {
         private _parent;
         private _rootUrl;
         private _defaultMaterial;
+        private _defaultSampler;
         private _rootNode;
         private _successCallback;
         private _progressCallback;
@@ -1083,14 +1089,15 @@ declare module BABYLON.GLTF2 {
         _loadMaterialBaseProperties(context: string, material: IGLTFMaterial): void;
         _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
         _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture;
+        private _loadSampler(context, sampler);
         private _loadImageAsync(context, image, onSuccess);
         _loadUriAsync(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
         _tryCatchOnError(handler: () => void): void;
         private static _AssignIndices(array?);
         static _GetProperty<T extends IGLTFProperty>(array?: ArrayLike<T>, index?: number): Nullable<T>;
-        private static _GetTextureWrapMode(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 _compileMaterialsAsync(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
-- 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))
 - 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))
   - Framing ([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 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
+
 - 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 `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))
 - 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))
-- 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))
 - 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 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))
 - 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))
@@ -47,17 +51,35 @@
 - 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))
 - 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))
+- 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
+
+- 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))
+- 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
+
 - `Gamepads` was removed in favor of `scene.gamepadManager`
 - `DynamicFloatArray`, `MapTexture` and `RectPakingMap` were removed because there were not used anymore
 - `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++;
                             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
                         if (Math.abs(absoluteCursorPosition - currentSize) > previousDist) {

+ 6 - 18
loaders/readme.md

@@ -1,24 +1,12 @@
 ## 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:
 
 ```

+ 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 _rootUrl: string;
         private _defaultMaterial: PBRMaterial;
+        private _defaultSampler = {} as IGLTFSampler;
         private _rootNode: IGLTFNode;
         private _successCallback: () => void;
         private _progressCallback: (event: ProgressEvent) => void;
@@ -219,6 +220,7 @@ module BABYLON.GLTF2 {
             GLTFLoader._AssignIndices(this._gltf.materials);
             GLTFLoader._AssignIndices(this._gltf.meshes);
             GLTFLoader._AssignIndices(this._gltf.nodes);
+            GLTFLoader._AssignIndices(this._gltf.samplers);
             GLTFLoader._AssignIndices(this._gltf.scenes);
             GLTFLoader._AssignIndices(this._gltf.skins);
             GLTFLoader._AssignIndices(this._gltf.textures);
@@ -227,7 +229,7 @@ module BABYLON.GLTF2 {
                 const buffers = this._gltf.buffers;
                 if (buffers && buffers[0] && !buffers[0].uri) {
                     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 + ")");
                     }
 
@@ -576,7 +578,7 @@ module BABYLON.GLTF2 {
          * @param {IGLTFAccessor} accessor 
          */
         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) {
                 return data as Float32Array;
             }
@@ -679,7 +681,7 @@ module BABYLON.GLTF2 {
                             break;
                         }
                         default: {
-                            Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                            Tools.Warn(context + ": Ignoring unrecognized attribute '" + attribute + "'");
                             break;
                         }
                     }
@@ -816,7 +818,7 @@ module BABYLON.GLTF2 {
                             break;
                         }
                         default: {
-                            Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                            Tools.Warn(context + ": Ignoring unrecognized attribute '" + attribute + "'");
                             break;
                         }
                     }
@@ -1223,14 +1225,15 @@ module BABYLON.GLTF2 {
             }
 
             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 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 {
                     switch (accessor.componentType) {
@@ -1276,7 +1279,7 @@ module BABYLON.GLTF2 {
 
             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);
             }
 
@@ -1528,16 +1531,15 @@ module BABYLON.GLTF2 {
         }
 
         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) {
                 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);
-            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._removePendingData(texture);
                 });
@@ -1574,8 +1576,8 @@ module BABYLON.GLTF2 {
             }
 
             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;
 
             if (this._parent.onTextureLoaded) {
@@ -1585,6 +1587,17 @@ module BABYLON.GLTF2 {
             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 {
             if (image.uri) {
                 this._loadUriAsync(context, image.uri, onSuccess);
@@ -1669,7 +1682,7 @@ module BABYLON.GLTF2 {
             return array[index];
         }
 
-        private static _GetTextureWrapMode(mode?: ETextureWrapMode): number {
+        private static _GetTextureWrapMode(context: string, mode?: ETextureWrapMode): number {
             // Set defaults if undefined
             mode = mode == undefined ? ETextureWrapMode.REPEAT : mode;
 
@@ -1678,12 +1691,12 @@ module BABYLON.GLTF2 {
                 case ETextureWrapMode.MIRRORED_REPEAT: return Texture.MIRROR_ADDRESSMODE;
                 case ETextureWrapMode.REPEAT: return Texture.WRAP_ADDRESSMODE;
                 default:
-                    Tools.Warn("Invalid texture wrap mode (" + mode + ")");
+                    Tools.Warn(context + ": Invalid texture wrap mode " + mode);
                     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
             magFilter = magFilter == undefined ? ETextureMagFilter.LINEAR : magFilter;
             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.LINEAR_MIPMAP_LINEAR: return Texture.LINEAR_LINEAR_MIPLINEAR;
                     default:
-                        Tools.Warn("Invalid texture minification filter (" + minFilter + ")");
+                        Tools.Warn(context + ": Invalid texture minification filter " + minFilter);
                         return Texture.LINEAR_LINEAR_MIPLINEAR;
                 }
             }
             else {
                 if (magFilter !== ETextureMagFilter.NEAREST) {
-                    Tools.Warn("Invalid texture magnification filter (" + magFilter + ")");
+                    Tools.Warn(context + ": Invalid texture magnification filter " + magFilter);
                 }
 
                 switch (minFilter) {
@@ -1714,13 +1727,13 @@ module BABYLON.GLTF2 {
                     case ETextureMinFilter.NEAREST_MIPMAP_LINEAR: return Texture.NEAREST_NEAREST_MIPLINEAR;
                     case ETextureMinFilter.LINEAR_MIPMAP_LINEAR: return Texture.NEAREST_LINEAR_MIPLINEAR;
                     default:
-                        Tools.Warn("Invalid texture minification filter (" + minFilter + ")");
+                        Tools.Warn(context + ": Invalid texture minification filter " + minFilter);
                         return Texture.NEAREST_NEAREST_MIPNEAREST;
                 }
             }
         }
 
-        private static _GetNumComponents(type: string): number {
+        private static _GetNumComponents(context: string, type: string): number {
             switch (type) {
                 case "SCALAR": return 1;
                 case "VEC2": return 2;
@@ -1731,7 +1744,7 @@ module BABYLON.GLTF2 {
                 case "MAT4": return 16;
             }
 
-            return 0;
+            throw new Error(context + ": Invalid type " + type);
         }
 
         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;
         wrapS?: ETextureWrapMode;
         wrapT?: ETextureWrapMode;
+
+        // Runtime values
+        index: number;
+        noMipMaps: boolean;
+        samplingMode: number;
+        wrapU: number;
+        wrapV: number;
     }
 
     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>
 <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();
-                                    divFps.innerHTML = engine.getFps().toFixed() + " fps";
-                                });
-                            }
+                                }
+                                divFps.innerHTML = engine.getFps().toFixed() + " fps";
+                            });
                         }
-
-                        // Resize
-                        window.addEventListener("resize", function () {
-                            engine.resize();
-                        });
-
                     }
                     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>

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

@@ -57,6 +57,8 @@ module BABYLON {
         private _teleportationAllowed: boolean = false;
         private _rotationAllowed: boolean = true;
         private _teleportationRequestInitiated = false;
+        private _teleportationBackRequestInitiated = false;
+        private teleportBackwardsVector = new Vector3(0, -1, -1);
         private _rotationRightAsked = false;
         private _rotationLeftAsked = false;
         private _teleportationCircle: Mesh;
@@ -122,6 +124,14 @@ module BABYLON {
                     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> {
@@ -150,24 +160,37 @@ module BABYLON {
             this._scene = scene;
             this._canvas = scene.getEngine().getRenderingCanvas();
 
-            this._defaultHeight = webVROptions.defaultHeight || 1.7;
-
+            // Parse options
             if (webVROptions.createFallbackVRDeviceOrientationFreeCamera === undefined) {
                 webVROptions.createFallbackVRDeviceOrientationFreeCamera = true;
             }
-
             if (webVROptions.createDeviceOrientationCamera === undefined) {
                 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.maxZ = this._scene.activeCamera.maxZ;
                     // Set rotation from previous camera
@@ -181,29 +204,22 @@ module BABYLON {
                         this._deviceOrientationCamera.rotation = targetCamera.rotation.clone();
                     }
                 }
+
                 this._scene.activeCamera = this._deviceOrientationCamera;
                 if (this._canvas) {
                     this._scene.activeCamera.attachControl(this._canvas);
                 }
-            }
-            else {
+            }else{
                 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) {
                 this._btnVR = <HTMLButtonElement>document.createElement("BUTTON");
                 this._btnVR.className = "babylonVRicon";
@@ -219,50 +235,42 @@ module BABYLON {
                 var style = document.createElement('style');
                 style.appendChild(document.createTextNode(css));
                 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();
                     }
                 });
             }
 
+            // Window events
+            window.addEventListener("resize", () => {
+                this.moveButtonToBottomRight();
+                if (this._fullscreenVRpresenting && this._webVRready) {
+                    this.exitVR();
+                }
+            });
             document.addEventListener("fullscreenchange", () => { this._onFullscreenChange() }, false);
             document.addEventListener("mozfullscreenchange", () => { this._onFullscreenChange() }, false);
             document.addEventListener("webkitfullscreenchange", () => { 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
@@ -294,17 +302,12 @@ module BABYLON {
                 this._webVRrequesting = false;
                 this.updateButtonVisibility();
             };
-
             scene.getEngine().onVRDisplayChangedObservable.add(this._onVRDisplayChanged);
             scene.getEngine().onVRRequestPresentStart.add(this._onVRRequestPresentStart);
             scene.getEngine().onVRRequestPresentComplete.add(this._onVRRequestPresentComplete);
             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._scene.gamepadManager.onGamepadConnectedObservable.add((pad) => this._onNewGamepadConnected(pad));
             this._scene.gamepadManager.onGamepadDisconnectedObservable.add((pad) => this._onNewGamepadDisconnected(pad));
@@ -395,6 +398,20 @@ module BABYLON {
             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() {
             if (!this._btnVR || this._useCustomVRButton) {
                 return;
@@ -414,10 +431,6 @@ module BABYLON {
          * Otherwise, will use the fullscreen API.
          */
         public enterVR() {
-            if (this._scene.activeCamera) {
-                this._position = this._scene.activeCamera.position.clone();
-            }
-
             if (this.onEnteringVR) {
                 try {
                     this.onEnteringVR.notifyObservers(this);
@@ -426,6 +439,11 @@ module BABYLON {
                     Tools.Warn("Error in your custom logic onEnteringVR: " + err);
                 }
             }
+
+            if (this._scene.activeCamera) {
+                this._position = this._scene.activeCamera.position.clone();
+            }
+
             if (this._webVRrequesting)
                 return;
 
@@ -617,23 +635,12 @@ module BABYLON {
                 if (gamepad.leftStick) {
                     gamepad.onleftstickchanged((stickValues) => {
                         if (this._teleportationEnabled) {
+                            this._checkTeleportBackwards(stickValues);
                             // Listening to classic/xbox gamepad only if no VR controller is active
                             if ((!this._leftLaserPointer && !this._rightLaserPointer) ||
                                 ((this._leftLaserPointer && !this._leftLaserPointer.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) {
                     gamepad.onrightstickchanged((stickValues) => {
                         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) {
                     (<Xbox360Pad>gamepad).onbuttondown((buttonPressed: Xbox360Button) => {
                         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) => {
                         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) => {
                     if (!this._pointerDownOnMeshAsked) {
                         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) {
             var controllerMesh = webVRController.mesh;
@@ -795,64 +880,9 @@ module BABYLON {
                     this._teleportationEnabledOnRightController = true;
                 }
                 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 _teleportCamera() {
+        private _workingQuaternion = Quaternion.Identity();
+        private _workingMatrix = Matrix.Identity();
+        private _teleportCamera(location:Nullable<Vector3> = null) {
             if (!(this.currentVRCamera instanceof FreeCamera)) {
                 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
             this.currentVRCamera.animations = [];
@@ -1081,7 +1117,7 @@ module BABYLON {
             },
             {
                 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
             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);
 
             super.update();

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

@@ -657,7 +657,7 @@
                 if (!this._collider) {
                     this._collider = new Collider();
                 }
-                this._collider.radius = this.collisionRadius;
+                this._collider._radius = this.collisionRadius;
                 this._newPosition.subtractToRef(this.position, this._collisionVelocity);
                 this._collisionTriggered = true;
                 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) => {
 
             if (this.getScene().workerCollisions && this.checkCollisions) {
-                newPosition.multiplyInPlace(this._collider.radius);
+                newPosition.multiplyInPlace(this._collider._radius);
             }
 
             if (!collidedMesh) {

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

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

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

@@ -55,23 +55,20 @@
                 return result;
             }
         }
-    )();
+        )();
 
     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 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;
+
+        /**
+         * Define last collided mesh
+         */
         public collidedMesh: Nullable<AbstractMesh>;
 
         private _collisionPoint = Vector3.Zero();
@@ -86,28 +83,48 @@
         private _slidePlaneNormal = 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;
-        
+
         public get collisionMask(): number {
             return this._collisionMask;
         }
-        
+
         public set collisionMask(mask: number) {
             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
         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;
         }
 
@@ -132,15 +149,15 @@
         }
 
         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;
             }
 
-            if (!intersectBoxAASphere(vecMin, vecMax, this.basePointWorld, this.velocityWorldLength + max))
+            if (!intersectBoxAASphere(vecMin, vecMax, this._basePointWorld, this._velocityWorldLength + max))
                 return false;
 
             return true;
@@ -162,11 +179,11 @@
 
             var trianglePlane = trianglePlaneArray[faceIndex];
 
-            if ((!hasMaterial) && !trianglePlane.isFrontFacingTo(this.normalizedVelocity, 0))
+            if ((!hasMaterial) && !trianglePlane.isFrontFacingTo(this._normalizedVelocity, 0))
                 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 (Math.abs(signedDistToTrianglePlane) >= 1.0)
@@ -199,8 +216,8 @@
             var t = 1.0;
 
             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);
 
                 if (this._checkPointInTriangle(this._planeIntersectionPoint, p1, p2, p3, trianglePlane.normal)) {
@@ -211,12 +228,12 @@
             }
 
             if (!found) {
-                var velocitySquaredLength = this.velocity.lengthSquared();
+                var velocitySquaredLength = this._velocity.lengthSquared();
 
                 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 lowestRoot = getLowestRoot(a, b, c, t);
@@ -226,8 +243,8 @@
                     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;
 
                 lowestRoot = getLowestRoot(a, b, c, t);
@@ -237,8 +254,8 @@
                     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;
 
                 lowestRoot = getLowestRoot(a, b, c, t);
@@ -249,13 +266,13 @@
                 }
 
                 p2.subtractToRef(p1, this._edge);
-                p1.subtractToRef(this.basePoint, this._baseToVertex);
+                p1.subtractToRef(this._basePoint, this._baseToVertex);
                 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);
 
                 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;
 
                 lowestRoot = getLowestRoot(a, b, c, t);
@@ -271,13 +288,13 @@
                 }
 
                 p3.subtractToRef(p2, this._edge);
-                p2.subtractToRef(this.basePoint, this._baseToVertex);
+                p2.subtractToRef(this._basePoint, this._baseToVertex);
                 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);
 
                 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;
                 lowestRoot = getLowestRoot(a, b, c, t);
                 if (lowestRoot.found) {
@@ -292,13 +309,13 @@
                 }
 
                 p1.subtractToRef(p3, this._edge);
-                p3.subtractToRef(this.basePoint, this._baseToVertex);
+                p3.subtractToRef(this._basePoint, this._baseToVertex);
                 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);
 
                 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;
 
                 lowestRoot = getLowestRoot(a, b, c, t);
@@ -315,15 +332,15 @@
             }
 
             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) {
                         this.intersectionPoint = this._collisionPoint.clone();
                     } else {
                         this.intersectionPoint.copyFrom(this._collisionPoint);
                     }
-                    this.nearestDistance = distToCollision;
+                    this._nearestDistance = distToCollision;
                     this.collisionFound = true;
                 }
             }
@@ -341,12 +358,12 @@
 
         public _getResponse(pos: Vector3, vel: Vector3): void {
             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);
             this._slidePlaneNormal.normalize();
-            this._slidePlaneNormal.scaleToRef(this.epsilon, this._displacementVector);
+            this._slidePlaneNormal.scaleToRef(this._epsilon, this._displacementVector);
 
             pos.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._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;
 
@@ -203,7 +203,7 @@ module BABYLON {
                 collider: {
                     position: this._scaledPosition.asArray(),
                     velocity: this._scaledVelocity.asArray(),
-                    radius: collider.radius.asArray()
+                    radius: collider._radius.asArray()
                 },
                 collisionId: collisionIndex,
                 excludedMeshUniqueId: excludedMesh ? excludedMesh.uniqueId : null,
@@ -360,15 +360,15 @@ module BABYLON {
         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 {
-            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.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._finalPosition.multiplyInPlace(collider.radius);
+            this._finalPosition.multiplyInPlace(collider._radius);
             //run the callback
             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 {
             var closeDistance = Engine.CollisionsEpsilon * 10.0;
 
-            if (collider.retry >= maximumRetry) {
+            if (collider._retry >= maximumRetry) {
                 finalPosition.copyFrom(position);
                 return;
             }
@@ -424,7 +424,7 @@ module BABYLON {
                 return;
             }
 
-            collider.retry++;
+            collider._retry++;
             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.
             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);
                 return;
             }
@@ -91,7 +91,7 @@ module BABYLON {
                 return;
             }
 
-            this.collider.retry++;
+            this.collider._retry++;
             this.collideWithWorld(position, velocity, maximumRetry, excludedMeshUniqueId);
         }
 
@@ -102,7 +102,7 @@ module BABYLON {
             };
 
             // 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);
             worldFromCache.multiplyToRef(this.collisionsScalingMatrix, this.collisionTranformationMatrix);
 
@@ -165,7 +165,7 @@ module BABYLON {
                 for (var i = start; i < end; i++) {
                     (<any>subMesh)['_lastColliderWorldVertices'].push(Vector3.TransformCoordinates((<any>meshGeometry)['positionsArray'][i], transformMatrix));
                 }
-            }        
+            }
 
             // Collide
             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();
             //create a 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);
             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 message = <BabylonMessage>event.data;
                 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 {
-            return "3.1-rc-0";
+            return "3.1-rc-1";
         }
 
         // Updatable statics so stick with vars here

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

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

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

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

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

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

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

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

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

@@ -42,12 +42,12 @@
             Y: 1,
             Z: 1
         };
-      
+
         private _facetDepthSort: boolean = false;                           // is the facet depth sort to be computed
         private _facetDepthSortEnabled: boolean = false;                    // is the facet depth sort initialized
         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 _facetDepthSortOrigin: Vector3;                             // same as facetDepthSortFrom but expressed in the mesh local space
         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 {
             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) {
                 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);
             return this;
@@ -1083,7 +1089,7 @@
         private _onCollisionPositionChange = (collisionId: number, newPosition: Vector3, collidedMesh: Nullable<AbstractMesh> = null) => {
             //TODO move this to the collision coordinator!
             if (this.getScene().workerCollisions)
-                newPosition.multiplyInPlace(this._collider.radius);
+                newPosition.multiplyInPlace(this._collider._radius);
 
             newPosition.subtractToRef(this._oldPositionForCollisions, this._diffPositionForCollisions);
 
@@ -1154,8 +1160,8 @@
 
             // Octrees
             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;
                 subMeshes = intersections.data;
@@ -1182,7 +1188,7 @@
                 return this;
 
             // 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._processCollisionsForSubMeshes(collider, this._collisionsTransformMatrix);
             return this;
@@ -1489,7 +1495,7 @@
                 }
                 else if (indices instanceof Uint32Array) {
                     this._depthSortedIndices = new Uint32Array(indices!);
-                } 
+                }
                 else {
                     var needs32bits = false;
                     for (var i = 0; i < indices!.length; i++) {
@@ -1500,12 +1506,12 @@
                     }
                     if (needs32bits) {
                         this._depthSortedIndices = new Uint32Array(indices!);
-                    } 
+                    }
                     else {
                         this._depthSortedIndices = new Uint16Array(indices!);
                     }
-                }               
-                this._facetDepthSortFunction = function(f1, f2) {
+                }
+                this._facetDepthSortFunction = function (f1, f2) {
                     return (f2.sqDistance - f1.sqDistance);
                 };
                 if (!this._facetDepthSortFrom) {
@@ -1553,7 +1559,7 @@
 
             if (this._facetDepthSort && this._facetDepthSortEnabled) {
                 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++) {
                     var sind = this._depthSortedFacets[f].ind;
                     this._depthSortedIndices[f * 3] = indices![sind];
@@ -1782,19 +1788,19 @@
          * Align the mesh with a normal.
          * 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;
             }
-            
+
             var axisX = Tmp.Vector3[0];
             var axisZ = Tmp.Vector3[1];
             Vector3.CrossToRef(upDirection, normal, axisZ);
             Vector3.CrossToRef(normal, axisZ, axisX);
-            
-            if(this.rotationQuaternion){
+
+            if (this.rotationQuaternion) {
                 Quaternion.RotationQuaternionFromAxisToRef(axisX, normal, axisZ, this.rotationQuaternion);
-            }else{
+            } else {
                 Vector3.RotationFromAxisToRef(axisX, normal, axisZ, this.rotation);
             }
             return this;

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

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

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

@@ -1439,13 +1439,13 @@
             else if (this.delayLoadState === Engine.DELAYLOADSTATE_NOTLOADED) {
                 this.delayLoadState = Engine.DELAYLOADSTATE_LOADING;
 
-                this._queueLoad(this, scene);
+                this._queueLoad(scene);
             }
             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);
 
@@ -1582,7 +1582,7 @@
          * Modifies the mesh geometry according to its own current World Matrix.  
          * 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.
-         * 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.   
          * Returns the Mesh.  
          */

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

@@ -948,7 +948,7 @@ module BABYLON {
             // Remove from scene
             this.getScene().removeTransformNode(this);
 
-            this._cache = null;
+            this._cache = {};
 
             if (!doNotRecurse) {
                 // 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.");
                 return;
             }
+
+            this._extendNamespace();
+
             this.world = new this.BJSCANNON.World();
             this.world.broadphase = new this.BJSCANNON.NaiveBroadphase();
             this.world.solver.iterations = iterations;
@@ -590,5 +593,46 @@
         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
                 var observer = this._scene.onDataLoadedObservable.add(() => {
                     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 {
                 behavior.attach(this);

+ 6 - 2
src/tsconfig.json

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

BIN
tests/validation/ReferenceImages/charting.png


+ 1 - 1
tests/validation/config.json

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