How does Scene.pick decide which mesh is picked when all have the same z value?

Hello,
I am working on a big 2D application with babylonJS, where you basically have a canvas with lots of items to interact with, e.g. hovering over them, selecting them, moving around etc. I am using Thin Instances to speed this up, e.g. I have one mesh per item type.

All my meshes have the same z value of 0.0. I disabled z-testing and all my meshes materials have needAlphaBlending set to true and I am basically using the alphaIndex to control the draw order.

This works all fine so far regarding drawing, but now I face a problem with the ActionManager: I use ActionManager to implement all the hover/select actions. I have two overlapping items and I get pointerIn/out events for an item that is underneath another item. So from a user’s point of view, the topmost item gets “unhovered” because some item underneath / not visible item is now hovered.

I could partially reproduce the problem in this playground: https://playground.babylonjs.com/#W29PVX#2

You see one square, but actually it is two squares: A bigger and a smaller one. When hovering the square, it changes its color to red, but once you move the mouse closer to the center, it changes its color back to gray.

So although you do not see the inner square, e.g. it is drawn “underneath” the big square, it has hover priority. If you change the order of initialization, e.g. swap the initialization of ground 1 and two, you can change the behavior so that the smaller square is ignored.

You can also uncomment the block regarding alphaIndex etc. and you can make the smaller square appear.

However, it will not change the pick priority.

I have to admit that simply changing the order of initialization of the meshes did not fix the issue in my application. I guess it is because of thin instances or some other delayed initialization. However, the basic problem is the same: ActionManager internally calls Scene.pick which returns only one result and somehow it has to decide which mesh to return if it is ambigous. Looks like I can pass a pickPredicate, but it only allows me to filter out a certain mesh. It does not give me the list of picks so I can pick one or sort them.

How can I influence which mesh is picked if the z-index is the same?

Any help is appreciated. I see that the alternative is to implement a huge logic on my application side

Best regards,
Axel

Just a guess but this sounds like the “fastCheck” parameter is true. “Fast” means if the ray hits any mesh, it returns a hit. The order should be according to scene.meshes.

Without a bit of distance it is almost impossible to differentiate which one should be picked first so scene creation order will be the default choice here.

Why can’t you introduce a small z offset between your meshes. I did a similar app and we just offset everything 0.001 in z. We kept the objects in a z-order array and allocated them to a z layer when they were created. This allows for easy front to back back to front ordering.

Also, unless you have hundreds or thousands of objects, thin instancing is probably overkill; you could get away with just instancing of even cloning. I do believe that alpha blending is a pretty big perf hit, so if any of your objects aren’t transparent, you way want to make them opaque. In our app, we determined whether an object needed alpha blending, testing, or was opaque based on the properties of the image when it was uploaded, so we only turned on alpha blending when neccessary.

Hi everyone,
I am gonna answer to all of you:

@Joe_Kerr Probably this parameter is true, but I dont see any way to change it as the pick called deep from within the action manager.
@sebavan Yes. In one case I could actually make it work by sorting my business objects list first before creating meshes from them.
@ericwood73 I’d consider adding a (small) random value a “hack” as I am so proud doing this no longer, disabling z-Test and use a “proper” draw oder. We used this approach in the past but the problem was always: If you chose the offset too big, you see it once you zoom in, if you do it too small, you still get z-Fighting.

I also want to elaborate why I am so into thin instances:

  • Basically, our application is backed by a redux store and we draw a bunch of lists of objects. Think about a canvas that has 30 items of this kind, 40 of another kind and so on.
    Whenever such a list changes, I need to re-create the babylon objects for them.
  • When using classic instances, I have one babylon-object per entry in my redux list. I need to diff the business-objects list with the list of babylon-objects and then need to create new objects/update existing ones/dispose deleted ones.
  • With thin instances, I only have one mesh/babylon-object per list. Whenever my redux list changes, I re-create the thin instance buffers and do not need to care for creating/disposing babylon objects. This is a pattern we figured out two years ago and we are pretty happy with it. Maybe from a performance point of view it seems overkill but regarding application architecture, it is very nice.

You probably already know this, but you can drastically reduce z fighting in this scenario by limiting your min and max z to just what you need for your min and max zoom. The defaults are way too large. I understand your point about using alpha index, and we looked at something similar. In our case users needed to be able to edit the draw order and we didn’t want to recreate all objects anytime a z position changed, so we chose the z hack.