I read the following thread with great interest a while back:
I was wondering then why the problem of sprites not being picked does not existing with OnPointerOverTrigger which always fires?
Today, I’ve customized my scene’s pointerMovePredicate method to avoid picking meshes through grounds (they’re clearly identified in my code). It works great, but the moment I add grounds to the pointerMovePredicate, it fails to pick sprites if there is a ground behind it.
The pointerMovePredicate is inspired by this post:
I’d like to understand what’s happening and if there is a way to get around this?
I’m trying to prep a PG for repro, but posting this in case someone already knows what’s hapenning.
This demonstrates that sprites are not “hovered” when they are in front of a mesh that’s part of the pointerMovePredicate, while other meshes are. If you comment out the pointerMovePredicate function, sprites behave as expected.
Just taking a look at the provided PG, it does look like the mesh is taking priority over the sprite when it comes to move picking. I’m not that familiar with how sprites are handled so let me dig in a little bit and see what’s going on.
Okay, so I think I know what’s going on. Specifically with Sprites, when the pick is done, it’s also checked if a mesh was picked. If a mesh was picked, the sprite will be explicitly ignored (spriteSceneComponent.ts, Line 340). As far as I can tell, there is no setting that can be changed to modify this behavior. You could, however, modify your pointerMovePredicate to account for this.
// This version should check for a sprite first and return false if there's a sprite in the way.
scene.pointerMovePredicate = function(mesh) {
// Since picking is done with the untranslated pointer position, let's use that to pick the sprite manually
const x = scene.unTranslatedPointer.x;
const y = scene.unTranslatedPointer.y;
const result = scene.pickSprite(x,y);
// We'll then add the check if we got a sprite hit. If we did, we ignore the mesh.
return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled() && mesh.name.startsWith('box') && !result.hit;
}
This should check for any sprites first and pick meshes if there aren’t any in the way. You may want to modify this to suit your needs but this might be a good workaround.
Edit: After reading this back, this seems a bit costly to perf so it might be worth it to either perform the sprite pick outside of the predicate or cache the result so that you only pick once per move event.
You could probably accomplish something like this with:
var foundSprite = false;
...
scene.onPrePointerObservable.add((eventData) => {
const x = scene.unTranslatedPointer.x;
const y = scene.unTranslatedPointer.y;
foundSprite = scene.pickSprite(x, y).hit;
});
...
scene.pointerMovePredicate = function(mesh) {
// We'll then add the check if we got a sprite hit. If we did, we ignore the mesh.
return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled() && mesh.name.startsWith('box') && !foundSprite;
}
And this highlights one thing I wasn’t paying attention to: pointerMovePredicate is called for each mesh each time the pointer moves . Thanks for making me realize this.