Changes
Co-authored-by: Reifonas <211114984+Reifonas@users.noreply.github.com>
This commit is contained in:
@@ -504,9 +504,138 @@ function GridAutoFollower() {
|
||||
}, 100);
|
||||
return () => clearTimeout(id);
|
||||
}, [models, scene]);
|
||||
/** Mouse drag handler for desktop "Posicionar" mode: translates/rotates the active model. */
|
||||
function PositionDragHandler() {
|
||||
const { camera, gl, scene } = useThree();
|
||||
const positionMode = useModelStore((s) => s.positionMode);
|
||||
const activeId = useModelStore((s) => s.activeModelId);
|
||||
|
||||
useEffect(() => {
|
||||
if (!positionMode) {
|
||||
gl.domElement.style.cursor = 'grab';
|
||||
return;
|
||||
}
|
||||
gl.domElement.style.cursor = 'move';
|
||||
|
||||
const canvas = gl.domElement;
|
||||
let dragging = false;
|
||||
let button = 0;
|
||||
let shiftKey = false;
|
||||
let lastX = 0;
|
||||
let lastY = 0;
|
||||
let pixelsPerWorldUnit = 1;
|
||||
|
||||
const computePixelScale = () => {
|
||||
const st = useModelStore.getState();
|
||||
const active = st.models.find((m) => m.id === st.activeModelId);
|
||||
if (!active) return;
|
||||
// Find the model's group position (approx world): use renderFactor + fineTuning pos
|
||||
const factor = st.scaleRatio?.factor ?? 1;
|
||||
const wp = new THREE.Vector3(
|
||||
active.fineTuning.posX * factor,
|
||||
active.fineTuning.posY * factor,
|
||||
active.fineTuning.posZ * factor,
|
||||
);
|
||||
const dist = camera.position.distanceTo(wp);
|
||||
const perspCam = camera as THREE.PerspectiveCamera;
|
||||
const fov = (perspCam.fov ?? 50) * (Math.PI / 180);
|
||||
const worldPerPixel = (2 * dist * Math.tan(fov / 2)) / canvas.clientHeight;
|
||||
pixelsPerWorldUnit = worldPerPixel; // world units per pixel
|
||||
};
|
||||
|
||||
const onDown = (e: PointerEvent) => {
|
||||
const st = useModelStore.getState();
|
||||
if (!st.positionMode || !st.activeModelId) return;
|
||||
dragging = true;
|
||||
button = e.button;
|
||||
shiftKey = e.shiftKey;
|
||||
lastX = e.clientX;
|
||||
lastY = e.clientY;
|
||||
computePixelScale();
|
||||
(e.target as Element).setPointerCapture?.(e.pointerId);
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
const onMove = (e: PointerEvent) => {
|
||||
if (!dragging) return;
|
||||
const st = useModelStore.getState();
|
||||
const active = st.models.find((m) => m.id === st.activeModelId);
|
||||
if (!active) return;
|
||||
|
||||
const dx = e.clientX - lastX;
|
||||
const dy = e.clientY - lastY;
|
||||
lastX = e.clientX;
|
||||
lastY = e.clientY;
|
||||
shiftKey = e.shiftKey;
|
||||
|
||||
const ft = active.fineTuning;
|
||||
const factor = st.scaleRatio?.factor ?? 1;
|
||||
|
||||
if (button === 2) {
|
||||
// Right button: rotate
|
||||
const sens = 0.4; // deg per pixel
|
||||
if (shiftKey) {
|
||||
useModelStore.getState().setFineTuning({ rotZ: ft.rotZ + dx * sens });
|
||||
} else {
|
||||
useModelStore.getState().setFineTuning({
|
||||
rotY: ft.rotY + dx * sens,
|
||||
rotX: ft.rotX + dy * sens,
|
||||
});
|
||||
}
|
||||
} else if (button === 1 || (button === 0 && shiftKey)) {
|
||||
// Middle or Shift+left: depth (Z in camera space)
|
||||
const worldDelta = dy * pixelsPerWorldUnit;
|
||||
const camDir = new THREE.Vector3();
|
||||
camera.getWorldDirection(camDir);
|
||||
const move = camDir.multiplyScalar(worldDelta).divideScalar(factor);
|
||||
useModelStore.getState().setFineTuning({
|
||||
posX: ft.posX + move.x,
|
||||
posY: ft.posY + move.y,
|
||||
posZ: ft.posZ + move.z,
|
||||
});
|
||||
} else {
|
||||
// Left: translate in camera plane
|
||||
const right = new THREE.Vector3();
|
||||
const up = new THREE.Vector3();
|
||||
camera.matrixWorld.extractBasis(right, up, new THREE.Vector3());
|
||||
const worldDX = dx * pixelsPerWorldUnit;
|
||||
const worldDY = -dy * pixelsPerWorldUnit;
|
||||
const move = right.multiplyScalar(worldDX).add(up.multiplyScalar(worldDY)).divideScalar(factor);
|
||||
useModelStore.getState().setFineTuning({
|
||||
posX: ft.posX + move.x,
|
||||
posY: ft.posY + move.y,
|
||||
posZ: ft.posZ + move.z,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const onUp = (e: PointerEvent) => {
|
||||
dragging = false;
|
||||
(e.target as Element).releasePointerCapture?.(e.pointerId);
|
||||
};
|
||||
|
||||
const onContext = (e: MouseEvent) => e.preventDefault();
|
||||
|
||||
canvas.addEventListener('pointerdown', onDown);
|
||||
canvas.addEventListener('pointermove', onMove);
|
||||
canvas.addEventListener('pointerup', onUp);
|
||||
canvas.addEventListener('pointercancel', onUp);
|
||||
canvas.addEventListener('contextmenu', onContext);
|
||||
return () => {
|
||||
canvas.removeEventListener('pointerdown', onDown);
|
||||
canvas.removeEventListener('pointermove', onMove);
|
||||
canvas.removeEventListener('pointerup', onUp);
|
||||
canvas.removeEventListener('pointercancel', onUp);
|
||||
canvas.removeEventListener('contextmenu', onContext);
|
||||
gl.domElement.style.cursor = 'grab';
|
||||
};
|
||||
}, [positionMode, activeId, camera, gl, scene]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
export function ModelViewerCanvas({ url }: ModelViewerProps) {
|
||||
return (
|
||||
<Canvas
|
||||
|
||||
Reference in New Issue
Block a user