Dynamically changing pointerDragBehavior

Hi All-

I am having great fun with babylon js! What an awesome piece of software. Many thanks. Ahem.

I have been able to make various pointerDragBehaviors work but I am unable to change the behavior dynamically. I want to test where on a mesh user is clicking and depending on test results change from moving in a plane to moving in a vector.

I tried various approaches. attach() and detach() made the most sense:

pointerDragBehavior.onDragStartObservable.add((event)=>{
    if(1 === 1){
        this.pointerDragBehavior.detach(event.source);
        this.pointerDragBehavior2.attach(event.source);

This throws ‘cannot read property ‘getScene’ of undefined’.
https://www.babylonjs-playground.com/#9UFEBE#80

Any advice?

TIA! Michael

Thanks a lot :wink: And welcome!

Let me invoke our gizmo manager :wink: @Cedric

Hi Michael!

Let me take a look at your PR. I’ll let you know when I’ve found something :slight_smile:

Try this:

https://www.babylonjs-playground.com/#9UFEBE#81

PointerDragBehavior._options is private, but I think it should do no harm to have it available through getter/setter: @Deltakosh?

No problem at all

Thank you, Evgeni, Cedric and Deltakosh.

Now my code is behaving better but not perfectly.

The expected behavior is that when you grab the top half of the box it move on the Y axis, which it does, and when you grab the bottom half it moves in the XZ plane, which it does sometimes.

If I make it so it move on the X axis instead, it works fine. Something is up with applying the dragPlaneNormal options. Could it be related to this issue, that is, some parameters not getting cleared?

Things are more clear now. dragPlaneNormal is used for picking, that means that it needs to be reset back when onDragEndObservable event is fired. That’s the first issue. Then, dragPlanePoint is the world coordinate on that plane. This means that if the dragPlaneNormal is (0,1,0), y will always be 1. give or take some epsilon corresponding to float precision.
So, you can’t do the test in onDragStartObservable with a y comparison. You can do some raypicking or do your test on some other checks.
In this PR:
https://www.babylonjs-playground.com/#9UFEBE#84
I do the test on z. Imagine a plane that passes by the center of the cube that cuts it in half.

image

If the user clicks below that line (z on the plane is < box._position.z) then keep the drag plane as is. Otherwise, set the dragAxis to (0,1,0).

The z comparison works in this case because the camera is properly aligned along the z axis. For any other camera orientation, you would have to compute the length of the dragPlanePoint to the camera eye position and compare it with the length of the box center to the camera eye position.

1 Like

PR created:

2 Likes

Thanks, @Cedric for pointing out that the dragPlaneNormal causes y = 1 regardless of where click it.

I understand your approach in your example but I don’t understand why it’s necessary.

Here’s an example where I restore the behavior to moving object in y vector after drag ends.

https://www.babylonjs-playground.com/#9UFEBE#85

When I click in the bottom half of the cube the cube moves toward the camera when I drag, not in the xz plane.

If I remove the onDragEndObservable callback something really puzzling happens.

https://www.babylonjs-playground.com/#9UFEBE#86

If I click on the lower half of the cube and drag, the cube move toward the camera.
If I click and release, THEN click and drag it moves in the xz plane, as expected.

Hi All-

Here’s a not so elegant solution.

https://www.babylonjs-playground.com/#9UFEBE#92

I have 2 pointerDragBehaviors, one on the y axis and one on the xz plane, and attach and detach them depending on where the click is. I transfer the dragID as well.

Thanks for all your help! I’m learning a lot and look forward to contributing. Eventually. :dizzy_face:

1 Like

I think it’s quite a good solution, as it may not be possible to do it by using a single PointerDragBehavior instance because some calculations depending on the current options are made before onDragStartObservable is called, which may explain why it does not work in the other PGs.

1 Like

I cleaned up my solution a bit.

I removed xzDrag.startDrag(dragId) because the existing drag can be transferred from one behavior uninterrupted. Doing a startDrag results in the clicks in the lower half of the box being “sticky”, i.e. one release (onDragEndObservable) event is missed.

https://www.babylonjs-playground.com/#9UFEBE#95

2 Likes