Преглед изворни кода

New scene.pointerDownPredicate, scene.pointerMovePredicate, scene.pointerUpPredicate to define your own predicates for meshes picking selection

David Catuhe пре 10 година
родитељ
комит
ce9f7a5a2e

Разлика између датотеке није приказан због своје велике величине
+ 22 - 32
dist/preview release/babylon.core.js


Разлика између датотеке није приказан због своје велике величине
+ 1041 - 1028
dist/preview release/babylon.d.ts


Разлика између датотеке није приказан због своје велике величине
+ 29 - 41
dist/preview release/babylon.js


Разлика између датотеке није приказан због своје велике величине
+ 4860 - 4817
dist/preview release/babylon.max.js


Разлика између датотеке није приказан због своје велике величине
+ 27 - 38
dist/preview release/babylon.noworker.js


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

@@ -8,6 +8,7 @@
     - StandardMaterial now supports Parallax and Parallax Occlusion Mapping ([nockawa](https://github.com/nockawa))
     - Animations blending. See [demo here](http://www.babylonjs-playground.com/#2BLI9T#2). More [info here](NEED DOC!) ([deltakosh](https://github.com/deltakosh))
   - **Updates**
+    - New scene.pointerDownPredicate, scene.pointerMovePredicate, scene.pointerUpPredicate to define your own predicates for meshes picking selection ([deltakosh](https://github.com/deltakosh))
     - New OnPickTrigger support for spritesManager ([deltakosh](https://github.com/deltakosh))
     - New SPS method `digest()` ([jerome](https://github.com/jbousquie))    
     - New SPS property `computeBoundingBox` ([jerome](https://github.com/jbousquie))  

+ 6 - 6
src/Materials/Textures/babylon.hdrcubetexture.ts

@@ -21,7 +21,7 @@ module BABYLON {
         ];
 
         public sphericalPolynomial: SphericalPolynomial = null;
-        
+
         public isPMREM = false;
 
         constructor(url: string, scene: Scene, size: number, noMipmap = false, generateHarmonics = true, useInGammaSpace = false, usePMREMGenerator = false) {
@@ -109,11 +109,10 @@ module BABYLON {
                 }
                 return results;
             }
-            
+
             var mipmapGenerator = null;
-            if (!this._noMipmap && this._usePMREMGenerator)
-            {
-                mipmapGenerator = (data: ArrayBufferView[]) => { 
+            if (!this._noMipmap && this._usePMREMGenerator) {
+                mipmapGenerator = (data: ArrayBufferView[]) => {
                     var generator = new BABYLON.Internals.PMREMGenerator(data,
                         this._size,
                         this._size,
@@ -124,7 +123,7 @@ module BABYLON {
                         0.25,
                         false,
                         true);
-                        
+
                     return generator.filterCubeMap();
                 };
             }
@@ -197,3 +196,4 @@ module BABYLON {
         }
     }
 } 
+

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

@@ -1285,6 +1285,20 @@ var BABYLON;
             this.multiplyToRef(q1, this);
             return this;
         };
+        Quaternion.prototype.conjugateToRef = function (ref) {
+            ref.copyFromFloats(-this.x, -this.y, -this.z, this.w);
+            return this;
+        };
+        Quaternion.prototype.conjugateInPlace = function () {
+            this.x *= -1;
+            this.y *= -1;
+            this.z *= -1;
+            return this;
+        };
+        Quaternion.prototype.conjugate = function () {
+            var result = new Quaternion(-this.x, -this.y, -this.z, this.w);
+            return result;
+        };
         Quaternion.prototype.length = function () {
             return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z) + (this.w * this.w));
         };

+ 5 - 4
src/Math/babylon.math.ts

@@ -591,7 +591,7 @@
     export class Vector3 {
 
         constructor(public x: number, public y: number, public z: number) {
-            
+
         }
 
         public toString(): string {
@@ -1592,19 +1592,19 @@
 
             return this;
         }
-        
+
         public conjugateToRef(ref: Quaternion) {
             ref.copyFromFloats(-this.x, -this.y, -this.z, this.w);
             return this;
         }
-        
+
         public conjugateInPlace() {
             this.x *= -1;
             this.y *= -1;
             this.z *= -1;
             return this;
         }
-        
+
         public conjugate() {
             var result = new Quaternion(-this.x, -this.y, -this.z, this.w);
             return result;
@@ -3733,3 +3733,4 @@
     }
 }
 
+

+ 17 - 3
src/Physics/Plugins/babylon.cannonJSPlugin.js

@@ -139,9 +139,11 @@ var BABYLON;
                 pivotB: jointData.connectedPivot ? new CANNON.Vec3().copy(jointData.connectedPivot) : null,
                 axisA: jointData.mainAxis ? new CANNON.Vec3().copy(jointData.mainAxis) : null,
                 axisB: jointData.connectedAxis ? new CANNON.Vec3().copy(jointData.connectedAxis) : null,
-                maxForce: jointData.nativeParams.maxForce
+                maxForce: jointData.nativeParams.maxForce,
+                collideConnected: !!jointData.collision
             };
-            if (!jointData.collision) {
+            //Not needed, Cannon has a collideConnected flag
+            /*if (!jointData.collision) {
                 //add 1st body to a collision group of its own, if it is not in 1
                 if (mainBody.collisionFilterGroup === 1) {
                     mainBody.collisionFilterGroup = this._currentCollisionGroup;
@@ -154,7 +156,7 @@ var BABYLON;
                 //add their mask to the collisionFilterMask of each other:
                 connectedBody.collisionFilterMask = connectedBody.collisionFilterMask | ~mainBody.collisionFilterGroup;
                 mainBody.collisionFilterMask = mainBody.collisionFilterMask | ~connectedBody.collisionFilterGroup;
-            }
+            }*/
             switch (impostorJoint.joint.type) {
                 case BABYLON.PhysicsJoint.HingeJoint:
                     constraint = new CANNON.HingeConstraint(mainBody, connectedBody, constraintData);
@@ -162,10 +164,22 @@ var BABYLON;
                 case BABYLON.PhysicsJoint.DistanceJoint:
                     constraint = new CANNON.DistanceConstraint(mainBody, connectedBody, jointData.maxDistance || 2);
                     break;
+                case BABYLON.PhysicsJoint.SpringJoint:
+                    var springData = jointData;
+                    constraint = new CANNON.Spring(mainBody, connectedBody, {
+                        restLength: springData.length,
+                        stiffness: springData.stiffness,
+                        damping: springData.damping,
+                        localAnchorA: constraintData.pivotA,
+                        localAnchorB: constraintData.pivotB
+                    });
+                    break;
                 default:
                     constraint = new CANNON.PointToPointConstraint(mainBody, constraintData.pivotA, connectedBody, constraintData.pivotA, constraintData.maxForce);
                     break;
             }
+            //set the collideConnected flag after the creation, since DistanceJoint ignores it.
+            constraint.collideConnected = !!jointData.collision;
             impostorJoint.joint.physicsJoint = constraint;
             this.world.addConstraint(constraint);
         };

+ 6 - 0
src/Physics/Plugins/babylon.oimoJSPlugin.js

@@ -193,6 +193,12 @@ var BABYLON;
                 case BABYLON.PhysicsJoint.BallAndSocketJoint:
                     type = "jointBall";
                     break;
+                case BABYLON.PhysicsJoint.SpringJoint:
+                    BABYLON.Tools.Warn("Oimo.js doesn't support Spring Constraint. Simulating using DistanceJoint instead");
+                    var springData = jointData;
+                    nativeJointData.min = springData.length || nativeJointData.min;
+                    //Max should also be set, just make sure it is at least min
+                    nativeJointData.max = Math.max(nativeJointData.min, nativeJointData.max);
                 case BABYLON.PhysicsJoint.DistanceJoint:
                     type = "jointDistance";
                     nativeJointData.max = jointData.maxDistance;

+ 10 - 4
src/Physics/babylon.physicsImpostor.js

@@ -12,7 +12,6 @@ var BABYLON;
             this._onAfterPhysicsStepCallbacks = new Array();
             this._onPhysicsCollideCallbacks = [];
             this._deltaPosition = BABYLON.Vector3.Zero();
-            this._deltaRotation = new BABYLON.Quaternion();
             this._tmpPositionWithDelta = BABYLON.Vector3.Zero();
             this._tmpRotationWithDelta = new BABYLON.Quaternion();
             /**
@@ -21,8 +20,9 @@ var BABYLON;
             this.beforeStep = function () {
                 _this.mesh.position.subtractToRef(_this._deltaPosition, _this._tmpPositionWithDelta);
                 //conjugate deltaRotation
-                _this._tmpRotationWithDelta.copyFrom(_this._deltaRotation);
-                _this._tmpRotationWithDelta.multiplyInPlace(_this.mesh.rotationQuaternion);
+                if (_this._deltaRotationConjugated) {
+                    _this.mesh.rotationQuaternion.multiplyToRef(_this._deltaRotationConjugated, _this._tmpRotationWithDelta);
+                }
                 _this._physicsEngine.getPhysicsPlugin().setPhysicsBodyTransformation(_this, _this._tmpPositionWithDelta, _this._tmpRotationWithDelta);
                 _this._onBeforePhysicsStepCallbacks.forEach(function (func) {
                     func(_this);
@@ -37,7 +37,9 @@ var BABYLON;
                 });
                 _this._physicsEngine.getPhysicsPlugin().setTransformationFromPhysicsBody(_this);
                 _this.mesh.position.addInPlace(_this._deltaPosition);
-                _this.mesh.rotationQuaternion.multiplyInPlace(_this._deltaRotation);
+                if (_this._deltaRotation) {
+                    _this.mesh.rotationQuaternion.multiplyInPlace(_this._deltaRotation);
+                }
             };
             //event and body object due to cannon's event-based architecture.
             this.onCollide = function (e) {
@@ -273,7 +275,11 @@ var BABYLON;
             this._deltaPosition.copyFrom(position);
         };
         PhysicsImpostor.prototype.setDeltaRotation = function (rotation) {
+            if (!this._deltaRotation) {
+                this._deltaRotation = new BABYLON.Quaternion();
+            }
             this._deltaRotation.copyFrom(rotation);
+            this._deltaRotationConjugated = this._deltaRotation.conjugate();
         };
         //Impostor types
         PhysicsImpostor.NoImpostor = 0;

+ 2 - 0
src/Physics/babylon.physicsJoint.js

@@ -34,6 +34,8 @@ var BABYLON;
         //Similar to a Ball-Joint. Different in params
         //TODO check!!
         PhysicsJoint.PointToPointJoint = 8;
+        //Cannon only at the moment
+        PhysicsJoint.SpringJoint = 9;
         return PhysicsJoint;
     })();
     BABYLON.PhysicsJoint = PhysicsJoint;

+ 12 - 16
src/Tools/HDR/babylon.tools.cubemaptosphericalpolynomial.ts

@@ -1,7 +1,6 @@
 module BABYLON.Internals {
 
-    class FileFaceOrientation
-    {
+    class FileFaceOrientation {
         public name: string;
         public worldAxisForNormal: Vector3; // the world axis corresponding to the normal to the face
         public worldAxisForFileX: Vector3; // the world axis corresponding to texture right x-axis in file
@@ -15,7 +14,7 @@ module BABYLON.Internals {
         }
     };
 
-    export class CubeMapToSphericalPolynomialTools {        
+    export class CubeMapToSphericalPolynomialTools {
 
         private static FileFaces: FileFaceOrientation[] = [
             new FileFaceOrientation("right", new Vector3(1, 0, 0), new Vector3(0, 0, -1), new Vector3(0, -1, 0)), // +X east
@@ -25,7 +24,7 @@ module BABYLON.Internals {
             new FileFaceOrientation("front", new Vector3(0, 0, 1), new Vector3(1, 0, 0), new Vector3(0, -1, 0)), // +Z top
             new FileFaceOrientation("back", new Vector3(0, 0, -1), new Vector3(-1, 0, 0), new Vector3(0, -1, 0))// -Z bottom
         ];
-        
+
         public static ConvertCubeMapToSphericalPolynomial(cubeInfo: CubeMapInfo): SphericalPolynomial {
             var sphericalHarmonics = new SphericalHarmonics();
             var totalSolidAngle = 0.0;
@@ -37,8 +36,7 @@ module BABYLON.Internals {
             // The (u,v) of the first texel is half a texel from the corner (-1,-1).
             var minUV = du * 0.5 - 1.0;
 
-            for (var faceIndex = 0; faceIndex < 6; faceIndex++)
-            {
+            for (var faceIndex = 0; faceIndex < 6; faceIndex++) {
                 var fileFace = this.FileFaces[faceIndex];
                 var dataArray = cubeInfo[fileFace.name];
                 var v = minUV;
@@ -47,17 +45,15 @@ module BABYLON.Internals {
                 // This is possible because during the summation we do not need the SH-specific properties, e.g. orthogonality.
                 // Because SP is still linear, so summation is fine in that basis.
 
-                for (var y = 0; y < cubeInfo.size; y++)
-                {
+                for (var y = 0; y < cubeInfo.size; y++) {
                     var u = minUV;
 
-                    for (var x = 0; x < cubeInfo.size; x++)
-                    {
+                    for (var x = 0; x < cubeInfo.size; x++) {
                         // World direction (not normalised)
                         var worldDirection =
                             fileFace.worldAxisForFileX.scale(u).add(
-                            fileFace.worldAxisForFileY.scale(v)).add(
-                            fileFace.worldAxisForNormal);
+                                fileFace.worldAxisForFileY.scale(v)).add(
+                                fileFace.worldAxisForNormal);
                         worldDirection.normalize();
 
                         var deltaSolidAngle = Math.pow(1.0 + u * u + v * v, -3.0 / 2.0);
@@ -69,14 +65,14 @@ module BABYLON.Internals {
 
                             var color = new Color3(r, g, b);
 
-                            sphericalHarmonics.addLight(worldDirection, color, deltaSolidAngle);    
+                            sphericalHarmonics.addLight(worldDirection, color, deltaSolidAngle);
                         }
                         else {
 
                             if (faceIndex == 0) {
                                 dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0] = 1;
                                 dataArray[(y * cubeInfo.size * 3) + (x * 3) + 1] = 0;
-                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2] = 0;                                
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2] = 0;
                             }
                             else if (faceIndex == 1) {
                                 dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0] = 0;
@@ -104,8 +100,8 @@ module BABYLON.Internals {
                                 dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2] = 1;
                             }
 
-                            var color = new Color3(dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0], 
-                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 1], 
+                            var color = new Color3(dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0],
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 1],
                                 dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2]);
 
                             sphericalHarmonics.addLight(worldDirection, color, deltaSolidAngle);

+ 9 - 9
src/Tools/HDR/babylon.tools.panoramaToCubemap.ts

@@ -57,12 +57,12 @@ module BABYLON.Internals {
                 throw "ConvertPanoramaToCubemap: input size is wrong";
             }
 
-            var textureFront  = this.CreateCubemapTexture(size, this.FACE_FRONT, float32Array, inputWidth, inputHeight);
-            var textureBack   = this.CreateCubemapTexture(size, this.FACE_BACK, float32Array, inputWidth, inputHeight);
-            var textureLeft   = this.CreateCubemapTexture(size, this.FACE_LEFT, float32Array, inputWidth, inputHeight);
-            var textureRight  = this.CreateCubemapTexture(size, this.FACE_RIGHT, float32Array, inputWidth, inputHeight);
-            var textureUp     = this.CreateCubemapTexture(size, this.FACE_UP, float32Array, inputWidth, inputHeight);
-            var textureDown   = this.CreateCubemapTexture(size, this.FACE_DOWN, float32Array, inputWidth, inputHeight);
+            var textureFront = this.CreateCubemapTexture(size, this.FACE_FRONT, float32Array, inputWidth, inputHeight);
+            var textureBack = this.CreateCubemapTexture(size, this.FACE_BACK, float32Array, inputWidth, inputHeight);
+            var textureLeft = this.CreateCubemapTexture(size, this.FACE_LEFT, float32Array, inputWidth, inputHeight);
+            var textureRight = this.CreateCubemapTexture(size, this.FACE_RIGHT, float32Array, inputWidth, inputHeight);
+            var textureUp = this.CreateCubemapTexture(size, this.FACE_UP, float32Array, inputWidth, inputHeight);
+            var textureDown = this.CreateCubemapTexture(size, this.FACE_DOWN, float32Array, inputWidth, inputHeight);
 
             return {
                 front: textureFront,
@@ -112,8 +112,8 @@ module BABYLON.Internals {
 
         private static CalcProjectionSpherical(vDir: Vector3, float32Array: Float32Array, inputWidth: number, inputHeight: number): any {
             var theta = Math.atan2(vDir.z, vDir.x);
-            var phi   = Math.acos(vDir.y);
-            
+            var phi = Math.acos(vDir.y);
+
             while (theta < -Math.PI) theta += 2 * Math.PI;
             while (theta > Math.PI) theta -= 2 * Math.PI;
 
@@ -143,4 +143,4 @@ module BABYLON.Internals {
             };
         }
     }
-} 
+} 

+ 2 - 2
src/Tools/HDR/babylon.tools.pmremgenerator.js

@@ -365,8 +365,8 @@ var BABYLON;
                 return PMREMGenerator._vectorTemp;
             };
             //--------------------------------------------------------------------------------------
-            //Original code from Ignacio CastaÒo
-            // This formula is from Manne ÷hrstrˆm's thesis.
+            //Original code from Ignacio Castao
+            // This formula is from Manne �hrstr�m's thesis.
             // Take two coordiantes in the range [-1, 1] that define a portion of a
             // cube face and return the area of the projection of that portion on the
             // surface of the sphere.

Разлика између датотеке није приказан због своје велике величине
+ 1195 - 1202
src/Tools/HDR/babylon.tools.pmremgenerator.ts


+ 3 - 7
src/babylon.engine.ts

@@ -1954,7 +1954,7 @@
 
                 if (!noMipmap && isPot) {
                     if (mipmmapGenerator) {
-                        
+
                         var arrayTemp: ArrayBufferView[] = [];
                         // Data are known to be in +X +Y +Z -X -Y -Z
                         // mipmmapGenerator data is expected to be order in +X -X +Y -Y +Z -Z
@@ -1984,7 +1984,7 @@
                             var faceData = rgbeDataArrays[index];
                             gl.texImage2D(facesIndex[index], 0, internalFormat, width, height, 0, internalFormat, textureType, faceData);
                         }
-                        
+
                         gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
                     }
                 }
@@ -2317,8 +2317,4 @@
             }
         }
     }
-}
-
-
-
-
+}

+ 12 - 11
src/babylon.scene.js

@@ -330,8 +330,11 @@ var BABYLON;
                 }
                 var canvas = _this._engine.getRenderingCanvas();
                 _this._updatePointerPosition(evt);
+                if (!_this.pointerMovePredicate) {
+                    _this.pointerMovePredicate = function (mesh) { return mesh.isPickable && mesh.isVisible && mesh.isReady() && (_this.constantlyUpdateMeshUnderPointer || mesh.actionManager !== null && mesh.actionManager !== undefined); };
+                }
                 // Meshes
-                var pickResult = _this.pick(_this._unTranslatedPointerX, _this._unTranslatedPointerY, function (mesh) { return mesh.isPickable && mesh.isVisible && mesh.isReady() && (_this.constantlyUpdateMeshUnderPointer || mesh.actionManager !== null && mesh.actionManager !== undefined); }, false, _this.cameraToUseForPointers);
+                var pickResult = _this.pick(_this._unTranslatedPointerX, _this._unTranslatedPointerY, _this.pointerMovePredicate, false, _this.cameraToUseForPointers);
                 if (pickResult.hit && pickResult.pickedMesh) {
                     _this.setPointerOverSprite(null);
                     _this.setPointerOverMesh(pickResult.pickedMesh);
@@ -368,15 +371,14 @@ var BABYLON;
                 _this._startingPointerPosition.x = _this._pointerX;
                 _this._startingPointerPosition.y = _this._pointerY;
                 _this._startingPointerTime = new Date().getTime();
-                var predicate = null;
-                // Meshes
-                _this._pickedDownMesh = null;
-                if (!_this.onPointerDown && !_this.onPointerPick) {
-                    predicate = function (mesh) {
+                if (!_this.pointerDownPredicate) {
+                    _this.pointerDownPredicate = function (mesh) {
                         return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.actionManager && mesh.actionManager.hasPointerTriggers;
                     };
                 }
-                var pickResult = _this.pick(_this._unTranslatedPointerX, _this._unTranslatedPointerY, predicate, false, _this.cameraToUseForPointers);
+                // Meshes
+                _this._pickedDownMesh = null;
+                var pickResult = _this.pick(_this._unTranslatedPointerX, _this._unTranslatedPointerY, _this.pointerDownPredicate, false, _this.cameraToUseForPointers);
                 if (pickResult.hit && pickResult.pickedMesh) {
                     if (pickResult.pickedMesh.actionManager) {
                         _this._pickedDownMesh = pickResult.pickedMesh;
@@ -440,15 +442,14 @@ var BABYLON;
                 if (!_this.cameraToUseForPointers && !_this.activeCamera) {
                     return;
                 }
-                var predicate = null;
                 _this._updatePointerPosition(evt);
-                if (!_this.onPointerUp && !_this.onPointerPick) {
-                    predicate = function (mesh) {
+                if (!_this.pointerUpPredicate) {
+                    _this.pointerUpPredicate = function (mesh) {
                         return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.actionManager && (mesh.actionManager.hasPickTriggers || mesh.actionManager.hasSpecificTrigger(BABYLON.ActionManager.OnLongPressTrigger));
                     };
                 }
                 // Meshes
-                var pickResult = _this.pick(_this._unTranslatedPointerX, _this._unTranslatedPointerY, predicate, false, _this.cameraToUseForPointers);
+                var pickResult = _this.pick(_this._unTranslatedPointerX, _this._unTranslatedPointerY, _this.pointerUpPredicate, false, _this.cameraToUseForPointers);
                 if (pickResult.hit && pickResult.pickedMesh) {
                     if (_this.onPointerPick && _this._pickedDownMesh != null && pickResult.pickedMesh == _this._pickedDownMesh) {
                         _this.onPointerPick(evt, pickResult);

+ 19 - 18
src/babylon.scene.ts

@@ -65,6 +65,9 @@
         public animations: Animation[] = [];
 
         // Pointers
+        public pointerDownPredicate: (Mesh: AbstractMesh) => boolean;
+        public pointerUpPredicate: (Mesh: AbstractMesh) => boolean;
+        public pointerMovePredicate: (Mesh: AbstractMesh) => boolean;
         private _onPointerMove: (evt: PointerEvent) => void;
         private _onPointerDown: (evt: PointerEvent) => void;
         private _onPointerUp: (evt: PointerEvent) => void;
@@ -479,12 +482,13 @@
 
                 this._updatePointerPosition(evt);
 
-                // Meshes
-                var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY,
-                    (mesh: AbstractMesh): boolean => mesh.isPickable && mesh.isVisible && mesh.isReady() && (this.constantlyUpdateMeshUnderPointer || mesh.actionManager !== null && mesh.actionManager !== undefined),
-                    false,
-                    this.cameraToUseForPointers);
+                if (!this.pointerMovePredicate) {
+                    this.pointerMovePredicate = (mesh: AbstractMesh): boolean => mesh.isPickable && mesh.isVisible && mesh.isReady() && (this.constantlyUpdateMeshUnderPointer || mesh.actionManager !== null && mesh.actionManager !== undefined);
+                }
 
+                // Meshes
+                var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerMovePredicate, false, this.cameraToUseForPointers);
+                    
                 if (pickResult.hit && pickResult.pickedMesh) {
                     this.setPointerOverSprite(null);
 
@@ -525,16 +529,15 @@
                 this._startingPointerPosition.y = this._pointerY;
                 this._startingPointerTime = new Date().getTime();
 
-                var predicate = null;
-
-                // Meshes
-                this._pickedDownMesh = null;
-                if (!this.onPointerDown && !this.onPointerPick) {
-                    predicate = (mesh: AbstractMesh): boolean => {
+                if (!this.pointerDownPredicate) {
+                    this.pointerDownPredicate = (mesh: AbstractMesh): boolean => {
                         return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.actionManager && mesh.actionManager.hasPointerTriggers;
                     };
                 }
-                var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, predicate, false, this.cameraToUseForPointers);
+
+                // Meshes
+                this._pickedDownMesh = null;
+                var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerDownPredicate, false, this.cameraToUseForPointers);
 
                 if (pickResult.hit && pickResult.pickedMesh) {
                     if (pickResult.pickedMesh.actionManager) {
@@ -607,19 +610,17 @@
                 if (!this.cameraToUseForPointers && !this.activeCamera) {
                     return;
                 }
-
-                var predicate = null;
-
+                
                 this._updatePointerPosition(evt);
 
-                if (!this.onPointerUp && !this.onPointerPick) {
-                    predicate = (mesh: AbstractMesh): boolean => {
+                if (!this.pointerUpPredicate) {
+                    this.pointerUpPredicate = (mesh: AbstractMesh): boolean => {
                         return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.actionManager && (mesh.actionManager.hasPickTriggers || mesh.actionManager.hasSpecificTrigger(ActionManager.OnLongPressTrigger));
                     };
                 }
 
                 // Meshes
-                var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, predicate, false, this.cameraToUseForPointers);
+                var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerUpPredicate, false, this.cameraToUseForPointers);
 
                 if (pickResult.hit && pickResult.pickedMesh) {
                     if (this.onPointerPick && this._pickedDownMesh != null && pickResult.pickedMesh == this._pickedDownMesh) {