浏览代码

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

# Conflicts:
#	dist/preview release/inspector/babylon.inspector.bundle.js.map
Jaskar 7 年之前
父节点
当前提交
138eec3811
共有 57 个文件被更改,包括 4690 次插入2527 次删除
  1. 778 453
      Playground/babylon.d.txt
  2. 2 1
      Tools/Gulp/config.json
  3. 16 13
      Viewer/dist/basicExample.html
  4. 3 1
      Viewer/src/configuration/types/default.ts
  5. 2 2
      Viewer/src/viewer/defaultViewer.ts
  6. 943 673
      dist/preview release/babylon.d.ts
  7. 1 1
      dist/preview release/babylon.js
  8. 614 270
      dist/preview release/babylon.max.js
  9. 614 270
      dist/preview release/babylon.no-module.max.js
  10. 1 1
      dist/preview release/babylon.worker.js
  11. 616 272
      dist/preview release/es6.js
  12. 1 1
      dist/preview release/glTF2Interface/package.json
  13. 1 1
      dist/preview release/gui/babylon.gui.min.js.map
  14. 1 1
      dist/preview release/gui/package.json
  15. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js.map
  16. 1 1
      dist/preview release/inspector/package.json
  17. 2 2
      dist/preview release/loaders/package.json
  18. 1 1
      dist/preview release/materialsLibrary/package.json
  19. 1 1
      dist/preview release/postProcessesLibrary/package.json
  20. 1 1
      dist/preview release/proceduralTexturesLibrary/package.json
  21. 2 2
      dist/preview release/serializers/package.json
  22. 4 4
      dist/preview release/viewer/babylon.viewer.d.ts
  23. 3 3
      dist/preview release/viewer/babylon.viewer.js
  24. 5 5
      dist/preview release/viewer/babylon.viewer.max.js
  25. 4 4
      dist/preview release/viewer/babylon.viewer.module.d.ts
  26. 226 221
      dist/preview release/what's new.md
  27. 2 2
      package.json
  28. 2 0
      src/Actions/babylon.action.ts
  29. 11 7
      src/Behaviors/Mesh/babylon.pointerDragBehavior.ts
  30. 4 0
      src/Behaviors/Mesh/babylon.sixDofDragBehavior.ts
  31. 18 0
      src/Cameras/VR/babylon.webVRCamera.ts
  32. 1 1
      src/Engine/babylon.engine.ts
  33. 35 29
      src/Gizmos/babylon.boundingBoxGizmo.ts
  34. 4 0
      src/Instrumentation/babylon.sceneInstrumentation.ts
  35. 4 1
      src/Materials/Textures/Procedurals/babylon.noiseProceduralTexture.ts
  36. 14 1
      src/Materials/Textures/Procedurals/babylon.proceduralTexture.ts
  37. 9 1
      src/Mesh/babylon.mesh.ts
  38. 96 7
      src/Particles/babylon.IParticleSystem.ts
  39. 22 1
      src/Particles/babylon.baseParticleSystem.ts
  40. 37 3
      src/Particles/babylon.gpuParticleSystem.ts
  41. 9 2
      src/Particles/babylon.particleHelper.ts
  42. 122 17
      src/Particles/babylon.particleSystem.ts
  43. 2 2
      src/PostProcess/babylon.postProcess.ts
  44. 2 2
      src/Rendering/babylon.renderingGroup.ts
  45. 2 2
      src/Rendering/babylon.renderingManager.ts
  46. 1 1
      src/Rendering/babylon.utilityLayerRenderer.ts
  47. 7 1
      src/Shaders/gpuRenderParticles.fragment.fx
  48. 7 22
      src/Shaders/gpuUpdateParticles.vertex.fx
  49. 1 2
      src/Shaders/noise.fragment.fx
  50. 7 2
      src/Shaders/particles.fragment.fx
  51. 2 2
      src/Sprites/babylon.sprite.ts
  52. 46 1
      src/Sprites/babylon.spriteManager.ts
  53. 297 0
      src/Sprites/babylon.spriteSceneComponent.ts
  54. 10 4
      src/Tools/babylon.filesInput.ts
  55. 8 0
      src/Tools/babylon.tools.ts
  56. 49 208
      src/babylon.scene.ts
  57. 15 0
      src/babylon.sceneComponent.ts

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


+ 2 - 1
Tools/Gulp/config.json

@@ -411,7 +411,8 @@
         "sprites": {
             "files": [
                 "../../src/Sprites/babylon.spriteManager.js",
-                "../../src/Sprites/babylon.sprite.js"
+                "../../src/Sprites/babylon.sprite.js",
+                "../../src/Sprites/babylon.spriteSceneComponent.js"
             ],
             "dependUpon": [
                 "core"

+ 16 - 13
Viewer/dist/basicExample.html

@@ -8,27 +8,30 @@
         <title>BabylonJS Viewer - Basic usage</title>
         <style>
             babylon {
-                max-width: 800px;
-                max-height: 500px;
-                width: 100%;
-                height: 600px;
+                width: 300px;
+                height: 200px;
             }
         </style>
     </head>
 
     <body>
-        <babylon id="babylon-viewer" configuration="config.json" model.title="Damaged Helmet" model.subtitle="BabylonJS" model.thumbnail="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png"
-            model.url="https://www.babylonjs.com/Assets/DamagedHelmet/glTF/DamagedHelmet.gltf" camera.behaviors.auto-rotate="0"
-            templates.nav-bar.params.disable-on-fullscreen="true"></babylon>
+        <babylon id="babylon-viewer" model="https://models.babylonjs.com/boombox.glb">
+            <!-- Setting the vr object (or vr="true" in the <babylon tag) is enough to enable VR.
+                 The object-scale-factor is optional an can be used to scale the model in VR mode.
+                 If setting "2", the model will be twice the size of its normalized size.
+            -->
+            <vr object-scale-factor="2">
+            </vr>
+            <!-- This is needed in order to show the VR button. It is also possible to toggleVR() using javascript -->
+            <templates>
+                <nav-bar>
+                    <params hide-vr="false"></params>
+                </nav-bar>
+            </templates>
+        </babylon>
         <script src="viewer.js"></script>
         <script>
-            // The following lines are redundant. 
-            // They are only here to show how you could achive the tag initialization on your own.
 
-            // a simple way of disabling auto init 
-            BabylonViewer.disableInit = true;
-            // Initializing the viewer on specific HTML tags.
-            BabylonViewer.InitTags('babylon');
         </script>
     </body>
 

+ 3 - 1
Viewer/src/configuration/types/default.ts

@@ -62,8 +62,10 @@ export let defaultConfiguration: ViewerConfiguration = {
                 }
             },
             events: {
+                click: {
+                    '.navbar-control': true
+                },
                 pointerdown: {
-                    '.navbar-control': true,
                     '.help-button': true
                 },
                 input: {

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

@@ -120,7 +120,7 @@ export class DefaultViewer extends AbstractViewer {
         let navbar = this.templateManager.getTemplate('navBar');
         if (navbar) {
             this.onFrameRenderedObservable.add(this._updateProgressBar);
-            this.templateManager.eventManager.registerCallback('navBar', this._handlePointerDown, 'pointerdown');
+            this.templateManager.eventManager.registerCallback('navBar', this._handlePointerClick, 'click');
             // an example how to trigger the help button. publiclly available
             this.templateManager.eventManager.registerCallback("navBar", () => {
                 // do your thing
@@ -158,7 +158,7 @@ export class DefaultViewer extends AbstractViewer {
     private _isAnimationPaused: boolean;
     private _resumePlay: boolean;
 
-    private _handlePointerDown = (event: EventCallback) => {
+    private _handlePointerClick = (event: EventCallback) => {
 
         let pointerDown = <PointerEvent>event.event;
         if (pointerDown.button !== 0) return;

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


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


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


文件差异内容过多而无法显示
+ 614 - 270
dist/preview release/babylon.no-module.max.js


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


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


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

@@ -1,7 +1,7 @@
 {
     "name": "babylonjs-gltf2interface",
     "description": "A typescript declaration of babylon's gltf2 inteface.",
-    "version": "3.3.0-beta.3",
+    "version": "3.3.0-beta.4",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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


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

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

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


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

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

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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-loaders",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
-    "version": "3.3.0-beta.3",
+    "version": "3.3.0-beta.4",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "3.3.0-beta.3"
+        "babylonjs-gltf2interface": "3.3.0-beta.4"
     },
     "peerDependencies": {
         "babylonjs": ">=3.2.0-alpha"

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

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

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

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

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

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

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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-serializers",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
-    "version": "3.3.0-beta.3",
+    "version": "3.3.0-beta.4",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "3.3.0-beta.3"
+        "babylonjs-gltf2interface": "3.3.0-beta.4"
     },
     "peerDependencies": {
         "babylonjs": ">=3.2.0-alpha"

+ 4 - 4
dist/preview release/viewer/babylon.viewer.d.ts

@@ -168,11 +168,11 @@ declare module BabylonViewer {
                 * Mainly used for help and errors
                 * @param subScreen the name of the subScreen. Those can be defined in the configuration object
                 */
-            showOverlayScreen(subScreen: string): Promise<string> | Promise<Template>;
+            showOverlayScreen(subScreen: string): Promise<Template> | Promise<string>;
             /**
                 * Hide the overlay screen.
                 */
-            hideOverlayScreen(): Promise<string> | Promise<Template>;
+            hideOverlayScreen(): Promise<Template> | Promise<string>;
             /**
                 * show the viewer (in case it was hidden)
                 *
@@ -189,11 +189,11 @@ declare module BabylonViewer {
                 * Show the loading screen.
                 * The loading screen can be configured using the configuration object
                 */
-            showLoadingScreen(): Promise<string> | Promise<Template>;
+            showLoadingScreen(): Promise<Template> | Promise<string>;
             /**
                 * Hide the loading screen
                 */
-            hideLoadingScreen(): Promise<string> | Promise<Template>;
+            hideLoadingScreen(): Promise<Template> | Promise<string>;
             dispose(): void;
             protected _onConfigurationLoaded(configuration: ViewerConfiguration): void;
     }

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


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


+ 4 - 4
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -200,11 +200,11 @@ declare module 'babylonjs-viewer/viewer/defaultViewer' {
                 * Mainly used for help and errors
                 * @param subScreen the name of the subScreen. Those can be defined in the configuration object
                 */
-            showOverlayScreen(subScreen: string): Promise<string> | Promise<Template>;
+            showOverlayScreen(subScreen: string): Promise<Template> | Promise<string>;
             /**
                 * Hide the overlay screen.
                 */
-            hideOverlayScreen(): Promise<string> | Promise<Template>;
+            hideOverlayScreen(): Promise<Template> | Promise<string>;
             /**
                 * show the viewer (in case it was hidden)
                 *
@@ -221,11 +221,11 @@ declare module 'babylonjs-viewer/viewer/defaultViewer' {
                 * Show the loading screen.
                 * The loading screen can be configured using the configuration object
                 */
-            showLoadingScreen(): Promise<string> | Promise<Template>;
+            showLoadingScreen(): Promise<Template> | Promise<string>;
             /**
                 * Hide the loading screen
                 */
-            hideLoadingScreen(): Promise<string> | Promise<Template>;
+            hideLoadingScreen(): Promise<Template> | Promise<string>;
             dispose(): void;
             protected _onConfigurationLoaded(configuration: ViewerConfiguration): void;
     }

+ 226 - 221
dist/preview release/what's new.md

@@ -1,221 +1,226 @@
-# 3.3.0
-
-## Major updates
-
-- GUI
-  - New GUI 3D controls toolset. [Complete doc + demos](http://doc.babylonjs.com/how_to/gui3d) ([Deltakosh](https://github.com/deltakosh))
-  - New GUI control: [Grid](http://doc.babylonjs.com/how_to/gui#grid) ([Deltakosh](https://github.com/deltakosh))
-  - New GUI control: [InputPassword](https://doc.babylonjs.com/how_to/gui#inputpassword) ([theom](https://github.com/theom))
-- Gizmo Support ([TrevorDev](https://github.com/TrevorDev))
-  - Gizmo and GizmoManager classes used to manipulate meshes in a scene. Gizmo types include: position, scale, rotation and bounding box. [Doc](http://doc.babylonjs.com/how_to/gizmo) ([TrevorDev](https://github.com/TrevorDev))
-  - New behaviors: PointerDragBehavior, SixDofDragBehavior and MultiPointerScaleBehavior to enable smooth drag and drop/scaling with mouse or 6dof controller on a mesh. [Doc](http://doc.babylonjs.com/how_to/meshbehavior) ([TrevorDev](https://github.com/TrevorDev))
-  - Added attachToBoxBehavior to attach UI to a bounding box ([TrevorDev](https://github.com/TrevorDev))
-  - Gizmo manager's internal gizmos are now public ([TrevorDev](https://github.com/TrevorDev))
-  - Ability to customize meshes on gizmos ([TrevorDev](https://github.com/TrevorDev))
-  - Added ignoreChildren field to bounding box to save performance when using heavily nested meshes ([TrevorDev](https://github.com/TrevorDev))
-  - Add uniform scaling drag support to scale gizmo ([TrevorDev](https://github.com/TrevorDev))
-  - Support interacting with child elements ([TrevorDev](https://github.com/TrevorDev))
-- Particle system improvements ([Deltakosh](https://github.com/deltakosh))
-  - Added a ParticleHelper class to create some pre-configured particle systems in a one-liner method style. [Doc](https://doc.babylonjs.com/How_To/ParticleHelper) ([Deltakosh](https://github.com/deltakosh)) / ([DevChris](https://github.com/yovanoc))
-  - Improved CPU particles rendering performance (up to x2 on low end devices)
-  - Added support for `isBillboardBased`. [Doc](http://doc.babylonjs.com/babylon101/particles#alignment)
-  - Added support for billboard mode. [Doc](https://doc.babylonjs.com/babylon101/particles#alignment)
-  - Added support for `minScaleX`, `minScaleY`, `maxScaleX`, `maxScaleY`. [Doc](https://doc.babylonjs.com/babylon101/particles#size)
-  - Added support for `radiusRange` for sphere emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#sphere-emitter)
-  - Added support for `radiusRange` and `heightRange` for cone emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#cone-emitter)
-  - Added new point emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#point-emitter)
-  - Added new hemispheric emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#hemispheric-emitter)
-  - Added support for `ParticleSystem.BLENDMODE_ADD` alpha mode. [Doc](https://doc.babylonjs.com/babylon101/particles#particle-blending)
-  - Added support for color gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#particle-colors)
-  - Added support for pre-warming. [Doc](https://doc.babylonjs.com/babylon101/particles#pre-warming)
-  - Added support for `minInitialRotation` and `maxInitialRotation`. [Doc](https://doc.babylonjs.com/babylon101/particles#rotation)
-  - Added support for size gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#size)
-  - Added support for life time gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#lifetime)
-  - Added support for angular speed gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#rotation)
-  - Added support for velocty gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#velocity-over-time)
-  - Added support for limit velocty gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#limit-velocity-over-time)
-  - Added support for noise textures. [Doc](http://doc.babylonjs.com/babylon101/particles#noise-texture)
-- Added SceneComponent to help decoupling Scene from its components. ([sebavan](http://www.github.com/sebavan))
-- Added [Environment Texture Tools](https://doc.babylonjs.com/how_to/physically_based_rendering#creating-a-compressed-environment-texture) to reduce the size of the usual .DDS file ([sebavan](http://www.github.com/sebavan))
-- Playground can now be used with TypeScript directly!. [Demo](https://www.babylonjs-playground.com/ts.html) ([Deltakosh](https://github.com/deltakosh), [NasimiAsl](https://github.com/NasimiAsl))
-- GUI and Inspector are now ES-Modules ([RaananW](https://github.com/RaananW))
-- Added support for noise procedural textures. [Doc](http://doc.babylonjs.com/how_to/how_to_use_procedural_textures#noise-procedural-texture) ([Deltakosh](https://github.com/deltakosh))
-- Added new `PhotoDome` object to display 360 photos. [Demo](https://www.babylonjs-playground.com/#14KRGG#0) ([SzeyinLee](https://github.com/SzeyinLee))
-- Added Video Recorder [Documentation](http://localhost:8080/How_To/Render_Scene_on_a_Video) ([sebavan](http://www.github.com/sebavan))
-
-## Updates
-
-- Updated TypeScript version to new major 3.0.1 ([christopherstock](https://github.com/christopherstock))
-- All NPM packages have `latest`and `preview` streams [#3055](https://github.com/BabylonJS/Babylon.js/issues/3055) ([RaananW](https://github.com/RaananW))
-- Added New Tools Tab in the inspector (env texture and screenshot tools so far) ([sebavan](http://www.github.com/sebavan))
-- Moved to gulp 4, updated dependencies to latest ([RaananW](https://github.com/RaananW))
-
-### GUI
-- Added dead key support and before key add observable to InputText. [Doc](https://doc.babylonjs.com/how_to/gui#using-onbeforekeyaddobservable-for-extended-keyboard-layouts-and-input-masks)([theom](https://github.com/theom))
-- Added `TextBlock.computeExpectedHeight`, added `TextWrapping.Ellipsis` as `TextBlock.wordWrapping` possible value ([adrientetar](https://github.com/adrientetar))
-- New vertical mode for sliders in 2D GUI. [Demo](https://www.babylonjs-playground.com/#U9AC0N#53) ([Saket Saurabh](https://github.com/ssaket))
-- Added `isEnabled` and `disabledColor` property to Gui Control ([barteq100](https://github.com/barteq100))
-
-### Core Engine
-
-- Added support for muyltiple clip planes. [Demo](https://www.babylonjs-playground.com/#Y6W087) ([Deltakosh](https://github.com/deltakosh))
-- Added new `MixMaterial` to the Materials Library allowing to mix up to 8 textures ([julien-moreau](https://github.com/julien-moreau))
-- Added new `BoundingInfo.scale()` function to let users control the size of the bounding info ([Deltakosh](https://github.com/deltakosh))
-- Added new `Animatable.waitAsync` function to use Promises with animations. Demo [Here](https://www.babylonjs-playground.com/#HZBCXR) ([Deltakosh](https://github.com/deltakosh))
-- Added the choice of [forming a closed loop](http://doc.babylonjs.com/how_to/how_to_use_curve3#catmull-rom-spline) to the catmull-rom-spline curve3 ([johnk](https://github.com/babylonjsguide))
-- Added support for specifying the center of rotation to textures ([bghgary](http://www.github.com/bghgary))
-- Added webVR support for Oculus Go ([TrevorDev](https://github.com/TrevorDev))
-- Added ability to not generate polynomials harmonics upon prefiltered texture creation ([sebavan](http://www.github.com/sebavan))
-- Added predicate function to customize the list of mesh included in the computation of bounding vectors in the ```getHierarchyBoundingVectors``` method ([sebavan](http://www.github.com/sebavan))
-- Added webVR constructor options: disable laser pointer toggle, teleportation floor meshes ([TrevorDev](https://github.com/TrevorDev))
-- Get a root mesh from an asset container, load a mesh from a file with a single string url ([TrevorDev](https://github.com/TrevorDev))
-- UtilityLayer class to render another scene as a layer on top of an existing scene ([TrevorDev](https://github.com/TrevorDev))
-- AnimationGroup has now onAnimationGroupEnd observable ([RaananW](https://github.com/RaananW))
-- New `serialize` and `Parse` functions to serialize and parse all procedural textures from the Procedural Textures Library ([julien-moreau](https://github.com/julien-moreau))
-- Added a new `mesh.ignoreNonUniformScaling` to turn off non uniform scaling compensation ([Deltakosh](https://github.com/deltakosh))
-- AssetsManager tasks will only run when their state is INIT. It is now possible to remove a task from the assets manager ([RaananW](https://github.com/RaananW))
-- Added sprite isVisible field ([TrevorDev](https://github.com/TrevorDev))
-- EnvironmentHelper will recreate ground and skybox meshes if force-disposed ([RaananW](https://github.com/RaananW))
-- Added viewport caching mechanism in engine ([sebavan](http://www.github.com/sebavan))
-- Added unpackFlipY caching mechanism in engine ([sebavan](http://www.github.com/sebavan))
-- Added rebind optimization of video texture ([sebavan](http://www.github.com/sebavan))
-- Fix Background Material effect caching ([sebavan](http://www.github.com/sebavan))
-- Prevent texture ```getSize``` to generate garbage collection ([sebavan](http://www.github.com/sebavan))
-- Prevent ```lodGenerationScale``` and ```lodGenerationOffset``` to force rebind ([sebavan](http://www.github.com/sebavan))
-- Added poster property on VideoTexture ([sebavan](http://www.github.com/sebavan))
-- Added ```onUserActionRequestedObservable``` to workaround and detect autoplay video policy restriction on VideoTexture ([sebavan](http://www.github.com/sebavan))
-- `Sound` now accepts `MediaStream` as source to enable easier WebAudio and WebRTC integrations ([menduz](https://github.com/menduz))
-- Vector x, y and z constructor parameters are now optional and default to 0 ([TrevorDev](https://github.com/TrevorDev))
-- Added and removed camera methods in the default pipeline ([TrevorDev](https://github.com/TrevorDev))
-- Added internal texture `format` support for RenderTargetCubeTexture ([PeapBoy](https://github.com/NicolasBuecher))
-- Added canvas toBlob polyfill in tools ([sebavan](http://www.github.com/sebavan))
-- Added `RawCubeTexture` class with RGBD and mipmap support ([bghgary](http://www.github.com/bghgary))
-- Added effect layer per rendering group addressing [Issue 4463](https://github.com/BabylonJS/Babylon.js/issues/4463) ([sebavan](http://www.github.com/sebavan))
-- Added predicate function `targetMask` argument to `scene.beginWeightedAnimation`, `scene.beginAnimation`, `scene.stopAnimation`, and `animatable.stop` to allow for selective application of animations.  ([fmmoret](http://github.com/fmmoret))
-- Oculus GO and GearVR 3dof controllers will now rotate with the user's head if they turn around in their room ([TrevorDev](https://github.com/TrevorDev))
-- Added onPoseUpdatedFromDeviceObservable to webVRCamera to detect when the camera's pose has been updated ([TrevorDev](https://github.com/TrevorDev))
-- Added gltf light falloff [Issue 4148](https://github.com/BabylonJS/Babylon.js/issues/4148) ([sebavan](http://www.github.com/sebavan))
-- Added falloff type per light to prevent material only inconsistencies [Issue 4148](https://github.com/BabylonJS/Babylon.js/issues/4148) ([sebavan](http://www.github.com/sebavan))
-- Added WeightedSound; selects one from many Sounds with random weight for playback. ([najadojo](https://github.com/najadojo))
-- Added HDR support to ReflectionProbe ([Deltakosh](https://github.com/deltakosh))
-- Added ACES ToneMapping to the image processing to help getting more parity with other engines ([sebavan](http://www.github.com/sebavan))
-- Added Image Processing to the particle system to allow consistency in one pass forward rendering scenes ([sebavan](http://www.github.com/sebavan))
-- Added Video Recorder [Issue 4708](https://github.com/BabylonJS/Babylon.js/issues/4708) ([sebavan](http://www.github.com/sebavan))
-- Added support for main WebGL2 texture formats ([PeapBoy](https://github.com/NicolasBuecher))
-- Added fadeInOutBehavior and tooltipText for holographic buttons ([TrevorDev](https://github.com/TrevorDev))
-- StartDrag method added to pointerDragBehavior to simulate the start of a drag ([TrevorDev](https://github.com/TrevorDev))
-- Added EdgesLineRenderer to address [#4919](https://github.com/BabylonJS/Babylon.js/pull/4919) ([barteq100](https://github.com/barteq100))
-- Added ```ambientTextureImpactOnAnalyticalLights``` in PBRMaterial to allow fine grained control of the AmbientTexture on the analytical diffuse light ([sebavan](http://www.github.com/sebavan))
-- BoundingBoxGizmo scalePivot field that can be used to always scale objects from the bottom ([TrevorDev](https://github.com/TrevorDev))
-- Cylinder particle emitter and constructor in baseParticle ([TrevorDev](https://github.com/TrevorDev))
-- Improved _isSyncronized performance and reduced GC in TransformNode.computeWorldMatrix by directly reading property. ([Bolloxim](https://github.com/Bolloxim))
-- Added supports for reflectionMatrix in Skybox Mode Cube Texture allowing offsetting the world center or rotating the matrix ([sebavan](http://www.github.com/sebavan))
-
-### glTF Loader
-
-- Added support for KHR_texture_transform ([bghgary](http://www.github.com/bghgary))
-- Added `onNodeLODsLoadedObservable` and `onMaterialLODsLoadedObservable` to MSFT_lod loader extension ([bghgary](http://www.github.com/bghgary))
-- Added glTF loader settings to the GLTF tab in the debug layer ([bghgary](http://www.github.com/bghgary))
-- Added debug logging and performance counters ([bghgary](http://www.github.com/bghgary))
-- Added support for EXT_lights_imageBased ([bghgary](http://www.github.com/bghgary))
-- Added support for MSFT_audio_emitter ([najadojo](http://www.github.com/najadojo))
-- Added support for custom loader extensions ([bghgary](http://www.github.com/bghgary))
-
-### Viewer
-
-- No fullscreen button on small devices ([RaananW](https://github.com/RaananW))
-- Nav-Bar is now displayed on fullscreen per default ([RaananW](https://github.com/RaananW))
-- Viewer configuration supports deprecated values using the new configurationCompatibility processor  ([RaananW](https://github.com/RaananW))
-- Shadows will only render while models are entering the scene or animating ([RaananW](https://github.com/RaananW))
-- Support for model drag and drop onto the canvas ([RaananW](https://github.com/RaananW))
-- New lab feature - global light rotation [#4347](https://github.com/BabylonJS/Babylon.js/issues/4347) ([RaananW](https://github.com/RaananW))
-- New NPM package - babylonjs-viewer-assets, to separate the binary assets and the code of the viewer ([RaananW](https://github.com/RaananW))
-- A new HD-Toggler button allows setting a better hardware scaling rate ([RaananW](https://github.com/RaananW))
-- An initial support for WebVR is implemented ([RaananW](https://github.com/RaananW))
-- It is now possible to choose the element that goes fullscreen in the default viewer ([RaananW](https://github.com/RaananW))
-- The default viewer has a plugin system with which new buttons can be added externally ([RaananW](https://github.com/RaananW))
-- The extended configuration is now the default when not providing the "extended" parameter ([RaananW](https://github.com/RaananW))
-- viewer.updateConfiguration also accepts a URL to download configuration remotely ([RaananW](https://github.com/RaananW))
-- Viewer supports 3D printing on windows 10 ([RaananW](https://github.com/RaananW))
-- The viewer's environment map is using the new .env feature ([RaananW](https://github.com/RaananW))
-
-### Materials Library
-
-- Added ```unlit``` mode to lava material ([sebavan](http://www.github.com/sebavan))
-
-### Documentation
-
-- Added all code comments for GUI
-
-## Bug fixes
-
-- VR experience helper will now fire pointer events even when no mesh is currently hit ([TrevorDev](https://github.com/TrevorDev))
-- RawTexture.CreateAlphaTexture no longer fails to create a usable texture ([TrevorDev](https://github.com/TrevorDev))
-- SceneSerializer.SerializeMesh now serializes all materials kinds (not only StandardMaterial) ([julien-moreau](https://github.com/julien-moreau))
-- WindowsMotionController's trackpad field will be updated prior to it's onTrackpadChangedObservable event ([TrevorDev](https://github.com/TrevorDev))
-- VR experience helper's controllers will not fire pointer events when laser's are disabled, instead the camera ray pointer event will be used ([TrevorDev](https://github.com/TrevorDev))
-- Node's setParent(node.parent) will no longer throw an exception when parent is undefined and will behave the same as setParent(null) ([TrevorDev](https://github.com/TrevorDev))
-- Mesh.MergeMeshes flips triangles on meshes with negative scaling ([SvenFrankson](http://svenfrankson.com))
-- Avoid firing button events multiple times when calling vrController.attachMesh() ([TrevorDev](https://github.com/TrevorDev))
-- Parse geometry when load binary mesh ([SinhNQ](https://github.com/quocsinh))
-- Removing observers during observable notify should not skip over valid observers ([TrevorDev](https://github.com/TrevorDev))
-- Initializing gamepadManager should register the gamepad update events ([TrevorDev](https://github.com/TrevorDev))
-- Do not generate mipmaps for RawCubeTexture if OES_texture_float_linear and/or EXT_color_buffer_float extensions are not supported ([PeapBoy](https://github.com/NicolasBuecher))
-- Do not modify passed camera array parameter when creating a default pipeline ([TrevorDev](https://github.com/TrevorDev))
-- Fixed issue where gaze trackers were appearing even after leaving VR ([atulyar](https://github.com/atulyar))
-- AdvancedDynamicTexture should not overwrite skipOnPointerObservable to false ([TrevorDev](https://github.com/TrevorDev))
-- Fixed issue where VRExperienceHelper.onExitingVR observable was being fired twice ([atulyar](https://github.com/atulyar))
-- Avoid firing onExitingVR observable multiple times when calling exitVR() and add observables to Viewer that can be used instead of the ones in VRExperienceHelper ([atulyar](https://github.com/atulyar))
-- GizmoManager should hide existing gizmos if a non-attachable mesh is selected ([TrevorDev](https://github.com/TrevorDev))
-- Ignore isPickable = false for vr ray casting if the mesh's name matches the specified floorMeshName to maintain backwards compatability ([TrevorDev](https://github.com/TrevorDev))
-- Fix File Loading if hosted from `file:`-Protocol ([ltetzlaff](https://github.com/ltetzlaff))
-- Do not throw error when updating a controller with no left stick ([TrevorDev](https://github.com/TrevorDev))
-- Exiting VR can result in messed up view ([TrevorDev](https://github.com/TrevorDev))
-- Dispose existing gazeTrackers when setting a new one, remove pivot matrix of meshes using boundingBoxGizmo ([TrevorDev](https://github.com/TrevorDev))
-- Set missing parentId in Mesh.serialize() for instances ([julien-moreau](https://github.com/julien-moreau))
-
-### Core Engine
-
-- Fixed ```shadowEnabled``` property on lights. Shadows are not visible anymore when disabled ([sebavan](http://www.github.com/sebavan))
-- Physics `unregisterOnPhysicsCollide` didn't remove callback correctly [#4291](https://github.com/BabylonJS/Babylon.js/issues/4291) ([RaananW](https://github.com/RaananW))
-- Added missing getter and setter for global exposure in ColorCurves ([RaananW](https://github.com/RaananW))
-- Fixed an issue with view matrix when `ArcRotateCamera` was used with collisions ([Deltakosh](https://github.com/deltakosh))
-- Fixed a bug with setting `unlit` on `PBRMaterial` after the material is ready (Wrong dirty flags) ([bghgary](http://www.github.com/bghgary))
-- Fixed `HighlightLayer` support on browsers not supporting HalfFloat ([sebavan](http://www.github.com/sebavan))
-- Fixed support for R and RG texture formats ([sebavan](http://www.github.com/sebavan))
-- Fixed `updatable` parameter setting in the SPS ([jerome](https://github.com/jbousquie))
-- Angular and linear velocity were using the wrong method to copy values to the physics engine ([RaananW](https://github.com/RaananW))
-- Fixed env texture generation in Byte Mode ([sebavan](http://www.github.com/sebavan))
-- Oimo.js now receives quaternion and not euler when a body is being constructed ([RaananW](https://github.com/RaananW))
-- Improving visual quality on SSAO2 shader ([CraigFeldspar](https://github.com/CraigFeldspar))
-- Fixed a bug where changing the sample count on `PostProcess` would not update the WebGL Texture ([CraigFeldspar](https://github.com/CraigFeldspar))
-
-### Viewer
-
-- Fix Navbar Interaction on Mozilla/Firefox ([SzeyinLee](https://github.com/SzeyinLee))
-- Fix Animation Slider Interaction on Mozilla/Firefox ([sebavan](http://www.github.com/sebavan))
-- Fix Animation Slider Clickable area size Cross Plat ([sebavan](http://www.github.com/sebavan))
-- Ground material didn't take the default main color is no material definition was provided ([RaananW](https://github.com/RaananW))
-- Model configuration was not extended correctly if loaded more than one model ([RaananW](https://github.com/RaananW))
-- It wasn't possible to disable camera behavior(s) using configuration  [#4348](https://github.com/BabylonJS/Babylon.js/issues/4348) ([RaananW](https://github.com/RaananW))
-- Animation blending was always set to true, ignoring configuration [#4412](https://github.com/BabylonJS/Babylon.js/issues/4412) ([RaananW](https://github.com/RaananW))
-- Animation navbar now updates correctly when a new model is loaded [#4441](https://github.com/BabylonJS/Babylon.js/issues/4441) ([RaananW](https://github.com/RaananW))
-- Non-normalized meshes didn't center and focus correctly ([RaananW](https://github.com/RaananW))
-- Meshes with skeletons could have incorrect animations ([RaananW](https://github.com/RaananW))
-- Removed element IDs from viewer's templates to allow muitiple viewers in a single page [#4500](https://github.com/BabylonJS/Babylon.js/issues/4500) ([RaananW](https://github.com/RaananW))
-- Viewer is not using Engine.LastCreatedScene anymore, to support multiple viewers in a single page [#4500](https://github.com/BabylonJS/Babylon.js/issues/4500) ([RaananW](https://github.com/RaananW))
-- Template location was ignored if html was defined ([RaananW](https://github.com/RaananW))
-- Drag and Drop only worked if a model was already loaded before ([RaananW](https://github.com/RaananW))
-- It was not possible to add new custom optimizers, only use existing ones ([RaananW](https://github.com/RaananW))
-- Button texts were truncated incorrectly ([RaananW](https://github.com/RaananW))
-- Animation names with more than one word didn't work correctly ([RaananW](https://github.com/RaananW))
-
-### Loaders
-
-- STL Loader only supported binary downloads and no data: urls [#4473](https://github.com/BabylonJS/Babylon.js/issues/4473) ([RaananW](https://github.com/RaananW))
-- OBJ Loader is now an async loader [#4571](https://github.com/BabylonJS/Babylon.js/issues/4571) ([RaananW](https://github.com/RaananW))
-
-## Breaking changes
-
-- Fixing support for R and RG texture formats made us remove TextureFormat_R32F and TextureFormat_RG32F as they were mixing formats and types. Please, use the respective TextureFormat_R and TextureFormat_RG with the Float types ([sebavan](http://www.github.com/sebavan))
-- Replacing `scene.onRenderingGroupObservable` by `onBeforeRenderingGroupObservable` and `onAfterRenderingGroupObservable` to prevent the stage check ([sebavan](http://www.github.com/sebavan))
+# 3.3.0
+
+## Major updates
+
+- GUI
+  - New GUI 3D controls toolset. [Complete doc + demos](http://doc.babylonjs.com/how_to/gui3d) ([Deltakosh](https://github.com/deltakosh))
+  - New GUI control: [Grid](http://doc.babylonjs.com/how_to/gui#grid) ([Deltakosh](https://github.com/deltakosh))
+  - New GUI control: [InputPassword](https://doc.babylonjs.com/how_to/gui#inputpassword) ([theom](https://github.com/theom))
+- Gizmo Support ([TrevorDev](https://github.com/TrevorDev))
+  - Gizmo and GizmoManager classes used to manipulate meshes in a scene. Gizmo types include: position, scale, rotation and bounding box. [Doc](http://doc.babylonjs.com/how_to/gizmo) ([TrevorDev](https://github.com/TrevorDev))
+  - New behaviors: PointerDragBehavior, SixDofDragBehavior and MultiPointerScaleBehavior to enable smooth drag and drop/scaling with mouse or 6dof controller on a mesh. [Doc](http://doc.babylonjs.com/how_to/meshbehavior) ([TrevorDev](https://github.com/TrevorDev))
+  - Added attachToBoxBehavior to attach UI to a bounding box ([TrevorDev](https://github.com/TrevorDev))
+  - Gizmo manager's internal gizmos are now public ([TrevorDev](https://github.com/TrevorDev))
+  - Ability to customize meshes on gizmos ([TrevorDev](https://github.com/TrevorDev))
+  - Added ignoreChildren field to bounding box to save performance when using heavily nested meshes ([TrevorDev](https://github.com/TrevorDev))
+  - Add uniform scaling drag support to scale gizmo ([TrevorDev](https://github.com/TrevorDev))
+  - Support interacting with child elements ([TrevorDev](https://github.com/TrevorDev))
+- Particle system improvements ([Deltakosh](https://github.com/deltakosh))
+  - Added a ParticleHelper class to create some pre-configured particle systems in a one-liner method style. [Doc](https://doc.babylonjs.com/How_To/ParticleHelper) ([Deltakosh](https://github.com/deltakosh)) / ([DevChris](https://github.com/yovanoc))
+  - Improved CPU particles rendering performance (up to x2 on low end devices)
+  - Added support for `isBillboardBased`. [Doc](http://doc.babylonjs.com/babylon101/particles#alignment)
+  - Added support for billboard mode. [Doc](https://doc.babylonjs.com/babylon101/particles#alignment)
+  - Added support for `minScaleX`, `minScaleY`, `maxScaleX`, `maxScaleY`. [Doc](https://doc.babylonjs.com/babylon101/particles#size)
+  - Added support for `radiusRange` for sphere emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#sphere-emitter)
+  - Added support for `radiusRange` and `heightRange` for cone emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#cone-emitter)
+  - Added new point emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#point-emitter)
+  - Added new hemispheric emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#hemispheric-emitter)
+  - Added support for `ParticleSystem.BLENDMODE_ADD` alpha mode. [Doc](https://doc.babylonjs.com/babylon101/particles#particle-blending)
+  - Added support for color gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#particle-colors)
+  - Added support for pre-warming. [Doc](https://doc.babylonjs.com/babylon101/particles#pre-warming)
+  - Added support for `minInitialRotation` and `maxInitialRotation`. [Doc](https://doc.babylonjs.com/babylon101/particles#rotation)
+  - Added support for size gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#size)
+  - Added support for life time gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#lifetime)
+  - Added support for angular speed gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#rotation)
+  - Added support for velocty gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#velocity-over-time)
+  - Added support for limit velocty gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#limit-velocity-over-time)
+  - Added support for noise textures. [Doc](http://doc.babylonjs.com/babylon101/particles#noise-texture)
+  - Added support for emit rate gradients. [Doc](http://doc.babylonjs.com/babylon101/particles#emit-rate-over-time)
+- Added SceneComponent to help decoupling Scene from its components. ([sebavan](http://www.github.com/sebavan))
+- Added [Environment Texture Tools](https://doc.babylonjs.com/how_to/physically_based_rendering#creating-a-compressed-environment-texture) to reduce the size of the usual .DDS file ([sebavan](http://www.github.com/sebavan))
+- Playground can now be used with TypeScript directly!. [Demo](https://www.babylonjs-playground.com/ts.html) ([Deltakosh](https://github.com/deltakosh), [NasimiAsl](https://github.com/NasimiAsl))
+- GUI and Inspector are now ES-Modules ([RaananW](https://github.com/RaananW))
+- Added support for noise procedural textures. [Doc](http://doc.babylonjs.com/how_to/how_to_use_procedural_textures#noise-procedural-texture) ([Deltakosh](https://github.com/deltakosh))
+- Added new `PhotoDome` object to display 360 photos. [Demo](https://www.babylonjs-playground.com/#14KRGG#0) ([SzeyinLee](https://github.com/SzeyinLee))
+- Added Video Recorder [Documentation](http://localhost:8080/How_To/Render_Scene_on_a_Video) ([sebavan](http://www.github.com/sebavan))
+
+## Updates
+
+- Updated TypeScript version to new major 3.0.1 ([christopherstock](https://github.com/christopherstock))
+- All NPM packages have `latest`and `preview` streams [#3055](https://github.com/BabylonJS/Babylon.js/issues/3055) ([RaananW](https://github.com/RaananW))
+- Added New Tools Tab in the inspector (env texture and screenshot tools so far) ([sebavan](http://www.github.com/sebavan))
+- Moved to gulp 4, updated dependencies to latest ([RaananW](https://github.com/RaananW))
+
+### GUI
+- Added dead key support and before key add observable to InputText. [Doc](https://doc.babylonjs.com/how_to/gui#using-onbeforekeyaddobservable-for-extended-keyboard-layouts-and-input-masks)([theom](https://github.com/theom))
+- Added `TextBlock.computeExpectedHeight`, added `TextWrapping.Ellipsis` as `TextBlock.wordWrapping` possible value ([adrientetar](https://github.com/adrientetar))
+- New vertical mode for sliders in 2D GUI. [Demo](https://www.babylonjs-playground.com/#U9AC0N#53) ([Saket Saurabh](https://github.com/ssaket))
+- Added `isEnabled` and `disabledColor` property to Gui Control ([barteq100](https://github.com/barteq100))
+
+### Core Engine
+
+- Added `scene.pickSpriteWithRay` function ([Deltakosh](https://github.com/deltakosh))
+- Added support for muyltiple clip planes. [Demo](https://www.babylonjs-playground.com/#Y6W087) ([Deltakosh](https://github.com/deltakosh))
+- Added new `MixMaterial` to the Materials Library allowing to mix up to 8 textures ([julien-moreau](https://github.com/julien-moreau))
+- Added new `BoundingInfo.scale()` function to let users control the size of the bounding info ([Deltakosh](https://github.com/deltakosh))
+- Added new `Animatable.waitAsync` function to use Promises with animations. Demo [Here](https://www.babylonjs-playground.com/#HZBCXR) ([Deltakosh](https://github.com/deltakosh))
+- Added the choice of [forming a closed loop](http://doc.babylonjs.com/how_to/how_to_use_curve3#catmull-rom-spline) to the catmull-rom-spline curve3 ([johnk](https://github.com/babylonjsguide))
+- Added support for specifying the center of rotation to textures ([bghgary](http://www.github.com/bghgary))
+- Added webVR support for Oculus Go ([TrevorDev](https://github.com/TrevorDev))
+- Added ability to not generate polynomials harmonics upon prefiltered texture creation ([sebavan](http://www.github.com/sebavan))
+- Added predicate function to customize the list of mesh included in the computation of bounding vectors in the ```getHierarchyBoundingVectors``` method ([sebavan](http://www.github.com/sebavan))
+- Added webVR constructor options: disable laser pointer toggle, teleportation floor meshes ([TrevorDev](https://github.com/TrevorDev))
+- Get a root mesh from an asset container, load a mesh from a file with a single string url ([TrevorDev](https://github.com/TrevorDev))
+- UtilityLayer class to render another scene as a layer on top of an existing scene ([TrevorDev](https://github.com/TrevorDev))
+- AnimationGroup has now onAnimationGroupEnd observable ([RaananW](https://github.com/RaananW))
+- New `serialize` and `Parse` functions to serialize and parse all procedural textures from the Procedural Textures Library ([julien-moreau](https://github.com/julien-moreau))
+- Added a new `mesh.ignoreNonUniformScaling` to turn off non uniform scaling compensation ([Deltakosh](https://github.com/deltakosh))
+- AssetsManager tasks will only run when their state is INIT. It is now possible to remove a task from the assets manager ([RaananW](https://github.com/RaananW))
+- Added sprite isVisible field ([TrevorDev](https://github.com/TrevorDev))
+- EnvironmentHelper will recreate ground and skybox meshes if force-disposed ([RaananW](https://github.com/RaananW))
+- Added viewport caching mechanism in engine ([sebavan](http://www.github.com/sebavan))
+- Added unpackFlipY caching mechanism in engine ([sebavan](http://www.github.com/sebavan))
+- Added rebind optimization of video texture ([sebavan](http://www.github.com/sebavan))
+- Fix Background Material effect caching ([sebavan](http://www.github.com/sebavan))
+- Prevent texture ```getSize``` to generate garbage collection ([sebavan](http://www.github.com/sebavan))
+- Prevent ```lodGenerationScale``` and ```lodGenerationOffset``` to force rebind ([sebavan](http://www.github.com/sebavan))
+- Added poster property on VideoTexture ([sebavan](http://www.github.com/sebavan))
+- Added ```onUserActionRequestedObservable``` to workaround and detect autoplay video policy restriction on VideoTexture ([sebavan](http://www.github.com/sebavan))
+- `Sound` now accepts `MediaStream` as source to enable easier WebAudio and WebRTC integrations ([menduz](https://github.com/menduz))
+- Vector x, y and z constructor parameters are now optional and default to 0 ([TrevorDev](https://github.com/TrevorDev))
+- Added and removed camera methods in the default pipeline ([TrevorDev](https://github.com/TrevorDev))
+- Added internal texture `format` support for RenderTargetCubeTexture ([PeapBoy](https://github.com/NicolasBuecher))
+- Added canvas toBlob polyfill in tools ([sebavan](http://www.github.com/sebavan))
+- Added `RawCubeTexture` class with RGBD and mipmap support ([bghgary](http://www.github.com/bghgary))
+- Added effect layer per rendering group addressing [Issue 4463](https://github.com/BabylonJS/Babylon.js/issues/4463) ([sebavan](http://www.github.com/sebavan))
+- Added predicate function `targetMask` argument to `scene.beginWeightedAnimation`, `scene.beginAnimation`, `scene.stopAnimation`, and `animatable.stop` to allow for selective application of animations.  ([fmmoret](http://github.com/fmmoret))
+- Oculus GO and GearVR 3dof controllers will now rotate with the user's head if they turn around in their room ([TrevorDev](https://github.com/TrevorDev))
+- Added onPoseUpdatedFromDeviceObservable to webVRCamera to detect when the camera's pose has been updated ([TrevorDev](https://github.com/TrevorDev))
+- Added gltf light falloff [Issue 4148](https://github.com/BabylonJS/Babylon.js/issues/4148) ([sebavan](http://www.github.com/sebavan))
+- Added falloff type per light to prevent material only inconsistencies [Issue 4148](https://github.com/BabylonJS/Babylon.js/issues/4148) ([sebavan](http://www.github.com/sebavan))
+- Added WeightedSound; selects one from many Sounds with random weight for playback. ([najadojo](https://github.com/najadojo))
+- Added HDR support to ReflectionProbe ([Deltakosh](https://github.com/deltakosh))
+- Added ACES ToneMapping to the image processing to help getting more parity with other engines ([sebavan](http://www.github.com/sebavan))
+- Added Image Processing to the particle system to allow consistency in one pass forward rendering scenes ([sebavan](http://www.github.com/sebavan))
+- Added Video Recorder [Issue 4708](https://github.com/BabylonJS/Babylon.js/issues/4708) ([sebavan](http://www.github.com/sebavan))
+- Added support for main WebGL2 texture formats ([PeapBoy](https://github.com/NicolasBuecher))
+- Added fadeInOutBehavior and tooltipText for holographic buttons ([TrevorDev](https://github.com/TrevorDev))
+- StartDrag method added to pointerDragBehavior to simulate the start of a drag ([TrevorDev](https://github.com/TrevorDev))
+- Added EdgesLineRenderer to address [#4919](https://github.com/BabylonJS/Babylon.js/pull/4919) ([barteq100](https://github.com/barteq100))
+- Added ```ambientTextureImpactOnAnalyticalLights``` in PBRMaterial to allow fine grained control of the AmbientTexture on the analytical diffuse light ([sebavan](http://www.github.com/sebavan))
+- BoundingBoxGizmo scalePivot field that can be used to always scale objects from the bottom ([TrevorDev](https://github.com/TrevorDev))
+- Cylinder particle emitter and constructor in baseParticle ([TrevorDev](https://github.com/TrevorDev))
+- Improved _isSyncronized performance and reduced GC in TransformNode.computeWorldMatrix by directly reading property. ([Bolloxim](https://github.com/Bolloxim))
+- Added supports for reflectionMatrix in Skybox Mode Cube Texture allowing offsetting the world center or rotating the matrix ([sebavan](http://www.github.com/sebavan))
+
+### glTF Loader
+
+- Added support for KHR_texture_transform ([bghgary](http://www.github.com/bghgary))
+- Added `onNodeLODsLoadedObservable` and `onMaterialLODsLoadedObservable` to MSFT_lod loader extension ([bghgary](http://www.github.com/bghgary))
+- Added glTF loader settings to the GLTF tab in the debug layer ([bghgary](http://www.github.com/bghgary))
+- Added debug logging and performance counters ([bghgary](http://www.github.com/bghgary))
+- Added support for EXT_lights_imageBased ([bghgary](http://www.github.com/bghgary))
+- Added support for MSFT_audio_emitter ([najadojo](http://www.github.com/najadojo))
+- Added support for custom loader extensions ([bghgary](http://www.github.com/bghgary))
+
+### Viewer
+
+- No fullscreen button on small devices ([RaananW](https://github.com/RaananW))
+- Nav-Bar is now displayed on fullscreen per default ([RaananW](https://github.com/RaananW))
+- Viewer configuration supports deprecated values using the new configurationCompatibility processor  ([RaananW](https://github.com/RaananW))
+- Shadows will only render while models are entering the scene or animating ([RaananW](https://github.com/RaananW))
+- Support for model drag and drop onto the canvas ([RaananW](https://github.com/RaananW))
+- New lab feature - global light rotation [#4347](https://github.com/BabylonJS/Babylon.js/issues/4347) ([RaananW](https://github.com/RaananW))
+- New NPM package - babylonjs-viewer-assets, to separate the binary assets and the code of the viewer ([RaananW](https://github.com/RaananW))
+- A new HD-Toggler button allows setting a better hardware scaling rate ([RaananW](https://github.com/RaananW))
+- An initial support for WebVR is implemented ([RaananW](https://github.com/RaananW))
+- It is now possible to choose the element that goes fullscreen in the default viewer ([RaananW](https://github.com/RaananW))
+- The default viewer has a plugin system with which new buttons can be added externally ([RaananW](https://github.com/RaananW))
+- The extended configuration is now the default when not providing the "extended" parameter ([RaananW](https://github.com/RaananW))
+- viewer.updateConfiguration also accepts a URL to download configuration remotely ([RaananW](https://github.com/RaananW))
+- Viewer supports 3D printing on windows 10 ([RaananW](https://github.com/RaananW))
+- The viewer's environment map is using the new .env feature ([RaananW](https://github.com/RaananW))
+
+### Materials Library
+
+- Added ```unlit``` mode to lava material ([sebavan](http://www.github.com/sebavan))
+
+### Documentation
+
+- Added all code comments for GUI
+
+## Bug fixes
+
+- VR experience helper will now fire pointer events even when no mesh is currently hit ([TrevorDev](https://github.com/TrevorDev))
+- RawTexture.CreateAlphaTexture no longer fails to create a usable texture ([TrevorDev](https://github.com/TrevorDev))
+- SceneSerializer.SerializeMesh now serializes all materials kinds (not only StandardMaterial) ([julien-moreau](https://github.com/julien-moreau))
+- WindowsMotionController's trackpad field will be updated prior to it's onTrackpadChangedObservable event ([TrevorDev](https://github.com/TrevorDev))
+- VR experience helper's controllers will not fire pointer events when laser's are disabled, instead the camera ray pointer event will be used ([TrevorDev](https://github.com/TrevorDev))
+- Node's setParent(node.parent) will no longer throw an exception when parent is undefined and will behave the same as setParent(null) ([TrevorDev](https://github.com/TrevorDev))
+- Mesh.MergeMeshes flips triangles on meshes with negative scaling ([SvenFrankson](http://svenfrankson.com))
+- Avoid firing button events multiple times when calling vrController.attachMesh() ([TrevorDev](https://github.com/TrevorDev))
+- Parse geometry when load binary mesh ([SinhNQ](https://github.com/quocsinh))
+- Removing observers during observable notify should not skip over valid observers ([TrevorDev](https://github.com/TrevorDev))
+- Initializing gamepadManager should register the gamepad update events ([TrevorDev](https://github.com/TrevorDev))
+- Do not generate mipmaps for RawCubeTexture if OES_texture_float_linear and/or EXT_color_buffer_float extensions are not supported ([PeapBoy](https://github.com/NicolasBuecher))
+- Do not modify passed camera array parameter when creating a default pipeline ([TrevorDev](https://github.com/TrevorDev))
+- Fixed issue where gaze trackers were appearing even after leaving VR ([atulyar](https://github.com/atulyar))
+- AdvancedDynamicTexture should not overwrite skipOnPointerObservable to false ([TrevorDev](https://github.com/TrevorDev))
+- Fixed issue where VRExperienceHelper.onExitingVR observable was being fired twice ([atulyar](https://github.com/atulyar))
+- Avoid firing onExitingVR observable multiple times when calling exitVR() and add observables to Viewer that can be used instead of the ones in VRExperienceHelper ([atulyar](https://github.com/atulyar))
+- GizmoManager should hide existing gizmos if a non-attachable mesh is selected ([TrevorDev](https://github.com/TrevorDev))
+- Ignore isPickable = false for vr ray casting if the mesh's name matches the specified floorMeshName to maintain backwards compatability ([TrevorDev](https://github.com/TrevorDev))
+- Fix File Loading if hosted from `file:`-Protocol ([ltetzlaff](https://github.com/ltetzlaff))
+- Do not throw error when updating a controller with no left stick ([TrevorDev](https://github.com/TrevorDev))
+- Exiting VR can result in messed up view ([TrevorDev](https://github.com/TrevorDev))
+- Dispose existing gazeTrackers when setting a new one ([TrevorDev](https://github.com/TrevorDev))
+- Set missing parentId in Mesh.serialize() for instances ([julien-moreau](https://github.com/julien-moreau))
+- Do not modify pivot point when using bounding box gizmo or behaviors ([TrevorDev](https://github.com/TrevorDev))
+- GPUParticleSystem does not get stuck in burst loop when stopped and started ([TrevorDev](https://github.com/TrevorDev))
+- trackPosition:false not working in webVRCamera ([TrevorDev](https://github.com/TrevorDev))
+
+### Core Engine
+
+- Fixed ```shadowEnabled``` property on lights. Shadows are not visible anymore when disabled ([sebavan](http://www.github.com/sebavan))
+- Physics `unregisterOnPhysicsCollide` didn't remove callback correctly [#4291](https://github.com/BabylonJS/Babylon.js/issues/4291) ([RaananW](https://github.com/RaananW))
+- Added missing getter and setter for global exposure in ColorCurves ([RaananW](https://github.com/RaananW))
+- Fixed an issue with view matrix when `ArcRotateCamera` was used with collisions ([Deltakosh](https://github.com/deltakosh))
+- Fixed a bug with setting `unlit` on `PBRMaterial` after the material is ready (Wrong dirty flags) ([bghgary](http://www.github.com/bghgary))
+- Fixed `HighlightLayer` support on browsers not supporting HalfFloat ([sebavan](http://www.github.com/sebavan))
+- Fixed support for R and RG texture formats ([sebavan](http://www.github.com/sebavan))
+- Fixed `updatable` parameter setting in the SPS ([jerome](https://github.com/jbousquie))
+- Angular and linear velocity were using the wrong method to copy values to the physics engine ([RaananW](https://github.com/RaananW))
+- Fixed env texture generation in Byte Mode ([sebavan](http://www.github.com/sebavan))
+- Oimo.js now receives quaternion and not euler when a body is being constructed ([RaananW](https://github.com/RaananW))
+- Improving visual quality on SSAO2 shader ([CraigFeldspar](https://github.com/CraigFeldspar))
+- Fixed a bug where changing the sample count on `PostProcess` would not update the WebGL Texture ([CraigFeldspar](https://github.com/CraigFeldspar))
+
+### Viewer
+
+- Fix Navbar Interaction on Mozilla/Firefox ([SzeyinLee](https://github.com/SzeyinLee))
+- Fix Animation Slider Interaction on Mozilla/Firefox ([sebavan](http://www.github.com/sebavan))
+- Fix Animation Slider Clickable area size Cross Plat ([sebavan](http://www.github.com/sebavan))
+- Ground material didn't take the default main color is no material definition was provided ([RaananW](https://github.com/RaananW))
+- Model configuration was not extended correctly if loaded more than one model ([RaananW](https://github.com/RaananW))
+- It wasn't possible to disable camera behavior(s) using configuration  [#4348](https://github.com/BabylonJS/Babylon.js/issues/4348) ([RaananW](https://github.com/RaananW))
+- Animation blending was always set to true, ignoring configuration [#4412](https://github.com/BabylonJS/Babylon.js/issues/4412) ([RaananW](https://github.com/RaananW))
+- Animation navbar now updates correctly when a new model is loaded [#4441](https://github.com/BabylonJS/Babylon.js/issues/4441) ([RaananW](https://github.com/RaananW))
+- Non-normalized meshes didn't center and focus correctly ([RaananW](https://github.com/RaananW))
+- Meshes with skeletons could have incorrect animations ([RaananW](https://github.com/RaananW))
+- Removed element IDs from viewer's templates to allow muitiple viewers in a single page [#4500](https://github.com/BabylonJS/Babylon.js/issues/4500) ([RaananW](https://github.com/RaananW))
+- Viewer is not using Engine.LastCreatedScene anymore, to support multiple viewers in a single page [#4500](https://github.com/BabylonJS/Babylon.js/issues/4500) ([RaananW](https://github.com/RaananW))
+- Template location was ignored if html was defined ([RaananW](https://github.com/RaananW))
+- Drag and Drop only worked if a model was already loaded before ([RaananW](https://github.com/RaananW))
+- It was not possible to add new custom optimizers, only use existing ones ([RaananW](https://github.com/RaananW))
+- Button texts were truncated incorrectly ([RaananW](https://github.com/RaananW))
+- Animation names with more than one word didn't work correctly ([RaananW](https://github.com/RaananW))
+
+### Loaders
+
+- STL Loader only supported binary downloads and no data: urls [#4473](https://github.com/BabylonJS/Babylon.js/issues/4473) ([RaananW](https://github.com/RaananW))
+- OBJ Loader is now an async loader [#4571](https://github.com/BabylonJS/Babylon.js/issues/4571) ([RaananW](https://github.com/RaananW))
+
+## Breaking changes
+
+- Fixing support for R and RG texture formats made us remove TextureFormat_R32F and TextureFormat_RG32F as they were mixing formats and types. Please, use the respective TextureFormat_R and TextureFormat_RG with the Float types ([sebavan](http://www.github.com/sebavan))
+- Replacing `scene.onRenderingGroupObservable` by `onBeforeRenderingGroupObservable` and `onAfterRenderingGroupObservable` to prevent the stage check ([sebavan](http://www.github.com/sebavan))

+ 2 - 2
package.json

@@ -9,7 +9,7 @@
     ],
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "3.3.0-beta.3",
+    "version": "3.3.0-beta.4",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -43,4 +43,4 @@
         "base64-font-loader": "0.0.4",
         "typescript": "^3.0.1"
     }
-}
+}

+ 2 - 0
src/Actions/babylon.action.ts

@@ -37,6 +37,8 @@
             if (triggerOptions.parameter) {
                 this.trigger = triggerOptions.trigger;
                 this._triggerParameter = triggerOptions.parameter;
+            } else if(triggerOptions.trigger) {
+                this.trigger = triggerOptions.trigger;
             } else {
                 this.trigger = triggerOptions;
             }

+ 11 - 7
src/Behaviors/Mesh/babylon.pointerDragBehavior.ts

@@ -3,7 +3,7 @@ module BABYLON {
      * A behavior that when attached to a mesh will allow the mesh to be dragged around the screen based on pointer events
      */
     export class PointerDragBehavior implements Behavior<Mesh> {
-        private _attachedNode: Node; 
+        private _attachedNode: Mesh; 
         private _dragPlane: Mesh;
         private _scene:Scene;
         private _pointerObserver:Nullable<Observer<PointerInfo>>;
@@ -177,11 +177,13 @@ module BABYLON {
 
             this._beforeRenderObserver = this._scene.onBeforeRenderObservable.add(()=>{
                 if(this._moving && this.moveAttached){
+                    BoundingBoxGizmo._RemoveAndStorePivotPoint(this._attachedNode);
                     // Slowly move mesh to avoid jitter
-                    this._targetPosition.subtractToRef((<Mesh>this._attachedNode).absolutePosition, this._tmpVector);
+                    this._targetPosition.subtractToRef((this._attachedNode).absolutePosition, this._tmpVector);
                     this._tmpVector.scaleInPlace(this.dragDeltaRatio);
-                    (<Mesh>this._attachedNode).getAbsolutePosition().addToRef(this._tmpVector, this._tmpVector);
-                    (<Mesh>this._attachedNode).setAbsolutePosition(this._tmpVector);
+                    (this._attachedNode).getAbsolutePosition().addToRef(this._tmpVector, this._tmpVector);
+                    (this._attachedNode).setAbsolutePosition(this._tmpVector);
+                    BoundingBoxGizmo._RestorePivotPoint(this._attachedNode);
                 }
             });
         }
@@ -219,6 +221,7 @@ module BABYLON {
                 return;
             }
             
+            BoundingBoxGizmo._RemoveAndStorePivotPoint(this._attachedNode);
             // Create start ray from the camera to the object
             if(fromRay){
                 this._startDragRay.direction.copyFrom(fromRay.direction)
@@ -237,7 +240,7 @@ module BABYLON {
                 this.currentDraggingPointerID = 1;
                 this.lastDragPosition.copyFrom(pickedPoint);
                 this.onDragStartObservable.notifyObservers({dragPlanePoint: pickedPoint, pointerId: this.currentDraggingPointerID});
-                this._targetPosition.copyFrom((<Mesh>this._attachedNode).absolutePosition)
+                this._targetPosition.copyFrom((this._attachedNode).absolutePosition)
 
                 // Detatch camera controls
                 if(this.detachCameraControls && this._scene.activeCamera && !this._scene.activeCamera.leftCamera){
@@ -249,6 +252,7 @@ module BABYLON {
                     }
                 }
             }
+            BoundingBoxGizmo._RestorePivotPoint(this._attachedNode);
         }
 
         private _dragDelta = new BABYLON.Vector3();
@@ -298,7 +302,7 @@ module BABYLON {
                 if(this._useAlternatePickedPointAboveMaxDragAngle){
                     // Invert ray direction along the towards object axis
                     this._tmpVector.copyFrom(ray.direction);
-                    (<Mesh>this._attachedNode).absolutePosition.subtractToRef(ray.origin, this._alternatePickedPoint);
+                    (this._attachedNode).absolutePosition.subtractToRef(ray.origin, this._alternatePickedPoint);
                     this._alternatePickedPoint.normalize();
                     this._alternatePickedPoint.scaleInPlace(-2*Vector3.Dot(this._alternatePickedPoint, this._tmpVector));
                     this._tmpVector.addInPlace(this._alternatePickedPoint);
@@ -307,7 +311,7 @@ module BABYLON {
                     var dot = Vector3.Dot(this._dragPlane.forward, this._tmpVector);
                     this._dragPlane.forward.scaleToRef(-dot, this._alternatePickedPoint);
                     this._alternatePickedPoint.addInPlace(this._tmpVector);
-                    this._alternatePickedPoint.addInPlace((<Mesh>this._attachedNode).absolutePosition);
+                    this._alternatePickedPoint.addInPlace((this._attachedNode).absolutePosition);
                     return this._alternatePickedPoint
                 }else{
                     return null;

+ 4 - 0
src/Behaviors/Mesh/babylon.sixDofDragBehavior.ts

@@ -83,6 +83,7 @@ module BABYLON {
                         }
                         
                         pickedMesh = this._ownerNode;
+                        BoundingBoxGizmo._RemoveAndStorePivotPoint(pickedMesh);
                         lastSixDofOriginPosition.copyFrom(pointerInfo.pickInfo.ray.origin);
 
                         // Set position and orientation of the controller
@@ -115,6 +116,7 @@ module BABYLON {
                                 attachedElement = null;
                             }
                         }
+                        BoundingBoxGizmo._RestorePivotPoint(pickedMesh);
                     }
                 }else if(pointerInfo.type == BABYLON.PointerEventTypes.POINTERUP){
                     if(this.currentDraggingPointerID == (<PointerEvent>pointerInfo.event).pointerId){
@@ -172,6 +174,7 @@ module BABYLON {
             // On every frame move towards target scaling to avoid jitter caused by vr controllers
             this._sceneRenderObserver = ownerNode.getScene().onBeforeRenderObservable.add(()=>{
                 if(this.dragging && this._moving && pickedMesh){
+                    BoundingBoxGizmo._RemoveAndStorePivotPoint(pickedMesh);
                     // Slowly move mesh to avoid jitter
                     pickedMesh.position.addInPlace(this._targetPosition.subtract(pickedMesh.position).scale(this.dragDeltaRatio));
                     
@@ -189,6 +192,7 @@ module BABYLON {
                     pickedMesh.setParent(null);
                     Quaternion.SlerpToRef(pickedMesh.rotationQuaternion!, tmpQuaternion, this.dragDeltaRatio, pickedMesh.rotationQuaternion!);
                     pickedMesh.setParent(oldParent);
+                    BoundingBoxGizmo._RestorePivotPoint(pickedMesh);
                 }
             });
         }

+ 18 - 0
src/Cameras/VR/babylon.webVRCamera.ts

@@ -525,6 +525,17 @@ module BABYLON {
 
         private updateCacheCalled: boolean;
 
+        // Remove translation from 6dof headset if trackposition is set to false
+        private _correctPositionIfNotTrackPosition(matrix:Matrix, isViewMatrix = false){
+            if(this.rawPose && this.rawPose.position && !this.webVROptions.trackPosition){
+                Matrix.TranslationToRef(this.rawPose.position[0], this.rawPose.position[1], -this.rawPose.position[2], this._tmpMatrix);
+                if(!isViewMatrix){
+                    this._tmpMatrix.invert();
+                }
+                this._tmpMatrix.multiplyToRef(matrix, matrix);
+            }
+        }
+
         /**
          * @hidden
          * Updates the cached values of the camera
@@ -559,6 +570,7 @@ module BABYLON {
                 // Update the gamepad to ensure the mesh is updated on the same frame as camera
                 this.controllers.forEach((controller) => {
                     controller._deviceToWorld.copyFrom(this._deviceToWorld);
+                    this._correctPositionIfNotTrackPosition(controller._deviceToWorld);
                     controller.update();
                 });
             }
@@ -596,6 +608,7 @@ module BABYLON {
             return Matrix.Identity();
         }
 
+        private _tmpMatrix = new BABYLON.Matrix();
         /**
          * This function is called by the two RIG cameras.
          * 'this' is the left or right camera (and NOT (!!!) the WebVRFreeCamera instance)
@@ -635,6 +648,9 @@ module BABYLON {
 
                 this._webvrViewMatrix.invert();
             }
+             
+            // Remove translation from 6dof headset if trackposition is set to false
+            parentCamera._correctPositionIfNotTrackPosition(this._webvrViewMatrix, true);
 
             parentCamera._worldToDevice.multiplyToRef(this._webvrViewMatrix, this._webvrViewMatrix);
 
@@ -704,6 +720,8 @@ module BABYLON {
                     let webVrController: WebVRController = <WebVRController>gamepad;
                     webVrController.deviceScaleFactor = this.deviceScaleFactor;
                     webVrController._deviceToWorld.copyFrom(this._deviceToWorld);
+                    this._correctPositionIfNotTrackPosition(webVrController._deviceToWorld);
+
                     if (this.webVROptions.controllerMeshes) {
                         if (webVrController.defaultModel) {
                             webVrController.defaultModel.setEnabled(true);

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

@@ -475,7 +475,7 @@
          * Returns the current version of the framework
          */
         public static get Version(): string {
-            return "3.3.0-beta.3";
+            return "3.3.0-beta.4";
         }
 
         // Updatable statics so stick with vars here

+ 35 - 29
src/Gizmos/babylon.boundingBoxGizmo.ts

@@ -63,32 +63,38 @@ module BABYLON {
         private _anchorMesh: AbstractMesh;
         private _existingMeshScale = new Vector3();
 
-        private _oldPivotPoint = new Vector3();
-        private _pivotTranslation = new Vector3();
-        private removeAndStorePivotPoint(){
-            if(this.attachedMesh){
+        // Stores the state of the pivot cache (_oldPivotPoint, _pivotTranslation)
+        // store/remove pivot point should only be applied during their outermost calls
+        private static _PivotCached = 0;
+        private static _OldPivotPoint = new Vector3();
+        private static _PivotTranslation = new Vector3();
+        private static _PivotTmpVector = new Vector3();
+        /** @hidden */
+        public static _RemoveAndStorePivotPoint(mesh:AbstractMesh){
+            if(mesh && BoundingBoxGizmo._PivotCached === 0){
                 // Save old pivot and set pivot to 0,0,0
-                this.attachedMesh.getPivotPointToRef(this._oldPivotPoint);
-                if(this._oldPivotPoint.equalsToFloats(0,0,0)){
-                    return;
+                mesh.getPivotPointToRef(BoundingBoxGizmo._OldPivotPoint);
+                if(!BoundingBoxGizmo._OldPivotPoint.equalsToFloats(0,0,0)){
+                    mesh.setPivotMatrix(Matrix.IdentityReadOnly);
+                    BoundingBoxGizmo._OldPivotPoint.subtractToRef(mesh.getPivotPoint(), BoundingBoxGizmo._PivotTranslation);
+                    BoundingBoxGizmo._PivotTmpVector.copyFromFloats(1,1,1);
+                    BoundingBoxGizmo._PivotTmpVector.subtractInPlace(mesh.scaling);
+                    BoundingBoxGizmo._PivotTmpVector.multiplyInPlace(BoundingBoxGizmo._PivotTranslation);
+                    mesh.position.addInPlace(BoundingBoxGizmo._PivotTmpVector);
                 }
-                this.attachedMesh.setPivotMatrix(Matrix.IdentityReadOnly);
-                this._oldPivotPoint.subtractToRef(this.attachedMesh.getPivotPoint(), this._pivotTranslation);
-                this._tmpVector.copyFromFloats(1,1,1);
-                this._tmpVector.subtractInPlace(this.attachedMesh.scaling);
-                this._tmpVector.multiplyInPlace(this._pivotTranslation);
-                this.attachedMesh.position.addInPlace(this._tmpVector);
             }
+            BoundingBoxGizmo._PivotCached++;
         }
-        private restorePivotPoint(){
-            if(this.attachedMesh && !this._oldPivotPoint.equalsToFloats(0,0,0)){
-                this.attachedMesh.setPivotPoint(this._oldPivotPoint);    
-                this._oldPivotPoint.subtractToRef(this.attachedMesh.getPivotPoint(), this._pivotTranslation);
-                this._tmpVector.copyFromFloats(1,1,1);
-                this._tmpVector.subtractInPlace(this.attachedMesh.scaling);
-                this._tmpVector.multiplyInPlace(this._pivotTranslation);
-                this.attachedMesh.position.subtractInPlace(this._tmpVector);
+        /** @hidden */
+        public static _RestorePivotPoint(mesh:AbstractMesh){
+            if(mesh && !BoundingBoxGizmo._OldPivotPoint.equalsToFloats(0,0,0) && BoundingBoxGizmo._PivotCached === 1){
+                mesh.setPivotPoint(BoundingBoxGizmo._OldPivotPoint);
+                BoundingBoxGizmo._PivotTmpVector.copyFromFloats(1,1,1);
+                BoundingBoxGizmo._PivotTmpVector.subtractInPlace(mesh.scaling);
+                BoundingBoxGizmo._PivotTmpVector.multiplyInPlace(BoundingBoxGizmo._PivotTranslation);
+                mesh.position.subtractInPlace(BoundingBoxGizmo._PivotTmpVector);
             }
+            this._PivotCached--;
         }
 
         /**
@@ -157,7 +163,7 @@ module BABYLON {
                 _dragBehavior.onDragObservable.add((event) => {
                     this.onRotationSphereDragObservable.notifyObservers({});
                     if (this.attachedMesh) {
-                        this.removeAndStorePivotPoint();
+                        BoundingBoxGizmo._RemoveAndStorePivotPoint(this.attachedMesh);
 
                         var worldDragDirection = startingTurnDirection;
 
@@ -197,7 +203,7 @@ module BABYLON {
                         }
                         this.updateBoundingBox();
 
-                        this.restorePivotPoint();
+                        BoundingBoxGizmo._RestorePivotPoint(this.attachedMesh);
                     }
                 });
 
@@ -232,13 +238,11 @@ module BABYLON {
                         _dragBehavior.onDragObservable.add((event) => {
                             this.onScaleBoxDragObservable.notifyObservers({});
                             if(this.attachedMesh){
-                                this.removeAndStorePivotPoint();
-                                
+                                BoundingBoxGizmo._RemoveAndStorePivotPoint(this.attachedMesh);
                                 var relativeDragDistance = (event.dragDistance / this._boundingDimensions.length())*this._anchorMesh.scaling.length();
                                 var deltaScale = new Vector3(relativeDragDistance,relativeDragDistance,relativeDragDistance);
                                 deltaScale.scaleInPlace(this._scaleDragSpeed);
                                 this.updateBoundingBox();
-
                                 if(this.scalePivot){
                                     this.attachedMesh.getWorldMatrix().getRotationMatrixToRef(this._tmpRotationMatrix);
                                     // Move anchor to desired pivot point (Bottom left corner + dimension/2)
@@ -261,7 +265,7 @@ module BABYLON {
                                 }
                                 this._anchorMesh.removeChild(this.attachedMesh);
 
-                                this.restorePivotPoint();
+                                BoundingBoxGizmo._RestorePivotPoint(this.attachedMesh);
                             }
                         })
 
@@ -313,8 +317,10 @@ module BABYLON {
             if (value) {
                 // Reset anchor mesh to match attached mesh's scale
                 // This is needed to avoid invalid box/sphere position on first drag
+                BoundingBoxGizmo._RemoveAndStorePivotPoint(value);
                 this._anchorMesh.addChild(value);
                 this._anchorMesh.removeChild(value);
+                BoundingBoxGizmo._RestorePivotPoint(value);
                 this.updateBoundingBox();
             }
         }
@@ -340,7 +346,7 @@ module BABYLON {
          */
         public updateBoundingBox(){
             if(this.attachedMesh){
-                this.removeAndStorePivotPoint();
+                BoundingBoxGizmo._RemoveAndStorePivotPoint(this.attachedMesh);
                 this._update();
                 // Rotate based on axis
                 if (!this.attachedMesh.rotationQuaternion) {
@@ -435,7 +441,7 @@ module BABYLON {
             }
             if (this.attachedMesh) {
                 this._existingMeshScale.copyFrom(this.attachedMesh.scaling);   
-                this.restorePivotPoint();
+                BoundingBoxGizmo._RestorePivotPoint(this.attachedMesh);
             }
         }
 

+ 4 - 0
src/Instrumentation/babylon.sceneInstrumentation.ts

@@ -214,6 +214,10 @@ module BABYLON {
 
             this._captureSpritesRenderTime = value;
 
+            if (!this.scene.spriteManagers) {
+                return;
+            }
+
             if (value) {
                 this._onBeforeSpritesRenderingObserver = this.scene.onBeforeSpritesRenderingObservable.add(() => {
                     Tools.StartPerformanceCounter("Sprites");

+ 4 - 1
src/Materials/Textures/Procedurals/babylon.noiseProceduralTexture.ts

@@ -40,11 +40,14 @@ module BABYLON {
             this._time += scene.getAnimationRatio() * this.animationSpeedFactor * 0.01;
 
             this.setFloat("brightness", this.brightness);
-            this.setInt("octaves", this.octaves);
             this.setFloat("persistence", this.persistence);
             this.setFloat("timeScale", this._time);
         }
 
+        protected _getDefines(): string {
+            return "#define OCTAVES " + this.octaves;
+        }
+
         /** Generate the current state of the procedural texture */
         public render(useCameraPostProcess?: boolean) {
             this._updateShaderUniforms();

+ 14 - 1
src/Materials/Textures/Procedurals/babylon.proceduralTexture.ts

@@ -38,6 +38,8 @@
         private _fallbackTextureUsed = false;
         private _engine: Engine;
 
+        private _cachedDefines = "";
+
         constructor(name: string, size: any, fragment: any, scene: Nullable<Scene>, fallbackTexture: Nullable<Texture> = null, generateMipMaps = true, public isCube = false) {
             super(null, scene, !generateMipMaps);
 
@@ -116,6 +118,10 @@
             engine._releaseEffect(this._effect);
         }
 
+        protected _getDefines(): string {
+            return "";
+        }
+
 
         public isReady(): boolean {
             var engine = this._engine;
@@ -129,6 +135,11 @@
                 return true;
             }
 
+            let defines = this._getDefines();
+            if (this._effect && defines === this._cachedDefines && this._effect.isReady()) {
+                return true;
+            }
+
             if (this._fragment.fragmentElement !== undefined) {
                 shaders = { vertex: "procedural", fragmentElement: this._fragment.fragmentElement };
             }
@@ -136,11 +147,13 @@
                 shaders = { vertex: "procedural", fragment: this._fragment };
             }
 
+            this._cachedDefines = defines;
+
             this._effect = engine.createEffect(shaders,
                 [VertexBuffer.PositionKind],
                 this._uniforms,
                 this._samplers,
-                "", undefined, undefined, () => {
+                defines, undefined, undefined, () => {
                     this.releaseInternalTexture();
 
                     if (this._fallbackTexture) {

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

@@ -2354,6 +2354,10 @@
             serializationObject.instances = [];
             for (var index = 0; index < this.instances.length; index++) {
                 var instance = this.instances[index];
+                if (instance.doNotSerialize) {
+                    continue;
+                }
+                
                 var serializationInstance: any = {
                     name: instance.name,
                     id: instance.id,
@@ -2683,7 +2687,11 @@
                     }
 
                     if (Tags) {
-                        Tags.AddTagsTo(instance, parsedInstance.tags);
+                        if (parsedInstance.tags) {
+                            Tags.AddTagsTo(instance, parsedInstance.tags);
+                        } else {
+                            Tags.AddTagsTo(instance, parsedMesh.tags);
+                        }
                     }
 
                     instance.position = Vector3.FromArray(parsedInstance.position);

+ 96 - 7
src/Particles/babylon.IParticleSystem.ts

@@ -200,17 +200,12 @@ module BABYLON {
         getCapacity(): number;
 
         /**
-         * Gets Wether the system has been started.
+         * Gets if the system has been started. (Note: this will still be true after stop is called)
          * @returns True if it has been started, otherwise false.
          */
         isStarted(): boolean;
 
         /**
-         * Gets if the particle system has been started.
-         * @return true if the system has been started, otherwise false.
-         */
-        isStarted(): boolean;
-        /**
          * Animates the particle system for this frame.
          */
         animate(): void;
@@ -375,6 +370,100 @@ module BABYLON {
          * @param gradient defines the gradient to remove
          * @returns the current particle system
          */
-        removeDragGradient(gradient: number): IParticleSystem;               
+        removeDragGradient(gradient: number): IParticleSystem;   
+        /**
+         * Gets the current list of drag gradients.
+         * You must use addDragGradient and removeDragGradient to udpate this list
+         * @returns the list of drag gradients
+         */
+        getDragGradients(): Nullable<Array<FactorGradient>>;                    
+        /**
+         * Adds a new emit rate gradient (please note that this will only work if you set the targetStopDuration property)
+         * @param gradient defines the gradient to use (between 0 and 1)
+         * @param factor defines the emit rate to affect to the specified gradient         
+         * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
+         * @returns the current particle system
+         */
+        addEmitRateGradient(gradient: number, factor: number, factor2?: number): IParticleSystem;
+        /**
+         * Remove a specific emit rate gradient
+         * @param gradient defines the gradient to remove
+         * @returns the current particle system
+         */
+        removeEmitRateGradient(gradient: number): IParticleSystem;    
+        /**
+         * Gets the current list of emit rate gradients.
+         * You must use addEmitRateGradient and removeEmitRateGradient to udpate this list
+         * @returns the list of emit rate gradients
+         */
+        getEmitRateGradients(): Nullable<Array<FactorGradient>>;                    
+        
+
+        /**
+         * Creates a Point Emitter for the particle system (emits directly from the emitter position)
+         * @param direction1 Particles are emitted between the direction1 and direction2 from within the box
+         * @param direction2 Particles are emitted between the direction1 and direction2 from within the box
+         * @returns the emitter
+         */
+        createPointEmitter(direction1: Vector3, direction2: Vector3): PointParticleEmitter;
+
+        /**
+         * Creates a Hemisphere Emitter for the particle system (emits along the hemisphere radius)
+         * @param radius The radius of the hemisphere to emit from
+         * @param radiusRange The range of the hemisphere to emit from [0-1] 0 Surface Only, 1 Entire Radius
+         * @returns the emitter
+         */
+        createHemisphericEmitter(radius: number, radiusRange: number): HemisphericParticleEmitter;
+
+        /**
+         * Creates a Sphere Emitter for the particle system (emits along the sphere radius)
+         * @param radius The radius of the sphere to emit from
+         * @param radiusRange The range of the sphere to emit from [0-1] 0 Surface Only, 1 Entire Radius
+         * @returns the emitter
+         */
+        createSphereEmitter(radius: number, radiusRange: number): SphereParticleEmitter;
+
+        /**
+         * Creates a Directed Sphere Emitter for the particle system (emits between direction1 and direction2)
+         * @param radius The radius of the sphere to emit from
+         * @param direction1 Particles are emitted between the direction1 and direction2 from within the sphere
+         * @param direction2 Particles are emitted between the direction1 and direction2 from within the sphere
+         * @returns the emitter
+         */
+        createDirectedSphereEmitter(radius: number, direction1:Vector3, direction2: Vector3): SphereDirectedParticleEmitter;
+
+        /**
+         * Creates a Cylinder Emitter for the particle system (emits from the cylinder to the particle position)
+         * @param radius The radius of the emission cylinder
+         * @param height The height of the emission cylinder
+         * @param radiusRange The range of emission [0-1] 0 Surface only, 1 Entire Radius
+         * @param directionRandomizer How much to randomize the particle direction [0-1]
+         * @returns the emitter
+         */
+        createCylinderEmitter(radius: number, height: number, radiusRange: number, directionRandomizer: number): CylinderParticleEmitter;
+
+        /**
+         * Creates a Cone Emitter for the particle system (emits from the cone to the particle position)
+         * @param radius The radius of the cone to emit from
+         * @param angle The base angle of the cone
+         * @returns the emitter
+         */
+        createConeEmitter(radius: number, angle: number): ConeParticleEmitter;
+
+        /**
+         * Creates a Box Emitter for the particle system. (emits between direction1 and direction2 from withing the box defined by minEmitBox and maxEmitBox)
+         * @param direction1 Particles are emitted between the direction1 and direction2 from within the box
+         * @param direction2 Particles are emitted between the direction1 and direction2 from within the box
+         * @param minEmitBox Particles are emitted from the box between minEmitBox and maxEmitBox
+         * @param maxEmitBox  Particles are emitted from the box between minEmitBox and maxEmitBox
+         * @returns the emitter
+         */
+        createBoxEmitter(direction1: Vector3, direction2: Vector3, minEmitBox: Vector3, maxEmitBox: Vector3): BoxParticleEmitter;   
+        
+        /**
+         * Get hosting scene
+         * @returns the scene
+         */
+        getScene(): Scene;
     }  
 }

+ 22 - 1
src/Particles/babylon.baseParticleSystem.ts

@@ -14,11 +14,14 @@ module BABYLON {
          * Blend current color and particle color using particle’s alpha.
          */
         public static BLENDMODE_STANDARD = 1;
-
         /**
          * Add current color and particle color multiplied by particle’s alpha.
          */
         public static BLENDMODE_ADD = 2;
+        /**
+         * Multiply current color with particle color 
+         */
+        public static BLENDMODE_MULTIPLY = 3;        
 
         /**
          * List of animations used by the particle system.
@@ -228,6 +231,14 @@ module BABYLON {
 
             this._reset();
         }
+        
+        /**
+         * Get hosting scene
+         * @returns the scene
+         */
+        public getScene(): Scene {
+            return this._scene;
+        }    
 
         /**
          * You can use gravity if you want to give an orientation to your particles.
@@ -241,6 +252,7 @@ module BABYLON {
         protected _velocityGradients: Nullable<Array<FactorGradient>> = null;
         protected _limitVelocityGradients: Nullable<Array<FactorGradient>> = null;
         protected _dragGradients: Nullable<Array<FactorGradient>> = null;
+        protected _emitRateGradients: Nullable<Array<FactorGradient>> = null;
 
         /**
          * Gets the current list of drag gradients.
@@ -309,6 +321,15 @@ module BABYLON {
         }         
 
         /**
+         * Gets the current list of emit rate gradients.
+         * You must use addEmitRateGradient and removeEmitRateGradient to udpate this list
+         * @returns the list of emit rate gradients
+         */
+        public getEmitRateGradients(): Nullable<Array<FactorGradient>> {
+            return this._emitRateGradients;
+        }             
+
+        /**
          * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
          * This only works when particleEmitterTyps is a BoxParticleEmitter
          */

+ 37 - 3
src/Particles/babylon.gpuParticleSystem.ts

@@ -108,7 +108,7 @@
         }        
 
         /**
-         * Gets Wether the system has been started.
+         * Gets if the system has been started. (Note: this will still be true after stop is called)
          * @returns True if it has been started, otherwise false.
          */
         public isStarted(): boolean {
@@ -428,7 +428,29 @@
             (<any>this._dragGradientsTexture) = null;
 
             return this;
-        }        
+        }   
+        
+        /**
+         * Not supported by GPUParticleSystem
+         * @param gradient defines the gradient to use (between 0 and 1)
+         * @param factor defines the emit rate value to affect to the specified gradient         
+         * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
+         * @returns the current particle system
+         */
+        public addEmitRateGradient(gradient: number, factor: number, factor2?: number): IParticleSystem {
+            // Do nothing as emit rate is not supported by GPUParticleSystem
+            return this;
+        }
+
+        /**
+         * Not supported by GPUParticleSystem
+         * @param gradient defines the gradient to remove
+         * @returns the current particle system
+         */
+        public removeEmitRateGradient(gradient: number): IParticleSystem {
+            // Do nothing as emit rate is not supported by GPUParticleSystem
+            return this;
+        } 
 
         /**
          * Instantiates a GPU particle system.
@@ -781,6 +803,10 @@
                 defines = "\n#define CLIPPLANE4";
             }
 
+            if (this.blendMode === ParticleSystem.BLENDMODE_MULTIPLY) {
+                defines = "\n#define BLENDMULTIPLYMODE";
+            }
+
             if (this._isBillboardBased) {
                 defines += "\n#define BILLBOARD";
 
@@ -1064,6 +1090,9 @@
                     case ParticleSystem.BLENDMODE_STANDARD:
                         this._engine.setAlphaMode(Engine.ALPHA_COMBINE);
                         break;
+                    case ParticleSystem.BLENDMODE_MULTIPLY:
+                        this._engine.setAlphaMode(Engine.ALPHA_MULTIPLY);
+                        break; 
                 }      
 
                 if (this.forceDepthWrite) {
@@ -1165,7 +1194,12 @@
             if (this._limitVelocityGradientsTexture) {
                 this._limitVelocityGradientsTexture.dispose();
                 (<any>this._limitVelocityGradientsTexture) = null;
-            }         
+            }                   
+
+            if (this._dragGradientsTexture) {
+                this._dragGradientsTexture.dispose();
+                (<any>this._dragGradientsTexture) = null;
+            }               
          
             if (this._randomTexture) {
                 this._randomTexture.dispose();

+ 9 - 2
src/Particles/babylon.particleHelper.ts

@@ -13,10 +13,17 @@ module BABYLON {
          * @param emitter defines the emitter to use
          * @param capacity defines the system capacity (default is 500 particles)
          * @param scene defines the hosting scene
+         * @param useGPU defines if a GPUParticleSystem must be created (default is false)
          * @returns the new Particle system
          */
-        public static CreateDefault(emitter: Nullable<AbstractMesh | Vector3>, capacity = 500, scene?: Scene): ParticleSystem {
-            var system = new ParticleSystem("default system", capacity, scene!);
+        public static CreateDefault(emitter: Nullable<AbstractMesh | Vector3>, capacity = 500, scene?: Scene, useGPU = false): IParticleSystem {
+            var system: IParticleSystem;
+            
+            if (useGPU) {
+                system= new GPUParticleSystem("default system", {capacity: capacity}, scene!);
+            } else {
+                system= new ParticleSystem("default system", capacity, scene!);
+            }
         
             system.emitter = emitter;
             system.particleTexture = new Texture("https://www.babylonjs.com/assets/Flare.png", system.getScene());

+ 122 - 17
src/Particles/babylon.particleSystem.ts

@@ -43,16 +43,6 @@
             this._onDisposeObserver = this.onDisposeObservable.add(callback);
         }
 
-
-
-        /**
-         * Get hosting scene
-         * @returns the scene
-         */
-        public getScene(): Scene {
-            return this._scene;
-        }    
-
         private _particles = new Array<Particle>();
         private _epsilon: number;
         private _capacity: number;
@@ -80,6 +70,13 @@
         private _scaledUpdateSpeed: number;
         private _vertexBufferSize: number;
 
+        /** @hidden */
+        public _currentEmitRateGradient: Nullable<FactorGradient>;
+        /** @hidden */
+        public _currentEmitRate1 = 0;
+        /** @hidden */
+        public _currentEmitRate2 = 0;              
+
         // end of sheet animation
 
         // Sub-emitters
@@ -413,8 +410,8 @@
             this._removeFactorGradient(this._angularSpeedGradients, gradient);
 
             return this;
-        }          
-        
+        }     
+                   
         /**
          * Adds a new velocity gradient
          * @param gradient defines the gradient to use (between 0 and 1)
@@ -497,6 +494,44 @@
             this._removeFactorGradient(this._dragGradients, gradient);
 
             return this;
+        }         
+        
+        /**
+         * Adds a new emit rate gradient (please note that this will only work if you set the targetStopDuration property)
+         * @param gradient defines the gradient to use (between 0 and 1)
+         * @param factor defines the emit rate value to affect to the specified gradient         
+         * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
+         * @returns the current particle system
+         */
+        public addEmitRateGradient(gradient: number, factor: number, factor2?: number): IParticleSystem {
+            if (!this._emitRateGradients) {
+                this._emitRateGradients = [];
+            }
+
+            this._addFactorGradient(this._emitRateGradients, gradient, factor, factor2);
+
+            if (!this._currentEmitRateGradient) {
+                this._currentEmitRateGradient = this._emitRateGradients[0];
+                this._currentEmitRate1 = this._currentEmitRateGradient.getFactor();
+                this._currentEmitRate2 = this._currentEmitRate1;
+            }
+
+            if (this._emitRateGradients.length === 2) {
+                this._currentEmitRate2 = this._emitRateGradients[1].getFactor();
+            }
+
+            return this;
+        }
+
+        /**
+         * Remove a specific emit rate gradient
+         * @param gradient defines the gradient to remove
+         * @returns the current particle system
+         */
+        public removeEmitRateGradient(gradient: number): IParticleSystem {
+            this._removeFactorGradient(this._emitRateGradients, gradient);
+
+            return this;
         }           
 
         /**
@@ -671,7 +706,7 @@
         }
 
         /**
-         * Gets whether the system has been started.
+         * Gets if the system has been started. (Note: this will still be true after stop is called)
          * @returns True if it has been started, otherwise false.
          */
         public isStarted(): boolean {
@@ -977,7 +1012,7 @@
                     } else {
                         particle._currentDrag2 = particle._currentDrag1;
                     }
-                }          
+                }            
 
                 // Color
                 if (!this._colorGradients || this._colorGradients.length === 0) {
@@ -1059,6 +1094,10 @@
                 defines.push("#define ANIMATESHEET");
             }
 
+            if (this.blendMode === ParticleSystem.BLENDMODE_MULTIPLY) {
+                defines.push("#define BLENDMULTIPLYMODE");
+            }
+
             if (this._isBillboardBased) {
                 defines.push("#define BILLBOARD");
 
@@ -1125,7 +1164,7 @@
 
             this._scaledUpdateSpeed = this.updateSpeed * (preWarmOnly ? this.preWarmStepOffset : this._scene.getAnimationRatio());
 
-            // determine the number of particles we need to create
+            // Determine the number of particles we need to create
             var newParticles;
 
             if (this.manualEmitCount > -1) {
@@ -1133,8 +1172,23 @@
                 this._newPartsExcess = 0;
                 this.manualEmitCount = 0;
             } else {
-                newParticles = ((this.emitRate * this._scaledUpdateSpeed) >> 0);
-                this._newPartsExcess += this.emitRate * this._scaledUpdateSpeed - newParticles;
+                let rate = this.emitRate;
+
+                if (this._emitRateGradients && this._emitRateGradients.length > 0 && this.targetStopDuration) {   
+                    const ratio = this._actualFrame / this.targetStopDuration;               
+                    Tools.GetCurrentGradient(ratio, this._emitRateGradients, (currentGradient, nextGradient, scale) => {
+                        if (currentGradient !== this._currentEmitRateGradient) {
+                            this._currentEmitRate1 = this._currentEmitRate2;
+                            this._currentEmitRate2 = (<FactorGradient>nextGradient).getFactor();    
+                            this._currentEmitRateGradient = (<FactorGradient>currentGradient);
+                        }                                
+                        
+                        rate = Scalar.Lerp(this._currentEmitRate1, this._currentEmitRate2, scale);
+                    });
+                }                   
+
+                newParticles = ((rate * this._scaledUpdateSpeed) >> 0);
+                this._newPartsExcess += rate * this._scaledUpdateSpeed - newParticles;
             }
 
             if (this._newPartsExcess > 1.0) {
@@ -1281,6 +1335,9 @@
                 case ParticleSystem.BLENDMODE_STANDARD:
                     engine.setAlphaMode(Engine.ALPHA_COMBINE);
                     break;
+                case ParticleSystem.BLENDMODE_MULTIPLY:
+                    engine.setAlphaMode(Engine.ALPHA_MULTIPLY);
+                    break;                    
             }
 
             if (this.forceDepthWrite) {
@@ -1530,6 +1587,42 @@
                 }
             }    
 
+            let dragGradients = particleSystem.getDragGradients();
+            if (dragGradients) {
+                serializationObject.dragyGradients = [];
+                for (var dragGradient of dragGradients) {
+
+                    var serializedGradient: any = {
+                        gradient: dragGradient.gradient,
+                        factor1: dragGradient.factor1
+                    };
+
+                    if (dragGradient.factor2 !== undefined) {
+                        serializedGradient.factor2 = dragGradient.factor2;
+                    }
+
+                    serializationObject.dragGradients.push(serializedGradient);
+                }
+            }    
+            
+            let emitRateGradients = particleSystem.getEmitRateGradients();
+            if (emitRateGradients) {
+                serializationObject.emitRateGradients = [];
+                for (var emitRateGradient of emitRateGradients) {
+
+                    var serializedGradient: any = {
+                        gradient: emitRateGradient.gradient,
+                        factor1: emitRateGradient.factor1
+                    };
+
+                    if (emitRateGradient.factor2 !== undefined) {
+                        serializedGradient.factor2 = emitRateGradient.factor2;
+                    }
+
+                    serializationObject.emitRateGradients.push(serializedGradient);
+                }
+            }                
+
             let limitVelocityGradients = particleSystem.getLimitVelocityGradients();
             if (limitVelocityGradients) {
                 serializationObject.limitVelocityGradients = [];
@@ -1659,6 +1752,18 @@
                 }
             }     
 
+            if (parsedParticleSystem.dragGradients) {
+                for (var dragGradient of parsedParticleSystem.dragGradients) {
+                    particleSystem.addDragGradient(dragGradient.gradient, dragGradient.factor1 !== undefined ?  dragGradient.factor1 : dragGradient.factor, dragGradient.factor2);
+                }
+            }        
+            
+            if (parsedParticleSystem.emitRateGradients) {
+                for (var emitRateGradient of parsedParticleSystem.emitRateGradients) {
+                    particleSystem.addEmitRateGradient(emitRateGradient.gradient, emitRateGradient.factor1 !== undefined ?  emitRateGradient.factor1 : emitRateGradient.factor, emitRateGradient.factor2);
+                }
+            }               
+
             if (parsedParticleSystem.limitVelocityGradients) {
                 for (var limitVelocityGradient of parsedParticleSystem.limitVelocityGradients) {
                     particleSystem.addLimitVelocityGradient(limitVelocityGradient.gradient, limitVelocityGradient.factor1 !== undefined ?  limitVelocityGradient.factor1 : limitVelocityGradient.factor, limitVelocityGradient.factor2);

+ 2 - 2
src/PostProcess/babylon.postProcess.ts

@@ -489,8 +489,8 @@
             this.onActivateObservable.notifyObservers(camera);
 
             // Clear
-            if (scene._allowPostProcessClear && this.autoClear && this.alphaMode === Engine.ALPHA_DISABLE) {
-                this._engine.clear(this.clearColor ? this.clearColor : scene.clearColor, true, true, true);
+            if (this.autoClear && this.alphaMode === Engine.ALPHA_DISABLE) {
+                this._engine.clear(this.clearColor ? this.clearColor : scene.clearColor, scene._allowPostProcessClearColor, true, true);
             }
 
             if (this._reusable) {

+ 2 - 2
src/Rendering/babylon.renderingGroup.ts

@@ -6,7 +6,7 @@
         private _alphaTestSubMeshes = new SmartArray<SubMesh>(256);
         private _depthOnlySubMeshes = new SmartArray<SubMesh>(256);
         private _particleSystems = new SmartArray<IParticleSystem>(256);
-        private _spriteManagers = new SmartArray<SpriteManager>(256);
+        private _spriteManagers = new SmartArray<ISpriteManager>(256);
 
         private _opaqueSortCompareFn: Nullable<(a: SubMesh, b: SubMesh) => number>;
         private _alphaTestSortCompareFn: Nullable<(a: SubMesh, b: SubMesh) => number>;
@@ -350,7 +350,7 @@
             }
         }
 
-        public dispatchSprites(spriteManager: SpriteManager) {
+        public dispatchSprites(spriteManager: ISpriteManager) {
             this._spriteManagers.push(spriteManager);
         }
 

+ 2 - 2
src/Rendering/babylon.renderingManager.ts

@@ -76,7 +76,7 @@
             info.camera = this._scene.activeCamera;
 
             // Dispatch sprites
-            if (renderSprites) {
+            if (this._scene.spriteManagers && renderSprites) {
                 for (let index = 0; index < this._scene.spriteManagers.length; index++) {
                     var manager = this._scene.spriteManagers[index];
                     this.dispatchSprites(manager);
@@ -158,7 +158,7 @@
             }
         }
 
-        public dispatchSprites(spriteManager: SpriteManager) {
+        public dispatchSprites(spriteManager: ISpriteManager) {
             var renderingGroupId = spriteManager.renderingGroupId || 0;
 
             this._prepareRenderingGroup(renderingGroupId);

+ 1 - 1
src/Rendering/babylon.utilityLayerRenderer.ts

@@ -72,7 +72,7 @@ module BABYLON {
             public originalScene: Scene){
             // Create scene which will be rendered in the foreground and remove it from being referenced by engine to avoid interfering with existing app
             this.utilityLayerScene = new BABYLON.Scene(originalScene.getEngine());
-            this.utilityLayerScene._allowPostProcessClear = false;
+            this.utilityLayerScene._allowPostProcessClearColor = false;
             originalScene.getEngine().scenes.pop();
       
             // Detach controls on utility scene, events will be fired by logic below to handle picking priority

+ 7 - 1
src/Shaders/gpuRenderParticles.fragment.fx

@@ -17,7 +17,13 @@ out vec4 outFragColor;
 
 void main() {
 	#include<clipPlaneFragment> 
-  	outFragColor = texture(textureSampler, vUV) * vColor;
+	vec4 textureColor = texture(textureSampler, vUV);
+  	outFragColor = textureColor * vColor;
+
+	#ifdef BLENDMULTIPLYMODE
+	float alpha = vColor.a * textureColor.a;
+	outFragColor.rgb = outFragColor.rgb * alpha + vec3(1.0) * (1.0 - alpha);	
+	#endif	  
 
 // Apply image processing if relevant. As this applies in linear space, 
 // We first move from gamma to linear.

+ 7 - 22
src/Shaders/gpuUpdateParticles.vertex.fx

@@ -138,26 +138,11 @@ vec4 getRandomVec4(float offset) {
 
 void main() {
   float newAge = age + timeDelta;
-  if (newAge >= life) {
-    if (stopFactor == 0.) {
-      outPosition = position;
-      outAge = life;
-      outLife = life;
-      outSeed = seed;
-#ifndef COLORGRADIENTS      
-      outColor = vec4(0.,0.,0.,0.);
-#endif
-      outSize = vec3(0., 0., 0.);
-#ifndef BILLBOARD        
-      outInitialDirection = initialDirection;
-#endif      
-      outDirection = direction;
-      outAngle = angle;
-#ifdef ANIMATESHEET      
-      outCellIndex = cellIndex;
-#endif
-      return;
-    }
+
+    
+
+  // If particle is dead and system is not stopped, spawn as new particle
+  if (newAge >= life && stopFactor != 0.) {
     vec3 position;
     vec3 direction;
 
@@ -165,8 +150,8 @@ void main() {
     vec4 randoms = getRandomVec4(seed.x);
 
     // Age and life
-    outAge = 0.0;
     outLife = lifeTime.x + (lifeTime.y - lifeTime.x) * randoms.r;
+    outAge = mod(newAge, outLife);
 
     // Seed
     outSeed = seed;
@@ -307,7 +292,7 @@ void main() {
     outCellIndex = cellInfos.x;
 #endif
 
-  } else {   
+  } else {
     float directionScale = timeDelta;
     outAge = newAge;
     float ageGradient = newAge / life;

+ 1 - 2
src/Shaders/noise.fragment.fx

@@ -2,7 +2,6 @@
 
 // Uniforms
 uniform float brightness;
-uniform int octaves;
 uniform float persistence;
 uniform float timeScale;
 
@@ -42,7 +41,7 @@ float perlinNoise2D(float x,float y)
     float sum = 0.0;
     float frequency = 0.0;
     float amplitude = 0.0;
-    for(int i = 0; i < octaves; i++)
+    for(int i = 0; i < OCTAVES; i++)
     {
         frequency = pow(2.0, float(i));
         amplitude = pow(persistence, float(i));

+ 7 - 2
src/Shaders/particles.fragment.fx

@@ -15,8 +15,13 @@ uniform sampler2D diffuseSampler;
 void main(void) {
 	#include<clipPlaneFragment>
 
-	vec4 baseColor = texture2D(diffuseSampler, vUV);
-	baseColor = (baseColor * textureMask + (vec4(1., 1., 1., 1.) - textureMask)) * vColor;
+	vec4 textureColor = texture2D(diffuseSampler, vUV);
+	vec4 baseColor = (textureColor * textureMask + (vec4(1., 1., 1., 1.) - textureMask)) * vColor;
+
+	#ifdef BLENDMULTIPLYMODE
+	float alpha = vColor.a * textureColor.a;
+	baseColor.rgb = baseColor.rgb * alpha + vec3(1.0) * (1.0 - alpha);
+	#endif
 
 // Apply image processing if relevant. As this applies in linear space, 
 // We first move from gamma to linear.

+ 2 - 2
src/Sprites/babylon.sprite.ts

@@ -19,7 +19,7 @@
         private _toIndex = 0;
         private _delay = 0;
         private _direction = 1;
-        private _manager: SpriteManager;
+        private _manager: ISpriteManager;
         private _time = 0;
         private _onAnimationEnd: () => void;
         /**
@@ -36,7 +36,7 @@
             this.height = value;
         }
 
-        constructor(public name: string, manager: SpriteManager) {
+        constructor(public name: string, manager: ISpriteManager) {
             this._manager = manager;
 
             this._manager.sprites.push(this);

+ 46 - 1
src/Sprites/babylon.spriteManager.ts

@@ -1,5 +1,47 @@
 module BABYLON {
-    export class SpriteManager {
+    /**
+     * Defines the minimum interface to fullfil in order to be a sprite manager.
+     */
+    export interface ISpriteManager extends IDisposable {
+        /**
+         * Restricts the camera to viewing objects with the same layerMask.
+         * A camera with a layerMask of 1 will render spriteManager.layerMask & camera.layerMask!== 0
+         */
+        layerMask: number;
+
+        /**
+         * Gets or sets a boolean indicating if the mesh can be picked (by scene.pick for instance or through actions). Default is true
+         */
+        isPickable: boolean;
+
+        /** 
+         * Specifies the rendering group id for this mesh (0 by default) 
+         * @see http://doc.babylonjs.com/resources/transparency_and_how_meshes_are_rendered#rendering-groups
+         */
+        renderingGroupId: number;
+
+        /**
+         * Defines the list of sprites managed by the manager.
+         */
+        sprites: Array<Sprite>;
+
+        /**
+         * Tests the intersection of a sprite with a specific ray.
+         * @param ray The ray we are sending to test the collision
+         * @param camera The camera space we are sending rays in
+         * @param predicate A predicate allowing excluding sprites from the list of object to test
+         * @param fastCheck Is the hit test done in a OOBB or AOBB fashion the faster, the less precise
+         * @returns picking info or null.
+         */
+        intersects(ray: Ray, camera:Camera, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean): Nullable<PickingInfo>;
+
+        /**
+         * Renders the list of sprites on screen.
+         */
+        render(): void;
+    }
+
+    export class SpriteManager implements ISpriteManager {
         public sprites = new Array<Sprite>();
         public renderingGroupId = 0;
         public layerMask: number = 0x0FFFFFFF;
@@ -43,6 +85,9 @@
         }
 
         constructor(public name: string, imgUrl: string, capacity: number, cellSize: any, scene: Scene, epsilon: number = 0.01, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) {
+            if (!scene._getComponent(SceneComponentConstants.NAME_SPRITE)) {
+                scene._addComponent(new SpriteSceneComponent(scene));
+            }
             this._capacity = capacity;
             this._spriteTexture = new Texture(imgUrl, scene, true, false, samplingMode);
             this._spriteTexture.wrapU = Texture.CLAMP_ADDRESSMODE;

+ 297 - 0
src/Sprites/babylon.spriteSceneComponent.ts

@@ -0,0 +1,297 @@
+module BABYLON {
+    export interface Scene {
+        /** @hidden */
+        _pointerOverSprite: Nullable<Sprite>;
+
+        /** @hidden */
+        _pickedDownSprite: Nullable<Sprite>;
+
+        /** @hidden */
+        _tempSpritePickingRay: Nullable<Ray>;
+
+        /**
+         * All of the sprite managers added to this scene
+         * @see http://doc.babylonjs.com/babylon101/sprites
+         */
+        spriteManagers: Array<ISpriteManager>;
+
+        /**
+         * An event triggered when sprites rendering is about to start
+         * Note: This event can be trigger more than once per frame (because sprites can be rendered by render target textures as well)
+         */
+        onBeforeSpritesRenderingObservable: Observable<Scene>;
+
+        /**
+         * An event triggered when sprites rendering is done
+         * Note: This event can be trigger more than once per frame (because sprites can be rendered by render target textures as well)
+         */
+        onAfterSpritesRenderingObservable: Observable<Scene>;
+
+        /** @hidden */
+        _internalPickSprites(ray: Ray, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean, camera?: Camera): Nullable<PickingInfo>;
+
+        /** Launch a ray to try to pick a sprite in the scene
+         * @param x position on screen
+         * @param y position on screen
+         * @param predicate Predicate function used to determine eligible sprites. Can be set to null. In this case, a sprite must have isPickable set to true
+         * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null.
+         * @param camera camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
+         * @returns a PickingInfo
+         */
+        pickSprite(x: number, y: number, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean, camera?: Camera): Nullable<PickingInfo>;
+
+        /** Use the given ray to pick a sprite in the scene
+         * @param ray The ray (in world space) to use to pick meshes
+         * @param predicate Predicate function used to determine eligible sprites. Can be set to null. In this case, a sprite must have isPickable set to true
+         * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null.
+         * @param camera camera to use. Can be set to null. In this case, the scene.activeCamera will be used
+         * @returns a PickingInfo
+         */
+        pickSpriteWithRay(ray: Ray, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean, camera?: Camera): Nullable<PickingInfo>;
+
+        /** 
+         * Force the sprite under the pointer
+         * @param sprite defines the sprite to use
+         */
+        setPointerOverSprite(sprite: Nullable<Sprite>): void;
+
+        /** 
+         * Gets the sprite under the pointer
+         * @returns a Sprite or null if no sprite is under the pointer
+         */
+        getPointerOverSprite(): Nullable<Sprite>;
+    }
+
+    Scene.prototype._internalPickSprites = function(ray: Ray, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean, camera?: Camera): Nullable<PickingInfo> {
+        if (!PickingInfo) {
+            return null;
+        }
+
+        var pickingInfo = null;
+
+        if (!camera) {
+            if (!this.activeCamera) {
+                return null;
+            }
+            camera = this.activeCamera;
+        }
+
+        if (this.spriteManagers.length > 0) {
+            for (var spriteIndex = 0; spriteIndex < this.spriteManagers.length; spriteIndex++) {
+                var spriteManager = this.spriteManagers[spriteIndex];
+
+                if (!spriteManager.isPickable) {
+                    continue;
+                }
+
+                var result = spriteManager.intersects(ray, camera, predicate, fastCheck);
+                if (!result || !result.hit)
+                    continue;
+
+                if (!fastCheck && pickingInfo != null && result.distance >= pickingInfo.distance)
+                    continue;
+
+                pickingInfo = result;
+
+                if (fastCheck) {
+                    break;
+                }
+            }
+        }
+
+        return pickingInfo || new PickingInfo();
+    }
+
+    Scene.prototype.pickSprite = function(x: number, y: number, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean, camera?: Camera): Nullable<PickingInfo> {
+        this.createPickingRayInCameraSpaceToRef(x, y, this._tempSpritePickingRay!, camera);
+
+        return this._internalPickSprites(this._tempSpritePickingRay!, predicate, fastCheck, camera);
+    }
+
+    Scene.prototype.pickSpriteWithRay = function(ray: Ray, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean, camera?: Camera): Nullable<PickingInfo> {
+        if (!this._tempSpritePickingRay) {
+            return null;
+        }
+
+        if (!camera) {
+            if (!this.activeCamera) {
+                return null;
+            }
+            camera = this.activeCamera;
+        }
+
+        Ray.TransformToRef(ray, camera.getViewMatrix(), this._tempSpritePickingRay);
+
+        return this._internalPickSprites(this._tempSpritePickingRay, predicate, fastCheck, camera);
+    }
+
+    Scene.prototype.setPointerOverSprite = function(sprite: Nullable<Sprite>): void {
+        if (this._pointerOverSprite === sprite) {
+            return;
+        }
+
+        if (this._pointerOverSprite && this._pointerOverSprite.actionManager) {
+            this._pointerOverSprite.actionManager.processTrigger(ActionManager.OnPointerOutTrigger, ActionEvent.CreateNewFromSprite(this._pointerOverSprite, this));
+        }
+
+        this._pointerOverSprite = sprite;
+        if (this._pointerOverSprite && this._pointerOverSprite.actionManager) {
+            this._pointerOverSprite.actionManager.processTrigger(ActionManager.OnPointerOverTrigger, ActionEvent.CreateNewFromSprite(this._pointerOverSprite, this));
+        }
+    }
+
+    Scene.prototype.getPointerOverSprite = function(): Nullable<Sprite> {
+        return this._pointerOverSprite;
+    }
+
+    /**
+     * Defines the sprite scene component responsible to manage sprites
+     * in a given scene.
+     */
+    export class SpriteSceneComponent implements ISceneComponent {
+        /**
+         * The component name helpfull to identify the component in the list of scene components.
+         */
+        public readonly name = SceneComponentConstants.NAME_SPRITE;
+
+        /**
+         * The scene the component belongs to.
+         */
+        public scene: Scene;
+
+        /** @hidden */
+        private _spritePredicate: (sprite: Sprite) => boolean;
+
+        /**
+         * Creates a new instance of the component for the given scene
+         * @param scene Defines the scene to register the component in
+         */
+        constructor(scene: Scene) {
+            this.scene = scene;
+            this.scene.spriteManagers = new Array<ISpriteManager>();
+            this.scene._tempSpritePickingRay = Ray ? Ray.Zero() : null;
+            this.scene.onBeforeSpritesRenderingObservable = new Observable<Scene>();
+            this.scene.onAfterSpritesRenderingObservable = new Observable<Scene>();
+            this._spritePredicate = (sprite: Sprite): boolean => {
+                return sprite.isPickable && sprite.actionManager && sprite.actionManager.hasPointerTriggers;
+            };
+        }
+
+        /**
+         * Registers the component in a given scene
+         */
+        public register(): void {
+            this.scene._pointerMoveStage.registerStep(SceneComponentConstants.STEP_POINTERMOVE_SPRITE, this, this._pointerMove);
+            this.scene._pointerDownStage.registerStep(SceneComponentConstants.STEP_POINTERDOWN_SPRITE, this, this._pointerDown);
+            this.scene._pointerUpStage.registerStep(SceneComponentConstants.STEP_POINTERUP_SPRITE, this, this._pointerUp);
+        }
+
+        /**
+         * Rebuilds the elements related to this component in case of
+         * context lost for instance.
+         */
+        public rebuild(): void {
+            /** Nothing to do for sprites */
+        }
+
+        /**
+         * Disposes the component and the associated ressources.
+         */
+        public dispose(): void {
+            this.scene.onBeforeSpritesRenderingObservable.clear();
+            this.scene.onAfterSpritesRenderingObservable.clear();
+
+            let spriteManagers = this.scene.spriteManagers;
+            while (spriteManagers.length) {
+                spriteManagers[0].dispose();
+            }
+        }
+
+        private _pickSpriteButKeepRay(originalPointerInfo: Nullable<PickingInfo>, x: number, y: number, fastCheck?: boolean, camera?: Camera): Nullable<PickingInfo> {
+            var result = this.scene.pickSprite(x, y, this._spritePredicate, fastCheck, camera);
+            if (result) {
+                result.ray = originalPointerInfo ? originalPointerInfo.ray : null;
+            }
+            return result;
+        }
+
+        private _pointerMove(unTranslatedPointerX: number, unTranslatedPointerY: number, pickResult: Nullable<PickingInfo>, isMeshPicked: boolean, canvas: HTMLCanvasElement): Nullable<PickingInfo> {
+            var scene = this.scene;
+            if (isMeshPicked) {
+                scene.setPointerOverSprite(null);
+            } else {
+                pickResult = this._pickSpriteButKeepRay(pickResult, unTranslatedPointerX, unTranslatedPointerY, false, scene.cameraToUseForPointers || undefined);
+
+                if (pickResult && pickResult.hit && pickResult.pickedSprite) {
+                    scene.setPointerOverSprite(pickResult.pickedSprite);
+                    if (scene._pointerOverSprite && scene._pointerOverSprite.actionManager && scene._pointerOverSprite.actionManager.hoverCursor) {
+                        canvas.style.cursor = scene._pointerOverSprite.actionManager.hoverCursor;
+                    } else {
+                        canvas.style.cursor = scene.hoverCursor;
+                    }
+                } else {
+                    scene.setPointerOverSprite(null);
+                    // Restore pointer
+                    canvas.style.cursor = scene.defaultCursor;
+                }
+            }
+
+            return pickResult;
+        }
+
+        private _pointerDown(unTranslatedPointerX: number, unTranslatedPointerY: number, pickResult: Nullable<PickingInfo>, evt: PointerEvent): Nullable<PickingInfo> {
+            var scene = this.scene;
+            scene._pickedDownSprite = null;
+            if (scene.spriteManagers.length > 0) {
+                pickResult = scene.pickSprite(unTranslatedPointerX, unTranslatedPointerY, this._spritePredicate, false, scene.cameraToUseForPointers || undefined);
+
+                if (pickResult && pickResult.hit && pickResult.pickedSprite) {
+                    if (pickResult.pickedSprite.actionManager) {
+                        scene._pickedDownSprite = pickResult.pickedSprite;
+                        switch (evt.button) {
+                            case 0:
+                                pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnLeftPickTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, scene, evt));
+                                break;
+                            case 1:
+                                pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnCenterPickTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, scene, evt));
+                                break;
+                            case 2:
+                                pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnRightPickTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, scene, evt));
+                                break;
+                        }
+                        if (pickResult.pickedSprite.actionManager) {
+                            pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnPickDownTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, scene, evt));
+                        }
+                    }
+                }
+            }
+
+            return pickResult;
+        }
+
+        private _pointerUp(unTranslatedPointerX: number, unTranslatedPointerY: number, pickResult: Nullable<PickingInfo>, evt: PointerEvent): Nullable<PickingInfo> {
+            var scene = this.scene;
+            if (scene.spriteManagers.length > 0) {
+                let spritePickResult = scene.pickSprite(unTranslatedPointerX, unTranslatedPointerY, this._spritePredicate, false, scene.cameraToUseForPointers || undefined);
+
+                if (spritePickResult) {
+                    if (spritePickResult.hit && spritePickResult.pickedSprite) {
+                        if (spritePickResult.pickedSprite.actionManager) {
+                            spritePickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnPickUpTrigger, ActionEvent.CreateNewFromSprite(spritePickResult.pickedSprite, scene, evt));
+                            if (spritePickResult.pickedSprite.actionManager) {
+                                if (!this.scene._isPointerSwiping()) {
+                                    spritePickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnPickTrigger, ActionEvent.CreateNewFromSprite(spritePickResult.pickedSprite, scene, evt));
+                                }
+                            }
+                        }
+                    }
+                    if (scene._pickedDownSprite && scene._pickedDownSprite.actionManager && scene._pickedDownSprite !== spritePickResult.pickedSprite) {
+                        scene._pickedDownSprite.actionManager.processTrigger(ActionManager.OnPickOutTrigger, ActionEvent.CreateNewFromSprite(scene._pickedDownSprite, scene, evt));
+                    }
+                }
+            }
+
+            return pickResult;
+        }
+    }
+}

+ 10 - 4
src/Tools/babylon.filesInput.ts

@@ -10,7 +10,7 @@
         private _progressCallback: (progress: SceneLoaderProgressEvent) => void;
         private _additionalRenderLoopLogicCallback: () => void;
         private _textureLoadingCallback: (remaining: number) => void;
-        private _startingProcessingFilesCallback: () => void;
+        private _startingProcessingFilesCallback: (files?: File[]) => void;
         private _onReloadCallback: (sceneFile: File) => void;
         private _errorCallback: (sceneFile: File, scene: Scene, message: string) => void;
         private _elementToMonitor: HTMLElement;
@@ -19,7 +19,7 @@
         private _filesToLoad: File[];
 
         constructor(engine: Engine, scene: Scene, sceneLoadedCallback: (sceneFile: File, scene: Scene) => void, progressCallback: (progress: SceneLoaderProgressEvent) => void, additionalRenderLoopLogicCallback: () => void, 
-            textureLoadingCallback: (remaining: number) => void, startingProcessingFilesCallback: () => void, onReloadCallback: (sceneFile: File) => void, errorCallback: (sceneFile: File, scene: Scene, message: string) => void) {
+            textureLoadingCallback: (remaining: number) => void, startingProcessingFilesCallback: (files?: File[]) => void, onReloadCallback: (sceneFile: File) => void, errorCallback: (sceneFile: File, scene: Scene, message: string) => void) {
             this._engine = engine;
             this._currentScene = scene;
 
@@ -136,8 +136,6 @@
         }
 
         public loadFiles(event: any): void {
-            if (this._startingProcessingFilesCallback) this._startingProcessingFilesCallback();
-
             // Handling data transfer via drag'n'drop
             if (event && event.dataTransfer && event.dataTransfer.files) {
                 this._filesToLoad = event.dataTransfer.files;
@@ -148,6 +146,14 @@
                 this._filesToLoad = event.target.files;
             }
 
+            if (!this._filesToLoad || this._filesToLoad.length === 0) {
+                return;
+            }
+
+            if (this._startingProcessingFilesCallback) {
+                this._startingProcessingFilesCallback(this._filesToLoad);
+            }
+
             if (this._filesToLoad && this._filesToLoad.length > 0) {
                 let files = new Array<File>();
                 let folders = [];

+ 8 - 0
src/Tools/babylon.tools.ts

@@ -836,6 +836,9 @@
          * content of this file is added into a new script element, attached to the DOM (body element)
          */
         public static LoadScript(scriptUrl: string, onSuccess: () => void, onError?: (message?: string, exception?: any) => void) {
+            if (!Tools.IsWindowObjectExist()) {
+                return;
+            }
             var head = document.getElementsByTagName('head')[0];
             var script = document.createElement('script');
             script.type = 'text/javascript';
@@ -1748,8 +1751,13 @@
                 if (ratio >= currentGradient.gradient && ratio <= nextGradient.gradient) {
                     let scale =  (ratio - currentGradient.gradient) / (nextGradient.gradient - currentGradient.gradient);
                     updateFunc(currentGradient, nextGradient, scale);
+                    return;
                }
             }
+
+            // Use last index if over
+            const lastIndex = gradients.length - 1;
+            updateFunc(gradients[lastIndex], gradients[lastIndex], 1.0);
         }
     }
 

+ 49 - 208
src/babylon.scene.ts

@@ -278,10 +278,6 @@
          */
         public disableOfflineSupportExceptionRules = new Array<RegExp>();
 
-        // Events
-
-        private _spritePredicate: (sprite: Sprite) => boolean;
-
         /**
         * An event triggered when the scene is disposed.
         */
@@ -416,18 +412,6 @@
         public onAfterParticlesRenderingObservable = new Observable<Scene>();
 
         /**
-        * An event triggered when sprites rendering is about to start
-        * Note: This event can be trigger more than once per frame (because sprites can be rendered by render target textures as well)
-        */
-        public onBeforeSpritesRenderingObservable = new Observable<Scene>();
-
-        /**
-        * An event triggered when sprites rendering is done
-        * Note: This event can be trigger more than once per frame (because sprites can be rendered by render target textures as well)
-        */
-        public onAfterSpritesRenderingObservable = new Observable<Scene>();
-
-        /**
         * An event triggered when SceneLoader.Append or SceneLoader.Load or SceneLoader.ImportMesh were successfully executed
         */
         public onDataLoadedObservable = new Observable<Scene>();
@@ -805,11 +789,6 @@
         * Gets or sets a boolean indicating if sprites are enabled on this scene
         */
         public spritesEnabled = true;
-        /**
-        * All of the sprite managers added to this scene
-        * @see http://doc.babylonjs.com/babylon101/sprites
-        */
-        public spriteManagers = new Array<SpriteManager>();
 
         // Skeletons
         private _skeletonsEnabled = true;
@@ -1055,13 +1034,11 @@
         private _selectionOctree: Octree<AbstractMesh>;
 
         private _pointerOverMesh: Nullable<AbstractMesh>;
-        private _pointerOverSprite: Nullable<Sprite>;
 
         private _debugLayer: DebugLayer;
 
         private _pickedDownMesh: Nullable<AbstractMesh>;
         private _pickedUpMesh: Nullable<AbstractMesh>;
-        private _pickedDownSprite: Nullable<Sprite>;
         private _externalData: StringDictionary<Object>;
         private _uid: Nullable<string>;
 
@@ -1187,6 +1164,21 @@
          * Defines the actions happening when Geometries are rebuilding.
          */
         public _rebuildGeometryStage = Stage.Create<SimpleStageAction>();
+        /**
+         * @hidden
+         * Defines the actions happening when a pointer move event happens.
+         */
+        public _pointerMoveStage = Stage.Create<PointerMoveStageAction>();
+        /**
+         * @hidden
+         * Defines the actions happening when a pointer down event happens.
+         */
+        public _pointerDownStage = Stage.Create<PointerUpDownStageAction>();
+        /**
+         * @hidden
+         * Defines the actions happening when a pointer up event happens.
+         */
+        public _pointerUpStage = Stage.Create<PointerUpDownStageAction>();
 
         /**
          * Creates a new Scene
@@ -1539,14 +1531,6 @@
         }
 
         // Pointers handling
-        private _pickSpriteButKeepRay(originalPointerInfo: Nullable<PickingInfo>, x: number, y: number, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean, camera?: Camera): Nullable<PickingInfo> {
-            var result = this.pickSprite(x, y, predicate, fastCheck, camera);
-            if (result) {
-                result.ray = originalPointerInfo ? originalPointerInfo.ray : null;
-            }
-            return result;
-        }
-
         private _setRayOnPointerInfo(pointerInfo: PointerInfo) {
             if (pointerInfo.pickInfo) {
                 if (!pointerInfo.pickInfo.ray) {
@@ -1579,37 +1563,15 @@
                 return this;
             }
 
-            if (pickResult && pickResult.hit && pickResult.pickedMesh) {
-                this.setPointerOverSprite(null);
-
-                this.setPointerOverMesh(pickResult.pickedMesh);
-
-                if (this._pointerOverMesh && this._pointerOverMesh.actionManager && this._pointerOverMesh.actionManager.hasPointerTriggers) {
-                    if (this._pointerOverMesh.actionManager.hoverCursor) {
-                        canvas.style.cursor = this._pointerOverMesh.actionManager.hoverCursor;
-                    } else {
-                        canvas.style.cursor = this.hoverCursor;
-                    }
-                } else {
-                    canvas.style.cursor = this.defaultCursor;
-                }
+            var isMeshPicked = (pickResult && pickResult.hit && pickResult.pickedMesh) ? true : false;
+            if (isMeshPicked) {
+                this.setPointerOverMesh(pickResult!.pickedMesh);
             } else {
                 this.setPointerOverMesh(null);
-                // Sprites
-                pickResult = this._pickSpriteButKeepRay(pickResult, this._unTranslatedPointerX, this._unTranslatedPointerY, this._spritePredicate, false, this.cameraToUseForPointers || undefined);
+            }
 
-                if (pickResult && pickResult.hit && pickResult.pickedSprite) {
-                    this.setPointerOverSprite(pickResult.pickedSprite);
-                    if (this._pointerOverSprite && this._pointerOverSprite.actionManager && this._pointerOverSprite.actionManager.hoverCursor) {
-                        canvas.style.cursor = this._pointerOverSprite.actionManager.hoverCursor;
-                    } else {
-                        canvas.style.cursor = this.hoverCursor;
-                    }
-                } else {
-                    this.setPointerOverSprite(null);
-                    // Restore pointer
-                    canvas.style.cursor = this.defaultCursor;
-                }
+            for (let step of this._pointerMoveStage) {
+                pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, isMeshPicked, canvas);
             }
 
             if (pickResult) {
@@ -1688,8 +1650,7 @@
                             if (pickResult && pickResult.hit && pickResult.pickedMesh && actionManager) {
                                 if (this._totalPointersPressed !== 0 &&
                                     ((Date.now() - this._startingPointerTime) > Scene.LongPressDelay) &&
-                                    (Math.abs(this._startingPointerPosition.x - this._pointerX) < Scene.DragMovementThreshold &&
-                                        Math.abs(this._startingPointerPosition.y - this._pointerY) < Scene.DragMovementThreshold)) {
+                                    !this._isPointerSwiping()) {
                                     this._startingPointerTime = 0;
                                     actionManager.processTrigger(ActionManager.OnLongPressTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
                                 }
@@ -1698,6 +1659,11 @@
                     }
                 }
             }
+            else {
+                for (let step of this._pointerDownStage) {
+                    pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, evt);
+                }
+            }
 
             if (pickResult) {
                 let type = PointerEventTypes.POINTERDOWN;
@@ -1762,6 +1728,14 @@
                     }
                 }
             }
+            else {
+                if (!clickInfo.ignore) {
+                    for (let step of this._pointerUpStage) {
+                        pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, evt);
+                    }
+                }
+            }
+
             if (this._pickedDownMesh &&
                 this._pickedDownMesh.actionManager &&
                 this._pickedDownMesh.actionManager.hasSpecificTrigger(ActionManager.OnPickOutTrigger) &&
@@ -1810,6 +1784,12 @@
             return this._pointerCaptures[pointerId];
         }
 
+        /** @hidden */
+        public _isPointerSwiping(): boolean {
+            return Math.abs(this._startingPointerPosition.x - this._pointerX) > Scene.DragMovementThreshold ||
+                   Math.abs(this._startingPointerPosition.y - this._pointerY) > Scene.DragMovementThreshold;
+        }
+
         /**
         * Attach events to the canvas (To handle actionManagers triggers and raise onPointerMove, onPointerDown and onPointerUp
         * @param attachUp defines if you want to attach events to pointerup
@@ -1855,8 +1835,7 @@
                 }
                 if (checkPicking) {
                     let btn = evt.button;
-                    clickInfo.hasSwiped = Math.abs(this._startingPointerPosition.x - this._pointerX) > Scene.DragMovementThreshold ||
-                        Math.abs(this._startingPointerPosition.y - this._pointerY) > Scene.DragMovementThreshold;
+                    clickInfo.hasSwiped = this._isPointerSwiping();
 
                     if (!clickInfo.hasSwiped) {
                         let checkSingleClickImmediately = !Scene.ExclusiveDoubleClickMode;
@@ -1903,8 +1882,7 @@
                             ) {
                                 // pointer has not moved for 2 clicks, it's a double click
                                 if (!clickInfo.hasSwiped &&
-                                    Math.abs(this._previousStartingPointerPosition.x - this._startingPointerPosition.x) < Scene.DragMovementThreshold &&
-                                    Math.abs(this._previousStartingPointerPosition.y - this._startingPointerPosition.y) < Scene.DragMovementThreshold) {
+                                    !this._isPointerSwiping()) {
                                     this._previousStartingPointerTime = 0;
                                     this._doubleClickOccured = true;
                                     clickInfo.doubleClick = true;
@@ -1950,10 +1928,6 @@
                 cb(clickInfo, this._currentPickResult);
             };
 
-            this._spritePredicate = (sprite: Sprite): boolean => {
-                return sprite.isPickable && sprite.actionManager && sprite.actionManager.hasPointerTriggers;
-            };
-
             this._onPointerMove = (evt: PointerEvent) => {
 
                 this._updatePointerPosition(evt);
@@ -2014,32 +1988,6 @@
                 var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerDownPredicate, false, this.cameraToUseForPointers);
 
                 this._processPointerDown(pickResult, evt);
-
-                // Sprites
-                this._pickedDownSprite = null;
-                if (this.spriteManagers.length > 0) {
-                    pickResult = this.pickSprite(this._unTranslatedPointerX, this._unTranslatedPointerY, this._spritePredicate, false, this.cameraToUseForPointers || undefined);
-
-                    if (pickResult && pickResult.hit && pickResult.pickedSprite) {
-                        if (pickResult.pickedSprite.actionManager) {
-                            this._pickedDownSprite = pickResult.pickedSprite;
-                            switch (evt.button) {
-                                case 0:
-                                    pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnLeftPickTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
-                                    break;
-                                case 1:
-                                    pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnCenterPickTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
-                                    break;
-                                case 2:
-                                    pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnRightPickTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
-                                    break;
-                            }
-                            if (pickResult.pickedSprite.actionManager) {
-                                pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnPickDownTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
-                            }
-                        }
-                    }
-                }
             };
 
             this._onPointerUp = (evt: PointerEvent) => {
@@ -2098,29 +2046,6 @@
 
                     this._processPointerUp(pickResult, evt, clickInfo);
 
-                    // Sprites
-                    if (!clickInfo.ignore) {
-                        if (this.spriteManagers.length > 0) {
-                            let spritePickResult = this.pickSprite(this._unTranslatedPointerX, this._unTranslatedPointerY, this._spritePredicate, false, this.cameraToUseForPointers || undefined);
-
-                            if (spritePickResult) {
-                                if (spritePickResult.hit && spritePickResult.pickedSprite) {
-                                    if (spritePickResult.pickedSprite.actionManager) {
-                                        spritePickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnPickUpTrigger, ActionEvent.CreateNewFromSprite(spritePickResult.pickedSprite, this, evt));
-                                        if (spritePickResult.pickedSprite.actionManager) {
-                                            if (Math.abs(this._startingPointerPosition.x - this._pointerX) < Scene.DragMovementThreshold && Math.abs(this._startingPointerPosition.y - this._pointerY) < Scene.DragMovementThreshold) {
-                                                spritePickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnPickTrigger, ActionEvent.CreateNewFromSprite(spritePickResult.pickedSprite, this, evt));
-                                            }
-                                        }
-                                    }
-                                }
-                                if (this._pickedDownSprite && this._pickedDownSprite.actionManager && this._pickedDownSprite !== spritePickResult.pickedSprite) {
-                                    this._pickedDownSprite.actionManager.processTrigger(ActionManager.OnPickOutTrigger, ActionEvent.CreateNewFromSprite(this._pickedDownSprite, this, evt));
-                                }
-                            }
-                        }
-                    }
-
                     this._previousPickResult = this._currentPickResult;
                 });
             };
@@ -4298,7 +4223,7 @@
             this._setAlternateTransformMatrix(alternateCamera.getViewMatrix(), alternateCamera.getProjectionMatrix());
         }
         /** @hidden */
-        public _allowPostProcessClear = true;
+        public _allowPostProcessClearColor = true;
         private _renderForCamera(camera: Camera, rigParent?: Camera): void {
             if (camera && camera._skipRendering) {
                 return;
@@ -4886,6 +4811,10 @@
             this._beforeCameraUpdateStage.clear();
             this._gatherRenderTargetsStage.clear();
             this._rebuildGeometryStage.clear();
+            this._pointerMoveStage.clear();
+            this._pointerDownStage.clear();
+            this._pointerUpStage.clear();
+
             for (let component of this._components) {
                 component.dispose();
             }
@@ -4936,8 +4865,6 @@
             this.onAfterActiveMeshesEvaluationObservable.clear();
             this.onBeforeParticlesRenderingObservable.clear();
             this.onAfterParticlesRenderingObservable.clear();
-            this.onBeforeSpritesRenderingObservable.clear();
-            this.onAfterSpritesRenderingObservable.clear();
             this.onBeforeDrawPhaseObservable.clear();
             this.onAfterDrawPhaseObservable.clear();
             this.onBeforePhysicsObservable.clear();
@@ -5009,11 +4936,6 @@
                 this.particleSystems[0].dispose();
             }
 
-            // Release sprites
-            while (this.spriteManagers.length) {
-                this.spriteManagers[0].dispose();
-            }
-
             // Release postProcesses
             while (this.postProcesses.length) {
                 this.postProcesses[0].dispose();
@@ -5329,46 +5251,6 @@
             return pickingInfos;
         }
 
-        private _internalPickSprites(ray: Ray, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean, camera?: Camera): Nullable<PickingInfo> {
-            if (!PickingInfo) {
-                return null;
-            }
-
-            var pickingInfo = null;
-
-            if (!camera) {
-                if (!this.activeCamera) {
-                    return null;
-                }
-                camera = this.activeCamera;
-            }
-
-            if (this.spriteManagers.length > 0) {
-                for (var spriteIndex = 0; spriteIndex < this.spriteManagers.length; spriteIndex++) {
-                    var spriteManager = this.spriteManagers[spriteIndex];
-
-                    if (!spriteManager.isPickable) {
-                        continue;
-                    }
-
-                    var result = spriteManager.intersects(ray, camera, predicate, fastCheck);
-                    if (!result || !result.hit)
-                        continue;
-
-                    if (!fastCheck && pickingInfo != null && result.distance >= pickingInfo.distance)
-                        continue;
-
-                    pickingInfo = result;
-
-                    if (fastCheck) {
-                        break;
-                    }
-                }
-            }
-
-            return pickingInfo || new PickingInfo();
-        }
-
         private _tempPickingRay: Nullable<Ray> = Ray ? Ray.Zero() : null;
 
         /** Launch a ray to try to pick a mesh in the scene
@@ -5393,25 +5275,11 @@
             return result;
         }
 
-        /** Launch a ray to try to pick a sprite in the scene
-         * @param x position on screen
-         * @param y position on screen
-         * @param predicate Predicate function used to determine eligible sprites. Can be set to null. In this case, a sprite must have isPickable set to true
-         * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null.
-         * @param camera camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
-         * @returns a PickingInfo
-         */
-        public pickSprite(x: number, y: number, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean, camera?: Camera): Nullable<PickingInfo> {
-            this.createPickingRayInCameraSpaceToRef(x, y, this._tempPickingRay!, camera);
-
-            return this._internalPickSprites(this._tempPickingRay!, predicate, fastCheck, camera);
-        }
-
         private _cachedRayForTransform: Ray;
 
         /** Use the given ray to pick a mesh in the scene
          * @param ray The ray to use to pick meshes
-         * @param predicate Predicate function used to determine eligible sprites. Can be set to null. In this case, a sprite must have isPickable set to true
+         * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must have isPickable set to true
          * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null
          * @returns a PickingInfo
          */
@@ -5496,33 +5364,6 @@
             return this._pointerOverMesh;
         }
 
-        /** 
-         * Force the sprite under the pointer
-         * @param sprite defines the sprite to use
-         */
-        public setPointerOverSprite(sprite: Nullable<Sprite>): void {
-            if (this._pointerOverSprite === sprite) {
-                return;
-            }
-
-            if (this._pointerOverSprite && this._pointerOverSprite.actionManager) {
-                this._pointerOverSprite.actionManager.processTrigger(ActionManager.OnPointerOutTrigger, ActionEvent.CreateNewFromSprite(this._pointerOverSprite, this));
-            }
-
-            this._pointerOverSprite = sprite;
-            if (this._pointerOverSprite && this._pointerOverSprite.actionManager) {
-                this._pointerOverSprite.actionManager.processTrigger(ActionManager.OnPointerOverTrigger, ActionEvent.CreateNewFromSprite(this._pointerOverSprite, this));
-            }
-        }
-
-        /** 
-         * Gets the sprite under the pointer
-         * @returns a Sprite or null if no sprite is under the pointer
-         */
-        public getPointerOverSprite(): Nullable<Sprite> {
-            return this._pointerOverSprite;
-        }
-
         // Physics
 
         /** 

+ 15 - 0
src/babylon.sceneComponent.ts

@@ -14,6 +14,7 @@
         public static readonly NAME_GEOMETRYBUFFERRENDERER = "GeometryBufferRenderer";
         public static readonly NAME_DEPTHRENDERER = "DepthRenderer";
         public static readonly NAME_POSTPROCESSRENDERPIPELINEMANAGER = "PostProcessRenderPipelineManager";
+        public static readonly NAME_SPRITE = "Sprite";
 
         public static readonly STEP_ISREADYFORMESH_EFFECTLAYER = 0;
 
@@ -44,6 +45,10 @@
         public static readonly STEP_GATHERRENDERTARGETS_POSTPROCESSRENDERPIPELINEMANAGER = 2;
 
         public static readonly STEP_REBUILDGEOMETRY_POSTPROCESSRENDERPIPELINEMANAGER = 0;
+
+        public static readonly STEP_POINTERMOVE_SPRITE = 0;
+        public static readonly STEP_POINTERDOWN_SPRITE = 0;
+        public static readonly STEP_POINTERUP_SPRITE = 0;
     }
 
     /**
@@ -141,6 +146,16 @@
     export type RenderTargetsStageAction = (renderTargets: SmartArrayNoDuplicate<RenderTargetTexture>) => void;
 
     /** 
+     * Strong typing of a pointer move action.
+     */
+    export type PointerMoveStageAction = (unTranslatedPointerX: number, unTranslatedPointerY: number, pickResult: Nullable<PickingInfo>, isMeshPicked: boolean, canvas: HTMLCanvasElement) => Nullable<PickingInfo>;
+
+    /** 
+     * Strong typing of a pointer up/down action.
+     */
+    export type PointerUpDownStageAction = (unTranslatedPointerX: number, unTranslatedPointerY: number, pickResult: Nullable<PickingInfo>, evt: PointerEvent) => Nullable<PickingInfo>;
+
+    /** 
      * Repressentation of a stage in the scene (Basically a list of ordered steps) 
      * @hidden
      */