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.
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?)
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 ) 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
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ā¦).
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;
});
};
Thanks. Bookmarked. You know, I just knew you could do it If you canāt, nobody can
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?
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?
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.