瀏覽代碼

Fix Sprite Instrumentation

sebastien 7 年之前
父節點
當前提交
41b1283c3d

文件差異過大導致無法顯示
+ 2191 - 2080
Playground/babylon.d.txt


文件差異過大導致無法顯示
+ 8542 - 8431
dist/preview release/babylon.d.ts


文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/babylon.js


+ 262 - 198
dist/preview release/babylon.max.js

@@ -23198,7 +23198,7 @@ var BABYLON;
             info.scene = this._scene;
             info.camera = this._scene.activeCamera;
             // Dispatch sprites
-            if (renderSprites) {
+            if (this._scene.spriteManagers && renderSprites) {
                 for (var index = 0; index < this._scene.spriteManagers.length; index++) {
                     var manager = this._scene.spriteManagers[index];
                     this.dispatchSprites(manager);
@@ -23735,6 +23735,7 @@ var BABYLON;
         SceneComponentConstants.NAME_GEOMETRYBUFFERRENDERER = "GeometryBufferRenderer";
         SceneComponentConstants.NAME_DEPTHRENDERER = "DepthRenderer";
         SceneComponentConstants.NAME_POSTPROCESSRENDERPIPELINEMANAGER = "PostProcessRenderPipelineManager";
+        SceneComponentConstants.NAME_SPRITE = "Sprite";
         SceneComponentConstants.STEP_ISREADYFORMESH_EFFECTLAYER = 0;
         SceneComponentConstants.STEP_BEFOREEVALUATEACTIVEMESH_BOUNDINGBOXRENDERER = 0;
         SceneComponentConstants.STEP_EVALUATESUBMESH_BOUNDINGBOXRENDERER = 0;
@@ -23754,6 +23755,9 @@ var BABYLON;
         SceneComponentConstants.STEP_GATHERRENDERTARGETS_DEPTHRENDERER = 1;
         SceneComponentConstants.STEP_GATHERRENDERTARGETS_POSTPROCESSRENDERPIPELINEMANAGER = 2;
         SceneComponentConstants.STEP_REBUILDGEOMETRY_POSTPROCESSRENDERPIPELINEMANAGER = 0;
+        SceneComponentConstants.STEP_POINTERMOVE_SPRITE = 0;
+        SceneComponentConstants.STEP_POINTERDOWN_SPRITE = 0;
+        SceneComponentConstants.STEP_POINTERUP_SPRITE = 0;
         return SceneComponentConstants;
     }());
     BABYLON.SceneComponentConstants = SceneComponentConstants;
@@ -24152,16 +24156,6 @@ var BABYLON;
             */
             _this.onAfterParticlesRenderingObservable = new BABYLON.Observable();
             /**
-            * An event triggered when sprites rendering is about to start
-            * Note: This event can be trigger more than once per frame (because sprites can be rendered by render target textures as well)
-            */
-            _this.onBeforeSpritesRenderingObservable = new BABYLON.Observable();
-            /**
-            * An event triggered when sprites rendering is done
-            * Note: This event can be trigger more than once per frame (because sprites can be rendered by render target textures as well)
-            */
-            _this.onAfterSpritesRenderingObservable = new BABYLON.Observable();
-            /**
             * An event triggered when SceneLoader.Append or SceneLoader.Load or SceneLoader.ImportMesh were successfully executed
             */
             _this.onDataLoadedObservable = new BABYLON.Observable();
@@ -24316,11 +24310,6 @@ var BABYLON;
             * Gets or sets a boolean indicating if sprites are enabled on this scene
             */
             _this.spritesEnabled = true;
-            /**
-            * All of the sprite managers added to this scene
-            * @see http://doc.babylonjs.com/babylon101/sprites
-            */
-            _this.spriteManagers = new Array();
             // Skeletons
             _this._skeletonsEnabled = true;
             // Lens flares
@@ -24515,6 +24504,21 @@ var BABYLON;
              * Defines the actions happening when Geometries are rebuilding.
              */
             _this._rebuildGeometryStage = BABYLON.Stage.Create();
+            /**
+             * @hidden
+             * Defines the actions happening when a pointer move event happens.
+             */
+            _this._pointerMoveStage = BABYLON.Stage.Create();
+            /**
+             * @hidden
+             * Defines the actions happening when a pointer down event happens.
+             */
+            _this._pointerDownStage = BABYLON.Stage.Create();
+            /**
+             * @hidden
+             * Defines the actions happening when a pointer up event happens.
+             */
+            _this._pointerUpStage = BABYLON.Stage.Create();
             _this._activeMeshesFrozen = false;
             /** @hidden */
             _this._allowPostProcessClearColor = true;
@@ -25267,13 +25271,6 @@ var BABYLON;
             this._alternateSceneUbo.addUniform("view", 16);
         };
         // Pointers handling
-        Scene.prototype._pickSpriteButKeepRay = function (originalPointerInfo, x, y, predicate, fastCheck, camera) {
-            var result = this.pickSprite(x, y, predicate, fastCheck, camera);
-            if (result) {
-                result.ray = originalPointerInfo ? originalPointerInfo.ray : null;
-            }
-            return result;
-        };
         Scene.prototype._setRayOnPointerInfo = function (pointerInfo) {
             if (pointerInfo.pickInfo) {
                 if (!pointerInfo.pickInfo.ray) {
@@ -25300,39 +25297,16 @@ var BABYLON;
             if (!canvas) {
                 return this;
             }
-            if (pickResult && pickResult.hit && pickResult.pickedMesh) {
-                this.setPointerOverSprite(null);
+            var isMeshPicked = (pickResult && pickResult.hit && pickResult.pickedMesh) ? true : false;
+            if (isMeshPicked) {
                 this.setPointerOverMesh(pickResult.pickedMesh);
-                if (this._pointerOverMesh && this._pointerOverMesh.actionManager && this._pointerOverMesh.actionManager.hasPointerTriggers) {
-                    if (this._pointerOverMesh.actionManager.hoverCursor) {
-                        canvas.style.cursor = this._pointerOverMesh.actionManager.hoverCursor;
-                    }
-                    else {
-                        canvas.style.cursor = this.hoverCursor;
-                    }
-                }
-                else {
-                    canvas.style.cursor = this.defaultCursor;
-                }
             }
             else {
                 this.setPointerOverMesh(null);
-                // Sprites
-                pickResult = this._pickSpriteButKeepRay(pickResult, this._unTranslatedPointerX, this._unTranslatedPointerY, this._spritePredicate, false, this.cameraToUseForPointers || undefined);
-                if (pickResult && pickResult.hit && pickResult.pickedSprite) {
-                    this.setPointerOverSprite(pickResult.pickedSprite);
-                    if (this._pointerOverSprite && this._pointerOverSprite.actionManager && this._pointerOverSprite.actionManager.hoverCursor) {
-                        canvas.style.cursor = this._pointerOverSprite.actionManager.hoverCursor;
-                    }
-                    else {
-                        canvas.style.cursor = this.hoverCursor;
-                    }
-                }
-                else {
-                    this.setPointerOverSprite(null);
-                    // Restore pointer
-                    canvas.style.cursor = this.defaultCursor;
-                }
+            }
+            for (var _i = 0, _a = this._pointerMoveStage; _i < _a.length; _i++) {
+                var step = _a[_i];
+                pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, isMeshPicked, canvas);
             }
             if (pickResult) {
                 var type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? BABYLON.PointerEventTypes.POINTERWHEEL : BABYLON.PointerEventTypes.POINTERMOVE;
@@ -25400,8 +25374,7 @@ var BABYLON;
                             if (pickResult && pickResult.hit && pickResult.pickedMesh && actionManager) {
                                 if (_this._totalPointersPressed !== 0 &&
                                     ((Date.now() - _this._startingPointerTime) > Scene.LongPressDelay) &&
-                                    (Math.abs(_this._startingPointerPosition.x - _this._pointerX) < Scene.DragMovementThreshold &&
-                                        Math.abs(_this._startingPointerPosition.y - _this._pointerY) < Scene.DragMovementThreshold)) {
+                                    !_this._isPointerSwiping()) {
                                     _this._startingPointerTime = 0;
                                     actionManager.processTrigger(BABYLON.ActionManager.OnLongPressTrigger, BABYLON.ActionEvent.CreateNew(pickResult.pickedMesh, evt));
                                 }
@@ -25410,6 +25383,12 @@ var BABYLON;
                     }
                 }
             }
+            else {
+                for (var _i = 0, _a = this._pointerDownStage; _i < _a.length; _i++) {
+                    var step = _a[_i];
+                    pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, evt);
+                }
+            }
             if (pickResult) {
                 var type = BABYLON.PointerEventTypes.POINTERDOWN;
                 if (this.onPointerDown) {
@@ -25466,6 +25445,14 @@ var BABYLON;
                     }
                 }
             }
+            else {
+                if (!clickInfo.ignore) {
+                    for (var _i = 0, _a = this._pointerUpStage; _i < _a.length; _i++) {
+                        var step = _a[_i];
+                        pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, evt);
+                    }
+                }
+            }
             if (this._pickedDownMesh &&
                 this._pickedDownMesh.actionManager &&
                 this._pickedDownMesh.actionManager.hasSpecificTrigger(BABYLON.ActionManager.OnPickOutTrigger) &&
@@ -25510,6 +25497,11 @@ var BABYLON;
             if (pointerId === void 0) { pointerId = 0; }
             return this._pointerCaptures[pointerId];
         };
+        /** @hidden */
+        Scene.prototype._isPointerSwiping = function () {
+            return Math.abs(this._startingPointerPosition.x - this._pointerX) > Scene.DragMovementThreshold ||
+                Math.abs(this._startingPointerPosition.y - this._pointerY) > Scene.DragMovementThreshold;
+        };
         /**
         * Attach events to the canvas (To handle actionManagers triggers and raise onPointerMove, onPointerDown and onPointerUp
         * @param attachUp defines if you want to attach events to pointerup
@@ -25556,8 +25548,7 @@ var BABYLON;
                 }
                 if (checkPicking) {
                     var btn = evt.button;
-                    clickInfo.hasSwiped = Math.abs(_this._startingPointerPosition.x - _this._pointerX) > Scene.DragMovementThreshold ||
-                        Math.abs(_this._startingPointerPosition.y - _this._pointerY) > Scene.DragMovementThreshold;
+                    clickInfo.hasSwiped = _this._isPointerSwiping();
                     if (!clickInfo.hasSwiped) {
                         var checkSingleClickImmediately = !Scene.ExclusiveDoubleClickMode;
                         if (!checkSingleClickImmediately) {
@@ -25597,8 +25588,7 @@ var BABYLON;
                                 !_this._doubleClickOccured) {
                                 // pointer has not moved for 2 clicks, it's a double click
                                 if (!clickInfo.hasSwiped &&
-                                    Math.abs(_this._previousStartingPointerPosition.x - _this._startingPointerPosition.x) < Scene.DragMovementThreshold &&
-                                    Math.abs(_this._previousStartingPointerPosition.y - _this._startingPointerPosition.y) < Scene.DragMovementThreshold) {
+                                    !_this._isPointerSwiping()) {
                                     _this._previousStartingPointerTime = 0;
                                     _this._doubleClickOccured = true;
                                     clickInfo.doubleClick = true;
@@ -25642,9 +25632,6 @@ var BABYLON;
                 clickInfo.ignore = true;
                 cb(clickInfo, _this._currentPickResult);
             };
-            this._spritePredicate = function (sprite) {
-                return sprite.isPickable && sprite.actionManager && sprite.actionManager.hasPointerTriggers;
-            };
             this._onPointerMove = function (evt) {
                 _this._updatePointerPosition(evt);
                 // PreObservable support
@@ -25690,30 +25677,6 @@ var BABYLON;
                 _this._pickedDownMesh = null;
                 var pickResult = _this.pick(_this._unTranslatedPointerX, _this._unTranslatedPointerY, _this.pointerDownPredicate, false, _this.cameraToUseForPointers);
                 _this._processPointerDown(pickResult, evt);
-                // Sprites
-                _this._pickedDownSprite = null;
-                if (_this.spriteManagers.length > 0) {
-                    pickResult = _this.pickSprite(_this._unTranslatedPointerX, _this._unTranslatedPointerY, _this._spritePredicate, false, _this.cameraToUseForPointers || undefined);
-                    if (pickResult && pickResult.hit && pickResult.pickedSprite) {
-                        if (pickResult.pickedSprite.actionManager) {
-                            _this._pickedDownSprite = pickResult.pickedSprite;
-                            switch (evt.button) {
-                                case 0:
-                                    pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnLeftPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, _this, evt));
-                                    break;
-                                case 1:
-                                    pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnCenterPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, _this, evt));
-                                    break;
-                                case 2:
-                                    pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnRightPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, _this, evt));
-                                    break;
-                            }
-                            if (pickResult.pickedSprite.actionManager) {
-                                pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickDownTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, _this, evt));
-                            }
-                        }
-                    }
-                }
             };
             this._onPointerUp = function (evt) {
                 if (_this._totalPointersPressed === 0) { // We are attaching the pointer up to windows because of a bug in FF                    
@@ -25763,27 +25726,6 @@ var BABYLON;
                         pickResult = _this._currentPickResult;
                     }
                     _this._processPointerUp(pickResult, evt, clickInfo);
-                    // Sprites
-                    if (!clickInfo.ignore) {
-                        if (_this.spriteManagers.length > 0) {
-                            var spritePickResult = _this.pickSprite(_this._unTranslatedPointerX, _this._unTranslatedPointerY, _this._spritePredicate, false, _this.cameraToUseForPointers || undefined);
-                            if (spritePickResult) {
-                                if (spritePickResult.hit && spritePickResult.pickedSprite) {
-                                    if (spritePickResult.pickedSprite.actionManager) {
-                                        spritePickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickUpTrigger, BABYLON.ActionEvent.CreateNewFromSprite(spritePickResult.pickedSprite, _this, evt));
-                                        if (spritePickResult.pickedSprite.actionManager) {
-                                            if (Math.abs(_this._startingPointerPosition.x - _this._pointerX) < Scene.DragMovementThreshold && Math.abs(_this._startingPointerPosition.y - _this._pointerY) < Scene.DragMovementThreshold) {
-                                                spritePickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(spritePickResult.pickedSprite, _this, evt));
-                                            }
-                                        }
-                                    }
-                                }
-                                if (_this._pickedDownSprite && _this._pickedDownSprite.actionManager && _this._pickedDownSprite !== spritePickResult.pickedSprite) {
-                                    _this._pickedDownSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickOutTrigger, BABYLON.ActionEvent.CreateNewFromSprite(_this._pickedDownSprite, _this, evt));
-                                }
-                            }
-                        }
-                    }
                     _this._previousPickResult = _this._currentPickResult;
                 });
             };
@@ -28188,6 +28130,9 @@ var BABYLON;
             this._beforeCameraUpdateStage.clear();
             this._gatherRenderTargetsStage.clear();
             this._rebuildGeometryStage.clear();
+            this._pointerMoveStage.clear();
+            this._pointerDownStage.clear();
+            this._pointerUpStage.clear();
             for (var _i = 0, _a = this._components; _i < _a.length; _i++) {
                 var component = _a[_i];
                 component.dispose();
@@ -28232,8 +28177,6 @@ var BABYLON;
             this.onAfterActiveMeshesEvaluationObservable.clear();
             this.onBeforeParticlesRenderingObservable.clear();
             this.onAfterParticlesRenderingObservable.clear();
-            this.onBeforeSpritesRenderingObservable.clear();
-            this.onAfterSpritesRenderingObservable.clear();
             this.onBeforeDrawPhaseObservable.clear();
             this.onAfterDrawPhaseObservable.clear();
             this.onBeforePhysicsObservable.clear();
@@ -28293,10 +28236,6 @@ var BABYLON;
             while (this.particleSystems.length) {
                 this.particleSystems[0].dispose();
             }
-            // Release sprites
-            while (this.spriteManagers.length) {
-                this.spriteManagers[0].dispose();
-            }
             // Release postProcesses
             while (this.postProcesses.length) {
                 this.postProcesses[0].dispose();
@@ -28557,36 +28496,6 @@ var BABYLON;
             }
             return pickingInfos;
         };
-        Scene.prototype._internalPickSprites = function (ray, predicate, fastCheck, camera) {
-            if (!BABYLON.PickingInfo) {
-                return null;
-            }
-            var pickingInfo = null;
-            if (!camera) {
-                if (!this.activeCamera) {
-                    return null;
-                }
-                camera = this.activeCamera;
-            }
-            if (this.spriteManagers.length > 0) {
-                for (var spriteIndex = 0; spriteIndex < this.spriteManagers.length; spriteIndex++) {
-                    var spriteManager = this.spriteManagers[spriteIndex];
-                    if (!spriteManager.isPickable) {
-                        continue;
-                    }
-                    var result = spriteManager.intersects(ray, camera, predicate, fastCheck);
-                    if (!result || !result.hit)
-                        continue;
-                    if (!fastCheck && pickingInfo != null && result.distance >= pickingInfo.distance)
-                        continue;
-                    pickingInfo = result;
-                    if (fastCheck) {
-                        break;
-                    }
-                }
-            }
-            return pickingInfo || new BABYLON.PickingInfo();
-        };
         /** Launch a ray to try to pick a mesh in the scene
          * @param x position on screen
          * @param y position on screen
@@ -28609,41 +28518,9 @@ var BABYLON;
             }
             return result;
         };
-        /** Launch a ray to try to pick a sprite in the scene
-         * @param x position on screen
-         * @param y position on screen
-         * @param predicate Predicate function used to determine eligible sprites. Can be set to null. In this case, a sprite must have isPickable set to true
-         * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null.
-         * @param camera camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
-         * @returns a PickingInfo
-         */
-        Scene.prototype.pickSprite = function (x, y, predicate, fastCheck, camera) {
-            this.createPickingRayInCameraSpaceToRef(x, y, this._tempPickingRay, camera);
-            return this._internalPickSprites(this._tempPickingRay, predicate, fastCheck, camera);
-        };
-        /** Use the given ray to pick a sprite in the scene
-         * @param ray The ray (in world space) to use to pick meshes
-         * @param predicate Predicate function used to determine eligible sprites. Can be set to null. In this case, a sprite must have isPickable set to true
-         * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null.
-         * @param camera camera to use. Can be set to null. In this case, the scene.activeCamera will be used
-         * @returns a PickingInfo
-         */
-        Scene.prototype.pickSpriteWithRay = function (ray, predicate, fastCheck, camera) {
-            if (!this._cachedRayForTransform) {
-                this._cachedRayForTransform = BABYLON.Ray.Zero();
-            }
-            if (!camera) {
-                if (!this.activeCamera) {
-                    return null;
-                }
-                camera = this.activeCamera;
-            }
-            BABYLON.Ray.TransformToRef(ray, camera.getViewMatrix(), this._cachedRayForTransform);
-            return this._internalPickSprites(this._cachedRayForTransform, predicate, fastCheck, camera);
-        };
         /** Use the given ray to pick a mesh in the scene
          * @param ray The ray to use to pick meshes
-         * @param predicate Predicate function used to determine eligible sprites. Can be set to null. In this case, a sprite must have isPickable set to true
+         * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must have isPickable set to true
          * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null
          * @returns a PickingInfo
          */
@@ -28720,29 +28597,6 @@ var BABYLON;
         Scene.prototype.getPointerOverMesh = function () {
             return this._pointerOverMesh;
         };
-        /**
-         * Force the sprite under the pointer
-         * @param sprite defines the sprite to use
-         */
-        Scene.prototype.setPointerOverSprite = function (sprite) {
-            if (this._pointerOverSprite === sprite) {
-                return;
-            }
-            if (this._pointerOverSprite && this._pointerOverSprite.actionManager) {
-                this._pointerOverSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPointerOutTrigger, BABYLON.ActionEvent.CreateNewFromSprite(this._pointerOverSprite, this));
-            }
-            this._pointerOverSprite = sprite;
-            if (this._pointerOverSprite && this._pointerOverSprite.actionManager) {
-                this._pointerOverSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPointerOverTrigger, BABYLON.ActionEvent.CreateNewFromSprite(this._pointerOverSprite, this));
-            }
-        };
-        /**
-         * Gets the sprite under the pointer
-         * @returns a Sprite or null if no sprite is under the pointer
-         */
-        Scene.prototype.getPointerOverSprite = function () {
-            return this._pointerOverSprite;
-        };
         // Physics
         /**
          * Gets the current physics engine
@@ -54385,6 +54239,9 @@ var BABYLON;
             */
             this.onDisposeObservable = new BABYLON.Observable();
             this._vertexBuffers = {};
+            if (!scene._getComponent(BABYLON.SceneComponentConstants.NAME_SPRITE)) {
+                scene._addComponent(new BABYLON.SpriteSceneComponent(scene));
+            }
             this._capacity = capacity;
             this._spriteTexture = new BABYLON.Texture(imgUrl, scene, true, false, samplingMode);
             this._spriteTexture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
@@ -54698,6 +54555,206 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    BABYLON.Scene.prototype._internalPickSprites = function (ray, predicate, fastCheck, camera) {
+        if (!BABYLON.PickingInfo) {
+            return null;
+        }
+        var pickingInfo = null;
+        if (!camera) {
+            if (!this.activeCamera) {
+                return null;
+            }
+            camera = this.activeCamera;
+        }
+        if (this.spriteManagers.length > 0) {
+            for (var spriteIndex = 0; spriteIndex < this.spriteManagers.length; spriteIndex++) {
+                var spriteManager = this.spriteManagers[spriteIndex];
+                if (!spriteManager.isPickable) {
+                    continue;
+                }
+                var result = spriteManager.intersects(ray, camera, predicate, fastCheck);
+                if (!result || !result.hit)
+                    continue;
+                if (!fastCheck && pickingInfo != null && result.distance >= pickingInfo.distance)
+                    continue;
+                pickingInfo = result;
+                if (fastCheck) {
+                    break;
+                }
+            }
+        }
+        return pickingInfo || new BABYLON.PickingInfo();
+    };
+    BABYLON.Scene.prototype.pickSprite = function (x, y, predicate, fastCheck, camera) {
+        this.createPickingRayInCameraSpaceToRef(x, y, this._tempSpritePickingRay, camera);
+        return this._internalPickSprites(this._tempSpritePickingRay, predicate, fastCheck, camera);
+    };
+    BABYLON.Scene.prototype.pickSpriteWithRay = function (ray, predicate, fastCheck, camera) {
+        if (!this._tempSpritePickingRay) {
+            return null;
+        }
+        if (!camera) {
+            if (!this.activeCamera) {
+                return null;
+            }
+            camera = this.activeCamera;
+        }
+        BABYLON.Ray.TransformToRef(ray, camera.getViewMatrix(), this._tempSpritePickingRay);
+        return this._internalPickSprites(this._tempSpritePickingRay, predicate, fastCheck, camera);
+    };
+    BABYLON.Scene.prototype.setPointerOverSprite = function (sprite) {
+        if (this._pointerOverSprite === sprite) {
+            return;
+        }
+        if (this._pointerOverSprite && this._pointerOverSprite.actionManager) {
+            this._pointerOverSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPointerOutTrigger, BABYLON.ActionEvent.CreateNewFromSprite(this._pointerOverSprite, this));
+        }
+        this._pointerOverSprite = sprite;
+        if (this._pointerOverSprite && this._pointerOverSprite.actionManager) {
+            this._pointerOverSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPointerOverTrigger, BABYLON.ActionEvent.CreateNewFromSprite(this._pointerOverSprite, this));
+        }
+    };
+    BABYLON.Scene.prototype.getPointerOverSprite = function () {
+        return this._pointerOverSprite;
+    };
+    /**
+     * Defines the sprite scene component responsible to manage sprites
+     * in a given scene.
+     */
+    var SpriteSceneComponent = /** @class */ (function () {
+        /**
+         * Creates a new instance of the component for the given scene
+         * @param scene Defines the scene to register the component in
+         */
+        function SpriteSceneComponent(scene) {
+            /**
+             * The component name helpfull to identify the component in the list of scene components.
+             */
+            this.name = BABYLON.SceneComponentConstants.NAME_SPRITE;
+            this.scene = scene;
+            this.scene.spriteManagers = new Array();
+            this.scene._tempSpritePickingRay = BABYLON.Ray ? BABYLON.Ray.Zero() : null;
+            this.scene.onBeforeSpritesRenderingObservable = new BABYLON.Observable();
+            this.scene.onAfterSpritesRenderingObservable = new BABYLON.Observable();
+            this._spritePredicate = function (sprite) {
+                return sprite.isPickable && sprite.actionManager && sprite.actionManager.hasPointerTriggers;
+            };
+        }
+        /**
+         * Registers the component in a given scene
+         */
+        SpriteSceneComponent.prototype.register = function () {
+            this.scene._pointerMoveStage.registerStep(BABYLON.SceneComponentConstants.STEP_POINTERMOVE_SPRITE, this, this._pointerMove);
+            this.scene._pointerDownStage.registerStep(BABYLON.SceneComponentConstants.STEP_POINTERDOWN_SPRITE, this, this._pointerDown);
+            this.scene._pointerUpStage.registerStep(BABYLON.SceneComponentConstants.STEP_POINTERUP_SPRITE, this, this._pointerUp);
+        };
+        /**
+         * Rebuilds the elements related to this component in case of
+         * context lost for instance.
+         */
+        SpriteSceneComponent.prototype.rebuild = function () {
+            /** Nothing to do for sprites */
+        };
+        /**
+         * Disposes the component and the associated ressources.
+         */
+        SpriteSceneComponent.prototype.dispose = function () {
+            this.scene.onBeforeSpritesRenderingObservable.clear();
+            this.scene.onAfterSpritesRenderingObservable.clear();
+            var spriteManagers = this.scene.spriteManagers;
+            while (spriteManagers.length) {
+                spriteManagers[0].dispose();
+            }
+        };
+        SpriteSceneComponent.prototype._pickSpriteButKeepRay = function (originalPointerInfo, x, y, fastCheck, camera) {
+            var result = this.scene.pickSprite(x, y, this._spritePredicate, fastCheck, camera);
+            if (result) {
+                result.ray = originalPointerInfo ? originalPointerInfo.ray : null;
+            }
+            return result;
+        };
+        SpriteSceneComponent.prototype._pointerMove = function (unTranslatedPointerX, unTranslatedPointerY, pickResult, isMeshPicked, canvas) {
+            var scene = this.scene;
+            if (isMeshPicked) {
+                scene.setPointerOverSprite(null);
+            }
+            else {
+                pickResult = this._pickSpriteButKeepRay(pickResult, unTranslatedPointerX, unTranslatedPointerY, false, scene.cameraToUseForPointers || undefined);
+                if (pickResult && pickResult.hit && pickResult.pickedSprite) {
+                    scene.setPointerOverSprite(pickResult.pickedSprite);
+                    if (scene._pointerOverSprite && scene._pointerOverSprite.actionManager && scene._pointerOverSprite.actionManager.hoverCursor) {
+                        canvas.style.cursor = scene._pointerOverSprite.actionManager.hoverCursor;
+                    }
+                    else {
+                        canvas.style.cursor = scene.hoverCursor;
+                    }
+                }
+                else {
+                    scene.setPointerOverSprite(null);
+                    // Restore pointer
+                    canvas.style.cursor = scene.defaultCursor;
+                }
+            }
+            return pickResult;
+        };
+        SpriteSceneComponent.prototype._pointerDown = function (unTranslatedPointerX, unTranslatedPointerY, pickResult, evt) {
+            var scene = this.scene;
+            scene._pickedDownSprite = null;
+            if (scene.spriteManagers.length > 0) {
+                pickResult = scene.pickSprite(unTranslatedPointerX, unTranslatedPointerY, this._spritePredicate, false, scene.cameraToUseForPointers || undefined);
+                if (pickResult && pickResult.hit && pickResult.pickedSprite) {
+                    if (pickResult.pickedSprite.actionManager) {
+                        scene._pickedDownSprite = pickResult.pickedSprite;
+                        switch (evt.button) {
+                            case 0:
+                                pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnLeftPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, scene, evt));
+                                break;
+                            case 1:
+                                pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnCenterPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, scene, evt));
+                                break;
+                            case 2:
+                                pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnRightPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, scene, evt));
+                                break;
+                        }
+                        if (pickResult.pickedSprite.actionManager) {
+                            pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickDownTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, scene, evt));
+                        }
+                    }
+                }
+            }
+            return pickResult;
+        };
+        SpriteSceneComponent.prototype._pointerUp = function (unTranslatedPointerX, unTranslatedPointerY, pickResult, evt) {
+            var scene = this.scene;
+            if (scene.spriteManagers.length > 0) {
+                var spritePickResult = scene.pickSprite(unTranslatedPointerX, unTranslatedPointerY, this._spritePredicate, false, scene.cameraToUseForPointers || undefined);
+                if (spritePickResult) {
+                    if (spritePickResult.hit && spritePickResult.pickedSprite) {
+                        if (spritePickResult.pickedSprite.actionManager) {
+                            spritePickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickUpTrigger, BABYLON.ActionEvent.CreateNewFromSprite(spritePickResult.pickedSprite, scene, evt));
+                            if (spritePickResult.pickedSprite.actionManager) {
+                                if (!this.scene._isPointerSwiping()) {
+                                    spritePickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(spritePickResult.pickedSprite, scene, evt));
+                                }
+                            }
+                        }
+                    }
+                    if (scene._pickedDownSprite && scene._pickedDownSprite.actionManager && scene._pickedDownSprite !== spritePickResult.pickedSprite) {
+                        scene._pickedDownSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickOutTrigger, BABYLON.ActionEvent.CreateNewFromSprite(scene._pickedDownSprite, scene, evt));
+                    }
+                }
+            }
+            return pickResult;
+        };
+        return SpriteSceneComponent;
+    }());
+    BABYLON.SpriteSceneComponent = SpriteSceneComponent;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.spriteSceneComponent.js.map
+
+var BABYLON;
+(function (BABYLON) {
     var IntersectionInfo = /** @class */ (function () {
         function IntersectionInfo(bu, bv, distance) {
             this.bu = bu;
@@ -62278,6 +62335,10 @@ var BABYLON;
                 this._limitVelocityGradientsTexture.dispose();
                 this._limitVelocityGradientsTexture = null;
             }
+            if (this._dragGradientsTexture) {
+                this._dragGradientsTexture.dispose();
+                this._dragGradientsTexture = null;
+            }
             if (this._randomTexture) {
                 this._randomTexture.dispose();
                 this._randomTexture = null;
@@ -105752,6 +105813,9 @@ var BABYLON;
                     return;
                 }
                 this._captureSpritesRenderTime = value;
+                if (!this.scene.spriteManagers) {
+                    return;
+                }
                 if (value) {
                     this._onBeforeSpritesRenderingObserver = this.scene.onBeforeSpritesRenderingObservable.add(function () {
                         BABYLON.Tools.StartPerformanceCounter("Sprites");

+ 262 - 198
dist/preview release/babylon.no-module.max.js

@@ -23165,7 +23165,7 @@ var BABYLON;
             info.scene = this._scene;
             info.camera = this._scene.activeCamera;
             // Dispatch sprites
-            if (renderSprites) {
+            if (this._scene.spriteManagers && renderSprites) {
                 for (var index = 0; index < this._scene.spriteManagers.length; index++) {
                     var manager = this._scene.spriteManagers[index];
                     this.dispatchSprites(manager);
@@ -23702,6 +23702,7 @@ var BABYLON;
         SceneComponentConstants.NAME_GEOMETRYBUFFERRENDERER = "GeometryBufferRenderer";
         SceneComponentConstants.NAME_DEPTHRENDERER = "DepthRenderer";
         SceneComponentConstants.NAME_POSTPROCESSRENDERPIPELINEMANAGER = "PostProcessRenderPipelineManager";
+        SceneComponentConstants.NAME_SPRITE = "Sprite";
         SceneComponentConstants.STEP_ISREADYFORMESH_EFFECTLAYER = 0;
         SceneComponentConstants.STEP_BEFOREEVALUATEACTIVEMESH_BOUNDINGBOXRENDERER = 0;
         SceneComponentConstants.STEP_EVALUATESUBMESH_BOUNDINGBOXRENDERER = 0;
@@ -23721,6 +23722,9 @@ var BABYLON;
         SceneComponentConstants.STEP_GATHERRENDERTARGETS_DEPTHRENDERER = 1;
         SceneComponentConstants.STEP_GATHERRENDERTARGETS_POSTPROCESSRENDERPIPELINEMANAGER = 2;
         SceneComponentConstants.STEP_REBUILDGEOMETRY_POSTPROCESSRENDERPIPELINEMANAGER = 0;
+        SceneComponentConstants.STEP_POINTERMOVE_SPRITE = 0;
+        SceneComponentConstants.STEP_POINTERDOWN_SPRITE = 0;
+        SceneComponentConstants.STEP_POINTERUP_SPRITE = 0;
         return SceneComponentConstants;
     }());
     BABYLON.SceneComponentConstants = SceneComponentConstants;
@@ -24119,16 +24123,6 @@ var BABYLON;
             */
             _this.onAfterParticlesRenderingObservable = new BABYLON.Observable();
             /**
-            * An event triggered when sprites rendering is about to start
-            * Note: This event can be trigger more than once per frame (because sprites can be rendered by render target textures as well)
-            */
-            _this.onBeforeSpritesRenderingObservable = new BABYLON.Observable();
-            /**
-            * An event triggered when sprites rendering is done
-            * Note: This event can be trigger more than once per frame (because sprites can be rendered by render target textures as well)
-            */
-            _this.onAfterSpritesRenderingObservable = new BABYLON.Observable();
-            /**
             * An event triggered when SceneLoader.Append or SceneLoader.Load or SceneLoader.ImportMesh were successfully executed
             */
             _this.onDataLoadedObservable = new BABYLON.Observable();
@@ -24283,11 +24277,6 @@ var BABYLON;
             * Gets or sets a boolean indicating if sprites are enabled on this scene
             */
             _this.spritesEnabled = true;
-            /**
-            * All of the sprite managers added to this scene
-            * @see http://doc.babylonjs.com/babylon101/sprites
-            */
-            _this.spriteManagers = new Array();
             // Skeletons
             _this._skeletonsEnabled = true;
             // Lens flares
@@ -24482,6 +24471,21 @@ var BABYLON;
              * Defines the actions happening when Geometries are rebuilding.
              */
             _this._rebuildGeometryStage = BABYLON.Stage.Create();
+            /**
+             * @hidden
+             * Defines the actions happening when a pointer move event happens.
+             */
+            _this._pointerMoveStage = BABYLON.Stage.Create();
+            /**
+             * @hidden
+             * Defines the actions happening when a pointer down event happens.
+             */
+            _this._pointerDownStage = BABYLON.Stage.Create();
+            /**
+             * @hidden
+             * Defines the actions happening when a pointer up event happens.
+             */
+            _this._pointerUpStage = BABYLON.Stage.Create();
             _this._activeMeshesFrozen = false;
             /** @hidden */
             _this._allowPostProcessClearColor = true;
@@ -25234,13 +25238,6 @@ var BABYLON;
             this._alternateSceneUbo.addUniform("view", 16);
         };
         // Pointers handling
-        Scene.prototype._pickSpriteButKeepRay = function (originalPointerInfo, x, y, predicate, fastCheck, camera) {
-            var result = this.pickSprite(x, y, predicate, fastCheck, camera);
-            if (result) {
-                result.ray = originalPointerInfo ? originalPointerInfo.ray : null;
-            }
-            return result;
-        };
         Scene.prototype._setRayOnPointerInfo = function (pointerInfo) {
             if (pointerInfo.pickInfo) {
                 if (!pointerInfo.pickInfo.ray) {
@@ -25267,39 +25264,16 @@ var BABYLON;
             if (!canvas) {
                 return this;
             }
-            if (pickResult && pickResult.hit && pickResult.pickedMesh) {
-                this.setPointerOverSprite(null);
+            var isMeshPicked = (pickResult && pickResult.hit && pickResult.pickedMesh) ? true : false;
+            if (isMeshPicked) {
                 this.setPointerOverMesh(pickResult.pickedMesh);
-                if (this._pointerOverMesh && this._pointerOverMesh.actionManager && this._pointerOverMesh.actionManager.hasPointerTriggers) {
-                    if (this._pointerOverMesh.actionManager.hoverCursor) {
-                        canvas.style.cursor = this._pointerOverMesh.actionManager.hoverCursor;
-                    }
-                    else {
-                        canvas.style.cursor = this.hoverCursor;
-                    }
-                }
-                else {
-                    canvas.style.cursor = this.defaultCursor;
-                }
             }
             else {
                 this.setPointerOverMesh(null);
-                // Sprites
-                pickResult = this._pickSpriteButKeepRay(pickResult, this._unTranslatedPointerX, this._unTranslatedPointerY, this._spritePredicate, false, this.cameraToUseForPointers || undefined);
-                if (pickResult && pickResult.hit && pickResult.pickedSprite) {
-                    this.setPointerOverSprite(pickResult.pickedSprite);
-                    if (this._pointerOverSprite && this._pointerOverSprite.actionManager && this._pointerOverSprite.actionManager.hoverCursor) {
-                        canvas.style.cursor = this._pointerOverSprite.actionManager.hoverCursor;
-                    }
-                    else {
-                        canvas.style.cursor = this.hoverCursor;
-                    }
-                }
-                else {
-                    this.setPointerOverSprite(null);
-                    // Restore pointer
-                    canvas.style.cursor = this.defaultCursor;
-                }
+            }
+            for (var _i = 0, _a = this._pointerMoveStage; _i < _a.length; _i++) {
+                var step = _a[_i];
+                pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, isMeshPicked, canvas);
             }
             if (pickResult) {
                 var type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? BABYLON.PointerEventTypes.POINTERWHEEL : BABYLON.PointerEventTypes.POINTERMOVE;
@@ -25367,8 +25341,7 @@ var BABYLON;
                             if (pickResult && pickResult.hit && pickResult.pickedMesh && actionManager) {
                                 if (_this._totalPointersPressed !== 0 &&
                                     ((Date.now() - _this._startingPointerTime) > Scene.LongPressDelay) &&
-                                    (Math.abs(_this._startingPointerPosition.x - _this._pointerX) < Scene.DragMovementThreshold &&
-                                        Math.abs(_this._startingPointerPosition.y - _this._pointerY) < Scene.DragMovementThreshold)) {
+                                    !_this._isPointerSwiping()) {
                                     _this._startingPointerTime = 0;
                                     actionManager.processTrigger(BABYLON.ActionManager.OnLongPressTrigger, BABYLON.ActionEvent.CreateNew(pickResult.pickedMesh, evt));
                                 }
@@ -25377,6 +25350,12 @@ var BABYLON;
                     }
                 }
             }
+            else {
+                for (var _i = 0, _a = this._pointerDownStage; _i < _a.length; _i++) {
+                    var step = _a[_i];
+                    pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, evt);
+                }
+            }
             if (pickResult) {
                 var type = BABYLON.PointerEventTypes.POINTERDOWN;
                 if (this.onPointerDown) {
@@ -25433,6 +25412,14 @@ var BABYLON;
                     }
                 }
             }
+            else {
+                if (!clickInfo.ignore) {
+                    for (var _i = 0, _a = this._pointerUpStage; _i < _a.length; _i++) {
+                        var step = _a[_i];
+                        pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, evt);
+                    }
+                }
+            }
             if (this._pickedDownMesh &&
                 this._pickedDownMesh.actionManager &&
                 this._pickedDownMesh.actionManager.hasSpecificTrigger(BABYLON.ActionManager.OnPickOutTrigger) &&
@@ -25477,6 +25464,11 @@ var BABYLON;
             if (pointerId === void 0) { pointerId = 0; }
             return this._pointerCaptures[pointerId];
         };
+        /** @hidden */
+        Scene.prototype._isPointerSwiping = function () {
+            return Math.abs(this._startingPointerPosition.x - this._pointerX) > Scene.DragMovementThreshold ||
+                Math.abs(this._startingPointerPosition.y - this._pointerY) > Scene.DragMovementThreshold;
+        };
         /**
         * Attach events to the canvas (To handle actionManagers triggers and raise onPointerMove, onPointerDown and onPointerUp
         * @param attachUp defines if you want to attach events to pointerup
@@ -25523,8 +25515,7 @@ var BABYLON;
                 }
                 if (checkPicking) {
                     var btn = evt.button;
-                    clickInfo.hasSwiped = Math.abs(_this._startingPointerPosition.x - _this._pointerX) > Scene.DragMovementThreshold ||
-                        Math.abs(_this._startingPointerPosition.y - _this._pointerY) > Scene.DragMovementThreshold;
+                    clickInfo.hasSwiped = _this._isPointerSwiping();
                     if (!clickInfo.hasSwiped) {
                         var checkSingleClickImmediately = !Scene.ExclusiveDoubleClickMode;
                         if (!checkSingleClickImmediately) {
@@ -25564,8 +25555,7 @@ var BABYLON;
                                 !_this._doubleClickOccured) {
                                 // pointer has not moved for 2 clicks, it's a double click
                                 if (!clickInfo.hasSwiped &&
-                                    Math.abs(_this._previousStartingPointerPosition.x - _this._startingPointerPosition.x) < Scene.DragMovementThreshold &&
-                                    Math.abs(_this._previousStartingPointerPosition.y - _this._startingPointerPosition.y) < Scene.DragMovementThreshold) {
+                                    !_this._isPointerSwiping()) {
                                     _this._previousStartingPointerTime = 0;
                                     _this._doubleClickOccured = true;
                                     clickInfo.doubleClick = true;
@@ -25609,9 +25599,6 @@ var BABYLON;
                 clickInfo.ignore = true;
                 cb(clickInfo, _this._currentPickResult);
             };
-            this._spritePredicate = function (sprite) {
-                return sprite.isPickable && sprite.actionManager && sprite.actionManager.hasPointerTriggers;
-            };
             this._onPointerMove = function (evt) {
                 _this._updatePointerPosition(evt);
                 // PreObservable support
@@ -25657,30 +25644,6 @@ var BABYLON;
                 _this._pickedDownMesh = null;
                 var pickResult = _this.pick(_this._unTranslatedPointerX, _this._unTranslatedPointerY, _this.pointerDownPredicate, false, _this.cameraToUseForPointers);
                 _this._processPointerDown(pickResult, evt);
-                // Sprites
-                _this._pickedDownSprite = null;
-                if (_this.spriteManagers.length > 0) {
-                    pickResult = _this.pickSprite(_this._unTranslatedPointerX, _this._unTranslatedPointerY, _this._spritePredicate, false, _this.cameraToUseForPointers || undefined);
-                    if (pickResult && pickResult.hit && pickResult.pickedSprite) {
-                        if (pickResult.pickedSprite.actionManager) {
-                            _this._pickedDownSprite = pickResult.pickedSprite;
-                            switch (evt.button) {
-                                case 0:
-                                    pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnLeftPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, _this, evt));
-                                    break;
-                                case 1:
-                                    pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnCenterPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, _this, evt));
-                                    break;
-                                case 2:
-                                    pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnRightPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, _this, evt));
-                                    break;
-                            }
-                            if (pickResult.pickedSprite.actionManager) {
-                                pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickDownTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, _this, evt));
-                            }
-                        }
-                    }
-                }
             };
             this._onPointerUp = function (evt) {
                 if (_this._totalPointersPressed === 0) { // We are attaching the pointer up to windows because of a bug in FF                    
@@ -25730,27 +25693,6 @@ var BABYLON;
                         pickResult = _this._currentPickResult;
                     }
                     _this._processPointerUp(pickResult, evt, clickInfo);
-                    // Sprites
-                    if (!clickInfo.ignore) {
-                        if (_this.spriteManagers.length > 0) {
-                            var spritePickResult = _this.pickSprite(_this._unTranslatedPointerX, _this._unTranslatedPointerY, _this._spritePredicate, false, _this.cameraToUseForPointers || undefined);
-                            if (spritePickResult) {
-                                if (spritePickResult.hit && spritePickResult.pickedSprite) {
-                                    if (spritePickResult.pickedSprite.actionManager) {
-                                        spritePickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickUpTrigger, BABYLON.ActionEvent.CreateNewFromSprite(spritePickResult.pickedSprite, _this, evt));
-                                        if (spritePickResult.pickedSprite.actionManager) {
-                                            if (Math.abs(_this._startingPointerPosition.x - _this._pointerX) < Scene.DragMovementThreshold && Math.abs(_this._startingPointerPosition.y - _this._pointerY) < Scene.DragMovementThreshold) {
-                                                spritePickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(spritePickResult.pickedSprite, _this, evt));
-                                            }
-                                        }
-                                    }
-                                }
-                                if (_this._pickedDownSprite && _this._pickedDownSprite.actionManager && _this._pickedDownSprite !== spritePickResult.pickedSprite) {
-                                    _this._pickedDownSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickOutTrigger, BABYLON.ActionEvent.CreateNewFromSprite(_this._pickedDownSprite, _this, evt));
-                                }
-                            }
-                        }
-                    }
                     _this._previousPickResult = _this._currentPickResult;
                 });
             };
@@ -28155,6 +28097,9 @@ var BABYLON;
             this._beforeCameraUpdateStage.clear();
             this._gatherRenderTargetsStage.clear();
             this._rebuildGeometryStage.clear();
+            this._pointerMoveStage.clear();
+            this._pointerDownStage.clear();
+            this._pointerUpStage.clear();
             for (var _i = 0, _a = this._components; _i < _a.length; _i++) {
                 var component = _a[_i];
                 component.dispose();
@@ -28199,8 +28144,6 @@ var BABYLON;
             this.onAfterActiveMeshesEvaluationObservable.clear();
             this.onBeforeParticlesRenderingObservable.clear();
             this.onAfterParticlesRenderingObservable.clear();
-            this.onBeforeSpritesRenderingObservable.clear();
-            this.onAfterSpritesRenderingObservable.clear();
             this.onBeforeDrawPhaseObservable.clear();
             this.onAfterDrawPhaseObservable.clear();
             this.onBeforePhysicsObservable.clear();
@@ -28260,10 +28203,6 @@ var BABYLON;
             while (this.particleSystems.length) {
                 this.particleSystems[0].dispose();
             }
-            // Release sprites
-            while (this.spriteManagers.length) {
-                this.spriteManagers[0].dispose();
-            }
             // Release postProcesses
             while (this.postProcesses.length) {
                 this.postProcesses[0].dispose();
@@ -28524,36 +28463,6 @@ var BABYLON;
             }
             return pickingInfos;
         };
-        Scene.prototype._internalPickSprites = function (ray, predicate, fastCheck, camera) {
-            if (!BABYLON.PickingInfo) {
-                return null;
-            }
-            var pickingInfo = null;
-            if (!camera) {
-                if (!this.activeCamera) {
-                    return null;
-                }
-                camera = this.activeCamera;
-            }
-            if (this.spriteManagers.length > 0) {
-                for (var spriteIndex = 0; spriteIndex < this.spriteManagers.length; spriteIndex++) {
-                    var spriteManager = this.spriteManagers[spriteIndex];
-                    if (!spriteManager.isPickable) {
-                        continue;
-                    }
-                    var result = spriteManager.intersects(ray, camera, predicate, fastCheck);
-                    if (!result || !result.hit)
-                        continue;
-                    if (!fastCheck && pickingInfo != null && result.distance >= pickingInfo.distance)
-                        continue;
-                    pickingInfo = result;
-                    if (fastCheck) {
-                        break;
-                    }
-                }
-            }
-            return pickingInfo || new BABYLON.PickingInfo();
-        };
         /** Launch a ray to try to pick a mesh in the scene
          * @param x position on screen
          * @param y position on screen
@@ -28576,41 +28485,9 @@ var BABYLON;
             }
             return result;
         };
-        /** Launch a ray to try to pick a sprite in the scene
-         * @param x position on screen
-         * @param y position on screen
-         * @param predicate Predicate function used to determine eligible sprites. Can be set to null. In this case, a sprite must have isPickable set to true
-         * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null.
-         * @param camera camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
-         * @returns a PickingInfo
-         */
-        Scene.prototype.pickSprite = function (x, y, predicate, fastCheck, camera) {
-            this.createPickingRayInCameraSpaceToRef(x, y, this._tempPickingRay, camera);
-            return this._internalPickSprites(this._tempPickingRay, predicate, fastCheck, camera);
-        };
-        /** Use the given ray to pick a sprite in the scene
-         * @param ray The ray (in world space) to use to pick meshes
-         * @param predicate Predicate function used to determine eligible sprites. Can be set to null. In this case, a sprite must have isPickable set to true
-         * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null.
-         * @param camera camera to use. Can be set to null. In this case, the scene.activeCamera will be used
-         * @returns a PickingInfo
-         */
-        Scene.prototype.pickSpriteWithRay = function (ray, predicate, fastCheck, camera) {
-            if (!this._cachedRayForTransform) {
-                this._cachedRayForTransform = BABYLON.Ray.Zero();
-            }
-            if (!camera) {
-                if (!this.activeCamera) {
-                    return null;
-                }
-                camera = this.activeCamera;
-            }
-            BABYLON.Ray.TransformToRef(ray, camera.getViewMatrix(), this._cachedRayForTransform);
-            return this._internalPickSprites(this._cachedRayForTransform, predicate, fastCheck, camera);
-        };
         /** Use the given ray to pick a mesh in the scene
          * @param ray The ray to use to pick meshes
-         * @param predicate Predicate function used to determine eligible sprites. Can be set to null. In this case, a sprite must have isPickable set to true
+         * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must have isPickable set to true
          * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null
          * @returns a PickingInfo
          */
@@ -28687,29 +28564,6 @@ var BABYLON;
         Scene.prototype.getPointerOverMesh = function () {
             return this._pointerOverMesh;
         };
-        /**
-         * Force the sprite under the pointer
-         * @param sprite defines the sprite to use
-         */
-        Scene.prototype.setPointerOverSprite = function (sprite) {
-            if (this._pointerOverSprite === sprite) {
-                return;
-            }
-            if (this._pointerOverSprite && this._pointerOverSprite.actionManager) {
-                this._pointerOverSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPointerOutTrigger, BABYLON.ActionEvent.CreateNewFromSprite(this._pointerOverSprite, this));
-            }
-            this._pointerOverSprite = sprite;
-            if (this._pointerOverSprite && this._pointerOverSprite.actionManager) {
-                this._pointerOverSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPointerOverTrigger, BABYLON.ActionEvent.CreateNewFromSprite(this._pointerOverSprite, this));
-            }
-        };
-        /**
-         * Gets the sprite under the pointer
-         * @returns a Sprite or null if no sprite is under the pointer
-         */
-        Scene.prototype.getPointerOverSprite = function () {
-            return this._pointerOverSprite;
-        };
         // Physics
         /**
          * Gets the current physics engine
@@ -54352,6 +54206,9 @@ var BABYLON;
             */
             this.onDisposeObservable = new BABYLON.Observable();
             this._vertexBuffers = {};
+            if (!scene._getComponent(BABYLON.SceneComponentConstants.NAME_SPRITE)) {
+                scene._addComponent(new BABYLON.SpriteSceneComponent(scene));
+            }
             this._capacity = capacity;
             this._spriteTexture = new BABYLON.Texture(imgUrl, scene, true, false, samplingMode);
             this._spriteTexture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
@@ -54665,6 +54522,206 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    BABYLON.Scene.prototype._internalPickSprites = function (ray, predicate, fastCheck, camera) {
+        if (!BABYLON.PickingInfo) {
+            return null;
+        }
+        var pickingInfo = null;
+        if (!camera) {
+            if (!this.activeCamera) {
+                return null;
+            }
+            camera = this.activeCamera;
+        }
+        if (this.spriteManagers.length > 0) {
+            for (var spriteIndex = 0; spriteIndex < this.spriteManagers.length; spriteIndex++) {
+                var spriteManager = this.spriteManagers[spriteIndex];
+                if (!spriteManager.isPickable) {
+                    continue;
+                }
+                var result = spriteManager.intersects(ray, camera, predicate, fastCheck);
+                if (!result || !result.hit)
+                    continue;
+                if (!fastCheck && pickingInfo != null && result.distance >= pickingInfo.distance)
+                    continue;
+                pickingInfo = result;
+                if (fastCheck) {
+                    break;
+                }
+            }
+        }
+        return pickingInfo || new BABYLON.PickingInfo();
+    };
+    BABYLON.Scene.prototype.pickSprite = function (x, y, predicate, fastCheck, camera) {
+        this.createPickingRayInCameraSpaceToRef(x, y, this._tempSpritePickingRay, camera);
+        return this._internalPickSprites(this._tempSpritePickingRay, predicate, fastCheck, camera);
+    };
+    BABYLON.Scene.prototype.pickSpriteWithRay = function (ray, predicate, fastCheck, camera) {
+        if (!this._tempSpritePickingRay) {
+            return null;
+        }
+        if (!camera) {
+            if (!this.activeCamera) {
+                return null;
+            }
+            camera = this.activeCamera;
+        }
+        BABYLON.Ray.TransformToRef(ray, camera.getViewMatrix(), this._tempSpritePickingRay);
+        return this._internalPickSprites(this._tempSpritePickingRay, predicate, fastCheck, camera);
+    };
+    BABYLON.Scene.prototype.setPointerOverSprite = function (sprite) {
+        if (this._pointerOverSprite === sprite) {
+            return;
+        }
+        if (this._pointerOverSprite && this._pointerOverSprite.actionManager) {
+            this._pointerOverSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPointerOutTrigger, BABYLON.ActionEvent.CreateNewFromSprite(this._pointerOverSprite, this));
+        }
+        this._pointerOverSprite = sprite;
+        if (this._pointerOverSprite && this._pointerOverSprite.actionManager) {
+            this._pointerOverSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPointerOverTrigger, BABYLON.ActionEvent.CreateNewFromSprite(this._pointerOverSprite, this));
+        }
+    };
+    BABYLON.Scene.prototype.getPointerOverSprite = function () {
+        return this._pointerOverSprite;
+    };
+    /**
+     * Defines the sprite scene component responsible to manage sprites
+     * in a given scene.
+     */
+    var SpriteSceneComponent = /** @class */ (function () {
+        /**
+         * Creates a new instance of the component for the given scene
+         * @param scene Defines the scene to register the component in
+         */
+        function SpriteSceneComponent(scene) {
+            /**
+             * The component name helpfull to identify the component in the list of scene components.
+             */
+            this.name = BABYLON.SceneComponentConstants.NAME_SPRITE;
+            this.scene = scene;
+            this.scene.spriteManagers = new Array();
+            this.scene._tempSpritePickingRay = BABYLON.Ray ? BABYLON.Ray.Zero() : null;
+            this.scene.onBeforeSpritesRenderingObservable = new BABYLON.Observable();
+            this.scene.onAfterSpritesRenderingObservable = new BABYLON.Observable();
+            this._spritePredicate = function (sprite) {
+                return sprite.isPickable && sprite.actionManager && sprite.actionManager.hasPointerTriggers;
+            };
+        }
+        /**
+         * Registers the component in a given scene
+         */
+        SpriteSceneComponent.prototype.register = function () {
+            this.scene._pointerMoveStage.registerStep(BABYLON.SceneComponentConstants.STEP_POINTERMOVE_SPRITE, this, this._pointerMove);
+            this.scene._pointerDownStage.registerStep(BABYLON.SceneComponentConstants.STEP_POINTERDOWN_SPRITE, this, this._pointerDown);
+            this.scene._pointerUpStage.registerStep(BABYLON.SceneComponentConstants.STEP_POINTERUP_SPRITE, this, this._pointerUp);
+        };
+        /**
+         * Rebuilds the elements related to this component in case of
+         * context lost for instance.
+         */
+        SpriteSceneComponent.prototype.rebuild = function () {
+            /** Nothing to do for sprites */
+        };
+        /**
+         * Disposes the component and the associated ressources.
+         */
+        SpriteSceneComponent.prototype.dispose = function () {
+            this.scene.onBeforeSpritesRenderingObservable.clear();
+            this.scene.onAfterSpritesRenderingObservable.clear();
+            var spriteManagers = this.scene.spriteManagers;
+            while (spriteManagers.length) {
+                spriteManagers[0].dispose();
+            }
+        };
+        SpriteSceneComponent.prototype._pickSpriteButKeepRay = function (originalPointerInfo, x, y, fastCheck, camera) {
+            var result = this.scene.pickSprite(x, y, this._spritePredicate, fastCheck, camera);
+            if (result) {
+                result.ray = originalPointerInfo ? originalPointerInfo.ray : null;
+            }
+            return result;
+        };
+        SpriteSceneComponent.prototype._pointerMove = function (unTranslatedPointerX, unTranslatedPointerY, pickResult, isMeshPicked, canvas) {
+            var scene = this.scene;
+            if (isMeshPicked) {
+                scene.setPointerOverSprite(null);
+            }
+            else {
+                pickResult = this._pickSpriteButKeepRay(pickResult, unTranslatedPointerX, unTranslatedPointerY, false, scene.cameraToUseForPointers || undefined);
+                if (pickResult && pickResult.hit && pickResult.pickedSprite) {
+                    scene.setPointerOverSprite(pickResult.pickedSprite);
+                    if (scene._pointerOverSprite && scene._pointerOverSprite.actionManager && scene._pointerOverSprite.actionManager.hoverCursor) {
+                        canvas.style.cursor = scene._pointerOverSprite.actionManager.hoverCursor;
+                    }
+                    else {
+                        canvas.style.cursor = scene.hoverCursor;
+                    }
+                }
+                else {
+                    scene.setPointerOverSprite(null);
+                    // Restore pointer
+                    canvas.style.cursor = scene.defaultCursor;
+                }
+            }
+            return pickResult;
+        };
+        SpriteSceneComponent.prototype._pointerDown = function (unTranslatedPointerX, unTranslatedPointerY, pickResult, evt) {
+            var scene = this.scene;
+            scene._pickedDownSprite = null;
+            if (scene.spriteManagers.length > 0) {
+                pickResult = scene.pickSprite(unTranslatedPointerX, unTranslatedPointerY, this._spritePredicate, false, scene.cameraToUseForPointers || undefined);
+                if (pickResult && pickResult.hit && pickResult.pickedSprite) {
+                    if (pickResult.pickedSprite.actionManager) {
+                        scene._pickedDownSprite = pickResult.pickedSprite;
+                        switch (evt.button) {
+                            case 0:
+                                pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnLeftPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, scene, evt));
+                                break;
+                            case 1:
+                                pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnCenterPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, scene, evt));
+                                break;
+                            case 2:
+                                pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnRightPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, scene, evt));
+                                break;
+                        }
+                        if (pickResult.pickedSprite.actionManager) {
+                            pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickDownTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, scene, evt));
+                        }
+                    }
+                }
+            }
+            return pickResult;
+        };
+        SpriteSceneComponent.prototype._pointerUp = function (unTranslatedPointerX, unTranslatedPointerY, pickResult, evt) {
+            var scene = this.scene;
+            if (scene.spriteManagers.length > 0) {
+                var spritePickResult = scene.pickSprite(unTranslatedPointerX, unTranslatedPointerY, this._spritePredicate, false, scene.cameraToUseForPointers || undefined);
+                if (spritePickResult) {
+                    if (spritePickResult.hit && spritePickResult.pickedSprite) {
+                        if (spritePickResult.pickedSprite.actionManager) {
+                            spritePickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickUpTrigger, BABYLON.ActionEvent.CreateNewFromSprite(spritePickResult.pickedSprite, scene, evt));
+                            if (spritePickResult.pickedSprite.actionManager) {
+                                if (!this.scene._isPointerSwiping()) {
+                                    spritePickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(spritePickResult.pickedSprite, scene, evt));
+                                }
+                            }
+                        }
+                    }
+                    if (scene._pickedDownSprite && scene._pickedDownSprite.actionManager && scene._pickedDownSprite !== spritePickResult.pickedSprite) {
+                        scene._pickedDownSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickOutTrigger, BABYLON.ActionEvent.CreateNewFromSprite(scene._pickedDownSprite, scene, evt));
+                    }
+                }
+            }
+            return pickResult;
+        };
+        return SpriteSceneComponent;
+    }());
+    BABYLON.SpriteSceneComponent = SpriteSceneComponent;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.spriteSceneComponent.js.map
+
+var BABYLON;
+(function (BABYLON) {
     var IntersectionInfo = /** @class */ (function () {
         function IntersectionInfo(bu, bv, distance) {
             this.bu = bu;
@@ -62245,6 +62302,10 @@ var BABYLON;
                 this._limitVelocityGradientsTexture.dispose();
                 this._limitVelocityGradientsTexture = null;
             }
+            if (this._dragGradientsTexture) {
+                this._dragGradientsTexture.dispose();
+                this._dragGradientsTexture = null;
+            }
             if (this._randomTexture) {
                 this._randomTexture.dispose();
                 this._randomTexture = null;
@@ -105719,6 +105780,9 @@ var BABYLON;
                     return;
                 }
                 this._captureSpritesRenderTime = value;
+                if (!this.scene.spriteManagers) {
+                    return;
+                }
                 if (value) {
                     this._onBeforeSpritesRenderingObserver = this.scene.onBeforeSpritesRenderingObservable.add(function () {
                         BABYLON.Tools.StartPerformanceCounter("Sprites");

文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/babylon.worker.js


文件差異過大導致無法顯示
+ 264 - 200
dist/preview release/es6.js


文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js.map


文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js.map


+ 19 - 5
dist/preview release/viewer/babylon.viewer.d.ts

@@ -168,11 +168,11 @@ declare module BabylonViewer {
                 * Mainly used for help and errors
                 * @param subScreen the name of the subScreen. Those can be defined in the configuration object
                 */
-            showOverlayScreen(subScreen: string): Promise<string> | Promise<Template>;
+            showOverlayScreen(subScreen: string): Promise<Template> | Promise<string>;
             /**
                 * Hide the overlay screen.
                 */
-            hideOverlayScreen(): Promise<string> | Promise<Template>;
+            hideOverlayScreen(): Promise<Template> | Promise<string>;
             /**
                 * show the viewer (in case it was hidden)
                 *
@@ -189,11 +189,11 @@ declare module BabylonViewer {
                 * Show the loading screen.
                 * The loading screen can be configured using the configuration object
                 */
-            showLoadingScreen(): Promise<string> | Promise<Template>;
+            showLoadingScreen(): Promise<Template> | Promise<string>;
             /**
                 * Hide the loading screen
                 */
-            hideLoadingScreen(): Promise<string> | Promise<Template>;
+            hideLoadingScreen(): Promise<Template> | Promise<string>;
             dispose(): void;
             protected _onConfigurationLoaded(configuration: ViewerConfiguration): void;
     }
@@ -924,7 +924,7 @@ declare module BabylonViewer {
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 declare module BabylonViewer {
@@ -1558,6 +1558,20 @@ declare module BabylonViewer {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 declare module BabylonViewer {
+    /**
+        * A custom upgrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedUpgrade(sceneManager: SceneManager): boolean;
+    /**
+        * A custom degrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedDegrade(sceneManager: SceneManager): boolean;
+}
+declare module BabylonViewer {
 }
 declare module BabylonViewer {
     export interface IEnvironmentMapConfiguration {

文件差異過大導致無法顯示
+ 2 - 2
dist/preview release/viewer/babylon.viewer.js


文件差異過大導致無法顯示
+ 4 - 4
dist/preview release/viewer/babylon.viewer.max.js


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

@@ -200,11 +200,11 @@ declare module 'babylonjs-viewer/viewer/defaultViewer' {
                 * Mainly used for help and errors
                 * @param subScreen the name of the subScreen. Those can be defined in the configuration object
                 */
-            showOverlayScreen(subScreen: string): Promise<string> | Promise<Template>;
+            showOverlayScreen(subScreen: string): Promise<Template> | Promise<string>;
             /**
                 * Hide the overlay screen.
                 */
-            hideOverlayScreen(): Promise<string> | Promise<Template>;
+            hideOverlayScreen(): Promise<Template> | Promise<string>;
             /**
                 * show the viewer (in case it was hidden)
                 *
@@ -221,11 +221,11 @@ declare module 'babylonjs-viewer/viewer/defaultViewer' {
                 * Show the loading screen.
                 * The loading screen can be configured using the configuration object
                 */
-            showLoadingScreen(): Promise<string> | Promise<Template>;
+            showLoadingScreen(): Promise<Template> | Promise<string>;
             /**
                 * Hide the loading screen
                 */
-            hideLoadingScreen(): Promise<string> | Promise<Template>;
+            hideLoadingScreen(): Promise<Template> | Promise<string>;
             dispose(): void;
             protected _onConfigurationLoaded(configuration: ViewerConfiguration): void;
     }
@@ -985,13 +985,14 @@ declare module 'babylonjs-viewer/templating/viewerTemplatePlugin' {
 }
 
 declare module 'babylonjs-viewer/optimizer/custom' {
+    import { extendedUpgrade } from "babylonjs-viewer/optimizer/custom/extended";
     import { SceneManager } from "babylonjs-viewer/managers/sceneManager";
     /**
       *
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 
@@ -1662,6 +1663,22 @@ declare module 'babylonjs-viewer/loader/plugins' {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 
+declare module 'babylonjs-viewer/optimizer/custom/extended' {
+    import { SceneManager } from 'babylonjs-viewer/managers/sceneManager';
+    /**
+        * A custom upgrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedUpgrade(sceneManager: SceneManager): boolean;
+    /**
+        * A custom degrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedDegrade(sceneManager: SceneManager): boolean;
+}
+
 declare module 'babylonjs-viewer/configuration/interfaces' {
     export * from 'babylonjs-viewer/configuration/interfaces/cameraConfiguration';
     export * from 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration';

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

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