I am new in Canvas and Three.js. I am looking for the right way to move a mesh inside a Canvas. I created a sandbox but I don’t know if it is the right way. Basically, I created ad wrapper which sets some eventlistener on the WebGLRenderer:
import { useThree } from "@react-three/fiber";
import React from "react";
import { PropsWithChildren, useEffect, useRef, useState } from "react";
import * as THREE from "three";
const MovingImage: React.FC<PropsWithChildren> = ({ children }) => {
const { raycaster, camera, gl } = useThree();
const [dragging, setDragging] = useState(false);
const meshRef = useRef<THREE.Mesh>(null);
const [offset, setOffset] = useState(new THREE.Vector3());
const onPointerDown = (event: PointerEvent) => {
if (!meshRef.current) return;
const rect = gl.domElement.getBoundingClientRect();
const mouseX = ((event.clientX - rect.left) / rect.width) * 2 - 1;
const mouseY = -((event.clientY - rect.top) / rect.height) * 2 + 1;
raycaster.setFromCamera(new THREE.Vector2(mouseX, mouseY), camera);
const planeIntersectPoint = new THREE.Vector3();
if (
raycaster.ray.intersectPlane(
new THREE.Plane(new THREE.Vector3(0, 0, 1), -0),
planeIntersectPoint
)
) {
setDragging(true);
setOffset(meshRef.current.position.clone().sub(planeIntersectPoint));
}
};
const onPointerMove = (event: PointerEvent) => {
if (!dragging || !meshRef.current) return;
const rect = gl.domElement.getBoundingClientRect();
const mouseX = ((event.clientX - rect.left) / rect.width) * 2 - 1;
const mouseY = -((event.clientY - rect.top) / rect.height) * 2 + 1;
raycaster.setFromCamera(new THREE.Vector2(mouseX, mouseY), camera);
const planeIntersectPoint = new THREE.Vector3();
if (
raycaster.ray.intersectPlane(
new THREE.Plane(new THREE.Vector3(0, 0, 1), -0),
planeIntersectPoint
)
) {
const position = planeIntersectPoint.add(offset);
meshRef.current.position.copy(position);
}
};
const onPointerUp = () => {
setDragging(false);
};
useEffect(() => {
gl.domElement.addEventListener("pointerdown", onPointerDown);
gl.domElement.addEventListener("pointermove", onPointerMove);
gl.domElement.addEventListener("pointerup", onPointerUp);
return () => {
gl.domElement.removeEventListener("pointerdown", onPointerDown);
gl.domElement.removeEventListener("pointermove", onPointerMove);
gl.domElement.removeEventListener("pointerup", onPointerUp);
};
}, [dragging]);
return <mesh ref={meshRef}>{children}</mesh>;
};
export default MovingImage;
Is there a better way to implement the movement of a mesh inside a canvas?