Hi,
I have some code that renders an array of meshes inside a group using stored matrices. All the meshes share the same rotation and only their position changes. I would like to be able to drag the groups of meshes around by altering the x and y transform of their matrices.
My current approach is to add a large plane which shares the same matrix as the first item in the array of meshes and raycast against it to calculate how far I’ve dragged.
This is what that looks like when the plane is made visible (and slightly smaller so it fits in a screenshot - in reality the plane is much larger):
The code below stores the initial point the raycast occurred on drag start and then on drag, performs another raycast, and subtracts that point from the initial point to calculate the delta. I then apply the delta x and y to the individual matrices of the items.
This works well when the plane is facing forward in my scene but when the plane is in any other position the dragging behaviour is incorrect. For example, if the plane faces backwards then the dragging is back to front.
I feel like my approach is largely correct, I’m just missing a step to generate proper values. Any help would be appreciated!
function MyComponent(props) {
const { items } = props;
const groupRef = useRef();
const dragPlane = useRef();
const { raycaster, camera } = useThree();
const {
movementMatrix,
currentDragPosition,
} = useMemo(() => {
return {
currentDragPosition: new Vector3(),
movementMatrix: new Matrix4(),
};
}, []);
const bind = useGesture({
onDrag: () => {
if (!dragPlane.current || !groupRef.current) return;
const intersection = raycaster.intersectObject(dragPlane.current);
if (!intersection.length) return;
const delta = currentDragPosition.sub(intersection[0].point);
movementMatrix.makeTranslation(-delta.x, -delta.y, 0);
groupRef.current.children.forEach((child) => {
child.matrix.multiply(movementMatrix);
});
currentDragPosition.copy(intersection[0].point);
},
onDragStart: () => {
if (dragPlane.current) {
const intersection = raycaster.intersectObject(dragPlane.current);
if (!intersection.length) return;
currentDragPosition.copy(intersection[0].point);
}
},
});
return (
<>
<group
ref={groupRef}
{...bind()}
>
{items.map((item) => (
<Item
key={item.id}
matrix={item.matrix}
/>
))}
</group>
<mesh
matrix={items[0].matrix}
matrixAutoUpdate={false}
ref={dragPlane}
>
<planeGeometry args={[100, 100, 1, 1]} />
<meshBasicMaterial visible={false} />
</mesh>
</>
);
}