Bladeren bron

Fix tiny issues with particle sub emitters

David Catuhe 7 jaren geleden
bovenliggende
commit
48bb8cdf15

File diff suppressed because it is too large
+ 14819 - 14738
dist/preview release/babylon.d.ts


File diff suppressed because it is too large
+ 41 - 41
dist/preview release/babylon.js


+ 285 - 56
dist/preview release/babylon.max.js

@@ -14894,7 +14894,7 @@ var BABYLON;
                 if (this._renderingCanvas) {
                     this._renderingCanvas.removeEventListener("focus", this._onCanvasFocus);
                     this._renderingCanvas.removeEventListener("blur", this._onCanvasBlur);
-                    this._renderingCanvas.removeEventListener("pointerout", this._onCanvasBlur);
+                    this._renderingCanvas.removeEventListener("pointerout", this._onCanvasPointerOut);
                     if (!this._doNotHandleContextLost) {
                         this._renderingCanvas.removeEventListener("webglcontextlost", this._onContextLost);
                         this._renderingCanvas.removeEventListener("webglcontextrestored", this._onContextRestored);
@@ -14930,6 +14930,7 @@ var BABYLON;
             this._currentBufferPointers = [];
             this._renderingCanvas = null;
             this._currentProgram = null;
+            this._bindedRenderFunction = null;
             this.onResizeObservable.clear();
             this.onCanvasBlurObservable.clear();
             this.onCanvasFocusObservable.clear();
@@ -18535,6 +18536,9 @@ var BABYLON;
             var _this = this;
             if (disposeMaterialAndTextures === void 0) { disposeMaterialAndTextures = false; }
             var index;
+            // Smart Array Retainers.
+            this.getScene().freeActiveMeshes();
+            this.getScene().freeRenderingGroups();
             // Action manager
             if (this.actionManager !== undefined && this.actionManager !== null) {
                 this.actionManager.dispose();
@@ -20809,13 +20813,19 @@ var BABYLON;
             }
         };
         RenderingManager.prototype.dispose = function () {
+            this.freeRenderingGroups();
+            this._renderingGroups.length = 0;
+        };
+        /**
+         * Clear the info related to rendering groups preventing retention points during dispose.
+         */
+        RenderingManager.prototype.freeRenderingGroups = function () {
             for (var index = RenderingManager.MIN_RENDERINGGROUPS; index < RenderingManager.MAX_RENDERINGGROUPS; index++) {
                 var renderingGroup = this._renderingGroups[index];
                 if (renderingGroup) {
                     renderingGroup.dispose();
                 }
             }
-            this._renderingGroups.length = 0;
         };
         RenderingManager.prototype._prepareRenderingGroup = function (renderingGroupId) {
             if (this._renderingGroups[renderingGroupId] === undefined) {
@@ -24009,6 +24019,45 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Clear the processed materials smart array preventing retention point in material dispose.
+         */
+        Scene.prototype.freeProcessedMaterials = function () {
+            this._processedMaterials.dispose();
+        };
+        /**
+         * Clear the active meshes smart array preventing retention point in mesh dispose.
+         */
+        Scene.prototype.freeActiveMeshes = function () {
+            this._activeMeshes.dispose();
+            if (this.activeCamera && this.activeCamera._activeMeshes) {
+                this.activeCamera._activeMeshes.dispose();
+            }
+            if (this.activeCameras) {
+                for (var i = 0; i < this.activeCameras.length; i++) {
+                    var activeCamera = this.activeCameras[i];
+                    if (activeCamera && activeCamera._activeMeshes) {
+                        activeCamera._activeMeshes.dispose();
+                    }
+                }
+            }
+        };
+        /**
+         * Clear the info related to rendering groups preventing retention points during dispose.
+         */
+        Scene.prototype.freeRenderingGroups = function () {
+            if (this._renderingManager) {
+                this._renderingManager.freeRenderingGroups();
+            }
+            if (this.textures) {
+                for (var i = 0; i < this.textures.length; i++) {
+                    var texture = this.textures[i];
+                    if (texture && texture.isRenderTarget) {
+                        texture.freeRenderingGroups();
+                    }
+                }
+            }
+        };
         Scene.prototype._isInIntermediateRendering = function () {
             return this._intermediateRendering;
         };
@@ -31810,6 +31859,7 @@ var BABYLON;
         Material.prototype.dispose = function (forceDisposeEffect, forceDisposeTextures) {
             // Animations
             this.getScene().stopAnimation(this);
+            this.getScene().freeProcessedMaterials();
             // Remove from scene
             var index = this._scene.materials.indexOf(this);
             if (index >= 0) {
@@ -50905,7 +50955,11 @@ var BABYLON;
          * Creates a new instance of @see Particle
          * @param particleSystem the particle system the particle belongs to
          */
-        function Particle(particleSystem) {
+        function Particle(
+            /**
+             * particleSystem the particle system the particle belongs to.
+             */
+            particleSystem) {
             this.particleSystem = particleSystem;
             /**
              * The world position of the particle in the scene.
@@ -50951,15 +51005,18 @@ var BABYLON;
             if (!this.particleSystem.isAnimationSheetEnabled) {
                 return;
             }
+            this.updateCellInfoFromSystem();
+        }
+        Particle.prototype.updateCellInfoFromSystem = function () {
             this.cellIndex = this.particleSystem.startSpriteCellID;
             if (this.particleSystem.spriteCellChangeSpeed == 0) {
-                this.updateCellIndex = this.updateCellIndexWithSpeedCalculated;
+                this.updateCellIndex = this._updateCellIndexWithSpeedCalculated;
             }
             else {
-                this.updateCellIndex = this.updateCellIndexWithCustomSpeed;
+                this.updateCellIndex = this._updateCellIndexWithCustomSpeed;
             }
-        }
-        Particle.prototype.updateCellIndexWithSpeedCalculated = function (scaledUpdateSpeed) {
+        };
+        Particle.prototype._updateCellIndexWithSpeedCalculated = function (scaledUpdateSpeed) {
             //   (ageOffset / scaledUpdateSpeed) / available cells
             var numberOfScaledUpdatesPerCell = ((this.lifeTime - this.age) / scaledUpdateSpeed) / (this.particleSystem.endSpriteCellID + 1 - this.cellIndex);
             this._currentFrameCounter += scaledUpdateSpeed;
@@ -50971,7 +51028,7 @@ var BABYLON;
                 }
             }
         };
-        Particle.prototype.updateCellIndexWithCustomSpeed = function () {
+        Particle.prototype._updateCellIndexWithCustomSpeed = function () {
             if (this._currentFrameCounter >= this.particleSystem.spriteCellChangeSpeed) {
                 this.cellIndex++;
                 this._currentFrameCounter = 0;
@@ -51188,6 +51245,55 @@ var BABYLON;
             this._stopped = false;
             this._actualFrame = 0;
             this._vertexBufferSize = 11;
+            this._isEmitting = false;
+            // start of sub system methods
+            /**
+             * "Recycles" one of the particle by copying it back to the "stock" of particles and removing it from the active list.
+             * Its lifetime will start back at 0.
+             */
+            this.recycleParticle = function (particle) {
+                var lastParticle = _this._particles.pop();
+                if (lastParticle !== particle) {
+                    lastParticle.copyTo(particle);
+                }
+                _this._stockParticles.push(lastParticle);
+            };
+            this._createParticle = function () {
+                var particle;
+                if (_this._stockParticles.length !== 0) {
+                    particle = _this._stockParticles.pop();
+                    particle.age = 0;
+                    particle.cellIndex = _this.startSpriteCellID;
+                }
+                else {
+                    particle = new BABYLON.Particle(_this);
+                }
+                return particle;
+            };
+            // to be overriden by subSystems
+            this._stoppedEmitting = function () {
+                if (!_this._rootParticleSystem) {
+                    return;
+                }
+                if (!_this.subEmitters || _this.subEmitters.length === 0) {
+                    _this._scene._toBeDisposed.push(_this);
+                    return;
+                }
+                var index = _this._rootParticleSystem.activeSubSystems.indexOf(_this, 0);
+                if (index > -1) {
+                    _this._rootParticleSystem.activeSubSystems.splice(index, 1);
+                    _this._scene._toBeDisposed.push(_this);
+                }
+            };
+            this._emitFromParticle = function (particle) {
+                if (!_this.subEmitters || _this.subEmitters.length === 0) {
+                    return;
+                }
+                var templateIndex = Math.floor(Math.random() * _this.subEmitters.length);
+                var subSystem = _this.subEmitters[templateIndex]._cloneToSubSystem(_this, particle.position.clone());
+                _this.activeSubSystems.push(subSystem);
+                subSystem.start();
+            };
             this._appendParticleVertexes = null;
             this.id = name;
             this.name = name;
@@ -51221,6 +51327,7 @@ var BABYLON;
                     var particle = particles[index];
                     particle.age += _this._scaledUpdateSpeed;
                     if (particle.age >= particle.lifeTime) {
+                        _this._emitFromParticle(particle);
                         _this.recycleParticle(particle);
                         index--;
                         continue;
@@ -51342,6 +51449,7 @@ var BABYLON;
             configurable: true
         });
         Object.defineProperty(ParticleSystem.prototype, "particles", {
+            //end of Sub-emitter
             /**
              * Gets the current list of active particles
              */
@@ -51373,18 +51481,6 @@ var BABYLON;
             this._indexBuffer = this._scene.getEngine().createIndexBuffer(indices);
         };
         /**
-         * "Recycles" one of the particle by copying it back to the "stock" of particles and removing it from the active list.
-         * Its lifetime will start back at 0.
-         * @param particle The particle to recycle
-         */
-        ParticleSystem.prototype.recycleParticle = function (particle) {
-            var lastParticle = this._particles.pop();
-            if (lastParticle !== particle) {
-                lastParticle.copyTo(particle);
-                this._stockParticles.push(lastParticle);
-            }
-        };
-        /**
          * Gets the maximum number of particles active at the same time.
          * @returns The max number of active particles.
          */
@@ -51412,13 +51508,22 @@ var BABYLON;
             this._started = true;
             this._stopped = false;
             this._actualFrame = 0;
+            if (this.subEmitters && this.subEmitters.length != 0) {
+                this.activeSubSystems = new Array();
+            }
         };
         /**
          * Stops the particle system.
+         * @param stopSubEmitters if true it will stop the current system and all created sub-Systems if false it will stop the current root system only, this param is used by the root particle system only. the default value is true.
          */
-        ParticleSystem.prototype.stop = function () {
+        ParticleSystem.prototype.stop = function (stopSubEmitters) {
+            if (stopSubEmitters === void 0) { stopSubEmitters = true; }
             this._stopped = true;
+            if (stopSubEmitters) {
+                this._stopSubEmitters();
+            }
         };
+        // animation sheet
         /**
          * Remove all active particles
          */
@@ -51469,9 +51574,24 @@ var BABYLON;
             this._vertexData[offset + 10] = offsetY;
             this._vertexData[offset + 11] = particle.cellIndex;
         };
+        ParticleSystem.prototype._stopSubEmitters = function () {
+            this.activeSubSystems.forEach(function (subSystem) {
+                subSystem.stop(true);
+                subSystem._stoppedEmitting();
+            });
+            this.activeSubSystems = new Array();
+        };
+        // end of sub system methods
         ParticleSystem.prototype._update = function (newParticles) {
             // Update current
             this._alive = this._particles.length > 0;
+            if (this._alive) {
+                this._isEmitting = true;
+            }
+            if (!this._alive && this._isEmitting) {
+                this._isEmitting = false;
+                this._stoppedEmitting();
+            }
             this.updateFunction(this._particles);
             // Add new ones
             var worldMatrix;
@@ -51488,14 +51608,7 @@ var BABYLON;
                 if (this._particles.length === this._capacity) {
                     break;
                 }
-                if (this._stockParticles.length !== 0) {
-                    particle = this._stockParticles.pop();
-                    particle.age = 0;
-                    particle.cellIndex = this.startSpriteCellID;
-                }
-                else {
-                    particle = new BABYLON.Particle(this);
-                }
+                particle = this._createParticle();
                 this._particles.push(particle);
                 var emitPower = BABYLON.Scalar.RandomRange(this.minEmitPower, this.maxEmitPower);
                 if (this.startPositionFunction) {
@@ -51770,6 +51883,29 @@ var BABYLON;
             this.particleEmitterType = particleEmitter;
             return particleEmitter;
         };
+        ParticleSystem.prototype._cloneToSubSystem = function (root, newEmitter) {
+            var custom = null;
+            var program = null;
+            if (this.customShader != null) {
+                program = this.customShader;
+                var defines = (program.shaderOptions.defines.length > 0) ? program.shaderOptions.defines.join("\n") : "";
+                custom = this._scene.getEngine().createEffectForParticles(program.shaderPath.fragmentElement, program.shaderOptions.uniforms, program.shaderOptions.samplers, defines);
+            }
+            var result = new ParticleSystem(name, this._capacity, this._scene, custom);
+            result.customShader = program;
+            BABYLON.Tools.DeepCopy(this, result, ["customShader"]);
+            result.name = name + "_Child";
+            result.id = result.name;
+            result.emitter = newEmitter;
+            result.subEmitters = this.subEmitters;
+            result.particleEmitterType = this.particleEmitterType;
+            result._rootParticleSystem = root;
+            if (this.particleTexture) {
+                result.particleTexture = new BABYLON.Texture(this.particleTexture.url, this._scene);
+            }
+            return result;
+        };
+        // Clone
         /**
          * Clones the particle system.
          * @param name The name of the cloned object
@@ -59002,6 +59138,14 @@ var BABYLON;
                 this._postProcessManager._rebuild();
             }
         };
+        /**
+         * Clear the info related to rendering groups preventing retention point in material dispose.
+         */
+        RenderTargetTexture.prototype.freeRenderingGroups = function () {
+            if (this._renderingManager) {
+                this._renderingManager.freeRenderingGroups();
+            }
+        };
         RenderTargetTexture._REFRESHRATE_RENDER_ONCE = 0;
         RenderTargetTexture._REFRESHRATE_RENDER_ONEVERYFRAME = 1;
         RenderTargetTexture._REFRESHRATE_RENDER_ONEVERYTWOFRAMES = 2;
@@ -60342,10 +60486,11 @@ var BABYLON;
 (function (BABYLON) {
     var PassPostProcess = /** @class */ (function (_super) {
         __extends(PassPostProcess, _super);
-        function PassPostProcess(name, options, camera, samplingMode, engine, reusable, textureType) {
+        function PassPostProcess(name, options, camera, samplingMode, engine, reusable, textureType, blockCompilation) {
             if (camera === void 0) { camera = null; }
             if (textureType === void 0) { textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; }
-            return _super.call(this, name, "pass", null, null, options, camera, samplingMode, engine, reusable, undefined, textureType) || this;
+            if (blockCompilation === void 0) { blockCompilation = false; }
+            return _super.call(this, name, "pass", null, null, options, camera, samplingMode, engine, reusable, undefined, textureType, undefined, null, blockCompilation) || this;
         }
         return PassPostProcess;
     }(BABYLON.PostProcess));
@@ -68974,10 +69119,12 @@ var BABYLON;
          * @param engine The engine which the post process will be applied. (default: current engine)
          * @param reusable If the post process can be reused on the same frame. (default: false)
          * @param textureType Type of textures used when performing the post process. (default: 0)
+         * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
          */
-        function ChromaticAberrationPostProcess(name, screenWidth, screenHeight, options, camera, samplingMode, engine, reusable, textureType) {
+        function ChromaticAberrationPostProcess(name, screenWidth, screenHeight, options, camera, samplingMode, engine, reusable, textureType, blockCompilation) {
             if (textureType === void 0) { textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; }
-            var _this = _super.call(this, name, "chromaticAberration", ["chromatic_aberration", "screen_width", "screen_height", "direction", "radialIntensity", "centerPosition"], [], options, camera, samplingMode, engine, reusable, null, textureType) || this;
+            if (blockCompilation === void 0) { blockCompilation = false; }
+            var _this = _super.call(this, name, "chromaticAberration", ["chromatic_aberration", "screen_width", "screen_height", "direction", "radialIntensity", "centerPosition"], [], options, camera, samplingMode, engine, reusable, null, textureType, undefined, null, blockCompilation) || this;
             /**
              * The amount of seperation of rgb channels (default: 0)
              */
@@ -69029,10 +69176,12 @@ var BABYLON;
          * @param engine The engine which the post process will be applied. (default: current engine)
          * @param reusable If the post process can be reused on the same frame. (default: false)
          * @param textureType Type of textures used when performing the post process. (default: 0)
+         * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
          */
-        function SharpenPostProcess(name, options, camera, samplingMode, engine, reusable, textureType) {
+        function SharpenPostProcess(name, options, camera, samplingMode, engine, reusable, textureType, blockCompilation) {
             if (textureType === void 0) { textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; }
-            var _this = _super.call(this, name, "sharpen", ["sharpnessAmounts", "screenSize"], null, options, camera, samplingMode, engine, reusable, null, textureType) || this;
+            if (blockCompilation === void 0) { blockCompilation = false; }
+            var _this = _super.call(this, name, "sharpen", ["sharpnessAmounts", "screenSize"], null, options, camera, samplingMode, engine, reusable, null, textureType, undefined, null, blockCompilation) || this;
             /**
              * How much of the original color should be applied. Setting this to 0 will display edge detection. (default: 1)
              */
@@ -69074,13 +69223,16 @@ var BABYLON;
          * @param engine The engine which the post process will be applied. (default: current engine)
          * @param reusable If the post process can be reused on the same frame. (default: false)
          * @param textureType Type of textures used when performing the post process. (default: 0)
+         * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
          */
-        function BlurPostProcess(name, /** The direction in which to blur the image. */ direction, kernel, options, camera, samplingMode, engine, reusable, textureType, defines) {
+        function BlurPostProcess(name, /** The direction in which to blur the image. */ direction, kernel, options, camera, samplingMode, engine, reusable, textureType, defines, blockCompilation) {
             if (samplingMode === void 0) { samplingMode = BABYLON.Texture.BILINEAR_SAMPLINGMODE; }
             if (textureType === void 0) { textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; }
             if (defines === void 0) { defines = ""; }
+            if (blockCompilation === void 0) { blockCompilation = false; }
             var _this = _super.call(this, name, "kernelBlur", ["delta", "direction", "cameraMinMaxZ"], ["circleOfConfusionSampler"], options, camera, samplingMode, engine, reusable, null, textureType, "kernelBlur", { varyingCount: 0, depCount: 0 }, true) || this;
             _this.direction = direction;
+            _this.blockCompilation = blockCompilation;
             _this._packedFloat = false;
             _this._staticDefines = "";
             _this._staticDefines = defines;
@@ -69107,7 +69259,9 @@ var BABYLON;
                 v = Math.max(v, 1);
                 this._idealKernel = v;
                 this._kernel = this._nearestBestKernel(v);
-                this._updateParameters();
+                if (!this.blockCompilation) {
+                    this._updateParameters();
+                }
             },
             enumerable: true,
             configurable: true
@@ -69127,12 +69281,29 @@ var BABYLON;
                     return;
                 }
                 this._packedFloat = v;
-                this._updateParameters();
+                if (!this.blockCompilation) {
+                    this._updateParameters();
+                }
             },
             enumerable: true,
             configurable: true
         });
-        BlurPostProcess.prototype._updateParameters = function () {
+        /**
+         * Updates the effect with the current post process compile time values and recompiles the shader.
+         * @param defines Define statements that should be added at the beginning of the shader. (default: null)
+         * @param uniforms Set of uniform variables that will be passed to the shader. (default: null)
+         * @param samplers Set of Texture2D variables that will be passed to the shader. (default: null)
+         * @param indexParameters The index parameters to be used for babylons include syntax "#include<kernelBlurVaryingDeclaration>[0..varyingCount]". (default: undefined) See usage in babylon.blurPostProcess.ts and kernelBlur.vertex.fx
+         * @param onCompiled Called when the shader has been compiled.
+         * @param onError Called if there is an error when compiling a shader.
+         */
+        BlurPostProcess.prototype.updateEffect = function (defines, uniforms, samplers, indexParameters, onCompiled, onError) {
+            if (defines === void 0) { defines = null; }
+            if (uniforms === void 0) { uniforms = null; }
+            if (samplers === void 0) { samplers = null; }
+            this._updateParameters(onCompiled, onError);
+        };
+        BlurPostProcess.prototype._updateParameters = function (onCompiled, onError) {
             // Generate sampling offsets and weights
             var N = this._kernel;
             var centerIndex = (N - 1) / 2;
@@ -69202,10 +69373,10 @@ var BABYLON;
             if (this.packedFloat) {
                 defines += "#define PACKEDFLOAT 1";
             }
-            this.updateEffect(defines, null, null, {
+            _super.prototype.updateEffect.call(this, defines, null, null, {
                 varyingCount: varyingCount,
                 depCount: depCount
-            });
+            }, onCompiled, onError);
         };
         /**
          * Best kernels are odd numbers that when divided by 2, their integer part is even, so 5, 9 or 13.
@@ -69286,12 +69457,14 @@ var BABYLON;
          * @param engine The engine which the post process will be applied. (default: current engine)
          * @param reusable If the post process can be reused on the same frame. (default: false)
          * @param textureType Type of textures used when performing the post process. (default: 0)
+         * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
          */
-        function DepthOfFieldBlurPostProcess(name, scene, direction, kernel, options, camera, circleOfConfusion, imageToBlur, samplingMode, engine, reusable, textureType) {
+        function DepthOfFieldBlurPostProcess(name, scene, direction, kernel, options, camera, circleOfConfusion, imageToBlur, samplingMode, engine, reusable, textureType, blockCompilation) {
             if (imageToBlur === void 0) { imageToBlur = null; }
             if (samplingMode === void 0) { samplingMode = BABYLON.Texture.BILINEAR_SAMPLINGMODE; }
             if (textureType === void 0) { textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; }
-            var _this = _super.call(this, name, direction, kernel, options, camera, samplingMode = BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, reusable, textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT, "#define DOF 1\r\n") || this;
+            if (blockCompilation === void 0) { blockCompilation = false; }
+            var _this = _super.call(this, name, direction, kernel, options, camera, samplingMode = BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, reusable, textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT, "#define DOF 1\r\n", blockCompilation) || this;
             _this.direction = direction;
             _this.onApplyObservable.add(function (effect) {
                 if (imageToBlur != null) {
@@ -69331,10 +69504,13 @@ var BABYLON;
          * @param engine The engine which the post process will be applied. (default: current engine)
          * @param reusable If the post process can be reused on the same frame. (default: false)
          * @param textureType Type of textures used when performing the post process. (default: 0)
+         * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
          */
-        function DepthOfFieldMergePostProcess(name, original, circleOfConfusion, blurSteps, options, camera, samplingMode, engine, reusable, textureType) {
+        function DepthOfFieldMergePostProcess(name, original, circleOfConfusion, blurSteps, options, camera, samplingMode, engine, reusable, textureType, blockCompilation) {
             if (textureType === void 0) { textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; }
-            var _this = _super.call(this, name, "depthOfFieldMerge", [], ["circleOfConfusionSampler", "originalSampler", "blurStep1", "blurStep2"], options, camera, samplingMode, engine, reusable, "#define BLUR_LEVEL " + blurSteps.length + "\n", textureType) || this;
+            if (blockCompilation === void 0) { blockCompilation = false; }
+            var _this = _super.call(this, name, "depthOfFieldMerge", [], ["circleOfConfusionSampler", "originalSampler", "blurStep1", "blurStep2"], options, camera, samplingMode, engine, reusable, null, textureType, undefined, null, true) || this;
+            _this.blurSteps = blurSteps;
             _this.onApplyObservable.add(function (effect) {
                 effect.setTextureFromPostProcess("circleOfConfusionSampler", circleOfConfusion);
                 effect.setTextureFromPostProcess("originalSampler", original);
@@ -69342,8 +69518,26 @@ var BABYLON;
                     effect.setTextureFromPostProcess("blurStep" + (index + 1), step);
                 });
             });
+            if (!blockCompilation) {
+                _this.updateEffect();
+            }
             return _this;
         }
+        /**
+         * Updates the effect with the current post process compile time values and recompiles the shader.
+         * @param defines Define statements that should be added at the beginning of the shader. (default: null)
+         * @param uniforms Set of uniform variables that will be passed to the shader. (default: null)
+         * @param samplers Set of Texture2D variables that will be passed to the shader. (default: null)
+         * @param indexParameters The index parameters to be used for babylons include syntax "#include<kernelBlurVaryingDeclaration>[0..varyingCount]". (default: undefined) See usage in babylon.blurPostProcess.ts and kernelBlur.vertex.fx
+         * @param onCompiled Called when the shader has been compiled.
+         * @param onError Called if there is an error when compiling a shader.
+         */
+        DepthOfFieldMergePostProcess.prototype.updateEffect = function (defines, uniforms, samplers, indexParameters, onCompiled, onError) {
+            if (defines === void 0) { defines = null; }
+            if (uniforms === void 0) { uniforms = null; }
+            if (samplers === void 0) { samplers = null; }
+            _super.prototype.updateEffect.call(this, defines ? defines : "#define BLUR_LEVEL " + this.blurSteps.length + "\n", uniforms, samplers, indexParameters, onCompiled, onError);
+        };
         return DepthOfFieldMergePostProcess;
     }(BABYLON.PostProcess));
     BABYLON.DepthOfFieldMergePostProcess = DepthOfFieldMergePostProcess;
@@ -69369,10 +69563,12 @@ var BABYLON;
          * @param engine The engine which the post process will be applied. (default: current engine)
          * @param reusable If the post process can be reused on the same frame. (default: false)
          * @param textureType Type of textures used when performing the post process. (default: 0)
+         * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
          */
-        function CircleOfConfusionPostProcess(name, depthTexture, options, camera, samplingMode, engine, reusable, textureType) {
+        function CircleOfConfusionPostProcess(name, depthTexture, options, camera, samplingMode, engine, reusable, textureType, blockCompilation) {
             if (textureType === void 0) { textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; }
-            var _this = _super.call(this, name, "circleOfConfusion", ["cameraMinMaxZ", "focusDistance", "cocPrecalculation"], ["depthSampler"], options, camera, samplingMode, engine, reusable, null, textureType) || this;
+            if (blockCompilation === void 0) { blockCompilation = false; }
+            var _this = _super.call(this, name, "circleOfConfusion", ["cameraMinMaxZ", "focusDistance", "cocPrecalculation"], ["depthSampler"], options, camera, samplingMode, engine, reusable, null, textureType, undefined, null, blockCompilation) || this;
             /**
              * Max lens size in scene units/1000 (eg. millimeter). Standard cameras are 50mm. (default: 50) The diamater of the resulting aperture can be computed by lensSize/fStop.
              */
@@ -69455,18 +69651,20 @@ var BABYLON;
          * @param scene The scene the effect belongs to.
          * @param depthTexture The depth texture of the scene to compute the circle of confusion.This must be set in order for this to function but may be set after initialization if needed.
          * @param pipelineTextureType The type of texture to be used when performing the post processing.
+         * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
          */
-        function DepthOfFieldEffect(scene, depthTexture, blurLevel, pipelineTextureType) {
+        function DepthOfFieldEffect(scene, depthTexture, blurLevel, pipelineTextureType, blockCompilation) {
             if (blurLevel === void 0) { blurLevel = DepthOfFieldEffectBlurLevel.Low; }
             if (pipelineTextureType === void 0) { pipelineTextureType = 0; }
+            if (blockCompilation === void 0) { blockCompilation = false; }
             var _this = _super.call(this, scene.getEngine(), "depth of field", function () {
                 return _this._effects;
             }, true) || this;
             _this._effects = [];
             // Circle of confusion value for each pixel is used to determine how much to blur that pixel
-            _this._circleOfConfusion = new BABYLON.CircleOfConfusionPostProcess("circleOfConfusion", depthTexture, 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType);
+            _this._circleOfConfusion = new BABYLON.CircleOfConfusionPostProcess("circleOfConfusion", depthTexture, 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
             // Capture circle of confusion texture
-            _this._depthOfFieldPass = new BABYLON.PassPostProcess("depthOfFieldPass", 1.0, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType);
+            _this._depthOfFieldPass = new BABYLON.PassPostProcess("depthOfFieldPass", 1.0, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
             _this._depthOfFieldPass.autoClear = false;
             // Create a pyramid of blurred images (eg. fullSize 1/4 blur, half size 1/2 blur, quarter size 3/4 blur, eith size 4/4 blur)
             // Blur the image but do not blur on sharp far to near distance changes to avoid bleeding artifacts 
@@ -69494,15 +69692,15 @@ var BABYLON;
             }
             var adjustedKernelSize = kernelSize / Math.pow(2, blurCount - 1);
             for (var i = 0; i < blurCount; i++) {
-                var blurY = new BABYLON.DepthOfFieldBlurPostProcess("verticle blur", scene, new BABYLON.Vector2(0, 1.0), adjustedKernelSize, 1.0 / Math.pow(2, i), null, _this._depthOfFieldPass, i == 0 ? _this._circleOfConfusion : null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType);
+                var blurY = new BABYLON.DepthOfFieldBlurPostProcess("verticle blur", scene, new BABYLON.Vector2(0, 1.0), adjustedKernelSize, 1.0 / Math.pow(2, i), null, _this._depthOfFieldPass, i == 0 ? _this._circleOfConfusion : null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
                 blurY.autoClear = false;
-                var blurX = new BABYLON.DepthOfFieldBlurPostProcess("horizontal blur", scene, new BABYLON.Vector2(1.0, 0), adjustedKernelSize, 1.0 / Math.pow(2, i), null, _this._depthOfFieldPass, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType);
+                var blurX = new BABYLON.DepthOfFieldBlurPostProcess("horizontal blur", scene, new BABYLON.Vector2(1.0, 0), adjustedKernelSize, 1.0 / Math.pow(2, i), null, _this._depthOfFieldPass, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
                 blurX.autoClear = false;
                 _this._depthOfFieldBlurY.push(blurY);
                 _this._depthOfFieldBlurX.push(blurX);
             }
             // Merge blurred images with original image based on circleOfConfusion
-            _this._depthOfFieldMerge = new BABYLON.DepthOfFieldMergePostProcess("depthOfFieldMerge", _this._circleOfConfusion, _this._depthOfFieldPass, _this._depthOfFieldBlurY.slice(1), 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType);
+            _this._depthOfFieldMerge = new BABYLON.DepthOfFieldMergePostProcess("depthOfFieldMerge", _this._circleOfConfusion, _this._depthOfFieldPass, _this._depthOfFieldBlurY.slice(1), 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
             _this._depthOfFieldMerge.autoClear = false;
             // Set all post processes on the effect.
             _this._effects = [_this._circleOfConfusion, _this._depthOfFieldPass];
@@ -69590,6 +69788,26 @@ var BABYLON;
             });
             this._depthOfFieldMerge.dispose(camera);
         };
+        /**
+         * Internal
+         */
+        DepthOfFieldEffect.prototype._updateEffects = function () {
+            for (var effect in this._effects) {
+                this._effects[effect].updateEffect();
+            }
+        };
+        /**
+         * Internal
+         * @returns if all the contained post processes are ready.
+         */
+        DepthOfFieldEffect.prototype._isReady = function () {
+            for (var effect in this._effects) {
+                if (!this._effects[effect].isReady()) {
+                    return false;
+                }
+            }
+            return true;
+        };
         return DepthOfFieldEffect;
     }(BABYLON.PostProcessRenderEffect));
     BABYLON.DepthOfFieldEffect = DepthOfFieldEffect;
@@ -69710,10 +69928,12 @@ var BABYLON;
             // Attach
             scene.postProcessRenderPipelineManager.addPipeline(_this);
             var engine = _this._scene.getEngine();
-            _this.sharpen = new BABYLON.SharpenPostProcess("sharpen", 1.0, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, false, _this._defaultPipelineTextureType);
+            // Create post processes before hand so they can be modified before enabled.
+            // Block compilation flag is set to true to avoid compilation prior to use, these will be updated on first use in build pipeline.
+            _this.sharpen = new BABYLON.SharpenPostProcess("sharpen", 1.0, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, false, _this._defaultPipelineTextureType, true);
             _this._sharpenEffect = new BABYLON.PostProcessRenderEffect(engine, _this.SharpenPostProcessId, function () { return _this.sharpen; }, true);
-            _this.depthOfField = new BABYLON.DepthOfFieldEffect(_this._scene, null, _this._depthOfFieldBlurLevel, _this._defaultPipelineTextureType);
-            _this.chromaticAberration = new BABYLON.ChromaticAberrationPostProcess("ChromaticAberration", engine.getRenderWidth(), engine.getRenderHeight(), 1.0, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, false, _this._defaultPipelineTextureType);
+            _this.depthOfField = new BABYLON.DepthOfFieldEffect(_this._scene, null, _this._depthOfFieldBlurLevel, _this._defaultPipelineTextureType, true);
+            _this.chromaticAberration = new BABYLON.ChromaticAberrationPostProcess("ChromaticAberration", engine.getRenderWidth(), engine.getRenderHeight(), 1.0, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, false, _this._defaultPipelineTextureType, true);
             _this._chromaticAberrationEffect = new BABYLON.PostProcessRenderEffect(engine, _this.ChromaticAberrationPostProcessId, function () { return _this.chromaticAberration; }, true);
             _this._buildPipeline();
             return _this;
@@ -69946,12 +70166,18 @@ var BABYLON;
             this._prevPostProcess = null;
             this._prevPrevPostProcess = null;
             if (this.sharpenEnabled) {
+                if (!this.sharpen.isReady()) {
+                    this.sharpen.updateEffect();
+                }
                 this.addEffect(this._sharpenEffect);
                 this._setAutoClearAndTextureSharing(this.sharpen);
             }
             if (this.depthOfFieldEnabled) {
                 var depthTexture = this._scene.enableDepthRenderer(this._cameras[0]).getDepthMap();
                 this.depthOfField.depthTexture = depthTexture;
+                if (!this.depthOfField._isReady()) {
+                    this.depthOfField._updateEffects();
+                }
                 this.addEffect(this.depthOfField);
                 this._setAutoClearAndTextureSharing(this.depthOfField._depthOfFieldMerge);
             }
@@ -70033,6 +70259,9 @@ var BABYLON;
                 this._setAutoClearAndTextureSharing(this.fxaa);
             }
             if (this.chromaticAberrationEnabled) {
+                if (!this.chromaticAberration.isReady()) {
+                    this.chromaticAberration.updateEffect();
+                }
                 this.addEffect(this._chromaticAberrationEffect);
                 this._setAutoClearAndTextureSharing(this.chromaticAberration);
             }

File diff suppressed because it is too large
+ 41 - 41
dist/preview release/babylon.worker.js


+ 285 - 56
dist/preview release/es6.js

@@ -14867,7 +14867,7 @@ var BABYLON;
                 if (this._renderingCanvas) {
                     this._renderingCanvas.removeEventListener("focus", this._onCanvasFocus);
                     this._renderingCanvas.removeEventListener("blur", this._onCanvasBlur);
-                    this._renderingCanvas.removeEventListener("pointerout", this._onCanvasBlur);
+                    this._renderingCanvas.removeEventListener("pointerout", this._onCanvasPointerOut);
                     if (!this._doNotHandleContextLost) {
                         this._renderingCanvas.removeEventListener("webglcontextlost", this._onContextLost);
                         this._renderingCanvas.removeEventListener("webglcontextrestored", this._onContextRestored);
@@ -14903,6 +14903,7 @@ var BABYLON;
             this._currentBufferPointers = [];
             this._renderingCanvas = null;
             this._currentProgram = null;
+            this._bindedRenderFunction = null;
             this.onResizeObservable.clear();
             this.onCanvasBlurObservable.clear();
             this.onCanvasFocusObservable.clear();
@@ -18508,6 +18509,9 @@ var BABYLON;
             var _this = this;
             if (disposeMaterialAndTextures === void 0) { disposeMaterialAndTextures = false; }
             var index;
+            // Smart Array Retainers.
+            this.getScene().freeActiveMeshes();
+            this.getScene().freeRenderingGroups();
             // Action manager
             if (this.actionManager !== undefined && this.actionManager !== null) {
                 this.actionManager.dispose();
@@ -20782,13 +20786,19 @@ var BABYLON;
             }
         };
         RenderingManager.prototype.dispose = function () {
+            this.freeRenderingGroups();
+            this._renderingGroups.length = 0;
+        };
+        /**
+         * Clear the info related to rendering groups preventing retention points during dispose.
+         */
+        RenderingManager.prototype.freeRenderingGroups = function () {
             for (var index = RenderingManager.MIN_RENDERINGGROUPS; index < RenderingManager.MAX_RENDERINGGROUPS; index++) {
                 var renderingGroup = this._renderingGroups[index];
                 if (renderingGroup) {
                     renderingGroup.dispose();
                 }
             }
-            this._renderingGroups.length = 0;
         };
         RenderingManager.prototype._prepareRenderingGroup = function (renderingGroupId) {
             if (this._renderingGroups[renderingGroupId] === undefined) {
@@ -23982,6 +23992,45 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Clear the processed materials smart array preventing retention point in material dispose.
+         */
+        Scene.prototype.freeProcessedMaterials = function () {
+            this._processedMaterials.dispose();
+        };
+        /**
+         * Clear the active meshes smart array preventing retention point in mesh dispose.
+         */
+        Scene.prototype.freeActiveMeshes = function () {
+            this._activeMeshes.dispose();
+            if (this.activeCamera && this.activeCamera._activeMeshes) {
+                this.activeCamera._activeMeshes.dispose();
+            }
+            if (this.activeCameras) {
+                for (var i = 0; i < this.activeCameras.length; i++) {
+                    var activeCamera = this.activeCameras[i];
+                    if (activeCamera && activeCamera._activeMeshes) {
+                        activeCamera._activeMeshes.dispose();
+                    }
+                }
+            }
+        };
+        /**
+         * Clear the info related to rendering groups preventing retention points during dispose.
+         */
+        Scene.prototype.freeRenderingGroups = function () {
+            if (this._renderingManager) {
+                this._renderingManager.freeRenderingGroups();
+            }
+            if (this.textures) {
+                for (var i = 0; i < this.textures.length; i++) {
+                    var texture = this.textures[i];
+                    if (texture && texture.isRenderTarget) {
+                        texture.freeRenderingGroups();
+                    }
+                }
+            }
+        };
         Scene.prototype._isInIntermediateRendering = function () {
             return this._intermediateRendering;
         };
@@ -31783,6 +31832,7 @@ var BABYLON;
         Material.prototype.dispose = function (forceDisposeEffect, forceDisposeTextures) {
             // Animations
             this.getScene().stopAnimation(this);
+            this.getScene().freeProcessedMaterials();
             // Remove from scene
             var index = this._scene.materials.indexOf(this);
             if (index >= 0) {
@@ -50878,7 +50928,11 @@ var BABYLON;
          * Creates a new instance of @see Particle
          * @param particleSystem the particle system the particle belongs to
          */
-        function Particle(particleSystem) {
+        function Particle(
+            /**
+             * particleSystem the particle system the particle belongs to.
+             */
+            particleSystem) {
             this.particleSystem = particleSystem;
             /**
              * The world position of the particle in the scene.
@@ -50924,15 +50978,18 @@ var BABYLON;
             if (!this.particleSystem.isAnimationSheetEnabled) {
                 return;
             }
+            this.updateCellInfoFromSystem();
+        }
+        Particle.prototype.updateCellInfoFromSystem = function () {
             this.cellIndex = this.particleSystem.startSpriteCellID;
             if (this.particleSystem.spriteCellChangeSpeed == 0) {
-                this.updateCellIndex = this.updateCellIndexWithSpeedCalculated;
+                this.updateCellIndex = this._updateCellIndexWithSpeedCalculated;
             }
             else {
-                this.updateCellIndex = this.updateCellIndexWithCustomSpeed;
+                this.updateCellIndex = this._updateCellIndexWithCustomSpeed;
             }
-        }
-        Particle.prototype.updateCellIndexWithSpeedCalculated = function (scaledUpdateSpeed) {
+        };
+        Particle.prototype._updateCellIndexWithSpeedCalculated = function (scaledUpdateSpeed) {
             //   (ageOffset / scaledUpdateSpeed) / available cells
             var numberOfScaledUpdatesPerCell = ((this.lifeTime - this.age) / scaledUpdateSpeed) / (this.particleSystem.endSpriteCellID + 1 - this.cellIndex);
             this._currentFrameCounter += scaledUpdateSpeed;
@@ -50944,7 +51001,7 @@ var BABYLON;
                 }
             }
         };
-        Particle.prototype.updateCellIndexWithCustomSpeed = function () {
+        Particle.prototype._updateCellIndexWithCustomSpeed = function () {
             if (this._currentFrameCounter >= this.particleSystem.spriteCellChangeSpeed) {
                 this.cellIndex++;
                 this._currentFrameCounter = 0;
@@ -51161,6 +51218,55 @@ var BABYLON;
             this._stopped = false;
             this._actualFrame = 0;
             this._vertexBufferSize = 11;
+            this._isEmitting = false;
+            // start of sub system methods
+            /**
+             * "Recycles" one of the particle by copying it back to the "stock" of particles and removing it from the active list.
+             * Its lifetime will start back at 0.
+             */
+            this.recycleParticle = function (particle) {
+                var lastParticle = _this._particles.pop();
+                if (lastParticle !== particle) {
+                    lastParticle.copyTo(particle);
+                }
+                _this._stockParticles.push(lastParticle);
+            };
+            this._createParticle = function () {
+                var particle;
+                if (_this._stockParticles.length !== 0) {
+                    particle = _this._stockParticles.pop();
+                    particle.age = 0;
+                    particle.cellIndex = _this.startSpriteCellID;
+                }
+                else {
+                    particle = new BABYLON.Particle(_this);
+                }
+                return particle;
+            };
+            // to be overriden by subSystems
+            this._stoppedEmitting = function () {
+                if (!_this._rootParticleSystem) {
+                    return;
+                }
+                if (!_this.subEmitters || _this.subEmitters.length === 0) {
+                    _this._scene._toBeDisposed.push(_this);
+                    return;
+                }
+                var index = _this._rootParticleSystem.activeSubSystems.indexOf(_this, 0);
+                if (index > -1) {
+                    _this._rootParticleSystem.activeSubSystems.splice(index, 1);
+                    _this._scene._toBeDisposed.push(_this);
+                }
+            };
+            this._emitFromParticle = function (particle) {
+                if (!_this.subEmitters || _this.subEmitters.length === 0) {
+                    return;
+                }
+                var templateIndex = Math.floor(Math.random() * _this.subEmitters.length);
+                var subSystem = _this.subEmitters[templateIndex]._cloneToSubSystem(_this, particle.position.clone());
+                _this.activeSubSystems.push(subSystem);
+                subSystem.start();
+            };
             this._appendParticleVertexes = null;
             this.id = name;
             this.name = name;
@@ -51194,6 +51300,7 @@ var BABYLON;
                     var particle = particles[index];
                     particle.age += _this._scaledUpdateSpeed;
                     if (particle.age >= particle.lifeTime) {
+                        _this._emitFromParticle(particle);
                         _this.recycleParticle(particle);
                         index--;
                         continue;
@@ -51315,6 +51422,7 @@ var BABYLON;
             configurable: true
         });
         Object.defineProperty(ParticleSystem.prototype, "particles", {
+            //end of Sub-emitter
             /**
              * Gets the current list of active particles
              */
@@ -51346,18 +51454,6 @@ var BABYLON;
             this._indexBuffer = this._scene.getEngine().createIndexBuffer(indices);
         };
         /**
-         * "Recycles" one of the particle by copying it back to the "stock" of particles and removing it from the active list.
-         * Its lifetime will start back at 0.
-         * @param particle The particle to recycle
-         */
-        ParticleSystem.prototype.recycleParticle = function (particle) {
-            var lastParticle = this._particles.pop();
-            if (lastParticle !== particle) {
-                lastParticle.copyTo(particle);
-                this._stockParticles.push(lastParticle);
-            }
-        };
-        /**
          * Gets the maximum number of particles active at the same time.
          * @returns The max number of active particles.
          */
@@ -51385,13 +51481,22 @@ var BABYLON;
             this._started = true;
             this._stopped = false;
             this._actualFrame = 0;
+            if (this.subEmitters && this.subEmitters.length != 0) {
+                this.activeSubSystems = new Array();
+            }
         };
         /**
          * Stops the particle system.
+         * @param stopSubEmitters if true it will stop the current system and all created sub-Systems if false it will stop the current root system only, this param is used by the root particle system only. the default value is true.
          */
-        ParticleSystem.prototype.stop = function () {
+        ParticleSystem.prototype.stop = function (stopSubEmitters) {
+            if (stopSubEmitters === void 0) { stopSubEmitters = true; }
             this._stopped = true;
+            if (stopSubEmitters) {
+                this._stopSubEmitters();
+            }
         };
+        // animation sheet
         /**
          * Remove all active particles
          */
@@ -51442,9 +51547,24 @@ var BABYLON;
             this._vertexData[offset + 10] = offsetY;
             this._vertexData[offset + 11] = particle.cellIndex;
         };
+        ParticleSystem.prototype._stopSubEmitters = function () {
+            this.activeSubSystems.forEach(function (subSystem) {
+                subSystem.stop(true);
+                subSystem._stoppedEmitting();
+            });
+            this.activeSubSystems = new Array();
+        };
+        // end of sub system methods
         ParticleSystem.prototype._update = function (newParticles) {
             // Update current
             this._alive = this._particles.length > 0;
+            if (this._alive) {
+                this._isEmitting = true;
+            }
+            if (!this._alive && this._isEmitting) {
+                this._isEmitting = false;
+                this._stoppedEmitting();
+            }
             this.updateFunction(this._particles);
             // Add new ones
             var worldMatrix;
@@ -51461,14 +51581,7 @@ var BABYLON;
                 if (this._particles.length === this._capacity) {
                     break;
                 }
-                if (this._stockParticles.length !== 0) {
-                    particle = this._stockParticles.pop();
-                    particle.age = 0;
-                    particle.cellIndex = this.startSpriteCellID;
-                }
-                else {
-                    particle = new BABYLON.Particle(this);
-                }
+                particle = this._createParticle();
                 this._particles.push(particle);
                 var emitPower = BABYLON.Scalar.RandomRange(this.minEmitPower, this.maxEmitPower);
                 if (this.startPositionFunction) {
@@ -51743,6 +51856,29 @@ var BABYLON;
             this.particleEmitterType = particleEmitter;
             return particleEmitter;
         };
+        ParticleSystem.prototype._cloneToSubSystem = function (root, newEmitter) {
+            var custom = null;
+            var program = null;
+            if (this.customShader != null) {
+                program = this.customShader;
+                var defines = (program.shaderOptions.defines.length > 0) ? program.shaderOptions.defines.join("\n") : "";
+                custom = this._scene.getEngine().createEffectForParticles(program.shaderPath.fragmentElement, program.shaderOptions.uniforms, program.shaderOptions.samplers, defines);
+            }
+            var result = new ParticleSystem(name, this._capacity, this._scene, custom);
+            result.customShader = program;
+            BABYLON.Tools.DeepCopy(this, result, ["customShader"]);
+            result.name = name + "_Child";
+            result.id = result.name;
+            result.emitter = newEmitter;
+            result.subEmitters = this.subEmitters;
+            result.particleEmitterType = this.particleEmitterType;
+            result._rootParticleSystem = root;
+            if (this.particleTexture) {
+                result.particleTexture = new BABYLON.Texture(this.particleTexture.url, this._scene);
+            }
+            return result;
+        };
+        // Clone
         /**
          * Clones the particle system.
          * @param name The name of the cloned object
@@ -58975,6 +59111,14 @@ var BABYLON;
                 this._postProcessManager._rebuild();
             }
         };
+        /**
+         * Clear the info related to rendering groups preventing retention point in material dispose.
+         */
+        RenderTargetTexture.prototype.freeRenderingGroups = function () {
+            if (this._renderingManager) {
+                this._renderingManager.freeRenderingGroups();
+            }
+        };
         RenderTargetTexture._REFRESHRATE_RENDER_ONCE = 0;
         RenderTargetTexture._REFRESHRATE_RENDER_ONEVERYFRAME = 1;
         RenderTargetTexture._REFRESHRATE_RENDER_ONEVERYTWOFRAMES = 2;
@@ -60315,10 +60459,11 @@ var BABYLON;
 (function (BABYLON) {
     var PassPostProcess = /** @class */ (function (_super) {
         __extends(PassPostProcess, _super);
-        function PassPostProcess(name, options, camera, samplingMode, engine, reusable, textureType) {
+        function PassPostProcess(name, options, camera, samplingMode, engine, reusable, textureType, blockCompilation) {
             if (camera === void 0) { camera = null; }
             if (textureType === void 0) { textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; }
-            return _super.call(this, name, "pass", null, null, options, camera, samplingMode, engine, reusable, undefined, textureType) || this;
+            if (blockCompilation === void 0) { blockCompilation = false; }
+            return _super.call(this, name, "pass", null, null, options, camera, samplingMode, engine, reusable, undefined, textureType, undefined, null, blockCompilation) || this;
         }
         return PassPostProcess;
     }(BABYLON.PostProcess));
@@ -68947,10 +69092,12 @@ var BABYLON;
          * @param engine The engine which the post process will be applied. (default: current engine)
          * @param reusable If the post process can be reused on the same frame. (default: false)
          * @param textureType Type of textures used when performing the post process. (default: 0)
+         * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
          */
-        function ChromaticAberrationPostProcess(name, screenWidth, screenHeight, options, camera, samplingMode, engine, reusable, textureType) {
+        function ChromaticAberrationPostProcess(name, screenWidth, screenHeight, options, camera, samplingMode, engine, reusable, textureType, blockCompilation) {
             if (textureType === void 0) { textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; }
-            var _this = _super.call(this, name, "chromaticAberration", ["chromatic_aberration", "screen_width", "screen_height", "direction", "radialIntensity", "centerPosition"], [], options, camera, samplingMode, engine, reusable, null, textureType) || this;
+            if (blockCompilation === void 0) { blockCompilation = false; }
+            var _this = _super.call(this, name, "chromaticAberration", ["chromatic_aberration", "screen_width", "screen_height", "direction", "radialIntensity", "centerPosition"], [], options, camera, samplingMode, engine, reusable, null, textureType, undefined, null, blockCompilation) || this;
             /**
              * The amount of seperation of rgb channels (default: 0)
              */
@@ -69002,10 +69149,12 @@ var BABYLON;
          * @param engine The engine which the post process will be applied. (default: current engine)
          * @param reusable If the post process can be reused on the same frame. (default: false)
          * @param textureType Type of textures used when performing the post process. (default: 0)
+         * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
          */
-        function SharpenPostProcess(name, options, camera, samplingMode, engine, reusable, textureType) {
+        function SharpenPostProcess(name, options, camera, samplingMode, engine, reusable, textureType, blockCompilation) {
             if (textureType === void 0) { textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; }
-            var _this = _super.call(this, name, "sharpen", ["sharpnessAmounts", "screenSize"], null, options, camera, samplingMode, engine, reusable, null, textureType) || this;
+            if (blockCompilation === void 0) { blockCompilation = false; }
+            var _this = _super.call(this, name, "sharpen", ["sharpnessAmounts", "screenSize"], null, options, camera, samplingMode, engine, reusable, null, textureType, undefined, null, blockCompilation) || this;
             /**
              * How much of the original color should be applied. Setting this to 0 will display edge detection. (default: 1)
              */
@@ -69047,13 +69196,16 @@ var BABYLON;
          * @param engine The engine which the post process will be applied. (default: current engine)
          * @param reusable If the post process can be reused on the same frame. (default: false)
          * @param textureType Type of textures used when performing the post process. (default: 0)
+         * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
          */
-        function BlurPostProcess(name, /** The direction in which to blur the image. */ direction, kernel, options, camera, samplingMode, engine, reusable, textureType, defines) {
+        function BlurPostProcess(name, /** The direction in which to blur the image. */ direction, kernel, options, camera, samplingMode, engine, reusable, textureType, defines, blockCompilation) {
             if (samplingMode === void 0) { samplingMode = BABYLON.Texture.BILINEAR_SAMPLINGMODE; }
             if (textureType === void 0) { textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; }
             if (defines === void 0) { defines = ""; }
+            if (blockCompilation === void 0) { blockCompilation = false; }
             var _this = _super.call(this, name, "kernelBlur", ["delta", "direction", "cameraMinMaxZ"], ["circleOfConfusionSampler"], options, camera, samplingMode, engine, reusable, null, textureType, "kernelBlur", { varyingCount: 0, depCount: 0 }, true) || this;
             _this.direction = direction;
+            _this.blockCompilation = blockCompilation;
             _this._packedFloat = false;
             _this._staticDefines = "";
             _this._staticDefines = defines;
@@ -69080,7 +69232,9 @@ var BABYLON;
                 v = Math.max(v, 1);
                 this._idealKernel = v;
                 this._kernel = this._nearestBestKernel(v);
-                this._updateParameters();
+                if (!this.blockCompilation) {
+                    this._updateParameters();
+                }
             },
             enumerable: true,
             configurable: true
@@ -69100,12 +69254,29 @@ var BABYLON;
                     return;
                 }
                 this._packedFloat = v;
-                this._updateParameters();
+                if (!this.blockCompilation) {
+                    this._updateParameters();
+                }
             },
             enumerable: true,
             configurable: true
         });
-        BlurPostProcess.prototype._updateParameters = function () {
+        /**
+         * Updates the effect with the current post process compile time values and recompiles the shader.
+         * @param defines Define statements that should be added at the beginning of the shader. (default: null)
+         * @param uniforms Set of uniform variables that will be passed to the shader. (default: null)
+         * @param samplers Set of Texture2D variables that will be passed to the shader. (default: null)
+         * @param indexParameters The index parameters to be used for babylons include syntax "#include<kernelBlurVaryingDeclaration>[0..varyingCount]". (default: undefined) See usage in babylon.blurPostProcess.ts and kernelBlur.vertex.fx
+         * @param onCompiled Called when the shader has been compiled.
+         * @param onError Called if there is an error when compiling a shader.
+         */
+        BlurPostProcess.prototype.updateEffect = function (defines, uniforms, samplers, indexParameters, onCompiled, onError) {
+            if (defines === void 0) { defines = null; }
+            if (uniforms === void 0) { uniforms = null; }
+            if (samplers === void 0) { samplers = null; }
+            this._updateParameters(onCompiled, onError);
+        };
+        BlurPostProcess.prototype._updateParameters = function (onCompiled, onError) {
             // Generate sampling offsets and weights
             var N = this._kernel;
             var centerIndex = (N - 1) / 2;
@@ -69175,10 +69346,10 @@ var BABYLON;
             if (this.packedFloat) {
                 defines += "#define PACKEDFLOAT 1";
             }
-            this.updateEffect(defines, null, null, {
+            _super.prototype.updateEffect.call(this, defines, null, null, {
                 varyingCount: varyingCount,
                 depCount: depCount
-            });
+            }, onCompiled, onError);
         };
         /**
          * Best kernels are odd numbers that when divided by 2, their integer part is even, so 5, 9 or 13.
@@ -69259,12 +69430,14 @@ var BABYLON;
          * @param engine The engine which the post process will be applied. (default: current engine)
          * @param reusable If the post process can be reused on the same frame. (default: false)
          * @param textureType Type of textures used when performing the post process. (default: 0)
+         * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
          */
-        function DepthOfFieldBlurPostProcess(name, scene, direction, kernel, options, camera, circleOfConfusion, imageToBlur, samplingMode, engine, reusable, textureType) {
+        function DepthOfFieldBlurPostProcess(name, scene, direction, kernel, options, camera, circleOfConfusion, imageToBlur, samplingMode, engine, reusable, textureType, blockCompilation) {
             if (imageToBlur === void 0) { imageToBlur = null; }
             if (samplingMode === void 0) { samplingMode = BABYLON.Texture.BILINEAR_SAMPLINGMODE; }
             if (textureType === void 0) { textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; }
-            var _this = _super.call(this, name, direction, kernel, options, camera, samplingMode = BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, reusable, textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT, "#define DOF 1\r\n") || this;
+            if (blockCompilation === void 0) { blockCompilation = false; }
+            var _this = _super.call(this, name, direction, kernel, options, camera, samplingMode = BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, reusable, textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT, "#define DOF 1\r\n", blockCompilation) || this;
             _this.direction = direction;
             _this.onApplyObservable.add(function (effect) {
                 if (imageToBlur != null) {
@@ -69304,10 +69477,13 @@ var BABYLON;
          * @param engine The engine which the post process will be applied. (default: current engine)
          * @param reusable If the post process can be reused on the same frame. (default: false)
          * @param textureType Type of textures used when performing the post process. (default: 0)
+         * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
          */
-        function DepthOfFieldMergePostProcess(name, original, circleOfConfusion, blurSteps, options, camera, samplingMode, engine, reusable, textureType) {
+        function DepthOfFieldMergePostProcess(name, original, circleOfConfusion, blurSteps, options, camera, samplingMode, engine, reusable, textureType, blockCompilation) {
             if (textureType === void 0) { textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; }
-            var _this = _super.call(this, name, "depthOfFieldMerge", [], ["circleOfConfusionSampler", "originalSampler", "blurStep1", "blurStep2"], options, camera, samplingMode, engine, reusable, "#define BLUR_LEVEL " + blurSteps.length + "\n", textureType) || this;
+            if (blockCompilation === void 0) { blockCompilation = false; }
+            var _this = _super.call(this, name, "depthOfFieldMerge", [], ["circleOfConfusionSampler", "originalSampler", "blurStep1", "blurStep2"], options, camera, samplingMode, engine, reusable, null, textureType, undefined, null, true) || this;
+            _this.blurSteps = blurSteps;
             _this.onApplyObservable.add(function (effect) {
                 effect.setTextureFromPostProcess("circleOfConfusionSampler", circleOfConfusion);
                 effect.setTextureFromPostProcess("originalSampler", original);
@@ -69315,8 +69491,26 @@ var BABYLON;
                     effect.setTextureFromPostProcess("blurStep" + (index + 1), step);
                 });
             });
+            if (!blockCompilation) {
+                _this.updateEffect();
+            }
             return _this;
         }
+        /**
+         * Updates the effect with the current post process compile time values and recompiles the shader.
+         * @param defines Define statements that should be added at the beginning of the shader. (default: null)
+         * @param uniforms Set of uniform variables that will be passed to the shader. (default: null)
+         * @param samplers Set of Texture2D variables that will be passed to the shader. (default: null)
+         * @param indexParameters The index parameters to be used for babylons include syntax "#include<kernelBlurVaryingDeclaration>[0..varyingCount]". (default: undefined) See usage in babylon.blurPostProcess.ts and kernelBlur.vertex.fx
+         * @param onCompiled Called when the shader has been compiled.
+         * @param onError Called if there is an error when compiling a shader.
+         */
+        DepthOfFieldMergePostProcess.prototype.updateEffect = function (defines, uniforms, samplers, indexParameters, onCompiled, onError) {
+            if (defines === void 0) { defines = null; }
+            if (uniforms === void 0) { uniforms = null; }
+            if (samplers === void 0) { samplers = null; }
+            _super.prototype.updateEffect.call(this, defines ? defines : "#define BLUR_LEVEL " + this.blurSteps.length + "\n", uniforms, samplers, indexParameters, onCompiled, onError);
+        };
         return DepthOfFieldMergePostProcess;
     }(BABYLON.PostProcess));
     BABYLON.DepthOfFieldMergePostProcess = DepthOfFieldMergePostProcess;
@@ -69342,10 +69536,12 @@ var BABYLON;
          * @param engine The engine which the post process will be applied. (default: current engine)
          * @param reusable If the post process can be reused on the same frame. (default: false)
          * @param textureType Type of textures used when performing the post process. (default: 0)
+         * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
          */
-        function CircleOfConfusionPostProcess(name, depthTexture, options, camera, samplingMode, engine, reusable, textureType) {
+        function CircleOfConfusionPostProcess(name, depthTexture, options, camera, samplingMode, engine, reusable, textureType, blockCompilation) {
             if (textureType === void 0) { textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; }
-            var _this = _super.call(this, name, "circleOfConfusion", ["cameraMinMaxZ", "focusDistance", "cocPrecalculation"], ["depthSampler"], options, camera, samplingMode, engine, reusable, null, textureType) || this;
+            if (blockCompilation === void 0) { blockCompilation = false; }
+            var _this = _super.call(this, name, "circleOfConfusion", ["cameraMinMaxZ", "focusDistance", "cocPrecalculation"], ["depthSampler"], options, camera, samplingMode, engine, reusable, null, textureType, undefined, null, blockCompilation) || this;
             /**
              * Max lens size in scene units/1000 (eg. millimeter). Standard cameras are 50mm. (default: 50) The diamater of the resulting aperture can be computed by lensSize/fStop.
              */
@@ -69428,18 +69624,20 @@ var BABYLON;
          * @param scene The scene the effect belongs to.
          * @param depthTexture The depth texture of the scene to compute the circle of confusion.This must be set in order for this to function but may be set after initialization if needed.
          * @param pipelineTextureType The type of texture to be used when performing the post processing.
+         * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
          */
-        function DepthOfFieldEffect(scene, depthTexture, blurLevel, pipelineTextureType) {
+        function DepthOfFieldEffect(scene, depthTexture, blurLevel, pipelineTextureType, blockCompilation) {
             if (blurLevel === void 0) { blurLevel = DepthOfFieldEffectBlurLevel.Low; }
             if (pipelineTextureType === void 0) { pipelineTextureType = 0; }
+            if (blockCompilation === void 0) { blockCompilation = false; }
             var _this = _super.call(this, scene.getEngine(), "depth of field", function () {
                 return _this._effects;
             }, true) || this;
             _this._effects = [];
             // Circle of confusion value for each pixel is used to determine how much to blur that pixel
-            _this._circleOfConfusion = new BABYLON.CircleOfConfusionPostProcess("circleOfConfusion", depthTexture, 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType);
+            _this._circleOfConfusion = new BABYLON.CircleOfConfusionPostProcess("circleOfConfusion", depthTexture, 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
             // Capture circle of confusion texture
-            _this._depthOfFieldPass = new BABYLON.PassPostProcess("depthOfFieldPass", 1.0, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType);
+            _this._depthOfFieldPass = new BABYLON.PassPostProcess("depthOfFieldPass", 1.0, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
             _this._depthOfFieldPass.autoClear = false;
             // Create a pyramid of blurred images (eg. fullSize 1/4 blur, half size 1/2 blur, quarter size 3/4 blur, eith size 4/4 blur)
             // Blur the image but do not blur on sharp far to near distance changes to avoid bleeding artifacts 
@@ -69467,15 +69665,15 @@ var BABYLON;
             }
             var adjustedKernelSize = kernelSize / Math.pow(2, blurCount - 1);
             for (var i = 0; i < blurCount; i++) {
-                var blurY = new BABYLON.DepthOfFieldBlurPostProcess("verticle blur", scene, new BABYLON.Vector2(0, 1.0), adjustedKernelSize, 1.0 / Math.pow(2, i), null, _this._depthOfFieldPass, i == 0 ? _this._circleOfConfusion : null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType);
+                var blurY = new BABYLON.DepthOfFieldBlurPostProcess("verticle blur", scene, new BABYLON.Vector2(0, 1.0), adjustedKernelSize, 1.0 / Math.pow(2, i), null, _this._depthOfFieldPass, i == 0 ? _this._circleOfConfusion : null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
                 blurY.autoClear = false;
-                var blurX = new BABYLON.DepthOfFieldBlurPostProcess("horizontal blur", scene, new BABYLON.Vector2(1.0, 0), adjustedKernelSize, 1.0 / Math.pow(2, i), null, _this._depthOfFieldPass, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType);
+                var blurX = new BABYLON.DepthOfFieldBlurPostProcess("horizontal blur", scene, new BABYLON.Vector2(1.0, 0), adjustedKernelSize, 1.0 / Math.pow(2, i), null, _this._depthOfFieldPass, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
                 blurX.autoClear = false;
                 _this._depthOfFieldBlurY.push(blurY);
                 _this._depthOfFieldBlurX.push(blurX);
             }
             // Merge blurred images with original image based on circleOfConfusion
-            _this._depthOfFieldMerge = new BABYLON.DepthOfFieldMergePostProcess("depthOfFieldMerge", _this._circleOfConfusion, _this._depthOfFieldPass, _this._depthOfFieldBlurY.slice(1), 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType);
+            _this._depthOfFieldMerge = new BABYLON.DepthOfFieldMergePostProcess("depthOfFieldMerge", _this._circleOfConfusion, _this._depthOfFieldPass, _this._depthOfFieldBlurY.slice(1), 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
             _this._depthOfFieldMerge.autoClear = false;
             // Set all post processes on the effect.
             _this._effects = [_this._circleOfConfusion, _this._depthOfFieldPass];
@@ -69563,6 +69761,26 @@ var BABYLON;
             });
             this._depthOfFieldMerge.dispose(camera);
         };
+        /**
+         * Internal
+         */
+        DepthOfFieldEffect.prototype._updateEffects = function () {
+            for (var effect in this._effects) {
+                this._effects[effect].updateEffect();
+            }
+        };
+        /**
+         * Internal
+         * @returns if all the contained post processes are ready.
+         */
+        DepthOfFieldEffect.prototype._isReady = function () {
+            for (var effect in this._effects) {
+                if (!this._effects[effect].isReady()) {
+                    return false;
+                }
+            }
+            return true;
+        };
         return DepthOfFieldEffect;
     }(BABYLON.PostProcessRenderEffect));
     BABYLON.DepthOfFieldEffect = DepthOfFieldEffect;
@@ -69683,10 +69901,12 @@ var BABYLON;
             // Attach
             scene.postProcessRenderPipelineManager.addPipeline(_this);
             var engine = _this._scene.getEngine();
-            _this.sharpen = new BABYLON.SharpenPostProcess("sharpen", 1.0, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, false, _this._defaultPipelineTextureType);
+            // Create post processes before hand so they can be modified before enabled.
+            // Block compilation flag is set to true to avoid compilation prior to use, these will be updated on first use in build pipeline.
+            _this.sharpen = new BABYLON.SharpenPostProcess("sharpen", 1.0, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, false, _this._defaultPipelineTextureType, true);
             _this._sharpenEffect = new BABYLON.PostProcessRenderEffect(engine, _this.SharpenPostProcessId, function () { return _this.sharpen; }, true);
-            _this.depthOfField = new BABYLON.DepthOfFieldEffect(_this._scene, null, _this._depthOfFieldBlurLevel, _this._defaultPipelineTextureType);
-            _this.chromaticAberration = new BABYLON.ChromaticAberrationPostProcess("ChromaticAberration", engine.getRenderWidth(), engine.getRenderHeight(), 1.0, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, false, _this._defaultPipelineTextureType);
+            _this.depthOfField = new BABYLON.DepthOfFieldEffect(_this._scene, null, _this._depthOfFieldBlurLevel, _this._defaultPipelineTextureType, true);
+            _this.chromaticAberration = new BABYLON.ChromaticAberrationPostProcess("ChromaticAberration", engine.getRenderWidth(), engine.getRenderHeight(), 1.0, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, false, _this._defaultPipelineTextureType, true);
             _this._chromaticAberrationEffect = new BABYLON.PostProcessRenderEffect(engine, _this.ChromaticAberrationPostProcessId, function () { return _this.chromaticAberration; }, true);
             _this._buildPipeline();
             return _this;
@@ -69919,12 +70139,18 @@ var BABYLON;
             this._prevPostProcess = null;
             this._prevPrevPostProcess = null;
             if (this.sharpenEnabled) {
+                if (!this.sharpen.isReady()) {
+                    this.sharpen.updateEffect();
+                }
                 this.addEffect(this._sharpenEffect);
                 this._setAutoClearAndTextureSharing(this.sharpen);
             }
             if (this.depthOfFieldEnabled) {
                 var depthTexture = this._scene.enableDepthRenderer(this._cameras[0]).getDepthMap();
                 this.depthOfField.depthTexture = depthTexture;
+                if (!this.depthOfField._isReady()) {
+                    this.depthOfField._updateEffects();
+                }
                 this.addEffect(this.depthOfField);
                 this._setAutoClearAndTextureSharing(this.depthOfField._depthOfFieldMerge);
             }
@@ -70006,6 +70232,9 @@ var BABYLON;
                 this._setAutoClearAndTextureSharing(this.fxaa);
             }
             if (this.chromaticAberrationEnabled) {
+                if (!this.chromaticAberration.isReady()) {
+                    this.chromaticAberration.updateEffect();
+                }
                 this.addEffect(this._chromaticAberrationEffect);
                 this._setAutoClearAndTextureSharing(this.chromaticAberration);
             }

+ 14 - 23
src/Particles/babylon.particleSystem.ts

@@ -345,7 +345,6 @@
         */
         public activeSubSystems: Array<ParticleSystem>;
         
-        private _isEmitting = false;
         private _rootParticleSystem: ParticleSystem;
         //end of Sub-emitter
 
@@ -507,7 +506,7 @@
         public stop(stopSubEmitters = true): void {
             this._stopped = true;
 
-            if(stopSubEmitters) {
+            if (stopSubEmitters) {
                 this._stopSubEmitters();
             }
         }
@@ -585,9 +584,11 @@
         };
 
         private _stopSubEmitters(): void {
+            if (!this.activeSubSystems) {
+                return;
+            }
             this.activeSubSystems.forEach(subSystem => {
                 subSystem.stop(true);
-                subSystem._stoppedEmitting();
             });
             this.activeSubSystems = new Array<ParticleSystem>();
         }
@@ -604,21 +605,14 @@
             return particle;
         }
 
-        // to be overriden by subSystems
-        private _stoppedEmitting: () => void = () => {
-            if(!this._rootParticleSystem){
+        private _removeFromRoot(): void {
+            if (!this._rootParticleSystem){
                 return;
             }
             
-            if(!this.subEmitters || this.subEmitters.length === 0){
-                this._scene._toBeDisposed.push(this);
-                return;
-            }
-
-            let index = this._rootParticleSystem.activeSubSystems.indexOf(this, 0);
-            if (index > -1) {
+            let index = this._rootParticleSystem.activeSubSystems.indexOf(this);
+            if (index !== -1) {
                 this._rootParticleSystem.activeSubSystems.splice(index, 1);
-                this._scene._toBeDisposed.push(this);
             }
         }
 
@@ -640,15 +634,6 @@
             // Update current
             this._alive = this._particles.length > 0;
 
-            if (this._alive) {
-                this._isEmitting = true;
-            }
-
-            if (!this._alive && this._isEmitting) {
-                this._isEmitting = false;
-                this._stoppedEmitting();
-            }
-
             this.updateFunction(this._particles);
 
             // Add new ones
@@ -827,6 +812,10 @@
             if (this._vertexBuffer) {
                 this._vertexBuffer.update(this._vertexData);
             }
+
+            if (this.manualEmitCount === 0 && this.disposeOnStop) {
+                this.stop();
+            }
         }
 
         private _appendParticleVertexes: Nullable<(offset: number, particle: Particle) => void> = null;
@@ -934,6 +923,8 @@
                 this.particleTexture = null;
             }
 
+            this._removeFromRoot();
+
             // Remove from scene
             var index = this._scene.particleSystems.indexOf(this);
             if (index > -1) {