working on panning, currently kinda glitchy
This commit is contained in:
parent
f5db701d3c
commit
e7ab6a2d76
1 changed files with 100 additions and 19 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import { useThree } from "@react-three/fiber";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { Plane, Raycaster, Vector2, Vector3 } from "three";
|
||||
|
||||
interface CameraTarget {
|
||||
x: number;
|
||||
|
|
@ -25,8 +26,18 @@ interface Props {
|
|||
export default function OrbitCameraControls(props: Props) {
|
||||
const { target, clampVerticalRotation, minPhi = 0.01, maxPhi = Math.PI - 0.01 } = props;
|
||||
const { camera, gl } = useThree();
|
||||
const panPlane = useRef(new Plane());
|
||||
const panStartPoint = useRef(new Vector3());
|
||||
const raycaster = useRef(new Raycaster());
|
||||
const mouse = useRef(new Vector2());
|
||||
const targetRef = useRef({
|
||||
x: target?.x ?? 0,
|
||||
y: target?.y ?? 0,
|
||||
z: target?.z ?? 0,
|
||||
});
|
||||
|
||||
const isDragging = useRef(false);
|
||||
const isPanning = useRef(false);
|
||||
const lastPos = useRef({ x: 0, y: 0 });
|
||||
|
||||
// Spherical coords
|
||||
|
|
@ -38,7 +49,7 @@ export default function OrbitCameraControls(props: Props) {
|
|||
|
||||
useEffect(() => {
|
||||
const canvas = gl.domElement;
|
||||
|
||||
canvas.addEventListener("contextmenu", e => e.preventDefault());
|
||||
const updateCamera = () => {
|
||||
const { radius, theta, phi } = spherical.current;
|
||||
|
||||
|
|
@ -47,41 +58,111 @@ export default function OrbitCameraControls(props: Props) {
|
|||
const z = radius * Math.sin(phi) * Math.cos(theta);
|
||||
|
||||
camera.position.set(x, y, z);
|
||||
camera.lookAt(target?.x ?? 0, target?.y ?? 0, target?.z ?? 0);
|
||||
camera.lookAt(
|
||||
targetRef.current.x,
|
||||
targetRef.current.y,
|
||||
targetRef.current.z
|
||||
);
|
||||
};
|
||||
|
||||
updateCamera();
|
||||
|
||||
const handleMouseDown = (e: MouseEvent) => {
|
||||
if (e.target !== canvas) return;
|
||||
isDragging.current = true;
|
||||
|
||||
lastPos.current = { x: e.clientX, y: e.clientY };
|
||||
|
||||
// Left click = rotate
|
||||
if (e.button === 0) {
|
||||
isDragging.current = true;
|
||||
isPanning.current = false;
|
||||
}
|
||||
|
||||
// Right click = pan
|
||||
if (e.button === 2) {
|
||||
isPanning.current = true;
|
||||
isDragging.current = false;
|
||||
|
||||
// plane facing camera through target
|
||||
const camDir = new Vector3();
|
||||
camera.getWorldDirection(camDir);
|
||||
|
||||
panPlane.current.setFromNormalAndCoplanarPoint(
|
||||
camDir,
|
||||
new Vector3(
|
||||
targetRef.current.x,
|
||||
targetRef.current.y,
|
||||
targetRef.current.z
|
||||
)
|
||||
);
|
||||
|
||||
// starting intersection point
|
||||
raycaster.current.setFromCamera(
|
||||
new Vector2(
|
||||
(e.clientX / window.innerWidth) * 2 - 1,
|
||||
-(e.clientY / window.innerHeight) * 2 + 1
|
||||
),
|
||||
camera
|
||||
);
|
||||
|
||||
raycaster.current.ray.intersectPlane(
|
||||
panPlane.current,
|
||||
panStartPoint.current
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
if (!isDragging.current) return;
|
||||
|
||||
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
const deltaX = e.clientX - lastPos.current.x;
|
||||
const deltaY = e.clientY - lastPos.current.y;
|
||||
|
||||
// ROTATE
|
||||
if (isDragging.current) {
|
||||
spherical.current.theta -= deltaX * 0.005;
|
||||
spherical.current.phi -= deltaY * 0.005;
|
||||
|
||||
// Clamp vertical rotation (prevents flipping)
|
||||
if (clampVerticalRotation) {
|
||||
spherical.current.phi = Math.max(
|
||||
minPhi,
|
||||
Math.min(maxPhi, spherical.current.phi)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// PAN
|
||||
if (isPanning.current) {
|
||||
const raycaster = new Raycaster();
|
||||
|
||||
mouse.current.x = (e.clientX / window.innerWidth) * 2 - 1;
|
||||
mouse.current.y = -(e.clientY / window.innerHeight) * 2 + 1;
|
||||
|
||||
raycaster.setFromCamera(mouse.current, camera);
|
||||
|
||||
const currentPoint = new Vector3();
|
||||
|
||||
raycaster.ray.intersectPlane(panPlane.current, currentPoint);
|
||||
|
||||
const delta = new Vector3().subVectors(
|
||||
panStartPoint.current,
|
||||
currentPoint
|
||||
);
|
||||
|
||||
targetRef.current.x += delta.x;
|
||||
targetRef.current.y += delta.y;
|
||||
targetRef.current.z += delta.z;
|
||||
|
||||
panStartPoint.current.copy(currentPoint);
|
||||
}
|
||||
|
||||
lastPos.current = { x: e.clientX, y: e.clientY };
|
||||
|
||||
updateCamera();
|
||||
};
|
||||
|
||||
const handleMouseUp = () => {
|
||||
isDragging.current = false;
|
||||
isPanning.current = false;
|
||||
};
|
||||
|
||||
const handleWheel = (e: WheelEvent) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue