ソースを参照

Merge pull request #4600 from BabylonJS/partHelper

Particle helper
David Catuhe 7 年 前
コミット
1e5430a0d0
28 ファイル変更20758 行追加20767 行削除
  1. 6906 7022
      Playground/babylon.d.txt
  2. 2 1
      Tools/Gulp/config.json
  3. 0 25
      assets/particles/systems/fire.json
  4. 0 25
      assets/particles/systems/smoke.json
  5. 339 0
      assets/particles/systems/sun.json
  6. BIN
      assets/particles/textures/flare.png
  7. BIN
      assets/particles/textures/sun/T_Star.png
  8. BIN
      assets/particles/textures/sun/T_SunFlare.png
  9. BIN
      assets/particles/textures/sun/T_SunSurface.png
  10. 12435 12552
      dist/preview release/babylon.d.ts
  11. 54 54
      dist/preview release/babylon.js
  12. 175 155
      dist/preview release/babylon.max.js
  13. 175 155
      dist/preview release/babylon.no-module.max.js
  14. 26 26
      dist/preview release/babylon.worker.js
  15. 177 157
      dist/preview release/es6.js
  16. 2 2
      dist/preview release/inspector/babylon.inspector.bundle.js
  17. 67 67
      dist/preview release/viewer/babylon.viewer.js
  18. 175 155
      dist/preview release/viewer/babylon.viewer.max.js
  19. 1 1
      dist/preview release/what's new.md
  20. 0 349
      src/Helpers/babylon.particleHelper.ts
  21. 2 2
      src/Particles/EmitterTypes/babylon.boxParticleEmitter.ts
  22. 2 2
      src/Particles/EmitterTypes/babylon.coneParticleEmitter.ts
  23. 2 0
      src/Particles/EmitterTypes/babylon.sphereParticleEmitter.ts
  24. 5 1
      src/Particles/babylon.IParticleSystem.ts
  25. 55 0
      src/Particles/babylon.particleHelper.ts
  26. 18 2
      src/Particles/babylon.particleSystem.ts
  27. 137 0
      src/Particles/babylon.particleSystemSet.ts
  28. 3 14
      tests/unit/babylon/src/Helpers/babylon.particleHelper.tests.ts

ファイルの差分が大きいため隠しています
+ 6906 - 7022
Playground/babylon.d.txt


+ 2 - 1
Tools/Gulp/config.json

@@ -1237,7 +1237,8 @@
         },
         "particleHelper": {
             "files": [
-                "../../src/Helpers/babylon.particleHelper.js"
+                "../../src/Particles/babylon.particleSystemSet.js",
+                "../../src/Particles/babylon.particleHelper.js"
             ],
             "dependUpon": [
                 "particles"

+ 0 - 25
assets/particles/systems/fire.json

@@ -1,25 +0,0 @@
-{
-  "type": "fire",
-  "emitterType": "box",
-  "capacity": 2000,
-  "textureFile": "flare.png",
-  "minEmitBox": { "x": -0.5, "y": 1, "z": -0.5 },
-  "maxEmitBox": { "x": 0.5, "y": 1, "z": 0.5 },
-  "color1": { "r": 1, "g": 0.5, "b": 0, "a": 1.0 },
-  "color2": { "r": 1, "g": 0.5, "b": 0, "a": 1.0 },
-  "colorDead": { "r": 0, "g": 0, "b": 0, "a": 0.0 },
-  "minSize": 0.3,
-  "maxSize": 1,
-  "minLifeTime": 0.2,
-  "maxLifeTime": 0.4,
-  "emitRate": 600,
-  "blendMode": 0,
-  "gravity": { "x": 0, "y": 0, "z": 0 },
-  "direction1": { "x": 0, "y": 4, "z": 0 },
-  "direction2": { "x": 0, "y": 4, "z": 0 },
-  "minAngularSpeed": 0,
-  "maxAngularSpeed": 3.141592653589793,
-  "minEmitPower": 1,
-  "maxEmitPower": 3,
-  "updateSpeed": 0.007
-}

+ 0 - 25
assets/particles/systems/smoke.json

@@ -1,25 +0,0 @@
-{
-  "type": "smoke",
-  "emitterType": "box",
-  "capacity": 1000,
-  "textureFile": "flare.png",
-  "minEmitBox": { "x": -0.5, "y": 1, "z": -0.5 },
-  "maxEmitBox": { "x": 0.5, "y": 1, "z": 0.5 },
-  "color1": { "r": 0.1, "g": 0.1, "b": 0.1, "a": 1.0 },
-  "color2": { "r": 0.1, "g": 0.1, "b": 0.1, "a": 1.0 },
-  "colorDead": { "r": 0, "g": 0, "b": 0, "a": 0.0 },
-  "minSize": 0.3,
-  "maxSize": 1,
-  "minLifeTime": 0.3,
-  "maxLifeTime": 1.5,
-  "emitRate": 350,
-  "blendMode": 0,
-  "gravity": { "x": 0, "y": 0, "z": 0 },
-  "direction1": { "x": -1.5, "y": 8, "z": -1.5 },
-  "direction2": { "x": 1.5, "y": 8, "z": 1.5 },
-  "minAngularSpeed": 0,
-  "maxAngularSpeed": 3.141592653589793,
-  "minEmitPower": 0.5,
-  "maxEmitPower": 1.5,
-  "updateSpeed": 0.005
-}

+ 339 - 0
assets/particles/systems/sun.json

@@ -0,0 +1,339 @@
+{
+  "emitter" : {
+    "kind": "Sphere",
+    "options": {
+      "diameter": 2.01,
+      "segments": 32,
+      "color": [
+      0.3773, 
+      0.0930, 
+      0.0266]
+    },
+    "renderingGroupId": 3
+  },
+  "systems": [
+    {
+      "name": "surfaceParticles",
+      "id": "surfaceParticles",
+      "capacity": 1600,
+      "renderingGroupId": 3,
+      "isBillboardBased": false,
+      "particleEmitterType": {
+        "type": "SphereParticleEmitter",
+        "radius": 1,
+        "radiusRange": 0,
+        "directionRandomizer": 0
+      },
+      "textureName": "sun/T_SunSurface.png",
+      "animations": [],
+      "minAngularSpeed": -0.4,
+      "maxAngularSpeed": 0.4,
+      "minSize": 0.4,
+      "maxSize": 0.7,
+      "minScaleX": 1,
+      "maxScaleX": 1,
+      "minScaleY": 1,
+      "maxScaleY": 1,
+      "minEmitPower": 0,
+      "maxEmitPower": 0,
+      "minLifeTime": 8,
+      "maxLifeTime": 8,
+      "emitRate": 200,
+      "gravity": [
+        0,
+        0,
+        0
+      ],
+      "color1": [
+        1,
+        1,
+        1,
+        1
+      ],
+      "color2": [
+        1,
+        1,
+        1,
+        1
+      ],
+      "colorDead": [
+        0,
+        0,
+        0,
+        1
+      ],
+      "updateSpeed": 0.005,
+      "targetStopDuration": 0,
+      "blendMode": 2,
+      "preWarmCycles": 100,
+      "preWarmStepOffset": 10,
+      "minInitialRotation": -6.283185307179586,
+      "maxInitialRotation": 6.283185307179586,
+      "colorGradients": [
+        {
+          "gradient": 0,
+          "color1": [
+            0.8509,
+            0.4784,
+            0.1019,
+            0
+          ]
+        },
+        {
+          "gradient": 0.4,
+          "color1": [
+            0.6259,
+            0.3056,
+            0.0619,
+            0.5
+          ]
+        },
+        {
+          "gradient": 0.5,
+          "color1": [
+            0.6039,
+            0.2887,
+            0.0579,
+            0.5
+          ]
+        },
+        {
+          "gradient": 1,
+          "color1": [
+            0.3207,
+            0.0713,
+            0.0075,
+            0
+          ]
+        }
+      ],
+      "textureMask": [
+        1,
+        1,
+        1,
+        1
+      ],
+      "customShader": null,
+      "preventAutoStart": true,
+      "startSpriteCellID": 0,
+      "endSpriteCellID": 0,
+      "spriteCellLoop": true,
+      "spriteCellChangeSpeed": 0,
+      "spriteCellWidth": 0,
+      "spriteCellHeight": 0,
+      "isAnimationSheetEnabled": false
+    },
+    {
+      "name": "flareParticles",
+      "id": "flareParticles",
+      "capacity": 20,
+      "renderingGroupId": 2,
+      "particleEmitterType": {
+        "type": "SphereParticleEmitter",
+        "radius": 1,
+        "radiusRange": 0,
+        "directionRandomizer": 0
+      },
+      "textureName": "sun/T_SunFlare.png",
+      "animations": [],
+      "minAngularSpeed": 0,
+      "maxAngularSpeed": 0,
+      "minSize": 1,
+      "maxSize": 1,
+      "minScaleX": 0.5,
+      "maxScaleX": 1,
+      "minScaleY": 0.5,
+      "maxScaleY": 1,
+      "minEmitPower": 0.001,
+      "maxEmitPower": 0.01,
+      "minLifeTime": 10,
+      "maxLifeTime": 10,
+      "emitRate": 1,
+      "gravity": [
+        0,
+        0,
+        0
+      ],
+      "color1": [
+        1,
+        1,
+        1,
+        1
+      ],
+      "color2": [
+        1,
+        1,
+        1,
+        1
+      ],
+      "colorDead": [
+        0,
+        0,
+        0,
+        1
+      ],
+      "updateSpeed": 0.01,
+      "targetStopDuration": 0,
+      "blendMode": 2,
+      "preWarmCycles": 100,
+      "preWarmStepOffset": 10,
+      "minInitialRotation": -6.283185307179586,
+      "maxInitialRotation": 6.283185307179586,
+      "colorGradients": [
+        {
+          "gradient": 0,
+          "color1": [
+            1,
+            0.9612,
+            0.5141,
+            0
+          ]
+        },
+        {
+          "gradient": 0.25,
+          "color1": [
+            0.9058,
+            0.7152,
+            0.3825,
+            1
+          ]
+        },
+        {
+          "gradient": 1,
+          "color1": [
+            0.632,
+            0,
+            0,
+            0
+          ]
+        }
+      ],
+      "sizeGradients": [
+        {
+          "gradient": 0,
+          "factor": 0
+        },
+        {
+          "gradient": 1,
+          "factor": 1
+        }
+      ],
+      "textureMask": [
+        1,
+        1,
+        1,
+        1
+      ],
+      "customShader": null,
+      "preventAutoStart": true,
+      "startSpriteCellID": 0,
+      "endSpriteCellID": 0,
+      "spriteCellLoop": true,
+      "spriteCellChangeSpeed": 0,
+      "spriteCellWidth": 0,
+      "spriteCellHeight": 0,
+      "isAnimationSheetEnabled": false
+    },
+    {
+      "name": "glareParticles",
+      "id": "glareParticles",
+      "renderingGroupId": 1,
+      "capacity": 600,
+      "particleEmitterType": {
+        "type": "SphereParticleEmitter",
+        "radius": 1,
+        "radiusRange": 0,
+        "directionRandomizer": 0
+      },
+      "textureName": "sun/T_Star.png",
+      "animations": [],
+      "minAngularSpeed": 0,
+      "maxAngularSpeed": 0,
+      "minSize": 1,
+      "maxSize": 1,
+      "minScaleX": 0.5,
+      "maxScaleX": 1.2,
+      "minScaleY": 0.75,
+      "maxScaleY": 3,
+      "minEmitPower": 0,
+      "maxEmitPower": 0,
+      "minLifeTime": 2,
+      "maxLifeTime": 2,
+      "emitRate": 300,
+      "gravity": [
+        0,
+        0,
+        0
+      ],
+      "color1": [
+        1,
+        1,
+        1,
+        1
+      ],
+      "color2": [
+        1,
+        1,
+        1,
+        1
+      ],
+      "colorDead": [
+        0,
+        0,
+        0,
+        1
+      ],
+      "updateSpeed": 0.01,
+      "targetStopDuration": 0,
+      "blendMode": 2,
+      "preWarmCycles": 100,
+      "preWarmStepOffset": 10,
+      "minInitialRotation": -6.283185307179586,
+      "maxInitialRotation": 6.283185307179586,
+      "colorGradients": [
+        {
+          "gradient": 0,
+          "color1": [
+            0.8509,
+            0.4784,
+            0.1019,
+            0
+          ]
+        },
+        {
+          "gradient": 0.5,
+          "color1": [
+            0.6039,
+            0.2887,
+            0.0579,
+            0.12
+          ]
+        },
+        {
+          "gradient": 1,
+          "color1": [
+            0.3207,
+            0.0713,
+            0.0075,
+            0
+          ]
+        }
+      ],
+      "textureMask": [
+        1,
+        1,
+        1,
+        1
+      ],
+      "customShader": null,
+      "preventAutoStart": true,
+      "startSpriteCellID": 0,
+      "endSpriteCellID": 0,
+      "spriteCellLoop": true,
+      "spriteCellChangeSpeed": 0,
+      "spriteCellWidth": 0,
+      "spriteCellHeight": 0,
+      "isAnimationSheetEnabled": false
+    }
+  ]
+}

BIN
assets/particles/textures/flare.png


BIN
assets/particles/textures/sun/T_Star.png


BIN
assets/particles/textures/sun/T_SunFlare.png


BIN
assets/particles/textures/sun/T_SunSurface.png


ファイルの差分が大きいため隠しています
+ 12435 - 12552
dist/preview release/babylon.d.ts


ファイルの差分が大きいため隠しています
+ 54 - 54
dist/preview release/babylon.js


+ 175 - 155
dist/preview release/babylon.max.js

@@ -24208,6 +24208,8 @@ var BABYLON;
             this._doubleClickOccured = false;
             /** Define this parameter if you are using multiple cameras and you want to specify which one should be used for pointer position */
             this.cameraToUseForPointers = null;
+            this._pointerX = 0;
+            this._pointerY = 0;
             this._startingPointerPosition = new BABYLON.Vector2(0, 0);
             this._previousStartingPointerPosition = new BABYLON.Vector2(0, 0);
             this._startingPointerTime = 0;
@@ -56451,6 +56453,8 @@ var BABYLON;
             // Animations
             BABYLON.Animation.AppendSerializedAnimations(particleSystem, serializationObject);
             // Particle system
+            serializationObject.renderingGroupId = particleSystem.renderingGroupId;
+            serializationObject.isBillboardBased = particleSystem.isBillboardBased;
             serializationObject.minAngularSpeed = particleSystem.minAngularSpeed;
             serializationObject.maxAngularSpeed = particleSystem.maxAngularSpeed;
             serializationObject.minSize = particleSystem.minSize;
@@ -56510,12 +56514,22 @@ var BABYLON;
                 particleSystem.particleTexture.name = parsedParticleSystem.textureName;
             }
             // Emitter
-            if (parsedParticleSystem.emitterId) {
+            if (parsedParticleSystem.emitterId === undefined) {
+                particleSystem.emitter = BABYLON.Vector3.Zero();
+            }
+            else if (parsedParticleSystem.emitterId) {
                 particleSystem.emitter = scene.getLastMeshByID(parsedParticleSystem.emitterId);
             }
             else {
                 particleSystem.emitter = BABYLON.Vector3.FromArray(parsedParticleSystem.emitter);
             }
+            // Misc.
+            if (parsedParticleSystem.renderingGroupId !== undefined) {
+                particleSystem.renderingGroupId = parsedParticleSystem.renderingGroupId;
+            }
+            if (parsedParticleSystem.isBillboardBased !== undefined) {
+                particleSystem.isBillboardBased = parsedParticleSystem.isBillboardBased;
+            }
             // Animations
             if (parsedParticleSystem.animations) {
                 for (var animationIndex = 0; animationIndex < parsedParticleSystem.animations.length; animationIndex++) {
@@ -56573,16 +56587,18 @@ var BABYLON;
             var emitterType;
             if (parsedParticleSystem.particleEmitterType) {
                 switch (parsedParticleSystem.particleEmitterType.type) {
-                    case "SphereEmitter":
+                    case "SphereParticleEmitter":
                         emitterType = new BABYLON.SphereParticleEmitter();
                         break;
                     case "SphereDirectedParticleEmitter":
                         emitterType = new BABYLON.SphereDirectedParticleEmitter();
                         break;
                     case "ConeEmitter":
+                    case "ConeParticleEmitter":
                         emitterType = new BABYLON.ConeParticleEmitter();
                         break;
                     case "BoxEmitter":
+                    case "BoxParticleEmitter":
                     default:
                         emitterType = new BABYLON.BoxParticleEmitter();
                         break;
@@ -56735,11 +56751,11 @@ var BABYLON;
             return "#define BOXEMITTER";
         };
         /**
-         * Returns the string "BoxEmitter"
+         * Returns the string "BoxParticleEmitter"
          * @returns a string containing the class name
          */
         BoxParticleEmitter.prototype.getClassName = function () {
-            return "BoxEmitter";
+            return "BoxParticleEmitter";
         };
         /**
          * Serializes the particle system to a JSON object.
@@ -56899,11 +56915,11 @@ var BABYLON;
             return "#define CONEEMITTER";
         };
         /**
-         * Returns the string "BoxEmitter"
+         * Returns the string "ConeParticleEmitter"
          * @returns a string containing the class name
          */
         ConeParticleEmitter.prototype.getClassName = function () {
-            return "ConeEmitter";
+            return "ConeParticleEmitter";
         };
         /**
          * Serializes the particle system to a JSON object.
@@ -57037,6 +57053,7 @@ var BABYLON;
             var serializationObject = {};
             serializationObject.type = this.getClassName();
             serializationObject.radius = this.radius;
+            serializationObject.radiusRange = this.radiusRange;
             serializationObject.directionRandomizer = this.directionRandomizer;
             return serializationObject;
         };
@@ -57046,6 +57063,7 @@ var BABYLON;
          */
         SphereParticleEmitter.prototype.parse = function (serializationObject) {
             this.radius = serializationObject.radius;
+            this.radiusRange = serializationObject.radiusRange;
             this.directionRandomizer = serializationObject.directionRandomizer;
         };
         return SphereParticleEmitter;
@@ -102560,21 +102578,152 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /** Internal class used to store shapes for emitters */
+    var ParticleSystemSetEmitterCreationOptions = /** @class */ (function () {
+        function ParticleSystemSetEmitterCreationOptions() {
+        }
+        return ParticleSystemSetEmitterCreationOptions;
+    }());
     /**
-     * This class is made for on one-liner static method to help creating particle systems.
+     * Represents a set of particle systems working together to create a specific effect
+     */
+    var ParticleSystemSet = /** @class */ (function () {
+        function ParticleSystemSet() {
+            /**
+             * Gets or sets the particle system list
+             */
+            this.systems = new Array();
+        }
+        Object.defineProperty(ParticleSystemSet.prototype, "emitterMesh", {
+            /**
+             * Gets or set the emitter mesh used with this set
+             */
+            get: function () {
+                return this._emitterMesh;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        /**
+         * Creates a new emitter mesh as a sphere
+         * @param options defines the options used to create the sphere
+         * @param renderingGroupId defines the renderingGroupId to use for the sphere
+         * @param scene defines the hosting scene
+         */
+        ParticleSystemSet.prototype.setEmitterAsSphere = function (options, renderingGroupId, scene) {
+            if (this._emitterMesh) {
+                this._emitterMesh.dispose();
+            }
+            this._emitterCreationOptions = {
+                kind: "Sphere",
+                options: options,
+                renderingGroupId: renderingGroupId
+            };
+            this._emitterMesh = BABYLON.MeshBuilder.CreateSphere("emitterSphere", { diameter: options.diameter, segments: options.segments }, scene);
+            this._emitterMesh.renderingGroupId = renderingGroupId;
+            var material = new BABYLON.StandardMaterial("emitterSphereMaterial", scene);
+            material.emissiveColor = options.color;
+            this._emitterMesh.material = material;
+            for (var _i = 0, _a = this.systems; _i < _a.length; _i++) {
+                var system = _a[_i];
+                system.emitter = this._emitterMesh;
+            }
+        };
+        /**
+         * Starts all particle systems of the set
+         * @param emitter defines an optional mesh to use as emitter for the particle systems
+         */
+        ParticleSystemSet.prototype.start = function (emitter) {
+            for (var _i = 0, _a = this.systems; _i < _a.length; _i++) {
+                var system = _a[_i];
+                if (emitter) {
+                    system.emitter = emitter;
+                }
+                system.start();
+            }
+        };
+        /**
+         * Release all associated resources
+         */
+        ParticleSystemSet.prototype.dispose = function () {
+            for (var _i = 0, _a = this.systems; _i < _a.length; _i++) {
+                var system = _a[_i];
+                system.dispose();
+            }
+            this.systems = [];
+            if (this._emitterMesh) {
+                this._emitterMesh.dispose();
+                this._emitterMesh = null;
+            }
+        };
+        /**
+         * Serialize the set into a JSON compatible object
+         * @returns a JSON compatible representation of the set
+         */
+        ParticleSystemSet.prototype.serialize = function () {
+            var result = {};
+            result.systems = [];
+            for (var _i = 0, _a = this.systems; _i < _a.length; _i++) {
+                var system = _a[_i];
+                result.systems.push(system.serialize());
+            }
+            if (this._emitterMesh) {
+                result.emitter = this._emitterCreationOptions;
+            }
+            return result;
+        };
+        /**
+         * Parse a new ParticleSystemSet from a serialized source
+         * @param data defines a JSON compatible representation of the set
+         * @param scene defines the hosting scene
+         * @param gpu defines if we want GPU particles or CPU particles
+         * @returns a new ParticleSystemSet
+         */
+        ParticleSystemSet.Parse = function (data, scene, gpu) {
+            if (gpu === void 0) { gpu = false; }
+            var result = new ParticleSystemSet();
+            var rootUrl = BABYLON.ParticleHelper.BaseAssetsUrl + "/textures/";
+            for (var _i = 0, _a = data.systems; _i < _a.length; _i++) {
+                var system = _a[_i];
+                result.systems.push(gpu ? BABYLON.GPUParticleSystem.Parse(system, scene, rootUrl) : BABYLON.ParticleSystem.Parse(system, scene, rootUrl));
+            }
+            if (data.emitter) {
+                var options = data.emitter.options;
+                switch (data.emitter.kind) {
+                    case "Sphere":
+                        result.setEmitterAsSphere({
+                            diameter: options.diameter,
+                            segments: options.segments,
+                            color: BABYLON.Color3.FromArray(options.color)
+                        }, data.emitter.renderingGroupId, scene);
+                        break;
+                }
+            }
+            return result;
+        };
+        return ParticleSystemSet;
+    }());
+    BABYLON.ParticleSystemSet = ParticleSystemSet;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.particleSystemSet.js.map
+
+var BABYLON;
+(function (BABYLON) {
+    /**
+     * This class is made for on one-liner static method to help creating particle system set.
      */
     var ParticleHelper = /** @class */ (function () {
         function ParticleHelper() {
         }
         /**
-         * This is the main static method (one-liner) of this helper to create different particle systems.
+         * This is the main static method (one-liner) of this helper to create different particle systems
          * @param type This string represents the type to the particle system to create
-         * @param emitter The object where the particle system will start to emit from.
-         * @param scene The scene where the particle system should live.
-         * @param gpu If the system will use gpu.
-         * @returns the ParticleSystem created.
+         * @param scene The scene where the particle system should live
+         * @param gpu If the system will use gpu
+         * @returns the ParticleSystemSet created
          */
-        ParticleHelper.CreateAsync = function (type, emitter, scene, gpu) {
+        ParticleHelper.CreateAsync = function (type, scene, gpu) {
             if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
             if (gpu === void 0) { gpu = false; }
             return new Promise(function (resolve, reject) {
@@ -102585,160 +102734,31 @@ var BABYLON;
                 if (gpu && !BABYLON.GPUParticleSystem.IsSupported) {
                     return reject("Particle system with GPU is not supported.");
                 }
-                BABYLON.Tools.LoadFile(ParticleHelper._baseAssetsUrl + "/systems/" + type + ".json", function (data, response) {
+                BABYLON.Tools.LoadFile(ParticleHelper.BaseAssetsUrl + "/systems/" + type + ".json", function (data, response) {
                     var newData = JSON.parse(data.toString());
-                    return resolve(ParticleHelper.CreateSystem(newData, scene, emitter));
+                    return resolve(BABYLON.ParticleSystemSet.Parse(newData, scene, gpu));
                 }, undefined, undefined, undefined, function (req, exception) {
                     return reject("An error occured while the creation of your particle system. Check if your type '" + type + "' exists.");
                 });
             });
         };
         /**
-         * Static function used to create a new particle system from a IParticleSystemData
-         * @param data defines the source data
-         * @param scene defines the hosting scene
-         * @param emitter defines the particle emitter
-         * @returns a new ParticleSystem based on referenced data
-         */
-        ParticleHelper.CreateSystem = function (data, scene, emitter) {
-            // Create a particle system
-            var system = new BABYLON.ParticleSystem(data.type, data.capacity, scene);
-            // Where the particles come from
-            system.emitter = emitter; // the starting object, the emitter            
-            ParticleHelper.UpdateSystem(system, data, scene);
-            return system;
-        };
-        /**
-         * Static function used to update a particle system from a IParticleSystemData
-         * @param system defines the particle system to update
-         * @param data defines the source data
-         * @param scene defines the hosting scene
+         * Static function used to export a particle system to a ParticleSystemSet variable.
+         * Please note that the emitter shape is not exported
+         * @param system defines the particle systems to export
          */
-        ParticleHelper.UpdateSystem = function (system, data, scene) {
-            // Texture of each particle
-            if (data.textureFile) {
-                system.particleTexture = new BABYLON.Texture(ParticleHelper._baseAssetsUrl + "/textures/" + data.textureFile, scene);
-            }
-            // Colors of all particles
-            system.color1 = new BABYLON.Color4(data.color1.r, data.color1.g, data.color1.b, data.color1.a);
-            system.color2 = new BABYLON.Color4(data.color2.r, data.color2.g, data.color2.b, data.color2.a);
-            system.colorDead = new BABYLON.Color4(data.colorDead.r, data.colorDead.g, data.colorDead.b, data.colorDead.a);
-            // Size of each particle (random between...
-            system.minSize = data.minSize;
-            system.maxSize = data.maxSize;
-            system.minScaleX = data.minScaleX;
-            system.maxScaleX = data.maxScaleX;
-            system.minScaleY = data.minScaleY;
-            system.maxScaleY = data.maxScaleY;
-            // Life time of each particle (random between...
-            system.minLifeTime = data.minLifeTime;
-            system.maxLifeTime = data.maxLifeTime;
-            // Emission rate
-            system.emitRate = data.emitRate;
-            // Blend mode : BLENDMODE_ONEONE, or BLENDMODE_STANDARD
-            system.blendMode = data.blendMode;
-            // Set the gravity of all particles
-            system.gravity = new BABYLON.Vector3(data.gravity.x, data.gravity.y, data.gravity.z);
-            // Angular speed, in radians
-            system.minAngularSpeed = data.minAngularSpeed;
-            system.maxAngularSpeed = data.maxAngularSpeed;
-            // Speed
-            system.minEmitPower = data.minEmitPower;
-            system.maxEmitPower = data.maxEmitPower;
-            system.updateSpeed = data.updateSpeed;
-            switch (data.emitterType) {
-                case "box":
-                    if (!data.direction1 || !data.direction2) {
-                        throw new Error("Directions are missing in this particle system.");
-                    }
-                    if (!data.minEmitBox || !data.maxEmitBox) {
-                        throw new Error("EmitBox is missing in this particle system.");
-                    }
-                    system.createBoxEmitter(new BABYLON.Vector3(data.direction1.x, data.direction1.y, data.direction1.z), new BABYLON.Vector3(data.direction2.x, data.direction2.y, data.direction2.z), new BABYLON.Vector3(data.minEmitBox.x, data.minEmitBox.y, data.minEmitBox.z), new BABYLON.Vector3(data.maxEmitBox.x, data.maxEmitBox.y, data.maxEmitBox.z));
-                    break;
-                case "sphere":
-                    system.createSphereEmitter(data.radius);
-                    break;
-                case "directed_sphere":
-                    if (!data.direction1 || !data.direction2) {
-                        throw new Error("Directions are missing in this particle system.");
-                    }
-                    system.createDirectedSphereEmitter(data.radius, new BABYLON.Vector3(data.direction1.x, data.direction1.y, data.direction1.z), new BABYLON.Vector3(data.direction2.x, data.direction2.y, data.direction2.z));
-                    break;
-                case "cone":
-                    system.createConeEmitter(data.radius, data.angle);
-                    break;
-                default:
-                    break;
-            }
-        };
-        /**
-         * Static function used to export a particle system to a IParticleSystemData variable.
-         * Please note that texture file name is not exported and must be added manually
-         * @param system defines the particle system to export
-         */
-        ParticleHelper.ExportSystem = function (system) {
-            var outData = {};
-            // Colors of all particles
-            outData.color1 = { r: system.color1.r, g: system.color1.g, b: system.color1.b, a: system.color1.a };
-            outData.color2 = { r: system.color2.r, g: system.color2.g, b: system.color2.b, a: system.color2.a };
-            outData.colorDead = { r: system.colorDead.r, g: system.colorDead.g, b: system.colorDead.b, a: system.colorDead.a };
-            // Size of each particle (random between...
-            outData.minSize = system.minSize;
-            outData.maxSize = system.maxSize;
-            outData.minScaleX = system.minScaleX;
-            outData.maxScaleX = system.maxScaleX;
-            outData.minScaleY = system.minScaleY;
-            outData.maxScaleY = system.maxScaleY;
-            // Life time of each particle (random between...
-            outData.minLifeTime = system.minLifeTime;
-            outData.maxLifeTime = system.maxLifeTime;
-            // Emission rate
-            outData.emitRate = system.emitRate;
-            // Blend mode : BLENDMODE_ONEONE, or BLENDMODE_STANDARD
-            outData.blendMode = system.blendMode;
-            // Set the gravity of all particles
-            outData.gravity = { x: system.gravity.x, y: system.gravity.y, z: system.gravity.z };
-            // Angular speed, in radians
-            outData.minAngularSpeed = system.minAngularSpeed;
-            outData.maxAngularSpeed = system.maxAngularSpeed;
-            // Speed
-            outData.minEmitPower = system.minEmitPower;
-            outData.maxEmitPower = system.maxEmitPower;
-            outData.updateSpeed = system.updateSpeed;
-            switch (system.particleEmitterType.getClassName()) {
-                case "BoxEmitter":
-                    outData.emitterType = "box";
-                    outData.direction1 = { x: system.direction1.x, y: system.direction1.y, z: system.direction1.z };
-                    outData.direction2 = { x: system.direction2.x, y: system.direction2.y, z: system.direction2.z };
-                    outData.minEmitBox = { x: system.minEmitBox.x, y: system.minEmitBox.y, z: system.minEmitBox.z };
-                    outData.maxEmitBox = { x: system.maxEmitBox.x, y: system.maxEmitBox.y, z: system.maxEmitBox.z };
-                    break;
-                case "SphereParticleEmitter":
-                    outData.emitterType = "sphere";
-                    outData.radius = system.particleEmitterType.radius;
-                    break;
-                case "SphereDirectedParticleEmitter":
-                    outData.emitterType = "directed_sphere";
-                    var sphereDirectedParticleEmitter = system.particleEmitterType;
-                    outData.radius = sphereDirectedParticleEmitter.radius;
-                    outData.direction1 = { x: sphereDirectedParticleEmitter.direction1.x, y: sphereDirectedParticleEmitter.direction1.y, z: sphereDirectedParticleEmitter.direction1.z };
-                    outData.direction2 = { x: sphereDirectedParticleEmitter.direction2.x, y: sphereDirectedParticleEmitter.direction2.y, z: sphereDirectedParticleEmitter.direction2.z };
-                    break;
-                case "ConeEmitter":
-                    outData.emitterType = "cone";
-                    outData.radius = system.particleEmitterType.radius;
-                    outData.angle = system.particleEmitterType.angle;
-                    break;
-                default:
-                    break;
+        ParticleHelper.ExportSet = function (systems) {
+            var set = new BABYLON.ParticleSystemSet();
+            for (var _i = 0, systems_1 = systems; _i < systems_1.length; _i++) {
+                var system = systems_1[_i];
+                set.systems.push(system);
             }
-            return outData;
+            return set;
         };
         /**
-         * Base Assets URL.
+         * Gets or sets base Assets URL
          */
-        ParticleHelper._baseAssetsUrl = "https://assets.babylonjs.com/particles";
+        ParticleHelper.BaseAssetsUrl = "https://assets.babylonjs.com/particles";
         return ParticleHelper;
     }());
     BABYLON.ParticleHelper = ParticleHelper;

+ 175 - 155
dist/preview release/babylon.no-module.max.js

@@ -24175,6 +24175,8 @@ var BABYLON;
             this._doubleClickOccured = false;
             /** Define this parameter if you are using multiple cameras and you want to specify which one should be used for pointer position */
             this.cameraToUseForPointers = null;
+            this._pointerX = 0;
+            this._pointerY = 0;
             this._startingPointerPosition = new BABYLON.Vector2(0, 0);
             this._previousStartingPointerPosition = new BABYLON.Vector2(0, 0);
             this._startingPointerTime = 0;
@@ -56418,6 +56420,8 @@ var BABYLON;
             // Animations
             BABYLON.Animation.AppendSerializedAnimations(particleSystem, serializationObject);
             // Particle system
+            serializationObject.renderingGroupId = particleSystem.renderingGroupId;
+            serializationObject.isBillboardBased = particleSystem.isBillboardBased;
             serializationObject.minAngularSpeed = particleSystem.minAngularSpeed;
             serializationObject.maxAngularSpeed = particleSystem.maxAngularSpeed;
             serializationObject.minSize = particleSystem.minSize;
@@ -56477,12 +56481,22 @@ var BABYLON;
                 particleSystem.particleTexture.name = parsedParticleSystem.textureName;
             }
             // Emitter
-            if (parsedParticleSystem.emitterId) {
+            if (parsedParticleSystem.emitterId === undefined) {
+                particleSystem.emitter = BABYLON.Vector3.Zero();
+            }
+            else if (parsedParticleSystem.emitterId) {
                 particleSystem.emitter = scene.getLastMeshByID(parsedParticleSystem.emitterId);
             }
             else {
                 particleSystem.emitter = BABYLON.Vector3.FromArray(parsedParticleSystem.emitter);
             }
+            // Misc.
+            if (parsedParticleSystem.renderingGroupId !== undefined) {
+                particleSystem.renderingGroupId = parsedParticleSystem.renderingGroupId;
+            }
+            if (parsedParticleSystem.isBillboardBased !== undefined) {
+                particleSystem.isBillboardBased = parsedParticleSystem.isBillboardBased;
+            }
             // Animations
             if (parsedParticleSystem.animations) {
                 for (var animationIndex = 0; animationIndex < parsedParticleSystem.animations.length; animationIndex++) {
@@ -56540,16 +56554,18 @@ var BABYLON;
             var emitterType;
             if (parsedParticleSystem.particleEmitterType) {
                 switch (parsedParticleSystem.particleEmitterType.type) {
-                    case "SphereEmitter":
+                    case "SphereParticleEmitter":
                         emitterType = new BABYLON.SphereParticleEmitter();
                         break;
                     case "SphereDirectedParticleEmitter":
                         emitterType = new BABYLON.SphereDirectedParticleEmitter();
                         break;
                     case "ConeEmitter":
+                    case "ConeParticleEmitter":
                         emitterType = new BABYLON.ConeParticleEmitter();
                         break;
                     case "BoxEmitter":
+                    case "BoxParticleEmitter":
                     default:
                         emitterType = new BABYLON.BoxParticleEmitter();
                         break;
@@ -56702,11 +56718,11 @@ var BABYLON;
             return "#define BOXEMITTER";
         };
         /**
-         * Returns the string "BoxEmitter"
+         * Returns the string "BoxParticleEmitter"
          * @returns a string containing the class name
          */
         BoxParticleEmitter.prototype.getClassName = function () {
-            return "BoxEmitter";
+            return "BoxParticleEmitter";
         };
         /**
          * Serializes the particle system to a JSON object.
@@ -56866,11 +56882,11 @@ var BABYLON;
             return "#define CONEEMITTER";
         };
         /**
-         * Returns the string "BoxEmitter"
+         * Returns the string "ConeParticleEmitter"
          * @returns a string containing the class name
          */
         ConeParticleEmitter.prototype.getClassName = function () {
-            return "ConeEmitter";
+            return "ConeParticleEmitter";
         };
         /**
          * Serializes the particle system to a JSON object.
@@ -57004,6 +57020,7 @@ var BABYLON;
             var serializationObject = {};
             serializationObject.type = this.getClassName();
             serializationObject.radius = this.radius;
+            serializationObject.radiusRange = this.radiusRange;
             serializationObject.directionRandomizer = this.directionRandomizer;
             return serializationObject;
         };
@@ -57013,6 +57030,7 @@ var BABYLON;
          */
         SphereParticleEmitter.prototype.parse = function (serializationObject) {
             this.radius = serializationObject.radius;
+            this.radiusRange = serializationObject.radiusRange;
             this.directionRandomizer = serializationObject.directionRandomizer;
         };
         return SphereParticleEmitter;
@@ -102527,21 +102545,152 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /** Internal class used to store shapes for emitters */
+    var ParticleSystemSetEmitterCreationOptions = /** @class */ (function () {
+        function ParticleSystemSetEmitterCreationOptions() {
+        }
+        return ParticleSystemSetEmitterCreationOptions;
+    }());
     /**
-     * This class is made for on one-liner static method to help creating particle systems.
+     * Represents a set of particle systems working together to create a specific effect
+     */
+    var ParticleSystemSet = /** @class */ (function () {
+        function ParticleSystemSet() {
+            /**
+             * Gets or sets the particle system list
+             */
+            this.systems = new Array();
+        }
+        Object.defineProperty(ParticleSystemSet.prototype, "emitterMesh", {
+            /**
+             * Gets or set the emitter mesh used with this set
+             */
+            get: function () {
+                return this._emitterMesh;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        /**
+         * Creates a new emitter mesh as a sphere
+         * @param options defines the options used to create the sphere
+         * @param renderingGroupId defines the renderingGroupId to use for the sphere
+         * @param scene defines the hosting scene
+         */
+        ParticleSystemSet.prototype.setEmitterAsSphere = function (options, renderingGroupId, scene) {
+            if (this._emitterMesh) {
+                this._emitterMesh.dispose();
+            }
+            this._emitterCreationOptions = {
+                kind: "Sphere",
+                options: options,
+                renderingGroupId: renderingGroupId
+            };
+            this._emitterMesh = BABYLON.MeshBuilder.CreateSphere("emitterSphere", { diameter: options.diameter, segments: options.segments }, scene);
+            this._emitterMesh.renderingGroupId = renderingGroupId;
+            var material = new BABYLON.StandardMaterial("emitterSphereMaterial", scene);
+            material.emissiveColor = options.color;
+            this._emitterMesh.material = material;
+            for (var _i = 0, _a = this.systems; _i < _a.length; _i++) {
+                var system = _a[_i];
+                system.emitter = this._emitterMesh;
+            }
+        };
+        /**
+         * Starts all particle systems of the set
+         * @param emitter defines an optional mesh to use as emitter for the particle systems
+         */
+        ParticleSystemSet.prototype.start = function (emitter) {
+            for (var _i = 0, _a = this.systems; _i < _a.length; _i++) {
+                var system = _a[_i];
+                if (emitter) {
+                    system.emitter = emitter;
+                }
+                system.start();
+            }
+        };
+        /**
+         * Release all associated resources
+         */
+        ParticleSystemSet.prototype.dispose = function () {
+            for (var _i = 0, _a = this.systems; _i < _a.length; _i++) {
+                var system = _a[_i];
+                system.dispose();
+            }
+            this.systems = [];
+            if (this._emitterMesh) {
+                this._emitterMesh.dispose();
+                this._emitterMesh = null;
+            }
+        };
+        /**
+         * Serialize the set into a JSON compatible object
+         * @returns a JSON compatible representation of the set
+         */
+        ParticleSystemSet.prototype.serialize = function () {
+            var result = {};
+            result.systems = [];
+            for (var _i = 0, _a = this.systems; _i < _a.length; _i++) {
+                var system = _a[_i];
+                result.systems.push(system.serialize());
+            }
+            if (this._emitterMesh) {
+                result.emitter = this._emitterCreationOptions;
+            }
+            return result;
+        };
+        /**
+         * Parse a new ParticleSystemSet from a serialized source
+         * @param data defines a JSON compatible representation of the set
+         * @param scene defines the hosting scene
+         * @param gpu defines if we want GPU particles or CPU particles
+         * @returns a new ParticleSystemSet
+         */
+        ParticleSystemSet.Parse = function (data, scene, gpu) {
+            if (gpu === void 0) { gpu = false; }
+            var result = new ParticleSystemSet();
+            var rootUrl = BABYLON.ParticleHelper.BaseAssetsUrl + "/textures/";
+            for (var _i = 0, _a = data.systems; _i < _a.length; _i++) {
+                var system = _a[_i];
+                result.systems.push(gpu ? BABYLON.GPUParticleSystem.Parse(system, scene, rootUrl) : BABYLON.ParticleSystem.Parse(system, scene, rootUrl));
+            }
+            if (data.emitter) {
+                var options = data.emitter.options;
+                switch (data.emitter.kind) {
+                    case "Sphere":
+                        result.setEmitterAsSphere({
+                            diameter: options.diameter,
+                            segments: options.segments,
+                            color: BABYLON.Color3.FromArray(options.color)
+                        }, data.emitter.renderingGroupId, scene);
+                        break;
+                }
+            }
+            return result;
+        };
+        return ParticleSystemSet;
+    }());
+    BABYLON.ParticleSystemSet = ParticleSystemSet;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.particleSystemSet.js.map
+
+var BABYLON;
+(function (BABYLON) {
+    /**
+     * This class is made for on one-liner static method to help creating particle system set.
      */
     var ParticleHelper = /** @class */ (function () {
         function ParticleHelper() {
         }
         /**
-         * This is the main static method (one-liner) of this helper to create different particle systems.
+         * This is the main static method (one-liner) of this helper to create different particle systems
          * @param type This string represents the type to the particle system to create
-         * @param emitter The object where the particle system will start to emit from.
-         * @param scene The scene where the particle system should live.
-         * @param gpu If the system will use gpu.
-         * @returns the ParticleSystem created.
+         * @param scene The scene where the particle system should live
+         * @param gpu If the system will use gpu
+         * @returns the ParticleSystemSet created
          */
-        ParticleHelper.CreateAsync = function (type, emitter, scene, gpu) {
+        ParticleHelper.CreateAsync = function (type, scene, gpu) {
             if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
             if (gpu === void 0) { gpu = false; }
             return new Promise(function (resolve, reject) {
@@ -102552,160 +102701,31 @@ var BABYLON;
                 if (gpu && !BABYLON.GPUParticleSystem.IsSupported) {
                     return reject("Particle system with GPU is not supported.");
                 }
-                BABYLON.Tools.LoadFile(ParticleHelper._baseAssetsUrl + "/systems/" + type + ".json", function (data, response) {
+                BABYLON.Tools.LoadFile(ParticleHelper.BaseAssetsUrl + "/systems/" + type + ".json", function (data, response) {
                     var newData = JSON.parse(data.toString());
-                    return resolve(ParticleHelper.CreateSystem(newData, scene, emitter));
+                    return resolve(BABYLON.ParticleSystemSet.Parse(newData, scene, gpu));
                 }, undefined, undefined, undefined, function (req, exception) {
                     return reject("An error occured while the creation of your particle system. Check if your type '" + type + "' exists.");
                 });
             });
         };
         /**
-         * Static function used to create a new particle system from a IParticleSystemData
-         * @param data defines the source data
-         * @param scene defines the hosting scene
-         * @param emitter defines the particle emitter
-         * @returns a new ParticleSystem based on referenced data
-         */
-        ParticleHelper.CreateSystem = function (data, scene, emitter) {
-            // Create a particle system
-            var system = new BABYLON.ParticleSystem(data.type, data.capacity, scene);
-            // Where the particles come from
-            system.emitter = emitter; // the starting object, the emitter            
-            ParticleHelper.UpdateSystem(system, data, scene);
-            return system;
-        };
-        /**
-         * Static function used to update a particle system from a IParticleSystemData
-         * @param system defines the particle system to update
-         * @param data defines the source data
-         * @param scene defines the hosting scene
+         * Static function used to export a particle system to a ParticleSystemSet variable.
+         * Please note that the emitter shape is not exported
+         * @param system defines the particle systems to export
          */
-        ParticleHelper.UpdateSystem = function (system, data, scene) {
-            // Texture of each particle
-            if (data.textureFile) {
-                system.particleTexture = new BABYLON.Texture(ParticleHelper._baseAssetsUrl + "/textures/" + data.textureFile, scene);
-            }
-            // Colors of all particles
-            system.color1 = new BABYLON.Color4(data.color1.r, data.color1.g, data.color1.b, data.color1.a);
-            system.color2 = new BABYLON.Color4(data.color2.r, data.color2.g, data.color2.b, data.color2.a);
-            system.colorDead = new BABYLON.Color4(data.colorDead.r, data.colorDead.g, data.colorDead.b, data.colorDead.a);
-            // Size of each particle (random between...
-            system.minSize = data.minSize;
-            system.maxSize = data.maxSize;
-            system.minScaleX = data.minScaleX;
-            system.maxScaleX = data.maxScaleX;
-            system.minScaleY = data.minScaleY;
-            system.maxScaleY = data.maxScaleY;
-            // Life time of each particle (random between...
-            system.minLifeTime = data.minLifeTime;
-            system.maxLifeTime = data.maxLifeTime;
-            // Emission rate
-            system.emitRate = data.emitRate;
-            // Blend mode : BLENDMODE_ONEONE, or BLENDMODE_STANDARD
-            system.blendMode = data.blendMode;
-            // Set the gravity of all particles
-            system.gravity = new BABYLON.Vector3(data.gravity.x, data.gravity.y, data.gravity.z);
-            // Angular speed, in radians
-            system.minAngularSpeed = data.minAngularSpeed;
-            system.maxAngularSpeed = data.maxAngularSpeed;
-            // Speed
-            system.minEmitPower = data.minEmitPower;
-            system.maxEmitPower = data.maxEmitPower;
-            system.updateSpeed = data.updateSpeed;
-            switch (data.emitterType) {
-                case "box":
-                    if (!data.direction1 || !data.direction2) {
-                        throw new Error("Directions are missing in this particle system.");
-                    }
-                    if (!data.minEmitBox || !data.maxEmitBox) {
-                        throw new Error("EmitBox is missing in this particle system.");
-                    }
-                    system.createBoxEmitter(new BABYLON.Vector3(data.direction1.x, data.direction1.y, data.direction1.z), new BABYLON.Vector3(data.direction2.x, data.direction2.y, data.direction2.z), new BABYLON.Vector3(data.minEmitBox.x, data.minEmitBox.y, data.minEmitBox.z), new BABYLON.Vector3(data.maxEmitBox.x, data.maxEmitBox.y, data.maxEmitBox.z));
-                    break;
-                case "sphere":
-                    system.createSphereEmitter(data.radius);
-                    break;
-                case "directed_sphere":
-                    if (!data.direction1 || !data.direction2) {
-                        throw new Error("Directions are missing in this particle system.");
-                    }
-                    system.createDirectedSphereEmitter(data.radius, new BABYLON.Vector3(data.direction1.x, data.direction1.y, data.direction1.z), new BABYLON.Vector3(data.direction2.x, data.direction2.y, data.direction2.z));
-                    break;
-                case "cone":
-                    system.createConeEmitter(data.radius, data.angle);
-                    break;
-                default:
-                    break;
-            }
-        };
-        /**
-         * Static function used to export a particle system to a IParticleSystemData variable.
-         * Please note that texture file name is not exported and must be added manually
-         * @param system defines the particle system to export
-         */
-        ParticleHelper.ExportSystem = function (system) {
-            var outData = {};
-            // Colors of all particles
-            outData.color1 = { r: system.color1.r, g: system.color1.g, b: system.color1.b, a: system.color1.a };
-            outData.color2 = { r: system.color2.r, g: system.color2.g, b: system.color2.b, a: system.color2.a };
-            outData.colorDead = { r: system.colorDead.r, g: system.colorDead.g, b: system.colorDead.b, a: system.colorDead.a };
-            // Size of each particle (random between...
-            outData.minSize = system.minSize;
-            outData.maxSize = system.maxSize;
-            outData.minScaleX = system.minScaleX;
-            outData.maxScaleX = system.maxScaleX;
-            outData.minScaleY = system.minScaleY;
-            outData.maxScaleY = system.maxScaleY;
-            // Life time of each particle (random between...
-            outData.minLifeTime = system.minLifeTime;
-            outData.maxLifeTime = system.maxLifeTime;
-            // Emission rate
-            outData.emitRate = system.emitRate;
-            // Blend mode : BLENDMODE_ONEONE, or BLENDMODE_STANDARD
-            outData.blendMode = system.blendMode;
-            // Set the gravity of all particles
-            outData.gravity = { x: system.gravity.x, y: system.gravity.y, z: system.gravity.z };
-            // Angular speed, in radians
-            outData.minAngularSpeed = system.minAngularSpeed;
-            outData.maxAngularSpeed = system.maxAngularSpeed;
-            // Speed
-            outData.minEmitPower = system.minEmitPower;
-            outData.maxEmitPower = system.maxEmitPower;
-            outData.updateSpeed = system.updateSpeed;
-            switch (system.particleEmitterType.getClassName()) {
-                case "BoxEmitter":
-                    outData.emitterType = "box";
-                    outData.direction1 = { x: system.direction1.x, y: system.direction1.y, z: system.direction1.z };
-                    outData.direction2 = { x: system.direction2.x, y: system.direction2.y, z: system.direction2.z };
-                    outData.minEmitBox = { x: system.minEmitBox.x, y: system.minEmitBox.y, z: system.minEmitBox.z };
-                    outData.maxEmitBox = { x: system.maxEmitBox.x, y: system.maxEmitBox.y, z: system.maxEmitBox.z };
-                    break;
-                case "SphereParticleEmitter":
-                    outData.emitterType = "sphere";
-                    outData.radius = system.particleEmitterType.radius;
-                    break;
-                case "SphereDirectedParticleEmitter":
-                    outData.emitterType = "directed_sphere";
-                    var sphereDirectedParticleEmitter = system.particleEmitterType;
-                    outData.radius = sphereDirectedParticleEmitter.radius;
-                    outData.direction1 = { x: sphereDirectedParticleEmitter.direction1.x, y: sphereDirectedParticleEmitter.direction1.y, z: sphereDirectedParticleEmitter.direction1.z };
-                    outData.direction2 = { x: sphereDirectedParticleEmitter.direction2.x, y: sphereDirectedParticleEmitter.direction2.y, z: sphereDirectedParticleEmitter.direction2.z };
-                    break;
-                case "ConeEmitter":
-                    outData.emitterType = "cone";
-                    outData.radius = system.particleEmitterType.radius;
-                    outData.angle = system.particleEmitterType.angle;
-                    break;
-                default:
-                    break;
+        ParticleHelper.ExportSet = function (systems) {
+            var set = new BABYLON.ParticleSystemSet();
+            for (var _i = 0, systems_1 = systems; _i < systems_1.length; _i++) {
+                var system = systems_1[_i];
+                set.systems.push(system);
             }
-            return outData;
+            return set;
         };
         /**
-         * Base Assets URL.
+         * Gets or sets base Assets URL
          */
-        ParticleHelper._baseAssetsUrl = "https://assets.babylonjs.com/particles";
+        ParticleHelper.BaseAssetsUrl = "https://assets.babylonjs.com/particles";
         return ParticleHelper;
     }());
     BABYLON.ParticleHelper = ParticleHelper;

ファイルの差分が大きいため隠しています
+ 26 - 26
dist/preview release/babylon.worker.js


ファイルの差分が大きいため隠しています
+ 177 - 157
dist/preview release/es6.js


ファイルの差分が大きいため隠しています
+ 2 - 2
dist/preview release/inspector/babylon.inspector.bundle.js


ファイルの差分が大きいため隠しています
+ 67 - 67
dist/preview release/viewer/babylon.viewer.js


+ 175 - 155
dist/preview release/viewer/babylon.viewer.max.js

@@ -24296,6 +24296,8 @@ var BABYLON;
             this._doubleClickOccured = false;
             /** Define this parameter if you are using multiple cameras and you want to specify which one should be used for pointer position */
             this.cameraToUseForPointers = null;
+            this._pointerX = 0;
+            this._pointerY = 0;
             this._startingPointerPosition = new BABYLON.Vector2(0, 0);
             this._previousStartingPointerPosition = new BABYLON.Vector2(0, 0);
             this._startingPointerTime = 0;
@@ -56539,6 +56541,8 @@ var BABYLON;
             // Animations
             BABYLON.Animation.AppendSerializedAnimations(particleSystem, serializationObject);
             // Particle system
+            serializationObject.renderingGroupId = particleSystem.renderingGroupId;
+            serializationObject.isBillboardBased = particleSystem.isBillboardBased;
             serializationObject.minAngularSpeed = particleSystem.minAngularSpeed;
             serializationObject.maxAngularSpeed = particleSystem.maxAngularSpeed;
             serializationObject.minSize = particleSystem.minSize;
@@ -56598,12 +56602,22 @@ var BABYLON;
                 particleSystem.particleTexture.name = parsedParticleSystem.textureName;
             }
             // Emitter
-            if (parsedParticleSystem.emitterId) {
+            if (parsedParticleSystem.emitterId === undefined) {
+                particleSystem.emitter = BABYLON.Vector3.Zero();
+            }
+            else if (parsedParticleSystem.emitterId) {
                 particleSystem.emitter = scene.getLastMeshByID(parsedParticleSystem.emitterId);
             }
             else {
                 particleSystem.emitter = BABYLON.Vector3.FromArray(parsedParticleSystem.emitter);
             }
+            // Misc.
+            if (parsedParticleSystem.renderingGroupId !== undefined) {
+                particleSystem.renderingGroupId = parsedParticleSystem.renderingGroupId;
+            }
+            if (parsedParticleSystem.isBillboardBased !== undefined) {
+                particleSystem.isBillboardBased = parsedParticleSystem.isBillboardBased;
+            }
             // Animations
             if (parsedParticleSystem.animations) {
                 for (var animationIndex = 0; animationIndex < parsedParticleSystem.animations.length; animationIndex++) {
@@ -56661,16 +56675,18 @@ var BABYLON;
             var emitterType;
             if (parsedParticleSystem.particleEmitterType) {
                 switch (parsedParticleSystem.particleEmitterType.type) {
-                    case "SphereEmitter":
+                    case "SphereParticleEmitter":
                         emitterType = new BABYLON.SphereParticleEmitter();
                         break;
                     case "SphereDirectedParticleEmitter":
                         emitterType = new BABYLON.SphereDirectedParticleEmitter();
                         break;
                     case "ConeEmitter":
+                    case "ConeParticleEmitter":
                         emitterType = new BABYLON.ConeParticleEmitter();
                         break;
                     case "BoxEmitter":
+                    case "BoxParticleEmitter":
                     default:
                         emitterType = new BABYLON.BoxParticleEmitter();
                         break;
@@ -56823,11 +56839,11 @@ var BABYLON;
             return "#define BOXEMITTER";
         };
         /**
-         * Returns the string "BoxEmitter"
+         * Returns the string "BoxParticleEmitter"
          * @returns a string containing the class name
          */
         BoxParticleEmitter.prototype.getClassName = function () {
-            return "BoxEmitter";
+            return "BoxParticleEmitter";
         };
         /**
          * Serializes the particle system to a JSON object.
@@ -56987,11 +57003,11 @@ var BABYLON;
             return "#define CONEEMITTER";
         };
         /**
-         * Returns the string "BoxEmitter"
+         * Returns the string "ConeParticleEmitter"
          * @returns a string containing the class name
          */
         ConeParticleEmitter.prototype.getClassName = function () {
-            return "ConeEmitter";
+            return "ConeParticleEmitter";
         };
         /**
          * Serializes the particle system to a JSON object.
@@ -57125,6 +57141,7 @@ var BABYLON;
             var serializationObject = {};
             serializationObject.type = this.getClassName();
             serializationObject.radius = this.radius;
+            serializationObject.radiusRange = this.radiusRange;
             serializationObject.directionRandomizer = this.directionRandomizer;
             return serializationObject;
         };
@@ -57134,6 +57151,7 @@ var BABYLON;
          */
         SphereParticleEmitter.prototype.parse = function (serializationObject) {
             this.radius = serializationObject.radius;
+            this.radiusRange = serializationObject.radiusRange;
             this.directionRandomizer = serializationObject.directionRandomizer;
         };
         return SphereParticleEmitter;
@@ -102648,21 +102666,152 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /** Internal class used to store shapes for emitters */
+    var ParticleSystemSetEmitterCreationOptions = /** @class */ (function () {
+        function ParticleSystemSetEmitterCreationOptions() {
+        }
+        return ParticleSystemSetEmitterCreationOptions;
+    }());
     /**
-     * This class is made for on one-liner static method to help creating particle systems.
+     * Represents a set of particle systems working together to create a specific effect
+     */
+    var ParticleSystemSet = /** @class */ (function () {
+        function ParticleSystemSet() {
+            /**
+             * Gets or sets the particle system list
+             */
+            this.systems = new Array();
+        }
+        Object.defineProperty(ParticleSystemSet.prototype, "emitterMesh", {
+            /**
+             * Gets or set the emitter mesh used with this set
+             */
+            get: function () {
+                return this._emitterMesh;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        /**
+         * Creates a new emitter mesh as a sphere
+         * @param options defines the options used to create the sphere
+         * @param renderingGroupId defines the renderingGroupId to use for the sphere
+         * @param scene defines the hosting scene
+         */
+        ParticleSystemSet.prototype.setEmitterAsSphere = function (options, renderingGroupId, scene) {
+            if (this._emitterMesh) {
+                this._emitterMesh.dispose();
+            }
+            this._emitterCreationOptions = {
+                kind: "Sphere",
+                options: options,
+                renderingGroupId: renderingGroupId
+            };
+            this._emitterMesh = BABYLON.MeshBuilder.CreateSphere("emitterSphere", { diameter: options.diameter, segments: options.segments }, scene);
+            this._emitterMesh.renderingGroupId = renderingGroupId;
+            var material = new BABYLON.StandardMaterial("emitterSphereMaterial", scene);
+            material.emissiveColor = options.color;
+            this._emitterMesh.material = material;
+            for (var _i = 0, _a = this.systems; _i < _a.length; _i++) {
+                var system = _a[_i];
+                system.emitter = this._emitterMesh;
+            }
+        };
+        /**
+         * Starts all particle systems of the set
+         * @param emitter defines an optional mesh to use as emitter for the particle systems
+         */
+        ParticleSystemSet.prototype.start = function (emitter) {
+            for (var _i = 0, _a = this.systems; _i < _a.length; _i++) {
+                var system = _a[_i];
+                if (emitter) {
+                    system.emitter = emitter;
+                }
+                system.start();
+            }
+        };
+        /**
+         * Release all associated resources
+         */
+        ParticleSystemSet.prototype.dispose = function () {
+            for (var _i = 0, _a = this.systems; _i < _a.length; _i++) {
+                var system = _a[_i];
+                system.dispose();
+            }
+            this.systems = [];
+            if (this._emitterMesh) {
+                this._emitterMesh.dispose();
+                this._emitterMesh = null;
+            }
+        };
+        /**
+         * Serialize the set into a JSON compatible object
+         * @returns a JSON compatible representation of the set
+         */
+        ParticleSystemSet.prototype.serialize = function () {
+            var result = {};
+            result.systems = [];
+            for (var _i = 0, _a = this.systems; _i < _a.length; _i++) {
+                var system = _a[_i];
+                result.systems.push(system.serialize());
+            }
+            if (this._emitterMesh) {
+                result.emitter = this._emitterCreationOptions;
+            }
+            return result;
+        };
+        /**
+         * Parse a new ParticleSystemSet from a serialized source
+         * @param data defines a JSON compatible representation of the set
+         * @param scene defines the hosting scene
+         * @param gpu defines if we want GPU particles or CPU particles
+         * @returns a new ParticleSystemSet
+         */
+        ParticleSystemSet.Parse = function (data, scene, gpu) {
+            if (gpu === void 0) { gpu = false; }
+            var result = new ParticleSystemSet();
+            var rootUrl = BABYLON.ParticleHelper.BaseAssetsUrl + "/textures/";
+            for (var _i = 0, _a = data.systems; _i < _a.length; _i++) {
+                var system = _a[_i];
+                result.systems.push(gpu ? BABYLON.GPUParticleSystem.Parse(system, scene, rootUrl) : BABYLON.ParticleSystem.Parse(system, scene, rootUrl));
+            }
+            if (data.emitter) {
+                var options = data.emitter.options;
+                switch (data.emitter.kind) {
+                    case "Sphere":
+                        result.setEmitterAsSphere({
+                            diameter: options.diameter,
+                            segments: options.segments,
+                            color: BABYLON.Color3.FromArray(options.color)
+                        }, data.emitter.renderingGroupId, scene);
+                        break;
+                }
+            }
+            return result;
+        };
+        return ParticleSystemSet;
+    }());
+    BABYLON.ParticleSystemSet = ParticleSystemSet;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.particleSystemSet.js.map
+
+var BABYLON;
+(function (BABYLON) {
+    /**
+     * This class is made for on one-liner static method to help creating particle system set.
      */
     var ParticleHelper = /** @class */ (function () {
         function ParticleHelper() {
         }
         /**
-         * This is the main static method (one-liner) of this helper to create different particle systems.
+         * This is the main static method (one-liner) of this helper to create different particle systems
          * @param type This string represents the type to the particle system to create
-         * @param emitter The object where the particle system will start to emit from.
-         * @param scene The scene where the particle system should live.
-         * @param gpu If the system will use gpu.
-         * @returns the ParticleSystem created.
+         * @param scene The scene where the particle system should live
+         * @param gpu If the system will use gpu
+         * @returns the ParticleSystemSet created
          */
-        ParticleHelper.CreateAsync = function (type, emitter, scene, gpu) {
+        ParticleHelper.CreateAsync = function (type, scene, gpu) {
             if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
             if (gpu === void 0) { gpu = false; }
             return new Promise(function (resolve, reject) {
@@ -102673,160 +102822,31 @@ var BABYLON;
                 if (gpu && !BABYLON.GPUParticleSystem.IsSupported) {
                     return reject("Particle system with GPU is not supported.");
                 }
-                BABYLON.Tools.LoadFile(ParticleHelper._baseAssetsUrl + "/systems/" + type + ".json", function (data, response) {
+                BABYLON.Tools.LoadFile(ParticleHelper.BaseAssetsUrl + "/systems/" + type + ".json", function (data, response) {
                     var newData = JSON.parse(data.toString());
-                    return resolve(ParticleHelper.CreateSystem(newData, scene, emitter));
+                    return resolve(BABYLON.ParticleSystemSet.Parse(newData, scene, gpu));
                 }, undefined, undefined, undefined, function (req, exception) {
                     return reject("An error occured while the creation of your particle system. Check if your type '" + type + "' exists.");
                 });
             });
         };
         /**
-         * Static function used to create a new particle system from a IParticleSystemData
-         * @param data defines the source data
-         * @param scene defines the hosting scene
-         * @param emitter defines the particle emitter
-         * @returns a new ParticleSystem based on referenced data
-         */
-        ParticleHelper.CreateSystem = function (data, scene, emitter) {
-            // Create a particle system
-            var system = new BABYLON.ParticleSystem(data.type, data.capacity, scene);
-            // Where the particles come from
-            system.emitter = emitter; // the starting object, the emitter            
-            ParticleHelper.UpdateSystem(system, data, scene);
-            return system;
-        };
-        /**
-         * Static function used to update a particle system from a IParticleSystemData
-         * @param system defines the particle system to update
-         * @param data defines the source data
-         * @param scene defines the hosting scene
+         * Static function used to export a particle system to a ParticleSystemSet variable.
+         * Please note that the emitter shape is not exported
+         * @param system defines the particle systems to export
          */
-        ParticleHelper.UpdateSystem = function (system, data, scene) {
-            // Texture of each particle
-            if (data.textureFile) {
-                system.particleTexture = new BABYLON.Texture(ParticleHelper._baseAssetsUrl + "/textures/" + data.textureFile, scene);
-            }
-            // Colors of all particles
-            system.color1 = new BABYLON.Color4(data.color1.r, data.color1.g, data.color1.b, data.color1.a);
-            system.color2 = new BABYLON.Color4(data.color2.r, data.color2.g, data.color2.b, data.color2.a);
-            system.colorDead = new BABYLON.Color4(data.colorDead.r, data.colorDead.g, data.colorDead.b, data.colorDead.a);
-            // Size of each particle (random between...
-            system.minSize = data.minSize;
-            system.maxSize = data.maxSize;
-            system.minScaleX = data.minScaleX;
-            system.maxScaleX = data.maxScaleX;
-            system.minScaleY = data.minScaleY;
-            system.maxScaleY = data.maxScaleY;
-            // Life time of each particle (random between...
-            system.minLifeTime = data.minLifeTime;
-            system.maxLifeTime = data.maxLifeTime;
-            // Emission rate
-            system.emitRate = data.emitRate;
-            // Blend mode : BLENDMODE_ONEONE, or BLENDMODE_STANDARD
-            system.blendMode = data.blendMode;
-            // Set the gravity of all particles
-            system.gravity = new BABYLON.Vector3(data.gravity.x, data.gravity.y, data.gravity.z);
-            // Angular speed, in radians
-            system.minAngularSpeed = data.minAngularSpeed;
-            system.maxAngularSpeed = data.maxAngularSpeed;
-            // Speed
-            system.minEmitPower = data.minEmitPower;
-            system.maxEmitPower = data.maxEmitPower;
-            system.updateSpeed = data.updateSpeed;
-            switch (data.emitterType) {
-                case "box":
-                    if (!data.direction1 || !data.direction2) {
-                        throw new Error("Directions are missing in this particle system.");
-                    }
-                    if (!data.minEmitBox || !data.maxEmitBox) {
-                        throw new Error("EmitBox is missing in this particle system.");
-                    }
-                    system.createBoxEmitter(new BABYLON.Vector3(data.direction1.x, data.direction1.y, data.direction1.z), new BABYLON.Vector3(data.direction2.x, data.direction2.y, data.direction2.z), new BABYLON.Vector3(data.minEmitBox.x, data.minEmitBox.y, data.minEmitBox.z), new BABYLON.Vector3(data.maxEmitBox.x, data.maxEmitBox.y, data.maxEmitBox.z));
-                    break;
-                case "sphere":
-                    system.createSphereEmitter(data.radius);
-                    break;
-                case "directed_sphere":
-                    if (!data.direction1 || !data.direction2) {
-                        throw new Error("Directions are missing in this particle system.");
-                    }
-                    system.createDirectedSphereEmitter(data.radius, new BABYLON.Vector3(data.direction1.x, data.direction1.y, data.direction1.z), new BABYLON.Vector3(data.direction2.x, data.direction2.y, data.direction2.z));
-                    break;
-                case "cone":
-                    system.createConeEmitter(data.radius, data.angle);
-                    break;
-                default:
-                    break;
-            }
-        };
-        /**
-         * Static function used to export a particle system to a IParticleSystemData variable.
-         * Please note that texture file name is not exported and must be added manually
-         * @param system defines the particle system to export
-         */
-        ParticleHelper.ExportSystem = function (system) {
-            var outData = {};
-            // Colors of all particles
-            outData.color1 = { r: system.color1.r, g: system.color1.g, b: system.color1.b, a: system.color1.a };
-            outData.color2 = { r: system.color2.r, g: system.color2.g, b: system.color2.b, a: system.color2.a };
-            outData.colorDead = { r: system.colorDead.r, g: system.colorDead.g, b: system.colorDead.b, a: system.colorDead.a };
-            // Size of each particle (random between...
-            outData.minSize = system.minSize;
-            outData.maxSize = system.maxSize;
-            outData.minScaleX = system.minScaleX;
-            outData.maxScaleX = system.maxScaleX;
-            outData.minScaleY = system.minScaleY;
-            outData.maxScaleY = system.maxScaleY;
-            // Life time of each particle (random between...
-            outData.minLifeTime = system.minLifeTime;
-            outData.maxLifeTime = system.maxLifeTime;
-            // Emission rate
-            outData.emitRate = system.emitRate;
-            // Blend mode : BLENDMODE_ONEONE, or BLENDMODE_STANDARD
-            outData.blendMode = system.blendMode;
-            // Set the gravity of all particles
-            outData.gravity = { x: system.gravity.x, y: system.gravity.y, z: system.gravity.z };
-            // Angular speed, in radians
-            outData.minAngularSpeed = system.minAngularSpeed;
-            outData.maxAngularSpeed = system.maxAngularSpeed;
-            // Speed
-            outData.minEmitPower = system.minEmitPower;
-            outData.maxEmitPower = system.maxEmitPower;
-            outData.updateSpeed = system.updateSpeed;
-            switch (system.particleEmitterType.getClassName()) {
-                case "BoxEmitter":
-                    outData.emitterType = "box";
-                    outData.direction1 = { x: system.direction1.x, y: system.direction1.y, z: system.direction1.z };
-                    outData.direction2 = { x: system.direction2.x, y: system.direction2.y, z: system.direction2.z };
-                    outData.minEmitBox = { x: system.minEmitBox.x, y: system.minEmitBox.y, z: system.minEmitBox.z };
-                    outData.maxEmitBox = { x: system.maxEmitBox.x, y: system.maxEmitBox.y, z: system.maxEmitBox.z };
-                    break;
-                case "SphereParticleEmitter":
-                    outData.emitterType = "sphere";
-                    outData.radius = system.particleEmitterType.radius;
-                    break;
-                case "SphereDirectedParticleEmitter":
-                    outData.emitterType = "directed_sphere";
-                    var sphereDirectedParticleEmitter = system.particleEmitterType;
-                    outData.radius = sphereDirectedParticleEmitter.radius;
-                    outData.direction1 = { x: sphereDirectedParticleEmitter.direction1.x, y: sphereDirectedParticleEmitter.direction1.y, z: sphereDirectedParticleEmitter.direction1.z };
-                    outData.direction2 = { x: sphereDirectedParticleEmitter.direction2.x, y: sphereDirectedParticleEmitter.direction2.y, z: sphereDirectedParticleEmitter.direction2.z };
-                    break;
-                case "ConeEmitter":
-                    outData.emitterType = "cone";
-                    outData.radius = system.particleEmitterType.radius;
-                    outData.angle = system.particleEmitterType.angle;
-                    break;
-                default:
-                    break;
+        ParticleHelper.ExportSet = function (systems) {
+            var set = new BABYLON.ParticleSystemSet();
+            for (var _i = 0, systems_1 = systems; _i < systems_1.length; _i++) {
+                var system = systems_1[_i];
+                set.systems.push(system);
             }
-            return outData;
+            return set;
         };
         /**
-         * Base Assets URL.
+         * Gets or sets base Assets URL
          */
-        ParticleHelper._baseAssetsUrl = "https://assets.babylonjs.com/particles";
+        ParticleHelper.BaseAssetsUrl = "https://assets.babylonjs.com/particles";
         return ParticleHelper;
     }());
     BABYLON.ParticleHelper = ParticleHelper;

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

@@ -2,7 +2,6 @@
 
 ## Major updates
 
-- Added a ParticleHelper class to create some pre-configured particle systems in a one-liner method style ([DevChris](https://github.com/yovanoc))
 - Added new `MixMaterial` to the Materials Library allowing to mix up to 8 textures ([julien-moreau](https://github.com/julien-moreau))
 - Added new `PhotoDome` object to display 360 photos. [Demo](https://www.babylonjs-playground.com/#14KRGG#0) ([SzeyinLee](https://github.com/SzeyinLee))
 - New GUI 3D controls toolset. [Complete doc + demos](http://doc.babylonjs.com/how_to/gui3d) ([Deltakosh](https://github.com/deltakosh))
@@ -10,6 +9,7 @@
 - New GUI control: the [Grid](http://doc.babylonjs.com/how_to/gui#grid) ([Deltakosh](https://github.com/deltakosh))
 - Gizmo and GizmoManager classes used to manipulate meshes in a scene. Gizmo types include: position, rotation, scale and bounding box ([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 ([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 `minScaleX`, `minScaleY`, `maxScaleX`, `maxScaleY`. [Doc](http://doc.babylonjs.com/babylon101/particles#size)

+ 0 - 349
src/Helpers/babylon.particleHelper.ts

@@ -1,349 +0,0 @@
-module BABYLON {
-    /**
-     * Represents all the data needed to create a ParticleSystem.
-     */
-    export interface IParticleSystemData {
-        /**
-         * ParticleSystem type
-         */
-        type: string;
-        /**
-         * Shape of the emitter
-         */
-        emitterType: string
-        /**
-         * Maximum number of particles in the system
-         */
-        capacity: number;
-        /**
-         * Link for the texture file
-         */
-        textureFile: string;
-        /**
-         * minEmitBox Vector3
-         */
-        minEmitBox?: { x: number, y: number, z: number };
-        /**
-         * maxEmitBox Vector3
-         */
-        maxEmitBox?: { x: number, y: number, z: number };
-        /**
-         * color1 Color4
-         */
-        color1: { r: number, g: number, b: number, a: number };
-        /**
-         * color2 Color4
-         */
-        color2: { r: number, g: number, b: number, a: number };
-        /**
-         * colorDead Color4
-         */
-        colorDead: { r: number, g: number, b: number, a: number };
-        /**
-         * Minimum size of each particle
-         */
-        minSize: number;
-        /**
-         * Maximum size of each particle
-         */
-        maxSize: number;
-        /**
-         * Minimum scale of each particle on X axis
-         */
-        minScaleX: number;
-        /**
-         * Maximum scale of each particle on X axis
-         */
-        maxScaleX: number;       
-        /**
-         * Minimum scale of each particle on Y axis
-         */
-        minScaleY: number;
-        /**
-         * Maximum scale of each particle on Y axis
-         */
-        maxScaleY: number;           
-        /**
-         * Minimum lifetime for each particle
-         */
-        minLifeTime: number;
-        /**
-         * Maximum lifetime for each particle
-         */
-        maxLifeTime: number;
-        /**
-         * Emit rate
-         */
-        emitRate: number;
-        /**
-         * Blend Mode
-         */
-        blendMode: number;
-        /**
-         * gravity Vector3
-         */
-        gravity: { x: number, y: number, z: number };
-        /**
-         * direction1 Vector3
-         */
-        direction1?: { x: number, y: number, z: number };
-        /**
-         * direction2 Vector3
-         */
-        direction2?: { x: number, y: number, z: number };
-        /**
-         * Minimum Angular Speed
-         */
-        minAngularSpeed: number;
-        /**
-         * Maximum Angular Speed
-         */
-        maxAngularSpeed: number;
-        /**
-         * Minimum Emit Power
-         */
-        minEmitPower: number;
-        /**
-         * Maximum Emit Power
-         */
-        maxEmitPower: number;
-        /**
-         * Update Speed
-         */
-        updateSpeed: number;
-        /**
-         * Radius
-         */
-        radius?: number;
-        /**
-         * Angle
-         */
-        angle?: number;
-    }
-    /**
-     * This class is made for on one-liner static method to help creating particle systems.
-     */
-    export class ParticleHelper {
-        /**
-         * Base Assets URL.
-         */
-        private static _baseAssetsUrl = "https://assets.babylonjs.com/particles";
-
-        /**
-         * This is the main static method (one-liner) of this helper to create different particle systems.
-         * @param type This string represents the type to the particle system to create
-         * @param emitter The object where the particle system will start to emit from.
-         * @param scene The scene where the particle system should live.
-         * @param gpu If the system will use gpu.
-         * @returns the ParticleSystem created.
-         */
-        public static CreateAsync(type: string, emitter: AbstractMesh,
-                                   scene: Nullable<Scene> = Engine.LastCreatedScene, gpu: boolean = false): Promise<ParticleSystem> {
-            
-            return new Promise((resolve, reject) => {
-                if (!scene) {
-                    scene = Engine.LastCreatedScene;;
-                }
-
-                if (gpu && !GPUParticleSystem.IsSupported) {
-                    return reject("Particle system with GPU is not supported.");
-                }
-
-                Tools.LoadFile(`${ParticleHelper._baseAssetsUrl}/systems/${type}.json`, (data, response) => {
-                    const newData = JSON.parse(data.toString()) as IParticleSystemData;
-                    return resolve(ParticleHelper.CreateSystem(newData, scene!, emitter));
-                }, undefined, undefined, undefined, (req, exception) => {
-                    return reject(`An error occured while the creation of your particle system. Check if your type '${type}' exists.`);
-                });
-
-            });
-        }
-
-        /**
-         * Static function used to create a new particle system from a IParticleSystemData
-         * @param data defines the source data
-         * @param scene defines the hosting scene
-         * @param emitter defines the particle emitter
-         * @returns a new ParticleSystem based on referenced data
-         */
-        public static CreateSystem(data: IParticleSystemData, scene: Scene, emitter: AbstractMesh): ParticleSystem {
-            // Create a particle system
-            const system = new ParticleSystem(data.type, data.capacity, scene);
-
-            // Where the particles come from
-            system.emitter = emitter; // the starting object, the emitter            
-
-            ParticleHelper.UpdateSystem(system, data, scene);
-
-            return system;
-        }
-
-        /**
-         * Static function used to update a particle system from a IParticleSystemData
-         * @param system defines the particle system to update
-         * @param data defines the source data
-         * @param scene defines the hosting scene
-         */
-        public static UpdateSystem(system: ParticleSystem, data: IParticleSystemData, scene: Scene): void {
-            // Texture of each particle
-            if (data.textureFile) {
-                system.particleTexture = new Texture(`${ParticleHelper._baseAssetsUrl}/textures/${data.textureFile}`, scene);
-            }
-
-            // Colors of all particles
-            system.color1 = new Color4(data.color1.r, data.color1.g, data.color1.b, data.color1.a);
-            system.color2 = new Color4(data.color2.r, data.color2.g, data.color2.b, data.color2.a);
-            system.colorDead = new Color4(data.colorDead.r, data.colorDead.g, data.colorDead.b, data.colorDead.a);
-
-            // Size of each particle (random between...
-            system.minSize = data.minSize;
-            system.maxSize = data.maxSize;
-
-            system.minScaleX = data.minScaleX;
-            system.maxScaleX = data.maxScaleX;    
-            
-            system.minScaleY = data.minScaleY;
-            system.maxScaleY = data.maxScaleY;              
-
-            // Life time of each particle (random between...
-            system.minLifeTime = data.minLifeTime;
-            system.maxLifeTime = data.maxLifeTime;
-
-            // Emission rate
-            system.emitRate = data.emitRate;
-
-            // Blend mode : BLENDMODE_ONEONE, or BLENDMODE_STANDARD
-            system.blendMode = data.blendMode;
-
-            // Set the gravity of all particles
-            system.gravity = new Vector3(data.gravity.x, data.gravity.y, data.gravity.z);
-
-            // Angular speed, in radians
-            system.minAngularSpeed = data.minAngularSpeed;
-            system.maxAngularSpeed = data.maxAngularSpeed;
-
-            // Speed
-            system.minEmitPower = data.minEmitPower;
-            system.maxEmitPower = data.maxEmitPower;
-            system.updateSpeed = data.updateSpeed;
-
-            switch (data.emitterType) {
-                case "box":
-
-                    if (!data.direction1 || !data.direction2) {
-                        throw new Error("Directions are missing in this particle system.");
-                    }
-
-                    if (!data.minEmitBox || !data.maxEmitBox) {
-                        throw new Error("EmitBox is missing in this particle system.");
-                    }
-
-                    system.createBoxEmitter(
-                        new Vector3(data.direction1.x, data.direction1.y, data.direction1.z),
-                        new Vector3(data.direction2.x, data.direction2.y, data.direction2.z),
-                        new Vector3(data.minEmitBox.x, data.minEmitBox.y, data.minEmitBox.z),
-                        new Vector3(data.maxEmitBox.x, data.maxEmitBox.y, data.maxEmitBox.z)
-                    );
-                    break;
-                case "sphere":
-                    system.createSphereEmitter(data.radius);
-                    break;
-                case "directed_sphere":
-                    
-                    if (!data.direction1 || !data.direction2) {
-                        throw new Error("Directions are missing in this particle system.");
-                    }
-                    
-                    system.createDirectedSphereEmitter(
-                        data.radius,
-                        new Vector3(data.direction1.x, data.direction1.y, data.direction1.z),
-                        new Vector3(data.direction2.x, data.direction2.y, data.direction2.z)
-                    );
-                    break;
-                case "cone":
-                    system.createConeEmitter(data.radius, data.angle);
-                    break;
-                default:
-                    break;
-            }
-        }
-
-        /**
-         * Static function used to export a particle system to a IParticleSystemData variable.
-         * Please note that texture file name is not exported and must be added manually
-         * @param system defines the particle system to export
-         */
-        public static ExportSystem(system: ParticleSystem): IParticleSystemData {
-            var outData: any = {};
-
-            // Colors of all particles
-            outData.color1 = { r: system.color1.r, g: system.color1.g, b: system.color1.b, a: system.color1.a };
-            outData.color2 = { r: system.color2.r, g: system.color2.g, b: system.color2.b, a: system.color2.a };
-            outData.colorDead = { r: system.colorDead.r, g: system.colorDead.g, b: system.colorDead.b, a: system.colorDead.a };
-
-            // Size of each particle (random between...
-            outData.minSize = system.minSize;
-            outData.maxSize = system.maxSize;
-
-            outData.minScaleX = system.minScaleX;
-            outData.maxScaleX = system.maxScaleX;     
-            
-            outData.minScaleY = system.minScaleY;
-            outData.maxScaleY = system.maxScaleY;             
-
-            // Life time of each particle (random between...
-            outData.minLifeTime = system.minLifeTime;
-            outData.maxLifeTime = system.maxLifeTime;
-
-            // Emission rate
-            outData.emitRate = system.emitRate;
-
-            // Blend mode : BLENDMODE_ONEONE, or BLENDMODE_STANDARD
-            outData.blendMode = system.blendMode;
-
-            // Set the gravity of all particles
-            outData.gravity = {x: system.gravity.x, y: system.gravity.y, z: system.gravity.z};
-
-            // Angular speed, in radians
-            outData.minAngularSpeed = system.minAngularSpeed;
-            outData.maxAngularSpeed = system.maxAngularSpeed;
-
-            // Speed
-            outData.minEmitPower = system.minEmitPower;
-            outData.maxEmitPower = system.maxEmitPower;
-            outData.updateSpeed = system.updateSpeed;
-
-            
-            switch (system.particleEmitterType.getClassName()) {
-                case "BoxEmitter":
-                    outData.emitterType = "box";
-                    outData.direction1 = {x: system.direction1.x, y: system.direction1.y, z: system.direction1.z };
-                    outData.direction2 = {x: system.direction2.x, y: system.direction2.y, z: system.direction2.z };
-                    outData.minEmitBox = {x: system.minEmitBox.x, y: system.minEmitBox.y, z: system.minEmitBox.z };
-                    outData.maxEmitBox = {x: system.maxEmitBox.x, y: system.maxEmitBox.y, z: system.maxEmitBox.z };
-                    break;
-                case "SphereParticleEmitter":
-                    outData.emitterType = "sphere";
-                    outData.radius = (system.particleEmitterType as SphereParticleEmitter).radius;
-                    break;
-                case "SphereDirectedParticleEmitter":
-                    outData.emitterType = "directed_sphere";
-                    var sphereDirectedParticleEmitter = system.particleEmitterType as SphereDirectedParticleEmitter;
-                    outData.radius = sphereDirectedParticleEmitter.radius;
-                    outData.direction1 = {x: sphereDirectedParticleEmitter.direction1.x, y: sphereDirectedParticleEmitter.direction1.y, z: sphereDirectedParticleEmitter.direction1.z };
-                    outData.direction2 = {x: sphereDirectedParticleEmitter.direction2.x, y: sphereDirectedParticleEmitter.direction2.y, z: sphereDirectedParticleEmitter.direction2.z };                
-                    break;
-                case "ConeEmitter":
-                    outData.emitterType = "cone";
-                    outData.radius = (system.particleEmitterType as ConeParticleEmitter).radius;
-                    outData.angle = (system.particleEmitterType as ConeParticleEmitter).angle;
-                    break;
-                default:
-                    break;
-            }
-
-            return outData;
-        }
-    }
-
-}

+ 2 - 2
src/Particles/EmitterTypes/babylon.boxParticleEmitter.ts

@@ -91,11 +91,11 @@ module BABYLON {
         }
 
         /**
-         * Returns the string "BoxEmitter"
+         * Returns the string "BoxParticleEmitter"
          * @returns a string containing the class name
          */
         public getClassName(): string {
-            return "BoxEmitter";
+            return "BoxParticleEmitter";
         }   
         
         /**

+ 2 - 2
src/Particles/EmitterTypes/babylon.coneParticleEmitter.ts

@@ -133,11 +133,11 @@ module BABYLON {
         }     
         
         /**
-         * Returns the string "BoxEmitter"
+         * Returns the string "ConeParticleEmitter"
          * @returns a string containing the class name
          */
         public getClassName(): string {
-            return "ConeEmitter";
+            return "ConeParticleEmitter";
         }  
         
         /**

+ 2 - 0
src/Particles/EmitterTypes/babylon.sphereParticleEmitter.ts

@@ -108,6 +108,7 @@ module BABYLON {
             var serializationObject: any = {};
             serializationObject.type = this.getClassName();
             serializationObject.radius = this.radius;
+            serializationObject.radiusRange = this.radiusRange;
             serializationObject.directionRandomizer = this.directionRandomizer;
 
             return serializationObject;
@@ -119,6 +120,7 @@ module BABYLON {
          */
         public parse(serializationObject: any): void {
             this.radius = serializationObject.radius;
+            this.radiusRange = serializationObject.radiusRange;
             this.directionRandomizer = serializationObject.directionRandomizer;
         }          
     }

+ 5 - 1
src/Particles/babylon.IParticleSystem.ts

@@ -22,6 +22,10 @@ module BABYLON {
          */
         emitter: Nullable<AbstractMesh | Vector3>;
         /**
+         * Gets or sets a boolean indicating if the particles must be rendered as billboard or aligned with the direction
+         */
+        isBillboardBased: boolean;        
+        /**
          * The rendering group used by the Particle system to chose when to render.
          */
         renderingGroupId: number;
@@ -46,7 +50,7 @@ module BABYLON {
         particleTexture: Nullable<Texture>;   
         
         /**
-         * Blend mode use to render the particle, it can be either ParticleSystem.BLENDMODE_ONEONE or ParticleSystem.BLENDMODE_STANDARD.
+         * Blend mode use to render the particle, it can be either ParticleSystem.BLENDMODE_ONEONE, ParticleSystem.BLENDMODE_STANDARD or ParticleSystem.BLENDMODE_ADD.
          */
         blendMode: number;   
         

+ 55 - 0
src/Particles/babylon.particleHelper.ts

@@ -0,0 +1,55 @@
+module BABYLON {
+    /**
+     * This class is made for on one-liner static method to help creating particle system set.
+     */
+    export class ParticleHelper {
+        /**
+         * Gets or sets base Assets URL
+         */
+        public static BaseAssetsUrl = "https://assets.babylonjs.com/particles";
+
+        /**
+         * This is the main static method (one-liner) of this helper to create different particle systems
+         * @param type This string represents the type to the particle system to create
+         * @param scene The scene where the particle system should live
+         * @param gpu If the system will use gpu
+         * @returns the ParticleSystemSet created
+         */
+        public static CreateAsync(type: string, scene: Nullable<Scene> = Engine.LastCreatedScene, gpu: boolean = false): Promise<ParticleSystemSet> {
+            
+            return new Promise((resolve, reject) => {
+                if (!scene) {
+                    scene = Engine.LastCreatedScene;;
+                }
+
+                if (gpu && !GPUParticleSystem.IsSupported) {
+                    return reject("Particle system with GPU is not supported.");
+                }
+
+                Tools.LoadFile(`${ParticleHelper.BaseAssetsUrl}/systems/${type}.json`, (data, response) => {
+                    const newData = JSON.parse(data.toString());
+                    return resolve(ParticleSystemSet.Parse(newData, scene!, gpu));
+                }, undefined, undefined, undefined, (req, exception) => {
+                    return reject(`An error occured while the creation of your particle system. Check if your type '${type}' exists.`);
+                });
+
+            });
+        }
+
+        /**
+         * Static function used to export a particle system to a ParticleSystemSet variable.
+         * Please note that the emitter shape is not exported
+         * @param system defines the particle systems to export
+         */
+        public static ExportSet(systems: ParticleSystem[]): ParticleSystemSet {
+            var set = new ParticleSystemSet();
+
+            for (var system of systems) {
+                set.systems.push(system);
+            }
+
+            return set;
+        }
+    }
+
+}

+ 18 - 2
src/Particles/babylon.particleSystem.ts

@@ -1416,6 +1416,8 @@
             Animation.AppendSerializedAnimations(particleSystem, serializationObject);
 
             // Particle system
+            serializationObject.renderingGroupId = particleSystem.renderingGroupId;
+            serializationObject.isBillboardBased = particleSystem.isBillboardBased;
             serializationObject.minAngularSpeed = particleSystem.minAngularSpeed;
             serializationObject.maxAngularSpeed = particleSystem.maxAngularSpeed;
             serializationObject.minSize = particleSystem.minSize;
@@ -1480,12 +1482,24 @@
             }
 
             // Emitter
-            if (parsedParticleSystem.emitterId) {
+            if (parsedParticleSystem.emitterId === undefined) {
+                particleSystem.emitter = Vector3.Zero();
+            }
+             else if (parsedParticleSystem.emitterId) {
                 particleSystem.emitter = scene.getLastMeshByID(parsedParticleSystem.emitterId);
             } else {
                 particleSystem.emitter = Vector3.FromArray(parsedParticleSystem.emitter);
             }
 
+            // Misc.
+            if (parsedParticleSystem.renderingGroupId !== undefined) {
+                particleSystem.renderingGroupId = parsedParticleSystem.renderingGroupId;
+            }
+
+            if (parsedParticleSystem.isBillboardBased !== undefined) {
+                particleSystem.isBillboardBased = parsedParticleSystem.isBillboardBased;
+            }
+
             // Animations
             if (parsedParticleSystem.animations) {
                 for (var animationIndex = 0; animationIndex < parsedParticleSystem.animations.length; animationIndex++) {
@@ -1551,16 +1565,18 @@
             let emitterType: IParticleEmitterType;
             if (parsedParticleSystem.particleEmitterType) {
                 switch (parsedParticleSystem.particleEmitterType.type) {
-                    case "SphereEmitter":
+                    case "SphereParticleEmitter":
                         emitterType = new SphereParticleEmitter();
                         break;
                     case "SphereDirectedParticleEmitter":
                         emitterType = new SphereDirectedParticleEmitter();
                         break;
                     case "ConeEmitter":
+                    case "ConeParticleEmitter":
                         emitterType = new ConeParticleEmitter();
                         break;
                     case "BoxEmitter":
+                    case "BoxParticleEmitter":
                     default:
                         emitterType = new BoxParticleEmitter();
                         break;                                                

+ 137 - 0
src/Particles/babylon.particleSystemSet.ts

@@ -0,0 +1,137 @@
+module BABYLON {
+
+    /** Internal class used to store shapes for emitters */
+    class ParticleSystemSetEmitterCreationOptions {
+        public kind: string;
+        public options: any;
+        public renderingGroupId: number;
+    }
+
+    /**
+     * Represents a set of particle systems working together to create a specific effect
+     */
+    export class ParticleSystemSet implements IDisposable {
+        private _emitterCreationOptions: ParticleSystemSetEmitterCreationOptions;
+        private _emitterMesh: Nullable<Mesh>;
+
+        /**
+         * Gets or sets the particle system list
+         */
+        public systems = new Array<IParticleSystem>();
+
+        /**
+         * Gets or set the emitter mesh used with this set
+         */
+        public get emitterMesh(): Nullable<Mesh> {
+            return this._emitterMesh;
+        }
+
+        /**
+         * Creates a new emitter mesh as a sphere
+         * @param options defines the options used to create the sphere
+         * @param renderingGroupId defines the renderingGroupId to use for the sphere
+         * @param scene defines the hosting scene
+         */
+        public setEmitterAsSphere(options: {diameter: number, segments: number, color: Color3} , renderingGroupId: number, scene: Scene) {
+            if (this._emitterMesh) {
+                this._emitterMesh.dispose();
+            }
+
+            this._emitterCreationOptions = {
+                kind: "Sphere",
+                options: options,
+                renderingGroupId: renderingGroupId
+            }
+
+            this._emitterMesh = MeshBuilder.CreateSphere("emitterSphere", {diameter: options.diameter, segments: options.segments}, scene);
+            this._emitterMesh.renderingGroupId = renderingGroupId;
+
+            var material = new BABYLON.StandardMaterial("emitterSphereMaterial", scene)
+            material.emissiveColor = options.color;    
+            this._emitterMesh.material = material;     
+            
+            for (var system of this.systems) {
+                system.emitter = this._emitterMesh;
+            }
+        }
+
+        /**
+         * Starts all particle systems of the set
+         * @param emitter defines an optional mesh to use as emitter for the particle systems
+         */
+        public start(emitter?: AbstractMesh): void {
+            for (var system of this.systems) {
+                if (emitter) {
+                    system.emitter = emitter;
+                }
+                system.start();
+            }
+        }
+
+        /**
+         * Release all associated resources
+         */
+        public dispose(): void {
+            for (var system of this.systems) {
+                system.dispose();
+            }
+
+            this.systems = [];
+
+            if (this._emitterMesh) {
+                this._emitterMesh.dispose();
+                this._emitterMesh = null;
+            }
+        }
+
+        /**
+         * Serialize the set into a JSON compatible object
+         * @returns a JSON compatible representation of the set
+         */
+        public serialize(): any {
+            var result:any = {};
+
+            result.systems = [];
+            for (var system of this.systems) {
+                result.systems.push(system.serialize());
+            }
+
+            if (this._emitterMesh) {
+                result.emitter = this._emitterCreationOptions;
+            }
+
+            return result;
+        }
+
+        /** 
+         * Parse a new ParticleSystemSet from a serialized source
+         * @param data defines a JSON compatible representation of the set
+         * @param scene defines the hosting scene
+         * @param gpu defines if we want GPU particles or CPU particles
+         * @returns a new ParticleSystemSet
+         */
+        public static Parse(data: any, scene: Scene, gpu = false): ParticleSystemSet {
+            var result = new ParticleSystemSet();
+            var rootUrl = ParticleHelper.BaseAssetsUrl + "/textures/";
+
+            for (var system of data.systems) {
+                result.systems.push(gpu ? GPUParticleSystem.Parse(system, scene, rootUrl) : ParticleSystem.Parse(system, scene, rootUrl));
+            }
+
+            if (data.emitter) {
+                let options = data.emitter.options;
+                switch (data.emitter.kind) {                    
+                    case "Sphere":
+                        result.setEmitterAsSphere({
+                            diameter: options.diameter, 
+                            segments: options.segments,
+                            color: Color3.FromArray(options.color)
+                        }, data.emitter.renderingGroupId, scene);
+                        break;
+                }
+            }
+
+            return result;
+        }
+    }
+}

+ 3 - 14
tests/unit/babylon/src/Helpers/babylon.particleHelper.tests.ts

@@ -33,15 +33,13 @@ describe('Babylon Particle Helper', function () {
 
   describe('#ParticleHelper.CreateAsync', () => {
       let scene: BABYLON.Scene;
-      let emitter: BABYLON.Mesh;
 
       beforeEach(() => {
         scene = new BABYLON.Scene(subject);
-        emitter = BABYLON.Mesh.CreateSphere("sphere", 10, 5, scene);
       });
 
-      it('creates a fire particle system', (done) => {
-        BABYLON.ParticleHelper.CreateAsync("fire", emitter, scene)
+      it('creates a sun particle system set', (done) => {
+        BABYLON.ParticleHelper.CreateAsync("fire", scene)
             .then((system) => {
                 expect(system).to.be.instanceof(BABYLON.ParticleSystem);
                 done();
@@ -49,17 +47,8 @@ describe('Babylon Particle Helper', function () {
             .catch((error) => { throw new Error("was not supposed to fail"); });
       });
 
-      it('creates a smoke particle system', (done) => {
-        BABYLON.ParticleHelper.CreateAsync("smoke", emitter, scene)
-            .then((system) => {
-                expect(system).to.be.instanceof(BABYLON.ParticleSystem);
-                done();
-            })
-            .catch((error) => { throw new Error("was not supposed to fail"); });
-    });
-
       it('rejects the creation of the particle system', (done) => {
-        BABYLON.ParticleHelper.CreateAsync("test", emitter, scene)
+        BABYLON.ParticleHelper.CreateAsync("test", scene)
             .then(() => { throw new Error("was not supposed to succeed"); })
             .catch((error) => {
                 expect(error).to.equals("An error occured while the creation of your particle system. Check if your type 'test' exists.");