How to let 2d gui block operation of 3d gui

I have a 2d button and a 3d button in the same scene but use different camera for each. The 3d button is render behind 2d button. When I click the 2d button , the 3d button also response to the click operation. I do not want this, I want only the 2d button to response to the click action. How to achieve that?

I donā€™t think itā€™s supported by the GUI system, as 2D GUI and 3D GUI are two separate sub-systems.

In 2D GUI you can use Control.isPointerBlocker=true to prevent an event to reach other controls when it has been intercepted by a control but this property is unknown to the 3D GUI.

Maybe @carolhmj will have an idea about that.

1 Like

Interesting case. I actually have something similar in my scene. I believe using the PointerBlocker ability of the ADT controls/containers would be the way to go (at least, I know it would work). The only question that remains is under which condition should the 3D GUI be enabled (below the ADT layer). You wouldnā€™t happen to have a PG or can provide some more details about this (like should the 3D GUI control be inactive only when ā€˜hiddenā€™ by a 2D Control ā€“ or ā€“ whenever the ADT layer is visible/active, all 3D controls should be blocked?)

1 Like


like it said in the above image, the 2d button will partially overlay 3d button, when I click 2d button, if the 3d button part are overlay by 2d button, then the 3d button should not response

Thatā€™s because the button control is not a pointerBlocker by default.

OK, my apologies there. It doesnā€™t seem to quite work like this. I was pretty sure I did it before in a scene, just canā€™t recall where and how.
I did this PG that only demonstrates that pointerBlocker does not work for the 3D GUI.
Calling back @Evgeni_Popov and @carolhmj on this case (and I will follow because I also want to know :wink:) Thanks,

I think the problem here is because the 2D and 3D GUI are using different cameras, so the 2D GUI will only block the events going through its own camera :thinking:

Yes, i remember how I did it now. I had no other choice than to use removeControl on the panel and add it again after the ADT GUI (FS) interaction. Not very sexy. It didnā€™t do too much harm in my case because my ADT was already a complete overlay of the scene, so nobody would notice. But, in this particular case seeing the control disappear and reapppear automagically would look real weird. Any idea of a possible solution?

Unfortunately I canā€™t see a solution (but Iā€™m no expert with inputs in general) except if the 2D icon bar is modal (meaning you can only click on icons in this bar or close the bar and canā€™t click anywhere else): in that case, when the 2D icon bar is displayed, you can disable the pointer event handlers of the 3D GUI until the 2D icon bar is dismissed, and then re-enable the handlers at that time (I guess itā€™s possible to disable/enable all event handlers at once for a 3D GUI, even if I donā€™t know howā€¦).

1 Like

If the 2d and 3d use the same camera, how can I let 2d gui always renders on top of 3d gui?

Well, @carolhmj @Evgeni_Popov Iā€™m also on this case since this morning for my own use.
And I would have some additional comments/questions.
From my tests, it appears that even a mesh does not block 3D GUI pointer events. You can check this from my PG above. Question is: How can we possibly block a 3D GUI pointer event? Other than with the clumsy (sry) solution of manually disabling pointer event handlers (and then one would need to know how to this for a start).

Ok, I found a way.

UtilityLayerRenderer has a pickingEnabled property that enables/disables event handling. Also, it is calling the Scene.isPointerCaptured to know if the event has already been handled or not.

By combining those info, we can do:

It overrides scene.isPointerCaptured:

    const saveIsPointerCaptures = scene.isPointerCaptured.bind(scene);

    let enable3DEvents = true;

    scene.isPointerCaptured = (pointerId) => {
        manager.utilityLayer.pickingEnabled = enable3DEvents;
        return saveIsPointerCaptures(pointerId);
    };

So we can use the onPointerEnterObservable / onPointerOutObservable observers of a Control2D to block 3D event handling:

    const block3DEvents = (ctrl2d) => {
        ctrl2d.onPointerEnterObservable.add(() => {
            enable3DEvents = false;
        });
        ctrl2d.onPointerOutObservable.add(() => {
            enable3DEvents = true;
        });
    };
3 Likes

Thanks. Bookmarked. You know, I just knew you could do it :wink: If you canā€™t, nobody can :grinning:
May be you can now quickly check out my other related finding of the day. The solution might also be around this UtilityLayerRenderer (hopefully?):

Totally Amazing! Thanks! Since u are such a master of BabylonJS, could u please help me with another difficult problem about GIF? Here is the problemā€™s link
:https://forum.babylonjs.com/t/re-is-there-an-easy-way-to-use-gif-as-a-texture/34789

There is one problem though, that is if I click the ā€œcloseā€ button which will set the gui to be invisible, then the out event will never be detected, hence the 3d gui will never be active. And I can not find an event called such as ā€œonInvisibleā€. Any idea?

I came with an solution, please help me check it whether it will has a performance problem?

This might be odd to say, but: Why donā€™t you just call ā€˜enable3DEventsā€™ when hidding your ADT controls?

1 Like

Actually I have over complicated my solution, thereā€™s no need to override isPointerCaptured:

You can just do:

    const enable3DEvents = (enable) => {
        manager.utilityLayer.pickingEnabled = enable;
    };

    const block3DEvents = (ctrl2d) => {
        ctrl2d.onPointerEnterObservable.add(() => {
            enable3DEvents(false);
        });
        ctrl2d.onPointerOutObservable.add(() => {
            enable3DEvents(true);
        });
    };

Regarding your last problem, as @mawa is saying, why not simply reenabling 3D event handling in the onClose button handler?

2 Likes

Yes, I could. The only problem is that I have to do this for every close button instead of just addBlock(gui). But it does have better performance .

How many close buttons do you have?
I suppose you could still declare this for all close buttons with a loop.
By any means, Iā€™m afraid thereā€™s no alternate way as of today. You will likely have to do with it until we eventually find better.

Not too many, this does work for now.

1 Like