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