dmpsuzuki's picture
Initial Upload
a82dc04
Raw
History Blame Contribute Delete
2.51 kB
import * as THREE from "three";
const LOOK_SPEED = 0.003;
const _yawQ = new THREE.Quaternion();
const _pitQ = new THREE.Quaternion();
const raycaster = new THREE.Raycaster();
const _ndc = new THREE.Vector2();
function raycastAt(mesh, camera, clientX, clientY) {
_ndc.set((clientX / innerWidth) * 2 - 1, -(clientY / innerHeight) * 2 + 1);
raycaster.setFromCamera(_ndc, camera);
const hits = [];
mesh.raycast(raycaster, hits);
hits.sort((a, b) => a.distance - b.distance);
return hits[0] ?? null;
}
export function setupControls(domElement, camera, mesh) {
let dragging = false,
dragButton = 0,
lastX = 0,
lastY = 0;
domElement.addEventListener("pointerdown", (e) => {
dragging = true;
dragButton = e.button;
lastX = e.clientX;
lastY = e.clientY;
domElement.setPointerCapture(e.pointerId);
});
domElement.addEventListener("pointermove", (e) => {
if (!dragging) return;
const dx = e.clientX - lastX,
dy = e.clientY - lastY;
lastX = e.clientX;
lastY = e.clientY;
if (dragButton === 0) {
// Left-drag: look around
const camUp = new THREE.Vector3(0, 1, 0).applyQuaternion(
camera.quaternion,
);
camera.quaternion.premultiply(
_yawQ.setFromAxisAngle(camUp, -dx * LOOK_SPEED),
);
const camRight = new THREE.Vector3(1, 0, 0).applyQuaternion(
camera.quaternion,
);
camera.quaternion.premultiply(
_pitQ.setFromAxisAngle(camRight, -dy * LOOK_SPEED),
);
camera.quaternion.normalize();
} else if (dragButton === 2) {
// Right-drag: pan
const hit = raycastAt(mesh, camera, lastX, lastY);
const panSpeed = (hit ? hit.distance : 5) * 0.001;
const right = new THREE.Vector3(1, 0, 0).applyQuaternion(
camera.quaternion,
);
const up = new THREE.Vector3(0, 1, 0).applyQuaternion(camera.quaternion);
camera.position.addScaledVector(right, -dx * panSpeed);
camera.position.addScaledVector(up, dy * panSpeed);
}
});
domElement.addEventListener("pointerup", () => {
dragging = false;
});
domElement.addEventListener("contextmenu", (e) => e.preventDefault());
domElement.addEventListener(
"wheel",
(e) => {
const hit = raycastAt(mesh, camera, e.clientX, e.clientY);
const dist = hit ? hit.distance : 10;
camera.position.addScaledVector(
raycaster.ray.direction,
-(dist * e.deltaY * 0.001),
);
},
{ passive: true },
);
}