three.js icon indicating copy to clipboard operation
three.js copied to clipboard

Allow flexibility on DragControls for multi-part GLTF models & other hierarchical objects

Open diarmidmackenzie opened this issue 2 years ago • 3 comments

I haven't raised a related issue - I can do so if required

Description

DragControls doesn't offer the flexibility needed to use DragControls with multi-part GLTF models (or other smilar hierarchical objects).

DragControls can be configured on an array of object3Ds. The drag behaviour then operates on all these objects, and all their descendants.

When dragging happens, it is applied to the object3D that the raycaster hit. If this is a descendant of an object specified in the array, then the descendant will be dragged independently of the ancestor object.

So if I have a multi-part GLTF, which gets mapped into a hierarchy of object3Ds, I can't use DragControls to move the GLTF as a whole. If I click and drag on it, I'll end up dragging the part of the model I clicked on, rather than the whole model.

DragControls does have a config option transformGroup which results in the entire group of objects being transformed (ignoring where the raycaster hit completely). However this can only be used when DragControls is being used on a single object. It can't be used when I want a single instance of DragControls to allow dragging of multiple objects.

Proposed fix is another flag, "transformDescendants". This is set to "true" by defult, preserving current behaviour.

When this is set to "false" (and transformGroup is also "false"), then the logic for which object to move is as follows:

  • if the object hit by the raycaster is in the specified aray of objects, allow it to be dragged
  • else look for the closest ancestor that is in the specified array of objects, and apply the drag to that object instead.

So far this fix has been tested in various A-Frame contexts: https://github.com/SeregPie/aframe-drag-controls/pull/2

However the same issue exists for vanilla Three.js when using multi-part GLTF models. Happy to create a pure Three.js example to illustrate the problem if that would be helpful.

diarmidmackenzie avatar May 25 '23 12:05 diarmidmackenzie

Can you please check if #26747 solved your issue.

Mugen87 avatar Oct 06 '23 09:10 Mugen87

@Mugen87 No, unfortunately the recursive property added in #26747 does not seem to solve the use case presented here.

The code pen below shows that setting dragControls.recursive = false prevents to select anything when only groups of objects are in the list of draggable objects: Code pen recursive property test (you can change g_dragControl_recursive to false or true at the top of the js file)

This PR successfully solve the issue: Code pen transformDescendants (you can change g_dragControl_transformDescendants to false or true at the top of the js file)

brainexcerpts avatar Oct 07 '23 03:10 brainexcerpts

#26747 solves a slightly different problem from this PR.

Suppose we have an object A, with children B, C.

If you set DragControls on A, standard behaviour (prior to #26747) is that any of A, B or C can now be dragged as an independent entity.

#26747 gives the ability to turn off recursive raycasting, so that only A can be dragged (and B & C will be dragged with it).

This will work well for the case e.g. where A is a box, and B & C are small decorations on that box (i.e. A constitutes the bulk of the geometry you might want to raycast against).

But in the case of a multipart GLTF (which is what this PR addresses), A is typically a Group that has no geometry, and so can't be hit with a raycaster at all. B & C are the parts that make up the object (e.g. a head and body).

With current functionality, the only options would be:

  • recursive = true: drag each of A, B or C independently.
  • recursive = false: can only drag A. But that doesn't work, because A has no geometry of its own.

This PR delivers functionality where (by setting transformDescendants: false) it's possible to drag either B or C, and all of A, B & C will move together. The movement is referred up to the nearest draggable ancestor object (in this case, A).

diarmidmackenzie avatar Oct 11 '23 19:10 diarmidmackenzie