Quellcode durchsuchen

Merge branch 'master' of https://github.com/nockawa/Babylon.js.git

nockawa vor 8 Jahren
Ursprung
Commit
8582242607
55 geänderte Dateien mit 7336 neuen und 14278 gelöschten Zeilen
  1. 26 0
      canvas2D/src/Engine/babylon.canvas2d.ts
  2. 10 3
      canvas2D/src/Engine/babylon.prim2dBase.ts
  3. 16 2
      canvas2D/src/Engine/babylon.smartPropertyPrim.ts
  4. 672 660
      dist/preview release/babylon.canvas2d.d.ts
  5. 8 8
      dist/preview release/babylon.canvas2d.js
  6. 35 3
      dist/preview release/babylon.canvas2d.max.js
  7. 23 23
      dist/preview release/babylon.core.js
  8. 1629 1536
      dist/preview release/babylon.d.ts
  9. 35 35
      dist/preview release/babylon.js
  10. 198 29
      dist/preview release/babylon.max.js
  11. 34 34
      dist/preview release/babylon.noworker.js
  12. 1 0
      dist/preview release/what's new.md
  13. 1 1
      materialsLibrary/dist/babylon.fireMaterial.js
  14. 1 1
      materialsLibrary/dist/babylon.fireMaterial.min.js
  15. 1 1
      materialsLibrary/dist/babylon.furMaterial.js
  16. 1 1
      materialsLibrary/dist/babylon.furMaterial.min.js
  17. 1 1
      materialsLibrary/dist/babylon.gradientMaterial.js
  18. 1 1
      materialsLibrary/dist/babylon.gradientMaterial.min.js
  19. 17 4
      materialsLibrary/dist/babylon.gridMaterial.js
  20. 1 1
      materialsLibrary/dist/babylon.gridMaterial.min.js
  21. 6 4
      materialsLibrary/dist/babylon.lavaMaterial.js
  22. 1 1
      materialsLibrary/dist/babylon.lavaMaterial.min.js
  23. 1 1
      materialsLibrary/dist/babylon.normalMaterial.js
  24. 1 1
      materialsLibrary/dist/babylon.normalMaterial.min.js
  25. 1 2
      materialsLibrary/dist/babylon.simpleMaterial.js
  26. 1 1
      materialsLibrary/dist/babylon.simpleMaterial.min.js
  27. 1 1
      materialsLibrary/dist/babylon.terrainMaterial.js
  28. 1 1
      materialsLibrary/dist/babylon.terrainMaterial.min.js
  29. 1 1
      materialsLibrary/dist/babylon.triPlanarMaterial.js
  30. 1 1
      materialsLibrary/dist/babylon.triPlanarMaterial.min.js
  31. 81 4
      materialsLibrary/dist/babylon.waterMaterial.js
  32. 1 1
      materialsLibrary/dist/babylon.waterMaterial.min.js
  33. 1 0
      materialsLibrary/dist/dts/babylon.lavaMaterial.d.ts
  34. 23 1
      materialsLibrary/dist/dts/babylon.waterMaterial.d.ts
  35. 44 26
      materialsLibrary/materials/grid/babylon.gridmaterial.ts
  36. 10 4
      materialsLibrary/materials/grid/grid.fragment.fx
  37. 11 0
      materialsLibrary/materials/grid/grid.vertex.fx
  38. 3987 11819
      materialsLibrary/test/refs/babylon.max.js
  39. 1 3
      postProcessLibrary/postProcesses/asciiArt/babylon.asciiArtPostProcess.ts
  40. 1 3
      postProcessLibrary/postProcesses/digitalRain/babylon.digitalRainPostProcess.ts
  41. 11 7
      src/Cameras/VR/babylon.webVRCamera.js
  42. 15 8
      src/Cameras/VR/babylon.webVRCamera.ts
  43. 25 8
      src/Cameras/babylon.camera.js
  44. 27 8
      src/Cameras/babylon.camera.ts
  45. 9 0
      src/Materials/Textures/babylon.baseTexture.ts
  46. 9 0
      src/Math/babylon.math.js
  47. 12 0
      src/Math/babylon.math.ts
  48. 14 13
      src/Particles/babylon.solidParticleSystem.js
  49. 14 15
      src/Particles/babylon.solidParticleSystem.ts
  50. 44 0
      src/Rendering/babylon.renderingManager.js
  51. 52 0
      src/Rendering/babylon.renderingManager.ts
  52. 8 0
      src/babylon.node.js
  53. 12 0
      src/babylon.node.ts
  54. 86 0
      src/babylon.scene.js
  55. 112 0
      src/babylon.scene.ts

+ 26 - 0
canvas2D/src/Engine/babylon.canvas2d.ts

@@ -76,6 +76,7 @@
             isScreenSpace?: boolean,
             isScreenSpace?: boolean,
             cachingStrategy?: number,
             cachingStrategy?: number,
             enableInteraction?: boolean,
             enableInteraction?: boolean,
+            allow3DEventBelowCanvas?: boolean,
             origin?: Vector2,
             origin?: Vector2,
             isVisible?: boolean,
             isVisible?: boolean,
             backgroundRoundRadius?: number,
             backgroundRoundRadius?: number,
@@ -169,6 +170,8 @@
             this._maxAdaptiveWorldSpaceCanvasSize = null;
             this._maxAdaptiveWorldSpaceCanvasSize = null;
             this._groupCacheMaps = new StringDictionary<MapTexture[]>();
             this._groupCacheMaps = new StringDictionary<MapTexture[]>();
 
 
+            this._changeFlags(SmartPropertyPrim.flagAllow3DEventsBelowCanvas, (settings.allow3DEventBelowCanvas != null) && settings.allow3DEventBelowCanvas);
+
             this._patchHierarchy(this);
             this._patchHierarchy(this);
 
 
             let enableInteraction = (settings.enableInteraction == null) ? true : settings.enableInteraction;
             let enableInteraction = (settings.enableInteraction == null) ? true : settings.enableInteraction;
@@ -487,6 +490,12 @@
             }
             }
 
 
             eventState.skipNextObservers = skip;
             eventState.skipNextObservers = skip;
+            if (!skip && (this._isFlagSet(SmartPropertyPrim.flagAllow3DEventsBelowCanvas)===false)) {
+                eventState.skipNextObservers = true;
+                if (eventData instanceof PointerInfoPre) {
+                    eventData.skipOnPointerObservable = true;
+                }
+            }
         }
         }
 
 
         private _updatePointerInfo(eventData: PointerInfoBase, localPosition: Vector2): boolean {
         private _updatePointerInfo(eventData: PointerInfoBase, localPosition: Vector2): boolean {
@@ -1062,6 +1071,21 @@
             return this.__engineData;
             return this.__engineData;
         }
         }
 
 
+        /**
+         * If true is returned, pointerEvent occurring above the Canvas area also sent in 3D scene, if false they are not sent in the 3D Scene
+         */
+        public get allow3DEventBelowCanvas(): boolean {
+            return this._isFlagSet(SmartPropertyPrim.flagAllow3DEventsBelowCanvas);
+        }
+
+        /**
+         * Set true if you want pointerEvent occurring above the Canvas area to also be sent in the 3D scene.
+         * Set false if you don't want the Scene to get the events
+         */
+        public set allow3DEventBelowCanvas(value: boolean) {
+            this._changeFlags(SmartPropertyPrim.flagAllow3DEventsBelowCanvas, value);
+        }
+
         public createCanvasProfileInfoCanvas(): Canvas2D {
         public createCanvasProfileInfoCanvas(): Canvas2D {
             if (this._profilingCanvas) {
             if (this._profilingCanvas) {
                 return this._profilingCanvas;
                 return this._profilingCanvas;
@@ -1817,6 +1841,7 @@
          *  - designUseHorizAxis: you can set this member if you use designSize to specify which axis is priority to compute the scale when the ratio of the canvas' size is different from the designSize's one.
          *  - designUseHorizAxis: you can set this member if you use designSize to specify which axis is priority to compute the scale when the ratio of the canvas' size is different from the designSize's one.
          *  - cachingStrategy: either CACHESTRATEGY_TOPLEVELGROUPS, CACHESTRATEGY_ALLGROUPS, CACHESTRATEGY_CANVAS, CACHESTRATEGY_DONTCACHE. Please refer to their respective documentation for more information. Default is Canvas2D.CACHESTRATEGY_DONTCACHE
          *  - cachingStrategy: either CACHESTRATEGY_TOPLEVELGROUPS, CACHESTRATEGY_ALLGROUPS, CACHESTRATEGY_CANVAS, CACHESTRATEGY_DONTCACHE. Please refer to their respective documentation for more information. Default is Canvas2D.CACHESTRATEGY_DONTCACHE
          *  - enableInteraction: if true the pointer events will be listened and rerouted to the appropriate primitives of the Canvas2D through the Prim2DBase.onPointerEventObservable observable property. Default is true.
          *  - enableInteraction: if true the pointer events will be listened and rerouted to the appropriate primitives of the Canvas2D through the Prim2DBase.onPointerEventObservable observable property. Default is true.
+         *  - allow3DEventBelowCanvas: by default pointerEvent occurring above the Canvas will prevent to be also sent in the 3D Scene. If you set this setting to true, events will be sent both for Canvas and 3D Scene
          *  - isVisible: true if the canvas must be visible, false for hidden. Default is true.
          *  - isVisible: true if the canvas must be visible, false for hidden. Default is true.
          * - backgroundRoundRadius: the round radius of the background, either backgroundFill or backgroundBorder must be specified.
          * - backgroundRoundRadius: the round radius of the background, either backgroundFill or backgroundBorder must be specified.
          * - backgroundFill: the brush to use to create a background fill for the canvas. can be a string value (see BABYLON.Canvas2D.GetBrushFromString) or a IBrush2D instance.
          * - backgroundFill: the brush to use to create a background fill for the canvas. can be a string value (see BABYLON.Canvas2D.GetBrushFromString) or a IBrush2D instance.
@@ -1846,6 +1871,7 @@
             cachingStrategy?: number,
             cachingStrategy?: number,
             cacheBehavior?: number,
             cacheBehavior?: number,
             enableInteraction?: boolean,
             enableInteraction?: boolean,
+            allow3DEventBelowCanvas?: boolean,
             isVisible?: boolean,
             isVisible?: boolean,
             backgroundRoundRadius?: number,
             backgroundRoundRadius?: number,
             backgroundFill?: IBrush2D | string,
             backgroundFill?: IBrush2D | string,

+ 10 - 3
canvas2D/src/Engine/babylon.prim2dBase.ts

@@ -1785,7 +1785,8 @@
 
 
         @instanceLevelProperty(1, pi => Prim2DBase.actualPositionProperty = pi, false, false, true)
         @instanceLevelProperty(1, pi => Prim2DBase.actualPositionProperty = pi, false, false, true)
         /**
         /**
-         * Return the position where the primitive is rendered in the Canvas, this position may be different than the one returned by the position property due to layout/alignment/margin/padding computing
+         * Return the position where the primitive is rendered in the Canvas, this position may be different than the one returned by the position property due to layout/alignment/margin/padding computing.
+         * BEWARE: don't change this value, it's read-only!
          */
          */
         public get actualPosition(): Vector2 {
         public get actualPosition(): Vector2 {
             if (this._actualPosition != null) {
             if (this._actualPosition != null) {
@@ -1841,7 +1842,10 @@
          */
          */
         @dynamicLevelProperty(SmartPropertyPrim.SMARTPROPERTYPRIM_PROPCOUNT + 3, pi => Prim2DBase.positionProperty = pi, false, false, true)
         @dynamicLevelProperty(SmartPropertyPrim.SMARTPROPERTYPRIM_PROPCOUNT + 3, pi => Prim2DBase.positionProperty = pi, false, false, true)
         public get position(): Vector2 {
         public get position(): Vector2 {
-            return this._position || Prim2DBase._nullPosition;
+            if (!this._position) {
+                this._position = Vector2.Zero();
+            }
+            return this._position;
         }
         }
 
 
         public set position(value: Vector2) {
         public set position(value: Vector2) {
@@ -2419,7 +2423,10 @@
          * The setter should only be called by a Layout Engine class.
          * The setter should only be called by a Layout Engine class.
          */
          */
         public get layoutAreaPos(): Vector2 {
         public get layoutAreaPos(): Vector2 {
-            return this._layoutAreaPos || Prim2DBase._nullPosition;
+            if (!this._layoutAreaPos) {
+                this._layoutAreaPos = Vector2.Zero();
+            }
+            return this._layoutAreaPos;
         }
         }
 
 
         public set layoutAreaPos(val: Vector2) {
         public set layoutAreaPos(val: Vector2) {

+ 16 - 2
canvas2D/src/Engine/babylon.smartPropertyPrim.ts

@@ -1057,7 +1057,20 @@
                         }
                         }
                     }
                     }
 
 
-                    modelKey += v.name + ":" + ((propVal != null) ? ((v.typeLevelCompare) ? Tools.getClassName(propVal) : propVal.toString()) : "[null]") + ";";
+                    let value = "[null]";
+                    if (propVal != null) {
+                        if (v.typeLevelCompare) {
+                            value = Tools.getClassName(propVal);
+                        } else {
+                            if (propVal instanceof BaseTexture) {
+                                value = propVal.uid;
+                            } else {
+                                value = propVal.toString();
+                            }
+                        }
+                    }
+
+                    modelKey += v.name + ":" + value + ";";
                 }
                 }
             });
             });
 
 
@@ -1265,7 +1278,8 @@
         public static flagActualScaleDirty        = 0x0040000;    // set if the actualScale property needs to be recomputed
         public static flagActualScaleDirty        = 0x0040000;    // set if the actualScale property needs to be recomputed
         public static flagDontInheritParentScale  = 0x0080000;    // set if the actualScale must not use its parent's scale to be computed
         public static flagDontInheritParentScale  = 0x0080000;    // set if the actualScale must not use its parent's scale to be computed
         public static flagGlobalTransformDirty    = 0x0100000;    // set if the global transform must be recomputed due to a local transform change
         public static flagGlobalTransformDirty    = 0x0100000;    // set if the global transform must be recomputed due to a local transform change
-        public static flagLayoutBoundingInfoDirty = 0x0100000;    // set if the layout bounding info is dirty
+        public static flagLayoutBoundingInfoDirty = 0x0200000;    // set if the layout bounding info is dirty
+        public static flagAllow3DEventsBelowCanvas= 0x0400000;    // set if pointer events should be sent to 3D Engine when the pointer is over the Canvas
 
 
         private   _flags              : number;
         private   _flags              : number;
         private   _modelKey           : string;
         private   _modelKey           : string;

Datei-Diff unterdrückt, da er zu groß ist
+ 672 - 660
dist/preview release/babylon.canvas2d.d.ts


Datei-Diff unterdrückt, da er zu groß ist
+ 8 - 8
dist/preview release/babylon.canvas2d.js


+ 35 - 3
dist/preview release/babylon.canvas2d.max.js

@@ -2635,7 +2635,8 @@ var BABYLON;
         SmartPropertyPrim.flagActualScaleDirty = 0x0040000; // set if the actualScale property needs to be recomputed
         SmartPropertyPrim.flagActualScaleDirty = 0x0040000; // set if the actualScale property needs to be recomputed
         SmartPropertyPrim.flagDontInheritParentScale = 0x0080000; // set if the actualScale must not use its parent's scale to be computed
         SmartPropertyPrim.flagDontInheritParentScale = 0x0080000; // set if the actualScale must not use its parent's scale to be computed
         SmartPropertyPrim.flagGlobalTransformDirty = 0x0100000; // set if the global transform must be recomputed due to a local transform change
         SmartPropertyPrim.flagGlobalTransformDirty = 0x0100000; // set if the global transform must be recomputed due to a local transform change
-        SmartPropertyPrim.flagLayoutBoundingInfoDirty = 0x0100000; // set if the layout bounding info is dirty
+        SmartPropertyPrim.flagLayoutBoundingInfoDirty = 0x0200000; // set if the layout bounding info is dirty
+        SmartPropertyPrim.flagAllow3DEventsBelowCanvas = 0x0400000; // set if pointer events should be sent to 3D Engine when the pointer is over the Canvas
         SmartPropertyPrim = __decorate([
         SmartPropertyPrim = __decorate([
             BABYLON.className("SmartPropertyPrim", "BABYLON")
             BABYLON.className("SmartPropertyPrim", "BABYLON")
         ], SmartPropertyPrim);
         ], SmartPropertyPrim);
@@ -4236,7 +4237,10 @@ var BABYLON;
              * Setting this property may have no effect is specific alignment are in effect.
              * Setting this property may have no effect is specific alignment are in effect.
              */
              */
             get: function () {
             get: function () {
-                return this._position || Prim2DBase._nullPosition;
+                if (!this._position) {
+                    this._position = BABYLON.Vector2.Zero();
+                }
+                return this._position;
             },
             },
             set: function (value) {
             set: function (value) {
                 if (!this._checkPositionChange()) {
                 if (!this._checkPositionChange()) {
@@ -4813,7 +4817,10 @@ var BABYLON;
              * The setter should only be called by a Layout Engine class.
              * The setter should only be called by a Layout Engine class.
              */
              */
             get: function () {
             get: function () {
-                return this._layoutAreaPos || Prim2DBase._nullPosition;
+                if (!this._layoutAreaPos) {
+                    this._layoutAreaPos = BABYLON.Vector2.Zero();
+                }
+                return this._layoutAreaPos;
             },
             },
             set: function (val) {
             set: function (val) {
                 if (this._layoutAreaPos && this._layoutAreaPos.equals(val)) {
                 if (this._layoutAreaPos && this._layoutAreaPos.equals(val)) {
@@ -11596,6 +11603,7 @@ var BABYLON;
             this._trackedGroups = new Array();
             this._trackedGroups = new Array();
             this._maxAdaptiveWorldSpaceCanvasSize = null;
             this._maxAdaptiveWorldSpaceCanvasSize = null;
             this._groupCacheMaps = new BABYLON.StringDictionary();
             this._groupCacheMaps = new BABYLON.StringDictionary();
+            this._changeFlags(BABYLON.SmartPropertyPrim.flagAllow3DEventsBelowCanvas, (settings.allow3DEventBelowCanvas != null) && settings.allow3DEventBelowCanvas);
             this._patchHierarchy(this);
             this._patchHierarchy(this);
             var enableInteraction = (settings.enableInteraction == null) ? true : settings.enableInteraction;
             var enableInteraction = (settings.enableInteraction == null) ? true : settings.enableInteraction;
             this._fitRenderingDevice = !settings.size;
             this._fitRenderingDevice = !settings.size;
@@ -11872,6 +11880,12 @@ var BABYLON;
                 skip = !this._bubbleNotifyPrimPointerObserver(targetPrim, BABYLON.PrimitivePointerInfo.PointerUp, eventData);
                 skip = !this._bubbleNotifyPrimPointerObserver(targetPrim, BABYLON.PrimitivePointerInfo.PointerUp, eventData);
             }
             }
             eventState.skipNextObservers = skip;
             eventState.skipNextObservers = skip;
+            if (!skip && (this._isFlagSet(BABYLON.SmartPropertyPrim.flagAllow3DEventsBelowCanvas) === false)) {
+                eventState.skipNextObservers = true;
+                if (eventData instanceof BABYLON.PointerInfoPre) {
+                    eventData.skipOnPointerObservable = true;
+                }
+            }
         };
         };
         Canvas2D.prototype._updatePointerInfo = function (eventData, localPosition) {
         Canvas2D.prototype._updatePointerInfo = function (eventData, localPosition) {
             var s = this.scale;
             var s = this.scale;
@@ -12426,6 +12440,23 @@ var BABYLON;
             enumerable: true,
             enumerable: true,
             configurable: true
             configurable: true
         });
         });
+        Object.defineProperty(Canvas2D.prototype, "allow3DEventBelowCanvas", {
+            /**
+             * If true is returned, pointerEvent occurring above the Canvas area also sent in 3D scene, if false they are not sent in the 3D Scene
+             */
+            get: function () {
+                return this._isFlagSet(BABYLON.SmartPropertyPrim.flagAllow3DEventsBelowCanvas);
+            },
+            /**
+             * Set true if you want pointerEvent occurring above the Canvas area to also be sent in the 3D scene.
+             * Set false if you don't want the Scene to get the events
+             */
+            set: function (value) {
+                this._changeFlags(BABYLON.SmartPropertyPrim.flagAllow3DEventsBelowCanvas, value);
+            },
+            enumerable: true,
+            configurable: true
+        });
         Canvas2D.prototype.createCanvasProfileInfoCanvas = function () {
         Canvas2D.prototype.createCanvasProfileInfoCanvas = function () {
             if (this._profilingCanvas) {
             if (this._profilingCanvas) {
                 return this._profilingCanvas;
                 return this._profilingCanvas;
@@ -13047,6 +13078,7 @@ var BABYLON;
          *  - designUseHorizAxis: you can set this member if you use designSize to specify which axis is priority to compute the scale when the ratio of the canvas' size is different from the designSize's one.
          *  - designUseHorizAxis: you can set this member if you use designSize to specify which axis is priority to compute the scale when the ratio of the canvas' size is different from the designSize's one.
          *  - cachingStrategy: either CACHESTRATEGY_TOPLEVELGROUPS, CACHESTRATEGY_ALLGROUPS, CACHESTRATEGY_CANVAS, CACHESTRATEGY_DONTCACHE. Please refer to their respective documentation for more information. Default is Canvas2D.CACHESTRATEGY_DONTCACHE
          *  - cachingStrategy: either CACHESTRATEGY_TOPLEVELGROUPS, CACHESTRATEGY_ALLGROUPS, CACHESTRATEGY_CANVAS, CACHESTRATEGY_DONTCACHE. Please refer to their respective documentation for more information. Default is Canvas2D.CACHESTRATEGY_DONTCACHE
          *  - enableInteraction: if true the pointer events will be listened and rerouted to the appropriate primitives of the Canvas2D through the Prim2DBase.onPointerEventObservable observable property. Default is true.
          *  - enableInteraction: if true the pointer events will be listened and rerouted to the appropriate primitives of the Canvas2D through the Prim2DBase.onPointerEventObservable observable property. Default is true.
+         *  - allow3DEventBelowCanvas: by default pointerEvent occurring above the Canvas will prevent to be also sent in the 3D Scene. If you set this setting to true, events will be sent both for Canvas and 3D Scene
          *  - isVisible: true if the canvas must be visible, false for hidden. Default is true.
          *  - isVisible: true if the canvas must be visible, false for hidden. Default is true.
          * - backgroundRoundRadius: the round radius of the background, either backgroundFill or backgroundBorder must be specified.
          * - backgroundRoundRadius: the round radius of the background, either backgroundFill or backgroundBorder must be specified.
          * - backgroundFill: the brush to use to create a background fill for the canvas. can be a string value (see BABYLON.Canvas2D.GetBrushFromString) or a IBrush2D instance.
          * - backgroundFill: the brush to use to create a background fill for the canvas. can be a string value (see BABYLON.Canvas2D.GetBrushFromString) or a IBrush2D instance.

Datei-Diff unterdrückt, da er zu groß ist
+ 23 - 23
dist/preview release/babylon.core.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1629 - 1536
dist/preview release/babylon.d.ts


Datei-Diff unterdrückt, da er zu groß ist
+ 35 - 35
dist/preview release/babylon.js


Datei-Diff unterdrückt, da er zu groß ist
+ 198 - 29
dist/preview release/babylon.max.js


Datei-Diff unterdrückt, da er zu groß ist
+ 34 - 34
dist/preview release/babylon.noworker.js


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

@@ -8,6 +8,7 @@
 - Canvas2D moved to a separate folder in main repo. Now you need to also include babylon.cavans2d.js to get Canvas@D feature ([deltakosh](https://github.com/deltakosh))
 - Canvas2D moved to a separate folder in main repo. Now you need to also include babylon.cavans2d.js to get Canvas@D feature ([deltakosh](https://github.com/deltakosh))
 
 
 ### Updates
 ### Updates
+- Added Node.getDirection ([abow](https://github.com/abow))
 - New ```Tools.CreateScreenshot``` function will capture all canvas data. Previous implementation is now called `CreateScreenshotUsingRenderTarget` ([deltakosh](https://github.com/deltakosh)) 
 - New ```Tools.CreateScreenshot``` function will capture all canvas data. Previous implementation is now called `CreateScreenshotUsingRenderTarget` ([deltakosh](https://github.com/deltakosh)) 
 - Cube textures are now cached by texture cache ([deltakosh](https://github.com/deltakosh)) 
 - Cube textures are now cached by texture cache ([deltakosh](https://github.com/deltakosh)) 
 - Added onAnimationEnd callback for `sprite.playAnimation` ([deltakosh](https://github.com/deltakosh)) 
 - Added onAnimationEnd callback for `sprite.playAnimation` ([deltakosh](https://github.com/deltakosh)) 

Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
materialsLibrary/dist/babylon.fireMaterial.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
materialsLibrary/dist/babylon.fireMaterial.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
materialsLibrary/dist/babylon.furMaterial.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
materialsLibrary/dist/babylon.furMaterial.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
materialsLibrary/dist/babylon.gradientMaterial.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
materialsLibrary/dist/babylon.gradientMaterial.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 17 - 4
materialsLibrary/dist/babylon.gridMaterial.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
materialsLibrary/dist/babylon.gridMaterial.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 6 - 4
materialsLibrary/dist/babylon.lavaMaterial.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
materialsLibrary/dist/babylon.lavaMaterial.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
materialsLibrary/dist/babylon.normalMaterial.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
materialsLibrary/dist/babylon.normalMaterial.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 2
materialsLibrary/dist/babylon.simpleMaterial.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
materialsLibrary/dist/babylon.simpleMaterial.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
materialsLibrary/dist/babylon.terrainMaterial.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
materialsLibrary/dist/babylon.terrainMaterial.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
materialsLibrary/dist/babylon.triPlanarMaterial.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
materialsLibrary/dist/babylon.triPlanarMaterial.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 81 - 4
materialsLibrary/dist/babylon.waterMaterial.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
materialsLibrary/dist/babylon.waterMaterial.min.js


+ 1 - 0
materialsLibrary/dist/dts/babylon.lavaMaterial.d.ts

@@ -11,6 +11,7 @@ declare module BABYLON {
         private _lastTime;
         private _lastTime;
         diffuseColor: Color3;
         diffuseColor: Color3;
         disableLighting: boolean;
         disableLighting: boolean;
+        maxSimultaneousLights: number;
         private _worldViewProjectionMatrix;
         private _worldViewProjectionMatrix;
         private _scaledDiffuse;
         private _scaledDiffuse;
         private _renderId;
         private _renderId;

+ 23 - 1
materialsLibrary/dist/dts/babylon.waterMaterial.d.ts

@@ -26,7 +26,19 @@ declare module BABYLON {
         */
         */
         bumpHeight: number;
         bumpHeight: number;
         /**
         /**
-        * @param {number}: The water color blended with the reflection and refraction samplers
+         * @param {boolean}: Add a smaller moving bump to less steady waves.
+         */
+        bumpSuperimpose: boolean;
+        /**
+         * @param {boolean}: Color refraction and reflection differently with .waterColor2 and .colorBlendFactor2. Non-linear (physically correct) fresnel.
+         */
+        fresnelSeparate: boolean;
+        /**
+         * @param {boolean}: bump Waves modify the reflection.
+         */
+        bumpAffectsReflection: boolean;
+        /**
+        * @param {number}: The water color blended with the refraction (near)
         */
         */
         waterColor: Color3;
         waterColor: Color3;
         /**
         /**
@@ -34,6 +46,14 @@ declare module BABYLON {
         */
         */
         colorBlendFactor: number;
         colorBlendFactor: number;
         /**
         /**
+         * @param {number}: The water color blended with the reflection (far)
+         */
+        waterColor2: Color3;
+        /**
+         * @param {number}: The blend factor related to the water color (reflection, far)
+         */
+        colorBlendFactor2: number;
+        /**
         * @param {number}: Represents the maximum length of a wave
         * @param {number}: Represents the maximum length of a wave
         */
         */
         waveLength: number;
         waveLength: number;
@@ -50,10 +70,12 @@ declare module BABYLON {
         private _renderId;
         private _renderId;
         private _defines;
         private _defines;
         private _cachedDefines;
         private _cachedDefines;
+        private _useLogarithmicDepth;
         /**
         /**
         * Constructor
         * Constructor
         */
         */
         constructor(name: string, scene: Scene, renderTargetSize?: Vector2);
         constructor(name: string, scene: Scene, renderTargetSize?: Vector2);
+        useLogarithmicDepth: boolean;
         refractionTexture: RenderTargetTexture;
         refractionTexture: RenderTargetTexture;
         reflectionTexture: RenderTargetTexture;
         reflectionTexture: RenderTargetTexture;
         addToRenderList(node: any): void;
         addToRenderList(node: any): void;

+ 44 - 26
materialsLibrary/materials/grid/babylon.gridmaterial.ts

@@ -4,60 +4,62 @@ module BABYLON {
     class GRIDMaterialDefines extends MaterialDefines {
     class GRIDMaterialDefines extends MaterialDefines {
         public TRANSPARENT = false;
         public TRANSPARENT = false;
 
 
+        public FOG = false;
+
         constructor() {
         constructor() {
             super();
             super();
             this._keys = Object.keys(this);
             this._keys = Object.keys(this);
         }
         }
     }
     }
-    
+
     /**
     /**
      * The grid materials allows you to wrap any shape with a grid.
      * The grid materials allows you to wrap any shape with a grid.
      * Colors are customizable.
      * Colors are customizable.
      */
      */
     export class GridMaterial extends BABYLON.Material {
     export class GridMaterial extends BABYLON.Material {
-        
+
         /**
         /**
          * Main color of the grid (e.g. between lines)
          * Main color of the grid (e.g. between lines)
          */
          */
         @serializeAsColor3()
         @serializeAsColor3()
         public mainColor = Color3.White();
         public mainColor = Color3.White();
-        
+
         /**
         /**
          * Color of the grid lines.
          * Color of the grid lines.
          */
          */
         @serializeAsColor3()
         @serializeAsColor3()
         public lineColor = Color3.Black();
         public lineColor = Color3.Black();
-        
+
         /**
         /**
          * The scale of the grid compared to unit.
          * The scale of the grid compared to unit.
          */
          */
         @serialize()
         @serialize()
         public gridRatio = 1.0;
         public gridRatio = 1.0;
-        
+
         /**
         /**
          * The frequency of thicker lines.
          * The frequency of thicker lines.
          */
          */
         @serialize()
         @serialize()
         public majorUnitFrequency = 10;
         public majorUnitFrequency = 10;
-        
+
         /**
         /**
          * The visibility of minor units in the grid.
          * The visibility of minor units in the grid.
          */
          */
         @serialize()
         @serialize()
         public minorUnitVisibility = 0.33;
         public minorUnitVisibility = 0.33;
-        
+
         /**
         /**
          * The grid opacity outside of the lines.
          * The grid opacity outside of the lines.
          */
          */
         @serialize()
         @serialize()
         public opacity = 1.0;
         public opacity = 1.0;
-        
+
         private _gridControl: Vector4 = new Vector4(this.gridRatio, this.majorUnitFrequency, this.minorUnitVisibility, this.opacity);
         private _gridControl: Vector4 = new Vector4(this.gridRatio, this.majorUnitFrequency, this.minorUnitVisibility, this.opacity);
-        
+
         private _renderId: number;
         private _renderId: number;
         private _defines = new GRIDMaterialDefines();
         private _defines = new GRIDMaterialDefines();
         private _cachedDefines = new GRIDMaterialDefines();
         private _cachedDefines = new GRIDMaterialDefines();
-        
+
         /**
         /**
          * constructor
          * constructor
          * @param name The name given to the material in order to identify it afterwards.
          * @param name The name given to the material in order to identify it afterwards.
@@ -66,14 +68,14 @@ module BABYLON {
         constructor(name: string, scene: Scene) {
         constructor(name: string, scene: Scene) {
             super(name, scene);
             super(name, scene);
         }
         }
-        
+
         /**
         /**
          * Returns wehter or not the grid requires alpha blending.
          * Returns wehter or not the grid requires alpha blending.
          */
          */
         public needAlphaBlending(): boolean {
         public needAlphaBlending(): boolean {
             return this.opacity < 1.0;
             return this.opacity < 1.0;
         }
         }
-          
+
         private _checkCache(scene: Scene, mesh?: AbstractMesh, useInstances?: boolean): boolean {
         private _checkCache(scene: Scene, mesh?: AbstractMesh, useInstances?: boolean): boolean {
             if (!mesh) {
             if (!mesh) {
                 return true;
                 return true;
@@ -112,6 +114,11 @@ module BABYLON {
                 this._defines.TRANSPARENT = true;
                 this._defines.TRANSPARENT = true;
             }
             }
 
 
+            // Fog
+            if (scene.fogEnabled && mesh && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE && this.fogEnabled) {
+                this._defines.FOG = true;
+            }
+
             // Get correct effect      
             // Get correct effect      
             if (!this._effect || !this._defines.isEqual(this._cachedDefines)) {
             if (!this._effect || !this._defines.isEqual(this._cachedDefines)) {
                 this._defines.cloneTo(this._cachedDefines);
                 this._defines.cloneTo(this._cachedDefines);
@@ -122,19 +129,19 @@ module BABYLON {
 
 
                 // Effect
                 // Effect
                 var shaderName = scene.getEngine().getCaps().standardDerivatives ? "grid" : "legacygrid";
                 var shaderName = scene.getEngine().getCaps().standardDerivatives ? "grid" : "legacygrid";
-                
+
                 // Defines
                 // Defines
                 var join = this._defines.toString();
                 var join = this._defines.toString();
                 this._effect = scene.getEngine().createEffect(shaderName,
                 this._effect = scene.getEngine().createEffect(shaderName,
                     attribs,
                     attribs,
-                    ["worldViewProjection", "mainColor", "lineColor", "gridControl"],
+                    ["worldViewProjection", "mainColor", "lineColor", "gridControl", "vFogInfos", "vFogColor", "world", "view"],
                     [],
                     [],
-                    join, 
-                    null, 
-                    this.onCompiled, 
+                    join,
+                    null,
+                    this.onCompiled,
                     this.onError);
                     this.onError);
             }
             }
-            
+
             if (!this._effect.isReady()) {
             if (!this._effect.isReady()) {
                 return false;
                 return false;
             }
             }
@@ -144,44 +151,55 @@ module BABYLON {
 
 
             return true;
             return true;
         }
         }
-        
+
         public bindOnlyWorldMatrix(world: Matrix): void {
         public bindOnlyWorldMatrix(world: Matrix): void {
             var scene = this.getScene();
             var scene = this.getScene();
 
 
             this._effect.setMatrix("worldViewProjection", world.multiply(scene.getTransformMatrix()));
             this._effect.setMatrix("worldViewProjection", world.multiply(scene.getTransformMatrix()));
+            this._effect.setMatrix("world", world);
+            this._effect.setMatrix("view", scene.getViewMatrix());
         }
         }
 
 
         public bind(world: Matrix, mesh?: Mesh): void {
         public bind(world: Matrix, mesh?: Mesh): void {
             var scene = this.getScene();
             var scene = this.getScene();
 
 
-            // Matrices        
+            // Matrices
             this.bindOnlyWorldMatrix(world);
             this.bindOnlyWorldMatrix(world);
-            
+
             // Uniforms
             // Uniforms
             if (scene.getCachedMaterial() !== (<BABYLON.Material>this)) {
             if (scene.getCachedMaterial() !== (<BABYLON.Material>this)) {
                 this._effect.setColor3("mainColor", this.mainColor);
                 this._effect.setColor3("mainColor", this.mainColor);
                 this._effect.setColor3("lineColor", this.lineColor);
                 this._effect.setColor3("lineColor", this.lineColor);
-                
+
                 this._gridControl.x = this.gridRatio;
                 this._gridControl.x = this.gridRatio;
                 this._gridControl.y = Math.round(this.majorUnitFrequency);
                 this._gridControl.y = Math.round(this.majorUnitFrequency);
                 this._gridControl.z = this.minorUnitVisibility;
                 this._gridControl.z = this.minorUnitVisibility;
                 this._gridControl.w = this.opacity;
                 this._gridControl.w = this.opacity;
                 this._effect.setVector4("gridControl", this._gridControl);
                 this._effect.setVector4("gridControl", this._gridControl);
             }
             }
+
+            // View
+            if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
+                this._effect.setMatrix("view", scene.getViewMatrix());
+            }
+
+            // Fog
+            MaterialHelper.BindFogParameters(scene, mesh, this._effect);
+
             super.bind(world, mesh);
             super.bind(world, mesh);
         }
         }
-        
+
         public dispose(forceDisposeEffect?: boolean): void {
         public dispose(forceDisposeEffect?: boolean): void {
             super.dispose(forceDisposeEffect);
             super.dispose(forceDisposeEffect);
         }
         }
-        
+
         public clone(name: string): GridMaterial {
         public clone(name: string): GridMaterial {
             return SerializationHelper.Clone(() => new GridMaterial(name, this.getScene()), this);
             return SerializationHelper.Clone(() => new GridMaterial(name, this.getScene()), this);
         }
         }
 
 
         public serialize(): any {
         public serialize(): any {
-            var serializationObject = SerializationHelper.Serialize(this); 
-            serializationObject.customType = "BABYLON.GridMaterial"; 
+            var serializationObject = SerializationHelper.Serialize(this);
+            serializationObject.customType = "BABYLON.GridMaterial";
             return serializationObject;
             return serializationObject;
         }
         }
 
 

+ 10 - 4
materialsLibrary/materials/grid/grid.fragment.fx

@@ -13,6 +13,8 @@ uniform vec4 gridControl;
 varying vec3 vPosition;
 varying vec3 vPosition;
 varying vec3 vNormal;
 varying vec3 vNormal;
 
 
+#include<fogFragmentDeclaration>
+
 float getVisibility(float position) {
 float getVisibility(float position) {
     // Major grid line every Frequency defined in material.
     // Major grid line every Frequency defined in material.
     float majorGridFrequency = gridControl.y;
     float majorGridFrequency = gridControl.y;
@@ -82,13 +84,17 @@ void main(void) {
     float grid = clamp(x + y + z, 0., 1.);
     float grid = clamp(x + y + z, 0., 1.);
     
     
     // Create the color.
     // Create the color.
-    vec3 gridColor = mix(mainColor, lineColor, grid);
+    vec3 color = mix(mainColor, lineColor, grid);
+
+#ifdef FOG
+    #include<fogFragment>
+#endif
 
 
 #ifdef TRANSPARENT
 #ifdef TRANSPARENT
-    float opacity = clamp(grid, 0.08, gridControl.w);
-    gl_FragColor = vec4(gridColor.rgb, opacity);
+    float opacity = clamp(grid, 0.08, color.w);
+    gl_FragColor = vec4(color.rgb, opacity);
 #else
 #else
     // Apply the color.
     // Apply the color.
-    gl_FragColor = vec4(gridColor.rgb, 1.0);
+    gl_FragColor = vec4(color.rgb, 1.0);
 #endif
 #endif
 }
 }

+ 11 - 0
materialsLibrary/materials/grid/grid.vertex.fx

@@ -6,12 +6,23 @@ attribute vec3 normal;
 
 
 // Uniforms
 // Uniforms
 uniform mat4 worldViewProjection;
 uniform mat4 worldViewProjection;
+uniform mat4 world;
+uniform mat4 view;
 
 
 // Varying
 // Varying
 varying vec3 vPosition;
 varying vec3 vPosition;
 varying vec3 vNormal;
 varying vec3 vNormal;
 
 
+#include<fogVertexDeclaration>
+
 void main(void) {
 void main(void) {
+
+    #ifdef FOG
+    vec4 worldPos = world * vec4(position, 1.0);
+    #endif
+
+    #include<fogVertex>
+
     gl_Position = worldViewProjection * vec4(position, 1.0);
     gl_Position = worldViewProjection * vec4(position, 1.0);
 
 
     vPosition = position;
     vPosition = position;

Datei-Diff unterdrückt, da er zu groß ist
+ 3987 - 11819
materialsLibrary/test/refs/babylon.max.js


+ 1 - 3
postProcessLibrary/postProcesses/asciiArt/babylon.asciiArtPostProcess.ts

@@ -1,6 +1,4 @@
- /// <reference path="../../../dist/preview release/babylon.d.ts"/>
- 
-module BABYLON {
+module BABYLON {
 
 
     /**
     /**
      * AsciiArtFontTexture is the helper class used to easily create your ascii art font texture.
      * AsciiArtFontTexture is the helper class used to easily create your ascii art font texture.

+ 1 - 3
postProcessLibrary/postProcesses/digitalRain/babylon.digitalRainPostProcess.ts

@@ -1,6 +1,4 @@
- /// <reference path="../../../dist/preview release/babylon.d.ts"/>
- 
-module BABYLON {
+module BABYLON {
 
 
     /**
     /**
      * DigitalRainFontTexture is the helper class used to easily create your digital rain font texture.
      * DigitalRainFontTexture is the helper class used to easily create your digital rain font texture.

+ 11 - 7
src/Cameras/VR/babylon.webVRCamera.js

@@ -16,6 +16,7 @@ var BABYLON;
             this._vrDevice = null;
             this._vrDevice = null;
             this._cacheState = null;
             this._cacheState = null;
             this._vrEnabled = false;
             this._vrEnabled = false;
+            this._attached = false;
             //enable VR
             //enable VR
             this.getEngine().initWebVR();
             this.getEngine().initWebVR();
             if (!this.getEngine().vrDisplaysPromise) {
             if (!this.getEngine().vrDisplaysPromise) {
@@ -24,6 +25,7 @@ var BABYLON;
             else {
             else {
                 //TODO get the metrics updated using the device's eye parameters!
                 //TODO get the metrics updated using the device's eye parameters!
                 //TODO also check that the device has the right capabilities!
                 //TODO also check that the device has the right capabilities!
+                this._frameData = new VRFrameData();
                 this.getEngine().vrDisplaysPromise.then(function (devices) {
                 this.getEngine().vrDisplaysPromise.then(function (devices) {
                     if (devices.length > 0) {
                     if (devices.length > 0) {
                         _this._vrEnabled = true;
                         _this._vrEnabled = true;
@@ -47,7 +49,10 @@ var BABYLON;
                             _this._vrDevice = devices[0];
                             _this._vrDevice = devices[0];
                         }
                         }
                         //reset the rig parameters.
                         //reset the rig parameters.
-                        _this.setCameraRigMode(BABYLON.Camera.RIG_MODE_WEBVR, { vrDisplay: _this._vrDevice });
+                        _this.setCameraRigMode(BABYLON.Camera.RIG_MODE_WEBVR, { vrDisplay: _this._vrDevice, frameData: _this._frameData });
+                        if (_this._attached) {
+                            _this.getEngine().enableVR(_this._vrDevice);
+                        }
                     }
                     }
                     else {
                     else {
                         BABYLON.Tools.Error("No WebVR devices found!");
                         BABYLON.Tools.Error("No WebVR devices found!");
@@ -58,25 +63,23 @@ var BABYLON;
             this._quaternionCache = new BABYLON.Quaternion();
             this._quaternionCache = new BABYLON.Quaternion();
         }
         }
         WebVRFreeCamera.prototype._checkInputs = function () {
         WebVRFreeCamera.prototype._checkInputs = function () {
-            if (this._vrEnabled) {
-                var currentPost = this._vrDevice.getPose();
+            if (this._vrEnabled && this._vrDevice.getFrameData(this._frameData)) {
+                var currentPost = this._frameData.pose;
                 //make sure we have data
                 //make sure we have data
                 if (currentPost && currentPost.orientation) {
                 if (currentPost && currentPost.orientation) {
                     this._cacheState = currentPost;
                     this._cacheState = currentPost;
-                    this.rotationQuaternion.copyFromFloats(this._cacheState.orientation[0], this._cacheState.orientation[1], this._cacheState.orientation[2], this._cacheState.orientation[3]);
+                    this.rotationQuaternion.copyFromFloats(this._cacheState.orientation[0], this._cacheState.orientation[1], -this._cacheState.orientation[2], -this._cacheState.orientation[3]);
                     if (this.webVROptions.trackPosition && this._cacheState.position) {
                     if (this.webVROptions.trackPosition && this._cacheState.position) {
                         this.position.copyFromFloats(this._cacheState.position[0], this._cacheState.position[1], -this._cacheState.position[2]);
                         this.position.copyFromFloats(this._cacheState.position[0], this._cacheState.position[1], -this._cacheState.position[2]);
                         this.webVROptions.positionScale && this.position.scaleInPlace(this.webVROptions.positionScale);
                         this.webVROptions.positionScale && this.position.scaleInPlace(this.webVROptions.positionScale);
                     }
                     }
-                    //Flip in XY plane
-                    this.rotationQuaternion.z *= -1;
-                    this.rotationQuaternion.w *= -1;
                 }
                 }
             }
             }
             _super.prototype._checkInputs.call(this);
             _super.prototype._checkInputs.call(this);
         };
         };
         WebVRFreeCamera.prototype.attachControl = function (element, noPreventDefault) {
         WebVRFreeCamera.prototype.attachControl = function (element, noPreventDefault) {
             _super.prototype.attachControl.call(this, element, noPreventDefault);
             _super.prototype.attachControl.call(this, element, noPreventDefault);
+            this._attached = true;
             noPreventDefault = BABYLON.Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
             noPreventDefault = BABYLON.Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
             if (this._vrEnabled) {
             if (this._vrEnabled) {
                 this.getEngine().enableVR(this._vrDevice);
                 this.getEngine().enableVR(this._vrDevice);
@@ -85,6 +88,7 @@ var BABYLON;
         WebVRFreeCamera.prototype.detachControl = function (element) {
         WebVRFreeCamera.prototype.detachControl = function (element) {
             _super.prototype.detachControl.call(this, element);
             _super.prototype.detachControl.call(this, element);
             this._vrEnabled = false;
             this._vrEnabled = false;
+            this._attached = false;
             this.getEngine().disableVR();
             this.getEngine().disableVR();
         };
         };
         WebVRFreeCamera.prototype.requestVRFullscreen = function (requestPointerlock) {
         WebVRFreeCamera.prototype.requestVRFullscreen = function (requestPointerlock) {

+ 15 - 8
src/Cameras/VR/babylon.webVRCamera.ts

@@ -1,5 +1,6 @@
 declare var HMDVRDevice;
 declare var HMDVRDevice;
 declare var VRDisplay;
 declare var VRDisplay;
+declare var VRFrameData;
 
 
 module BABYLON {
 module BABYLON {
 
 
@@ -13,10 +14,13 @@ module BABYLON {
         public _vrDevice = null;
         public _vrDevice = null;
         private _cacheState = null;
         private _cacheState = null;
         private _vrEnabled = false;
         private _vrEnabled = false;
+        private _attached: boolean = false;
 
 
         private _oldSize: BABYLON.Size;
         private _oldSize: BABYLON.Size;
         private _oldHardwareScaleFactor: number;
         private _oldHardwareScaleFactor: number;
 
 
+        private _frameData;
+
         private _quaternionCache: Quaternion;
         private _quaternionCache: Quaternion;
 
 
         constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = false, private webVROptions: WebVROptions = {}) {
         constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = false, private webVROptions: WebVROptions = {}) {
@@ -30,6 +34,7 @@ module BABYLON {
             } else {
             } else {
                 //TODO get the metrics updated using the device's eye parameters!
                 //TODO get the metrics updated using the device's eye parameters!
                 //TODO also check that the device has the right capabilities!
                 //TODO also check that the device has the right capabilities!
+                this._frameData = new VRFrameData();
                 this.getEngine().vrDisplaysPromise.then((devices) => {
                 this.getEngine().vrDisplaysPromise.then((devices) => {
                     if (devices.length > 0) {
                     if (devices.length > 0) {
                         this._vrEnabled = true;
                         this._vrEnabled = true;
@@ -52,7 +57,11 @@ module BABYLON {
                         }
                         }
 
 
                         //reset the rig parameters.
                         //reset the rig parameters.
-                        this.setCameraRigMode(Camera.RIG_MODE_WEBVR, { vrDisplay: this._vrDevice });
+                        this.setCameraRigMode(Camera.RIG_MODE_WEBVR, { vrDisplay: this._vrDevice, frameData: this._frameData });
+
+                        if (this._attached) {
+                            this.getEngine().enableVR(this._vrDevice)
+                        }
                     } else {
                     } else {
                         Tools.Error("No WebVR devices found!");
                         Tools.Error("No WebVR devices found!");
                     }
                     }
@@ -64,21 +73,17 @@ module BABYLON {
         }
         }
 
 
         public _checkInputs(): void {
         public _checkInputs(): void {
-            if (this._vrEnabled) {
-                var currentPost = this._vrDevice.getPose();
+            if (this._vrEnabled && this._vrDevice.getFrameData(this._frameData)) {
+                var currentPost = this._frameData.pose;
                 //make sure we have data
                 //make sure we have data
                 if (currentPost && currentPost.orientation) {
                 if (currentPost && currentPost.orientation) {
                     this._cacheState = currentPost;
                     this._cacheState = currentPost;
-                    this.rotationQuaternion.copyFromFloats(this._cacheState.orientation[0], this._cacheState.orientation[1], this._cacheState.orientation[2], this._cacheState.orientation[3]);
+                    this.rotationQuaternion.copyFromFloats(this._cacheState.orientation[0], this._cacheState.orientation[1], -this._cacheState.orientation[2], -this._cacheState.orientation[3]);
                     if (this.webVROptions.trackPosition && this._cacheState.position) {
                     if (this.webVROptions.trackPosition && this._cacheState.position) {
                         this.position.copyFromFloats(this._cacheState.position[0], this._cacheState.position[1], -this._cacheState.position[2]);
                         this.position.copyFromFloats(this._cacheState.position[0], this._cacheState.position[1], -this._cacheState.position[2]);
                         this.webVROptions.positionScale && this.position.scaleInPlace(this.webVROptions.positionScale)
                         this.webVROptions.positionScale && this.position.scaleInPlace(this.webVROptions.positionScale)
                     }
                     }
-                    //Flip in XY plane
-                    this.rotationQuaternion.z *= -1;
-                    this.rotationQuaternion.w *= -1;
                 }
                 }
-
             }
             }
 
 
             super._checkInputs();
             super._checkInputs();
@@ -86,6 +91,7 @@ module BABYLON {
 
 
         public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
         public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
             super.attachControl(element, noPreventDefault);
             super.attachControl(element, noPreventDefault);
+            this._attached = true;
 
 
             noPreventDefault = Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
             noPreventDefault = Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
 
 
@@ -97,6 +103,7 @@ module BABYLON {
         public detachControl(element: HTMLElement): void {
         public detachControl(element: HTMLElement): void {
             super.detachControl(element);
             super.detachControl(element);
             this._vrEnabled = false;
             this._vrEnabled = false;
+            this._attached = false;
             this.getEngine().disableVR();
             this.getEngine().disableVR();
         }
         }
 
 

+ 25 - 8
src/Cameras/babylon.camera.js

@@ -37,6 +37,7 @@ var BABYLON;
             this._projectionMatrix = new BABYLON.Matrix();
             this._projectionMatrix = new BABYLON.Matrix();
             this._postProcesses = new Array();
             this._postProcesses = new Array();
             this._transformMatrix = BABYLON.Matrix.Zero();
             this._transformMatrix = BABYLON.Matrix.Zero();
+            this._webvrViewMatrix = BABYLON.Matrix.Identity();
             this._activeMeshes = new BABYLON.SmartArray(256);
             this._activeMeshes = new BABYLON.SmartArray(256);
             this._globalPosition = BABYLON.Vector3.Zero();
             this._globalPosition = BABYLON.Vector3.Zero();
             this._refreshFrustumPlanes = true;
             this._refreshFrustumPlanes = true;
@@ -462,16 +463,18 @@ var BABYLON;
                     break;
                     break;
                 case Camera.RIG_MODE_WEBVR:
                 case Camera.RIG_MODE_WEBVR:
                     if (rigParams.vrDisplay) {
                     if (rigParams.vrDisplay) {
-                        var leftEye = rigParams.vrDisplay.getEyeParameters('left');
-                        var rightEye = rigParams.vrDisplay.getEyeParameters('right');
+                        //var leftEye = rigParams.vrDisplay.getEyeParameters('left');
+                        //var rightEye = rigParams.vrDisplay.getEyeParameters('right');
                         this._rigCameras[0].viewport = new BABYLON.Viewport(0, 0, 0.5, 1.0);
                         this._rigCameras[0].viewport = new BABYLON.Viewport(0, 0, 0.5, 1.0);
-                        this._rigCameras[0].setCameraRigParameter("vrFieldOfView", leftEye.fieldOfView);
-                        this._rigCameras[0].setCameraRigParameter("vrOffsetMatrix", BABYLON.Matrix.Translation(-leftEye.offset[0], leftEye.offset[1], -leftEye.offset[2]));
+                        this._rigCameras[0].setCameraRigParameter("left", true);
+                        this._rigCameras[0].setCameraRigParameter("frameData", rigParams.frameData);
+                        //this._rigCameras[0].setCameraRigParameter("vrOffsetMatrix", Matrix.Translation(-leftEye.offset[0], leftEye.offset[1], -leftEye.offset[2]));
                         this._rigCameras[0]._cameraRigParams.vrWorkMatrix = new BABYLON.Matrix();
                         this._rigCameras[0]._cameraRigParams.vrWorkMatrix = new BABYLON.Matrix();
                         this._rigCameras[0].getProjectionMatrix = this._getWebVRProjectionMatrix;
                         this._rigCameras[0].getProjectionMatrix = this._getWebVRProjectionMatrix;
+                        //this._rigCameras[0]._getViewMatrix = this._getWebVRViewMatrix;
                         this._rigCameras[1].viewport = new BABYLON.Viewport(0.5, 0, 0.5, 1.0);
                         this._rigCameras[1].viewport = new BABYLON.Viewport(0.5, 0, 0.5, 1.0);
-                        this._rigCameras[1].setCameraRigParameter("vrFieldOfView", rightEye.fieldOfView);
-                        this._rigCameras[1].setCameraRigParameter("vrOffsetMatrix", BABYLON.Matrix.Translation(-rightEye.offset[0], rightEye.offset[1], -rightEye.offset[2]));
+                        this._rigCameras[1].setCameraRigParameter("frameData", rigParams.frameData);
+                        //this._rigCameras[1].setCameraRigParameter("vrOffsetMatrix", Matrix.Translation(-rightEye.offset[0], rightEye.offset[1], -rightEye.offset[2]));
                         this._rigCameras[1]._cameraRigParams.vrWorkMatrix = new BABYLON.Matrix();
                         this._rigCameras[1]._cameraRigParams.vrWorkMatrix = new BABYLON.Matrix();
                         this._rigCameras[1].getProjectionMatrix = this._getWebVRProjectionMatrix;
                         this._rigCameras[1].getProjectionMatrix = this._getWebVRProjectionMatrix;
                     }
                     }
@@ -487,10 +490,24 @@ var BABYLON;
             return this._projectionMatrix;
             return this._projectionMatrix;
         };
         };
         Camera.prototype._getWebVRProjectionMatrix = function () {
         Camera.prototype._getWebVRProjectionMatrix = function () {
-            BABYLON.Matrix.PerspectiveFovWebVRToRef(this._cameraRigParams['vrFieldOfView'], this.minZ, this.maxZ, this._cameraRigParams.vrWorkMatrix);
-            this._cameraRigParams.vrWorkMatrix.multiplyToRef(this._cameraRigParams['vrOffsetMatrix'], this._projectionMatrix);
+            var projectionArray = this._cameraRigParams["left"] ? this._cameraRigParams["frameData"].leftProjectionMatrix : this._cameraRigParams["frameData"].rightProjectionMatrix;
+            //babylon compatible matrix
+            [8, 9, 10, 11].forEach(function (num) {
+                projectionArray[num] *= -1;
+            });
+            BABYLON.Matrix.FromArrayToRef(projectionArray, 0, this._projectionMatrix);
             return this._projectionMatrix;
             return this._projectionMatrix;
         };
         };
+        //Can be used, but we'll use the free camera's view matrix calculation
+        Camera.prototype._getWebVRViewMatrix = function () {
+            var projectionArray = this._cameraRigParams["left"] ? this._cameraRigParams["frameData"].leftViewMatrix : this._cameraRigParams["frameData"].rightViewMatrix;
+            //babylon compatible matrix
+            [8, 9, 10, 11].forEach(function (num) {
+                projectionArray[num] *= -1;
+            });
+            BABYLON.Matrix.FromArrayToRef(projectionArray, 0, this._webvrViewMatrix);
+            return this._webvrViewMatrix;
+        };
         Camera.prototype.setCameraRigParameter = function (name, value) {
         Camera.prototype.setCameraRigParameter = function (name, value) {
             if (!this._cameraRigParams) {
             if (!this._cameraRigParams) {
                 this._cameraRigParams = {};
                 this._cameraRigParams = {};

+ 27 - 8
src/Cameras/babylon.camera.ts

@@ -126,6 +126,7 @@
         private _worldMatrix: Matrix;
         private _worldMatrix: Matrix;
         public _postProcesses = new Array<PostProcess>();
         public _postProcesses = new Array<PostProcess>();
         private _transformMatrix = Matrix.Zero();
         private _transformMatrix = Matrix.Zero();
+        private _webvrViewMatrix = Matrix.Identity();
 
 
         public _activeMeshes = new SmartArray<Mesh>(256);
         public _activeMeshes = new SmartArray<Mesh>(256);
 
 
@@ -574,18 +575,21 @@
                     break;
                     break;
                 case Camera.RIG_MODE_WEBVR:
                 case Camera.RIG_MODE_WEBVR:
                     if (rigParams.vrDisplay) {
                     if (rigParams.vrDisplay) {
-                        var leftEye = rigParams.vrDisplay.getEyeParameters('left');
-                        var rightEye = rigParams.vrDisplay.getEyeParameters('right');
+                        //var leftEye = rigParams.vrDisplay.getEyeParameters('left');
+                        //var rightEye = rigParams.vrDisplay.getEyeParameters('right');
                         this._rigCameras[0].viewport = new Viewport(0, 0, 0.5, 1.0);
                         this._rigCameras[0].viewport = new Viewport(0, 0, 0.5, 1.0);
-                        this._rigCameras[0].setCameraRigParameter("vrFieldOfView", leftEye.fieldOfView);
-                        this._rigCameras[0].setCameraRigParameter("vrOffsetMatrix", Matrix.Translation(-leftEye.offset[0], leftEye.offset[1], -leftEye.offset[2]));
+                        this._rigCameras[0].setCameraRigParameter("left", true);
+                        this._rigCameras[0].setCameraRigParameter("frameData", rigParams.frameData);
+                        //this._rigCameras[0].setCameraRigParameter("vrOffsetMatrix", Matrix.Translation(-leftEye.offset[0], leftEye.offset[1], -leftEye.offset[2]));
                         this._rigCameras[0]._cameraRigParams.vrWorkMatrix = new Matrix();
                         this._rigCameras[0]._cameraRigParams.vrWorkMatrix = new Matrix();
                         this._rigCameras[0].getProjectionMatrix = this._getWebVRProjectionMatrix;
                         this._rigCameras[0].getProjectionMatrix = this._getWebVRProjectionMatrix;
+                        //this._rigCameras[0]._getViewMatrix = this._getWebVRViewMatrix;
                         this._rigCameras[1].viewport = new Viewport(0.5, 0, 0.5, 1.0);
                         this._rigCameras[1].viewport = new Viewport(0.5, 0, 0.5, 1.0);
-                        this._rigCameras[1].setCameraRigParameter("vrFieldOfView", rightEye.fieldOfView);
-                        this._rigCameras[1].setCameraRigParameter("vrOffsetMatrix", Matrix.Translation(-rightEye.offset[0], rightEye.offset[1], -rightEye.offset[2]));
+                        this._rigCameras[1].setCameraRigParameter("frameData", rigParams.frameData);
+                        //this._rigCameras[1].setCameraRigParameter("vrOffsetMatrix", Matrix.Translation(-rightEye.offset[0], rightEye.offset[1], -rightEye.offset[2]));
                         this._rigCameras[1]._cameraRigParams.vrWorkMatrix = new Matrix();
                         this._rigCameras[1]._cameraRigParams.vrWorkMatrix = new Matrix();
                         this._rigCameras[1].getProjectionMatrix = this._getWebVRProjectionMatrix;
                         this._rigCameras[1].getProjectionMatrix = this._getWebVRProjectionMatrix;
+                        //this._rigCameras[1]._getViewMatrix = this._getWebVRViewMatrix;
                     }
                     }
                     break;
                     break;
 
 
@@ -603,11 +607,26 @@
         }
         }
 
 
         private _getWebVRProjectionMatrix(): Matrix {
         private _getWebVRProjectionMatrix(): Matrix {
-            Matrix.PerspectiveFovWebVRToRef(this._cameraRigParams['vrFieldOfView'], this.minZ, this.maxZ, this._cameraRigParams.vrWorkMatrix);
-            this._cameraRigParams.vrWorkMatrix.multiplyToRef(this._cameraRigParams['vrOffsetMatrix'], this._projectionMatrix);
+            var projectionArray = this._cameraRigParams["left"] ? this._cameraRigParams["frameData"].leftProjectionMatrix : this._cameraRigParams["frameData"].rightProjectionMatrix;
+            //babylon compatible matrix
+            [8, 9, 10, 11].forEach(function (num) {
+                projectionArray[num] *= -1;
+            });
+            Matrix.FromArrayToRef(projectionArray, 0, this._projectionMatrix);
             return this._projectionMatrix;
             return this._projectionMatrix;
         }
         }
 
 
+        //Can be used, but we'll use the free camera's view matrix calculation
+        private _getWebVRViewMatrix(): Matrix {
+            var projectionArray = this._cameraRigParams["left"] ? this._cameraRigParams["frameData"].leftViewMatrix : this._cameraRigParams["frameData"].rightViewMatrix;
+            //babylon compatible matrix
+            [8, 9, 10, 11].forEach(function (num) {
+                projectionArray[num] *= -1;
+            });
+            Matrix.FromArrayToRef(projectionArray, 0, this._webvrViewMatrix);
+            return this._webvrViewMatrix;
+        }
+
         public setCameraRigParameter(name: string, value: any) {
         public setCameraRigParameter(name: string, value: any) {
             if (!this._cameraRigParams) {
             if (!this._cameraRigParams) {
                 this._cameraRigParams = {};
                 this._cameraRigParams = {};

+ 9 - 0
src/Materials/Textures/babylon.baseTexture.ts

@@ -33,6 +33,13 @@
         @serialize()
         @serialize()
         public isRenderTarget = false;
         public isRenderTarget = false;
 
 
+        public get uid(): string {
+            if (!this._uid) {
+                this._uid = Tools.RandomId();
+            }
+            return this._uid;
+        }
+
         public toString(): string {
         public toString(): string {
             return this.name;
             return this.name;
         }
         }
@@ -59,10 +66,12 @@
 
 
         private _scene: Scene;
         private _scene: Scene;
         public _texture: WebGLTexture;
         public _texture: WebGLTexture;
+        private _uid: string;
 
 
         constructor(scene: Scene) {
         constructor(scene: Scene) {
             this._scene = scene;
             this._scene = scene;
             this._scene.textures.push(this);
             this._scene.textures.push(this);
+            this._uid = null;
         }
         }
 
 
         public getScene(): Scene {
         public getScene(): Scene {

+ 9 - 0
src/Math/babylon.math.js

@@ -818,6 +818,15 @@ var BABYLON;
         Vector3.Up = function () {
         Vector3.Up = function () {
             return new Vector3(0, 1.0, 0);
             return new Vector3(0, 1.0, 0);
         };
         };
+        Vector3.Forward = function () {
+            return new Vector3(0, 0, 1.0);
+        };
+        Vector3.Right = function () {
+            return new Vector3(1.0, 0, 0);
+        };
+        Vector3.Left = function () {
+            return new Vector3(-1.0, 0, 0);
+        };
         Vector3.TransformCoordinates = function (vector, transformation) {
         Vector3.TransformCoordinates = function (vector, transformation) {
             var result = Vector3.Zero();
             var result = Vector3.Zero();
             Vector3.TransformCoordinatesToRef(vector, transformation, result);
             Vector3.TransformCoordinatesToRef(vector, transformation, result);

+ 12 - 0
src/Math/babylon.math.ts

@@ -1023,6 +1023,18 @@
             return new Vector3(0, 1.0, 0);
             return new Vector3(0, 1.0, 0);
         }
         }
 
 
+        public static Forward(): Vector3 {
+            return new Vector3(0, 0, 1.0);
+        }
+
+        public static Right(): Vector3 {
+            return new Vector3(1.0, 0, 0);
+        }
+
+        public static Left(): Vector3 {
+            return new Vector3(-1.0, 0, 0);
+        }
+
         public static TransformCoordinates(vector: Vector3, transformation: Matrix): Vector3 {
         public static TransformCoordinates(vector: Vector3, transformation: Matrix): Vector3 {
             var result = Vector3.Zero();
             var result = Vector3.Zero();
 
 

+ 14 - 13
src/Particles/babylon.solidParticleSystem.js

@@ -88,6 +88,8 @@ var BABYLON;
             this._maximum = BABYLON.Tmp.Vector3[1];
             this._maximum = BABYLON.Tmp.Vector3[1];
             this._scale = BABYLON.Tmp.Vector3[2];
             this._scale = BABYLON.Tmp.Vector3[2];
             this._translation = BABYLON.Tmp.Vector3[3];
             this._translation = BABYLON.Tmp.Vector3[3];
+            this._minBbox = BABYLON.Tmp.Vector3[4];
+            this._maxBbox = BABYLON.Tmp.Vector3[5];
             this._particlesIntersect = false;
             this._particlesIntersect = false;
             this.name = name;
             this.name = name;
             this._scene = scene;
             this._scene = scene;
@@ -137,7 +139,6 @@ var BABYLON;
             vertexData.applyToMesh(mesh, this._updatable);
             vertexData.applyToMesh(mesh, this._updatable);
             this.mesh = mesh;
             this.mesh = mesh;
             this.mesh.isPickable = this._pickable;
             this.mesh.isPickable = this._pickable;
-            this._wm = this.mesh.getWorldMatrix();
             // free memory
             // free memory
             this._positions = null;
             this._positions = null;
             this._normals = null;
             this._normals = null;
@@ -469,7 +470,7 @@ var BABYLON;
             // if the particles will always face the camera
             // if the particles will always face the camera
             if (this.billboard) {
             if (this.billboard) {
                 // compute the camera position and un-rotate it by the current mesh rotation
                 // compute the camera position and un-rotate it by the current mesh rotation
-                if (this._wm.decompose(this._scale, this._quaternion, this._translation)) {
+                if (this.mesh._worldMatrix.decompose(this._scale, this._quaternion, this._translation)) {
                     this._quaternionToRotationMatrix();
                     this._quaternionToRotationMatrix();
                     this._rotMatrix.invertToRef(this._invertMatrix);
                     this._rotMatrix.invertToRef(this._invertMatrix);
                     this._camera._currentTarget.subtractToRef(this._camera.globalPosition, this._camDir);
                     this._camera._currentTarget.subtractToRef(this._camera.globalPosition, this._camDir);
@@ -637,15 +638,15 @@ var BABYLON;
                     }
                     }
                     // place and scale the particle bouding sphere in the SPS local system
                     // place and scale the particle bouding sphere in the SPS local system
                     if (this._particle.isVisible) {
                     if (this._particle.isVisible) {
-                        this._minimum.x = this._particle._modelBoundingInfo.minimum.x * this._particle.scaling.x;
-                        this._minimum.y = this._particle._modelBoundingInfo.minimum.y * this._particle.scaling.y;
-                        this._minimum.z = this._particle._modelBoundingInfo.minimum.z * this._particle.scaling.z;
-                        this._maximum.x = this._particle._modelBoundingInfo.maximum.x * this._particle.scaling.x;
-                        this._maximum.y = this._particle._modelBoundingInfo.maximum.y * this._particle.scaling.y;
-                        this._maximum.z = this._particle._modelBoundingInfo.maximum.z * this._particle.scaling.z;
-                        bSphere.center.x = this._particle.position.x + (this._minimum.x + this._maximum.x) * 0.5;
-                        bSphere.center.y = this._particle.position.y + (this._minimum.y + this._maximum.y) * 0.5;
-                        bSphere.center.z = this._particle.position.z + (this._minimum.z + this._maximum.z) * 0.5;
+                        this._minBbox.x = this._particle._modelBoundingInfo.minimum.x * this._particle.scaling.x;
+                        this._minBbox.y = this._particle._modelBoundingInfo.minimum.y * this._particle.scaling.y;
+                        this._minBbox.z = this._particle._modelBoundingInfo.minimum.z * this._particle.scaling.z;
+                        this._maxBbox.x = this._particle._modelBoundingInfo.maximum.x * this._particle.scaling.x;
+                        this._maxBbox.y = this._particle._modelBoundingInfo.maximum.y * this._particle.scaling.y;
+                        this._maxBbox.z = this._particle._modelBoundingInfo.maximum.z * this._particle.scaling.z;
+                        bSphere.center.x = this._particle.position.x + (this._minBbox.x + this._maxBbox.x) * 0.5;
+                        bSphere.center.y = this._particle.position.y + (this._minBbox.y + this._maxBbox.y) * 0.5;
+                        bSphere.center.z = this._particle.position.z + (this._minBbox.z + this._maxBbox.z) * 0.5;
                         bSphere.radius = BABYLON.Vector3.Distance(this._minimum, this._maximum) * 0.5;
                         bSphere.radius = BABYLON.Vector3.Distance(this._minimum, this._maximum) * 0.5;
                     }
                     }
                     else {
                     else {
@@ -655,8 +656,8 @@ var BABYLON;
                         bSphere.radius = 0.0;
                         bSphere.radius = 0.0;
                     }
                     }
                     // then update the bbox and the bsphere into the world system
                     // then update the bbox and the bsphere into the world system
-                    bBox._update(this._wm);
-                    bSphere._update(this._wm);
+                    bBox._update(this.mesh._worldMatrix);
+                    bSphere._update(this.mesh._worldMatrix);
                 }
                 }
                 // increment indexes for the next particle
                 // increment indexes for the next particle
                 index = idx + 3;
                 index = idx + 3;

+ 14 - 15
src/Particles/babylon.solidParticleSystem.ts

@@ -108,9 +108,9 @@
         private _maximum: Vector3 = Tmp.Vector3[1];
         private _maximum: Vector3 = Tmp.Vector3[1];
         private _scale: Vector3 = Tmp.Vector3[2];
         private _scale: Vector3 = Tmp.Vector3[2];
         private _translation: Vector3 = Tmp.Vector3[3];
         private _translation: Vector3 = Tmp.Vector3[3];
+        private _minBbox: Vector3 = Tmp.Vector3[4];
+        private _maxBbox: Vector3 = Tmp.Vector3[5];
         private _particlesIntersect: boolean = false;
         private _particlesIntersect: boolean = false;
-        private _wm: Matrix;
-
 
 
         /**
         /**
         * Creates a SPS (Solid Particle System) object.
         * Creates a SPS (Solid Particle System) object.
@@ -168,7 +168,6 @@
             vertexData.applyToMesh(mesh, this._updatable);
             vertexData.applyToMesh(mesh, this._updatable);
             this.mesh = mesh;
             this.mesh = mesh;
             this.mesh.isPickable = this._pickable;
             this.mesh.isPickable = this._pickable;
-            this._wm = this.mesh.getWorldMatrix();
 
 
             // free memory
             // free memory
             this._positions = null;
             this._positions = null;
@@ -541,7 +540,7 @@
             // if the particles will always face the camera
             // if the particles will always face the camera
             if (this.billboard) {
             if (this.billboard) {
                 // compute the camera position and un-rotate it by the current mesh rotation
                 // compute the camera position and un-rotate it by the current mesh rotation
-                if (this._wm.decompose(this._scale, this._quaternion, this._translation)) {
+                if (this.mesh._worldMatrix.decompose(this._scale, this._quaternion, this._translation)) {
                     this._quaternionToRotationMatrix();
                     this._quaternionToRotationMatrix();
                     this._rotMatrix.invertToRef(this._invertMatrix);
                     this._rotMatrix.invertToRef(this._invertMatrix);
                     this._camera._currentTarget.subtractToRef(this._camera.globalPosition, this._camDir);
                     this._camera._currentTarget.subtractToRef(this._camera.globalPosition, this._camDir);
@@ -729,15 +728,15 @@
                     }
                     }
                     // place and scale the particle bouding sphere in the SPS local system
                     // place and scale the particle bouding sphere in the SPS local system
                     if (this._particle.isVisible) {
                     if (this._particle.isVisible) {
-                        this._minimum.x = this._particle._modelBoundingInfo.minimum.x * this._particle.scaling.x;
-                        this._minimum.y = this._particle._modelBoundingInfo.minimum.y * this._particle.scaling.y;
-                        this._minimum.z = this._particle._modelBoundingInfo.minimum.z * this._particle.scaling.z;
-                        this._maximum.x = this._particle._modelBoundingInfo.maximum.x * this._particle.scaling.x;
-                        this._maximum.y = this._particle._modelBoundingInfo.maximum.y * this._particle.scaling.y;
-                        this._maximum.z = this._particle._modelBoundingInfo.maximum.z * this._particle.scaling.z;
-                        bSphere.center.x = this._particle.position.x + (this._minimum.x + this._maximum.x) * 0.5;
-                        bSphere.center.y = this._particle.position.y + (this._minimum.y + this._maximum.y) * 0.5;
-                        bSphere.center.z = this._particle.position.z + (this._minimum.z + this._maximum.z) * 0.5;
+                        this._minBbox.x = this._particle._modelBoundingInfo.minimum.x * this._particle.scaling.x;
+                        this._minBbox.y = this._particle._modelBoundingInfo.minimum.y * this._particle.scaling.y;
+                        this._minBbox.z = this._particle._modelBoundingInfo.minimum.z * this._particle.scaling.z;
+                        this._maxBbox.x = this._particle._modelBoundingInfo.maximum.x * this._particle.scaling.x;
+                        this._maxBbox.y = this._particle._modelBoundingInfo.maximum.y * this._particle.scaling.y;
+                        this._maxBbox.z = this._particle._modelBoundingInfo.maximum.z * this._particle.scaling.z;
+                        bSphere.center.x = this._particle.position.x + (this._minBbox.x + this._maxBbox.x) * 0.5;
+                        bSphere.center.y = this._particle.position.y + (this._minBbox.y + this._maxBbox.y) * 0.5;
+                        bSphere.center.z = this._particle.position.z + (this._minBbox.z + this._maxBbox.z) * 0.5;
                         bSphere.radius = Vector3.Distance(this._minimum, this._maximum) * 0.5;
                         bSphere.radius = Vector3.Distance(this._minimum, this._maximum) * 0.5;
                     } else {
                     } else {
                         bSphere.center.x = this._camera.position.x;
                         bSphere.center.x = this._camera.position.x;
@@ -747,8 +746,8 @@
                     }
                     }
 
 
                     // then update the bbox and the bsphere into the world system
                     // then update the bbox and the bsphere into the world system
-                    bBox._update(this._wm);
-                    bSphere._update(this._wm);
+                    bBox._update(this.mesh._worldMatrix);
+                    bSphere._update(this.mesh._worldMatrix);
                 }
                 }
 
 
                 // increment indexes for the next particle
                 // increment indexes for the next particle

+ 44 - 0
src/Rendering/babylon.renderingManager.js

@@ -7,6 +7,7 @@ var BABYLON;
             this._customOpaqueSortCompareFn = {};
             this._customOpaqueSortCompareFn = {};
             this._customAlphaTestSortCompareFn = {};
             this._customAlphaTestSortCompareFn = {};
             this._customTransparentSortCompareFn = {};
             this._customTransparentSortCompareFn = {};
+            this._renderinGroupInfo = null;
             this._scene = scene;
             this._scene = scene;
             for (var i = RenderingManager.MIN_RENDERINGGROUPS; i < RenderingManager.MAX_RENDERINGGROUPS; i++) {
             for (var i = RenderingManager.MIN_RENDERINGGROUPS; i < RenderingManager.MAX_RENDERINGGROUPS; i++) {
                 this._autoClearDepthStencil[i] = true;
                 this._autoClearDepthStencil[i] = true;
@@ -66,6 +67,17 @@ var BABYLON;
             }
             }
         };
         };
         RenderingManager.prototype.render = function (customRenderFunction, activeMeshes, renderParticles, renderSprites) {
         RenderingManager.prototype.render = function (customRenderFunction, activeMeshes, renderParticles, renderSprites) {
+            // Check if there's at least on observer on the onRenderingGroupObservable and initialize things to fire it
+            var observable = this._scene.onRenderingGroupObservable.hasObservers() ? this._scene.onRenderingGroupObservable : null;
+            var info = null;
+            if (observable) {
+                if (!this._renderinGroupInfo) {
+                    this._renderinGroupInfo = new BABYLON.RenderingGroupInfo();
+                }
+                info = this._renderinGroupInfo;
+                info.scene = this._scene;
+                info.camera = this._scene.activeCamera;
+            }
             this._currentActiveMeshes = activeMeshes;
             this._currentActiveMeshes = activeMeshes;
             this._currentRenderParticles = renderParticles;
             this._currentRenderParticles = renderParticles;
             this._currentRenderSprites = renderSprites;
             this._currentRenderSprites = renderSprites;
@@ -75,20 +87,52 @@ var BABYLON;
                 var needToStepBack = false;
                 var needToStepBack = false;
                 this._currentIndex = index;
                 this._currentIndex = index;
                 if (renderingGroup) {
                 if (renderingGroup) {
+                    var renderingGroupMask = 0;
+                    // Fire PRECLEAR stage
+                    if (observable) {
+                        renderingGroupMask = Math.pow(2, index);
+                        info.renderStage = BABYLON.RenderingGroupInfo.STAGE_PRECLEAR;
+                        info.renderingGroupId = index;
+                        observable.notifyObservers(info, renderingGroupMask);
+                    }
+                    // Clear depth/stencil if needed
                     if (this._autoClearDepthStencil[index]) {
                     if (this._autoClearDepthStencil[index]) {
                         this._clearDepthStencilBuffer();
                         this._clearDepthStencilBuffer();
                     }
                     }
+                    // Fire PREOPAQUE stage
+                    if (observable) {
+                        info.renderStage = BABYLON.RenderingGroupInfo.STAGE_PREOPAQUE;
+                        observable.notifyObservers(info, renderingGroupMask);
+                    }
                     if (!renderingGroup.onBeforeTransparentRendering) {
                     if (!renderingGroup.onBeforeTransparentRendering) {
                         renderingGroup.onBeforeTransparentRendering = this._renderSpritesAndParticles.bind(this);
                         renderingGroup.onBeforeTransparentRendering = this._renderSpritesAndParticles.bind(this);
                     }
                     }
+                    // Fire PRETRANSPARENT stage
+                    if (observable) {
+                        info.renderStage = BABYLON.RenderingGroupInfo.STAGE_PRETRANSPARENT;
+                        observable.notifyObservers(info, renderingGroupMask);
+                    }
                     if (!renderingGroup.render(customRenderFunction)) {
                     if (!renderingGroup.render(customRenderFunction)) {
                         this._renderingGroups.splice(index, 1);
                         this._renderingGroups.splice(index, 1);
                         needToStepBack = true;
                         needToStepBack = true;
                         this._renderSpritesAndParticles();
                         this._renderSpritesAndParticles();
                     }
                     }
+                    // Fire POSTTRANSPARENT stage
+                    if (observable) {
+                        info.renderStage = BABYLON.RenderingGroupInfo.STAGE_POSTTRANSPARENT;
+                        observable.notifyObservers(info, renderingGroupMask);
+                    }
                 }
                 }
                 else {
                 else {
                     this._renderSpritesAndParticles();
                     this._renderSpritesAndParticles();
+                    if (observable) {
+                        var renderingGroupMask = Math.pow(2, index);
+                        info.renderStage = BABYLON.RenderingGroupInfo.STAGE_PRECLEAR;
+                        info.renderingGroupId = index;
+                        observable.notifyObservers(info, renderingGroupMask);
+                        info.renderStage = BABYLON.RenderingGroupInfo.STAGE_POSTTRANSPARENT;
+                        observable.notifyObservers(info, renderingGroupMask);
+                    }
                 }
                 }
                 if (needToStepBack) {
                 if (needToStepBack) {
                     index--;
                     index--;

+ 52 - 0
src/Rendering/babylon.renderingManager.ts

@@ -23,6 +23,7 @@
         private _customOpaqueSortCompareFn: { [id:number]: (a: SubMesh, b: SubMesh) => number } = {};
         private _customOpaqueSortCompareFn: { [id:number]: (a: SubMesh, b: SubMesh) => number } = {};
         private _customAlphaTestSortCompareFn: { [id:number]: (a: SubMesh, b: SubMesh) => number } = {};
         private _customAlphaTestSortCompareFn: { [id:number]: (a: SubMesh, b: SubMesh) => number } = {};
         private _customTransparentSortCompareFn: { [id:number]: (a: SubMesh, b: SubMesh) => number } = {};
         private _customTransparentSortCompareFn: { [id:number]: (a: SubMesh, b: SubMesh) => number } = {};
+        private _renderinGroupInfo: RenderingGroupInfo = null;
 
 
         constructor(scene: Scene) {
         constructor(scene: Scene) {
             this._scene = scene;
             this._scene = scene;
@@ -101,6 +102,18 @@
         public render(customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>) => void,
         public render(customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>) => void,
             activeMeshes: AbstractMesh[], renderParticles: boolean, renderSprites: boolean): void {
             activeMeshes: AbstractMesh[], renderParticles: boolean, renderSprites: boolean): void {
 
 
+            // Check if there's at least on observer on the onRenderingGroupObservable and initialize things to fire it
+            let observable = this._scene.onRenderingGroupObservable.hasObservers() ? this._scene.onRenderingGroupObservable : null;
+            let info: RenderingGroupInfo = null;
+            if (observable) {
+                if (!this._renderinGroupInfo) {
+                    this._renderinGroupInfo = new RenderingGroupInfo();
+                }
+                info = this._renderinGroupInfo;
+                info.scene = this._scene;
+                info.camera = this._scene.activeCamera;
+            }
+
             this._currentActiveMeshes = activeMeshes;
             this._currentActiveMeshes = activeMeshes;
             this._currentRenderParticles = renderParticles;
             this._currentRenderParticles = renderParticles;
             this._currentRenderSprites = renderSprites;
             this._currentRenderSprites = renderSprites;
@@ -113,21 +126,60 @@
                 this._currentIndex = index;
                 this._currentIndex = index;
 
 
                 if (renderingGroup) {
                 if (renderingGroup) {
+                    let renderingGroupMask = 0;
+
+                    // Fire PRECLEAR stage
+                    if (observable) {
+                        renderingGroupMask = Math.pow(2, index);
+                        info.renderStage = RenderingGroupInfo.STAGE_PRECLEAR;
+                        info.renderingGroupId = index;
+                        observable.notifyObservers(info, renderingGroupMask);
+                    }
+
+                    // Clear depth/stencil if needed
                     if (this._autoClearDepthStencil[index]) {
                     if (this._autoClearDepthStencil[index]) {
                         this._clearDepthStencilBuffer();
                         this._clearDepthStencilBuffer();
                     }
                     }
 
 
+                    // Fire PREOPAQUE stage
+                    if (observable) {
+                        info.renderStage = RenderingGroupInfo.STAGE_PREOPAQUE;
+                        observable.notifyObservers(info, renderingGroupMask);
+                    }
+
                     if (!renderingGroup.onBeforeTransparentRendering) {
                     if (!renderingGroup.onBeforeTransparentRendering) {
                         renderingGroup.onBeforeTransparentRendering = this._renderSpritesAndParticles.bind(this);
                         renderingGroup.onBeforeTransparentRendering = this._renderSpritesAndParticles.bind(this);
                     }
                     }
 
 
+                    // Fire PRETRANSPARENT stage
+                    if (observable) {
+                        info.renderStage = RenderingGroupInfo.STAGE_PRETRANSPARENT;
+                        observable.notifyObservers(info, renderingGroupMask);
+                    }
+
                     if (!renderingGroup.render(customRenderFunction)) {
                     if (!renderingGroup.render(customRenderFunction)) {
                         this._renderingGroups.splice(index, 1);
                         this._renderingGroups.splice(index, 1);
                         needToStepBack = true;
                         needToStepBack = true;
                         this._renderSpritesAndParticles();
                         this._renderSpritesAndParticles();
                     }
                     }
+
+                    // Fire POSTTRANSPARENT stage
+                    if (observable) {
+                        info.renderStage = RenderingGroupInfo.STAGE_POSTTRANSPARENT;
+                        observable.notifyObservers(info, renderingGroupMask);
+                    }
                 } else {
                 } else {
                     this._renderSpritesAndParticles();
                     this._renderSpritesAndParticles();
+
+                    if (observable) {
+                        let renderingGroupMask = Math.pow(2, index);
+                        info.renderStage = RenderingGroupInfo.STAGE_PRECLEAR;
+                        info.renderingGroupId = index;
+                        observable.notifyObservers(info, renderingGroupMask);
+
+                        info.renderStage = RenderingGroupInfo.STAGE_POSTTRANSPARENT;
+                        observable.notifyObservers(info, renderingGroupMask);
+                    }
                 }
                 }
 
 
                 if (needToStepBack) {
                 if (needToStepBack) {

+ 8 - 0
src/babylon.node.js

@@ -273,6 +273,14 @@ var BABYLON;
         Node.prototype.dispose = function () {
         Node.prototype.dispose = function () {
             this.parent = null;
             this.parent = null;
         };
         };
+        Node.prototype.getDirection = function (localAxis) {
+            var result = BABYLON.Vector3.Zero();
+            this.getDirectionToRef(localAxis, result);
+            return result;
+        };
+        Node.prototype.getDirectionToRef = function (localAxis, result) {
+            BABYLON.Vector3.TransformNormalToRef(localAxis, this.getWorldMatrix(), result);
+        };
         Node.ParseAnimationRanges = function (node, parsedNode, scene) {
         Node.ParseAnimationRanges = function (node, parsedNode, scene) {
             if (parsedNode.ranges) {
             if (parsedNode.ranges) {
                 for (var index = 0; index < parsedNode.ranges.length; index++) {
                 for (var index = 0; index < parsedNode.ranges.length; index++) {

+ 12 - 0
src/babylon.node.ts

@@ -343,6 +343,18 @@
             this.parent = null;
             this.parent = null;
         }
         }
 
 
+        public getDirection(localAxis:BABYLON.Vector3): BABYLON.Vector3 {
+            var result = BABYLON.Vector3.Zero();
+
+            this.getDirectionToRef(localAxis, result);
+            
+            return result;
+        }
+
+        public getDirectionToRef(localAxis:BABYLON.Vector3, result:BABYLON.Vector3): void {
+            BABYLON.Vector3.TransformNormalToRef(localAxis, this.getWorldMatrix(), result);
+        }
+
         public static ParseAnimationRanges(node: Node, parsedNode: any, scene: Scene): void {
         public static ParseAnimationRanges(node: Node, parsedNode: any, scene: Scene): void {
             if (parsedNode.ranges) {
             if (parsedNode.ranges) {
                 for (var index = 0; index < parsedNode.ranges.length; index++) {
                 for (var index = 0; index < parsedNode.ranges.length; index++) {

+ 86 - 0
src/babylon.scene.js

@@ -87,6 +87,35 @@ var BABYLON;
     }(PointerInfoBase));
     }(PointerInfoBase));
     BABYLON.PointerInfo = PointerInfo;
     BABYLON.PointerInfo = PointerInfo;
     /**
     /**
+     * This class is used by the onRenderingGroupObservable
+     */
+    var RenderingGroupInfo = (function () {
+        function RenderingGroupInfo() {
+        }
+        /**
+         * Stage corresponding to the very first hook in the renderingGroup phase: before the render buffer may be cleared
+         * This stage will be fired no matter what
+         */
+        RenderingGroupInfo.STAGE_PRECLEAR = 1;
+        /**
+         * Called before opaque object are rendered.
+         * This stage will be fired only if there's 3D Opaque content to render
+         */
+        RenderingGroupInfo.STAGE_PREOPAQUE = 2;
+        /**
+         * Called after the opaque objects are rendered and before the transparent ones
+         * This stage will be fired only if there's 3D transparent content to render
+         */
+        RenderingGroupInfo.STAGE_PRETRANSPARENT = 3;
+        /**
+         * Called after the transparent object are rendered, last hook of the renderingGroup phase
+         * This stage will be fired no matter what
+         */
+        RenderingGroupInfo.STAGE_POSTTRANSPARENT = 4;
+        return RenderingGroupInfo;
+    }());
+    BABYLON.RenderingGroupInfo = RenderingGroupInfo;
+    /**
      * Represents a scene to be rendered by the engine.
      * Represents a scene to be rendered by the engine.
      * @see http://doc.babylonjs.com/page.php?p=21911
      * @see http://doc.babylonjs.com/page.php?p=21911
      */
      */
@@ -178,6 +207,12 @@ var BABYLON;
             * @type {BABYLON.Observable}
             * @type {BABYLON.Observable}
             */
             */
             this.onMeshRemovedObservable = new BABYLON.Observable();
             this.onMeshRemovedObservable = new BABYLON.Observable();
+            /**
+             * This Observable will be triggered for each stage of each renderingGroup of each rendered camera.
+             * The RenderinGroupInfo class contains all the information about the context in which the observable is called
+             * If you wish to register an Observer only for a given set of renderingGroup, use the mask with a combination of the renderingGroup index elevated to the power of two (1 for renderingGroup 0, 2 for renderingrOup1, 4 for 2 and 8 for 3)
+             */
+            this.onRenderingGroupObservable = new BABYLON.Observable();
             // Animations
             // Animations
             this.animations = [];
             this.animations = [];
             /**
             /**
@@ -311,6 +346,8 @@ var BABYLON;
             this._uniqueIdCounter = 0;
             this._uniqueIdCounter = 0;
             this._engine = engine;
             this._engine = engine;
             engine.scenes.push(this);
             engine.scenes.push(this);
+            this._externalData = new BABYLON.StringDictionary();
+            this._uid = null;
             this._renderingManager = new BABYLON.RenderingManager(this);
             this._renderingManager = new BABYLON.RenderingManager(this);
             this.postProcessManager = new BABYLON.PostProcessManager(this);
             this.postProcessManager = new BABYLON.PostProcessManager(this);
             this.postProcessRenderPipelineManager = new BABYLON.PostProcessRenderPipelineManager();
             this.postProcessRenderPipelineManager = new BABYLON.PostProcessRenderPipelineManager();
@@ -1538,6 +1575,55 @@ var BABYLON;
         Scene.prototype.isActiveMesh = function (mesh) {
         Scene.prototype.isActiveMesh = function (mesh) {
             return (this._activeMeshes.indexOf(mesh) !== -1);
             return (this._activeMeshes.indexOf(mesh) !== -1);
         };
         };
+        Object.defineProperty(Scene.prototype, "uid", {
+            /**
+             * Return a unique id as a string which can serve as an identifier for the scene
+             */
+            get: function () {
+                if (!this._uid) {
+                    this._uid = BABYLON.Tools.RandomId();
+                }
+                return this._uid;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        /**
+         * Add an externaly attached data from its key.
+         * This method call will fail and return false, if such key already exists.
+         * If you don't care and just want to get the data no matter what, use the more convenient getOrAddExternalDataWithFactory() method.
+         * @param key the unique key that identifies the data
+         * @param data the data object to associate to the key for this Engine instance
+         * @return true if no such key were already present and the data was added successfully, false otherwise
+         */
+        Scene.prototype.addExternalData = function (key, data) {
+            return this._externalData.add(key, data);
+        };
+        /**
+         * Get an externaly attached data from its key
+         * @param key the unique key that identifies the data
+         * @return the associated data, if present (can be null), or undefined if not present
+         */
+        Scene.prototype.getExternalData = function (key) {
+            return this._externalData.get(key);
+        };
+        /**
+         * Get an externaly attached data from its key, create it using a factory if it's not already present
+         * @param key the unique key that identifies the data
+         * @param factory the factory that will be called to create the instance if and only if it doesn't exists
+         * @return the associated data, can be null if the factory returned null.
+         */
+        Scene.prototype.getOrAddExternalDataWithFactory = function (key, factory) {
+            return this._externalData.getOrAddWithFactory(key, factory);
+        };
+        /**
+         * Remove an externaly attached data from the Engine instance
+         * @param key the unique key that identifies the data
+         * @return true if the data was successfully removed, false if it doesn't exist
+         */
+        Scene.prototype.removeExternalData = function (key) {
+            return this._externalData.remove(key);
+        };
         Scene.prototype._evaluateSubMesh = function (subMesh, mesh) {
         Scene.prototype._evaluateSubMesh = function (subMesh, mesh) {
             if (mesh.alwaysSelectAsActiveMesh || mesh.subMeshes.length === 1 || subMesh.isInFrustum(this._frustumPlanes)) {
             if (mesh.alwaysSelectAsActiveMesh || mesh.subMeshes.length === 1 || subMesh.isInFrustum(this._frustumPlanes)) {
                 var material = subMesh.getMaterial();
                 var material = subMesh.getMaterial();

+ 112 - 0
src/babylon.scene.ts

@@ -63,6 +63,55 @@
     }
     }
 
 
     /**
     /**
+     * This class is used by the onRenderingGroupObservable
+     */
+    export class RenderingGroupInfo {
+        /**
+         * The Scene that being rendered
+         */
+        scene: Scene;
+
+        /**
+         * The camera currently used for the rendering pass
+         */
+        camera: Camera;
+
+        /**
+         * The ID of the renderingGroup being processed
+         */
+        renderingGroupId: number;
+
+        /**
+         * The rendering stage, can be either STAGE_PRECLEAR, STAGE_PREOPAQUE, STAGE_PRETRANSPARENT, STAGE_POSTTRANSPARENT
+         */
+        renderStage: number;
+
+        /**
+         * Stage corresponding to the very first hook in the renderingGroup phase: before the render buffer may be cleared
+         * This stage will be fired no matter what
+         */
+        static STAGE_PRECLEAR = 1;
+
+        /**
+         * Called before opaque object are rendered.
+         * This stage will be fired only if there's 3D Opaque content to render
+         */
+        static STAGE_PREOPAQUE = 2;
+
+        /**
+         * Called after the opaque objects are rendered and before the transparent ones
+         * This stage will be fired only if there's 3D transparent content to render
+         */
+        static STAGE_PRETRANSPARENT = 3;
+
+        /**
+         * Called after the transparent object are rendered, last hook of the renderingGroup phase
+         * This stage will be fired no matter what
+         */
+        static STAGE_POSTTRANSPARENT = 4;
+    }
+
+    /**
      * Represents a scene to be rendered by the engine.
      * Represents a scene to be rendered by the engine.
      * @see http://doc.babylonjs.com/page.php?p=21911
      * @see http://doc.babylonjs.com/page.php?p=21911
      */
      */
@@ -234,6 +283,13 @@
         */
         */
         public onMeshRemovedObservable = new Observable<AbstractMesh>();
         public onMeshRemovedObservable = new Observable<AbstractMesh>();
 
 
+        /**
+         * This Observable will be triggered for each stage of each renderingGroup of each rendered camera.
+         * The RenderinGroupInfo class contains all the information about the context in which the observable is called
+         * If you wish to register an Observer only for a given set of renderingGroup, use the mask with a combination of the renderingGroup index elevated to the power of two (1 for renderingGroup 0, 2 for renderingrOup1, 4 for 2 and 8 for 3)
+         */
+        public onRenderingGroupObservable = new Observable<RenderingGroupInfo>();
+
         // Animations
         // Animations
         public animations: Animation[] = [];
         public animations: Animation[] = [];
 
 
@@ -496,6 +552,9 @@
 
 
         private _pickedDownMesh: AbstractMesh;
         private _pickedDownMesh: AbstractMesh;
         private _pickedDownSprite: Sprite;
         private _pickedDownSprite: Sprite;
+        private _externalData: StringDictionary<Object>;
+        private _uid: string;
+
 
 
         /**
         /**
          * @constructor
          * @constructor
@@ -506,6 +565,9 @@
 
 
             engine.scenes.push(this);
             engine.scenes.push(this);
 
 
+            this._externalData = new StringDictionary<Object>();
+            this._uid = null;
+
             this._renderingManager = new RenderingManager(this);
             this._renderingManager = new RenderingManager(this);
 
 
             this.postProcessManager = new PostProcessManager(this);
             this.postProcessManager = new PostProcessManager(this);
@@ -1812,6 +1874,56 @@
             return (this._activeMeshes.indexOf(mesh) !== -1);
             return (this._activeMeshes.indexOf(mesh) !== -1);
         }
         }
 
 
+        /**
+         * Return a unique id as a string which can serve as an identifier for the scene
+         */
+        public get uid(): string {
+            if (!this._uid) {
+                this._uid = Tools.RandomId();
+            }
+            return this._uid;
+        }
+
+        /**
+         * Add an externaly attached data from its key.
+         * This method call will fail and return false, if such key already exists.
+         * If you don't care and just want to get the data no matter what, use the more convenient getOrAddExternalDataWithFactory() method.
+         * @param key the unique key that identifies the data
+         * @param data the data object to associate to the key for this Engine instance
+         * @return true if no such key were already present and the data was added successfully, false otherwise
+         */
+        public addExternalData<T>(key: string, data: T): boolean {
+            return this._externalData.add(key, data);
+        }
+
+        /**
+         * Get an externaly attached data from its key
+         * @param key the unique key that identifies the data
+         * @return the associated data, if present (can be null), or undefined if not present
+         */
+        public getExternalData<T>(key: string): T {
+            return <T>this._externalData.get(key);
+        }
+
+        /**
+         * Get an externaly attached data from its key, create it using a factory if it's not already present
+         * @param key the unique key that identifies the data
+         * @param factory the factory that will be called to create the instance if and only if it doesn't exists
+         * @return the associated data, can be null if the factory returned null.
+         */
+        public getOrAddExternalDataWithFactory<T>(key: string, factory: (k: string) => T): T {
+            return <T>this._externalData.getOrAddWithFactory(key, factory);
+        }
+
+        /**
+         * Remove an externaly attached data from the Engine instance
+         * @param key the unique key that identifies the data
+         * @return true if the data was successfully removed, false if it doesn't exist
+         */
+        public removeExternalData(key): boolean {
+            return this._externalData.remove(key);
+        }
+
         private _evaluateSubMesh(subMesh: SubMesh, mesh: AbstractMesh): void {
         private _evaluateSubMesh(subMesh: SubMesh, mesh: AbstractMesh): void {
             if (mesh.alwaysSelectAsActiveMesh || mesh.subMeshes.length === 1 || subMesh.isInFrustum(this._frustumPlanes)) {
             if (mesh.alwaysSelectAsActiveMesh || mesh.subMeshes.length === 1 || subMesh.isInFrustum(this._frustumPlanes)) {
                 var material = subMesh.getMaterial();
                 var material = subMesh.getMaterial();