Corrigiu seleção do modelo 3D
X-Lovable-Edit-ID: edt-4d77ca34-5604-4bfa-8684-94d3365da153 Co-authored-by: Reifonas <211114984+Reifonas@users.noreply.github.com>
This commit is contained in:
@@ -83,6 +83,7 @@ function GLBModel({ sceneModel, isActive }: { sceneModel: SceneModel; isActive:
|
|||||||
const edgeThresholdAngle = useModelStore((s) => s.edgeThresholdAngle);
|
const edgeThresholdAngle = useModelStore((s) => s.edgeThresholdAngle);
|
||||||
const checklist = useModelStore((s) => s.checklist);
|
const checklist = useModelStore((s) => s.checklist);
|
||||||
const setActive = useModelStore((s) => s.setActiveModel);
|
const setActive = useModelStore((s) => s.setActiveModel);
|
||||||
|
const selectionMode = useModelStore((s) => s.selectionMode);
|
||||||
const fineTuning = sceneModel.fineTuning;
|
const fineTuning = sceneModel.fineTuning;
|
||||||
|
|
||||||
const modelInfo = useMemo(() => {
|
const modelInfo = useMemo(() => {
|
||||||
@@ -184,7 +185,20 @@ function GLBModel({ sceneModel, isActive }: { sceneModel: SceneModel; isActive:
|
|||||||
return (
|
return (
|
||||||
<group
|
<group
|
||||||
scale={[renderFactor, renderFactor, renderFactor]}
|
scale={[renderFactor, renderFactor, renderFactor]}
|
||||||
onClick={(e) => { e.stopPropagation(); setActive(sceneModel.id); }}
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if ((e.delta ?? 0) > 4) return;
|
||||||
|
|
||||||
|
if (selectionMode) {
|
||||||
|
const element = findElementRoot(e.object);
|
||||||
|
if (element) {
|
||||||
|
useModelStore.getState().toggleElementSelection(elementKey(sceneModel.id, element));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setActive(sceneModel.id);
|
||||||
|
}}
|
||||||
userData={{ modelId: sceneModel.id, dominantAxis }}
|
userData={{ modelId: sceneModel.id, dominantAxis }}
|
||||||
>
|
>
|
||||||
{/* Translation */}
|
{/* Translation */}
|
||||||
@@ -707,43 +721,27 @@ function SelectionHandler() {
|
|||||||
const prevCursor = gl.domElement.style.cursor;
|
const prevCursor = gl.domElement.style.cursor;
|
||||||
gl.domElement.style.cursor = 'cell';
|
gl.domElement.style.cursor = 'cell';
|
||||||
const canvas = gl.domElement;
|
const canvas = gl.domElement;
|
||||||
let downX = 0, downY = 0, armed = false;
|
|
||||||
|
|
||||||
const onDown = (e: PointerEvent) => {
|
|
||||||
if (e.button !== 0) { armed = false; return; }
|
|
||||||
downX = e.clientX; downY = e.clientY; armed = true;
|
|
||||||
};
|
|
||||||
const onUp = (e: PointerEvent) => {
|
|
||||||
if (!armed) return;
|
|
||||||
armed = false;
|
|
||||||
if (Math.hypot(e.clientX - downX, e.clientY - downY) > 4) return;
|
|
||||||
|
|
||||||
|
const onR3FMiss = (event: Event) => {
|
||||||
|
const detail = (event as CustomEvent<PointerEvent>).detail;
|
||||||
|
if (!detail || detail.button !== 0) return;
|
||||||
const rect = canvas.getBoundingClientRect();
|
const rect = canvas.getBoundingClientRect();
|
||||||
mouse.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;
|
mouse.x = ((detail.clientX - rect.left) / rect.width) * 2 - 1;
|
||||||
mouse.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;
|
mouse.y = -((detail.clientY - rect.top) / rect.height) * 2 + 1;
|
||||||
raycaster.setFromCamera(mouse, camera);
|
raycaster.setFromCamera(mouse, camera);
|
||||||
const intersects = raycaster.intersectObjects(scene.children, true);
|
const intersects = raycaster.intersectObjects(scene.children, true);
|
||||||
const hit = intersects.find((i) => isPickableModelMesh(i.object));
|
const hit = intersects.find((i) => isPickableModelMesh(i.object));
|
||||||
if (!hit) return;
|
if (!hit) return;
|
||||||
|
|
||||||
const element = findElementRoot(hit.object);
|
const element = findElementRoot(hit.object);
|
||||||
let cur: THREE.Object3D | null = hit.object;
|
const modelId = useModelStore.getState().activeModelId;
|
||||||
let modelId: string | null = null;
|
|
||||||
while (cur) {
|
|
||||||
if (!modelId && cur.userData?.modelId) modelId = cur.userData.modelId as string;
|
|
||||||
cur = cur.parent;
|
|
||||||
}
|
|
||||||
if (!modelId) modelId = useModelStore.getState().activeModelId;
|
|
||||||
if (!modelId || !element) return;
|
if (!modelId || !element) return;
|
||||||
const key = elementKey(modelId, element);
|
useModelStore.getState().toggleElementSelection(elementKey(modelId, element));
|
||||||
useModelStore.getState().toggleElementSelection(key);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
canvas.addEventListener('pointerdown', onDown);
|
canvas.addEventListener('tsxr-selection-miss', onR3FMiss);
|
||||||
canvas.addEventListener('pointerup', onUp);
|
|
||||||
return () => {
|
return () => {
|
||||||
canvas.removeEventListener('pointerdown', onDown);
|
canvas.removeEventListener('tsxr-selection-miss', onR3FMiss);
|
||||||
canvas.removeEventListener('pointerup', onUp);
|
|
||||||
gl.domElement.style.cursor = prevCursor;
|
gl.domElement.style.cursor = prevCursor;
|
||||||
};
|
};
|
||||||
}, [selectionMode, camera, scene, gl, raycaster, mouse]);
|
}, [selectionMode, camera, scene, gl, raycaster, mouse]);
|
||||||
@@ -1021,6 +1019,11 @@ export function ModelViewerCanvas({ url }: ModelViewerProps) {
|
|||||||
gl={{ antialias: true, alpha: true, powerPreference: 'high-performance', preserveDrawingBuffer: true }}
|
gl={{ antialias: true, alpha: true, powerPreference: 'high-performance', preserveDrawingBuffer: true }}
|
||||||
frameloop="always"
|
frameloop="always"
|
||||||
className="!bg-background"
|
className="!bg-background"
|
||||||
|
onPointerMissed={(e) => {
|
||||||
|
if (useModelStore.getState().selectionMode) {
|
||||||
|
(e.target as HTMLCanvasElement).dispatchEvent(new CustomEvent('tsxr-selection-miss', { detail: e }));
|
||||||
|
}
|
||||||
|
}}
|
||||||
onCreated={({ gl }) => {
|
onCreated={({ gl }) => {
|
||||||
const isApple = /Mac|iPhone|iPad/.test(navigator.platform);
|
const isApple = /Mac|iPhone|iPad/.test(navigator.platform);
|
||||||
const maxRatio = isApple ? 2 : 1.5;
|
const maxRatio = isApple ? 2 : 1.5;
|
||||||
|
|||||||
Reference in New Issue
Block a user