Sincronizou cubo ao quaternion
X-Lovable-Edit-ID: edt-89f942ba-4eaa-4ce5-aae9-570b432a9c90 Co-authored-by: Reifonas <211114984+Reifonas@users.noreply.github.com>
This commit is contained in:
@@ -12,6 +12,7 @@ import {
|
|||||||
subscribeCalibration,
|
subscribeCalibration,
|
||||||
} from './three/viewCubeBus';
|
} from './three/viewCubeBus';
|
||||||
import { useModelStore } from '@/stores/useModelStore';
|
import { useModelStore } from '@/stores/useModelStore';
|
||||||
|
import { getModelLocalGroup } from '@/lib/modelTransforms';
|
||||||
import { Check, RotateCcw } from 'lucide-react';
|
import { Check, RotateCcw } from 'lucide-react';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
|
|
||||||
@@ -52,8 +53,9 @@ const FACE_DEFS: { label: string; dir: [number, number, number] }[] = [
|
|||||||
{ label: 'ATRÁS', dir: [ 0, 0,-1] },
|
{ label: 'ATRÁS', dir: [ 0, 0,-1] },
|
||||||
];
|
];
|
||||||
|
|
||||||
function CubeMesh({ calibrating }: { calibrating: boolean }) {
|
function CubeMesh({ calibrating, activeModelId }: { calibrating: boolean; activeModelId: string | null }) {
|
||||||
const meshRef = useRef<THREE.Mesh>(null);
|
const meshRef = useRef<THREE.Mesh>(null);
|
||||||
|
const groupRef = useRef<THREE.Group>(null);
|
||||||
const { camera: localCam } = useThree();
|
const { camera: localCam } = useThree();
|
||||||
const [hover, setHover] = useState<number | null>(null);
|
const [hover, setHover] = useState<number | null>(null);
|
||||||
|
|
||||||
@@ -85,6 +87,21 @@ function CubeMesh({ calibrating }: { calibrating: boolean }) {
|
|||||||
});
|
});
|
||||||
}, [hover, materials]);
|
}, [hover, materials]);
|
||||||
|
|
||||||
|
// Reusable temp objects for the per-frame model-quaternion sync.
|
||||||
|
const modelQuat = useMemo(() => new THREE.Quaternion(), []);
|
||||||
|
/** Returns the active model's current world quaternion (fineTuning rotation
|
||||||
|
* + calibration). Used to keep the cube glued to the piece's pose. */
|
||||||
|
const getModelWorldQuat = (): THREE.Quaternion => {
|
||||||
|
const g = getModelLocalGroup(activeModelId);
|
||||||
|
if (g) {
|
||||||
|
g.updateWorldMatrix(true, false);
|
||||||
|
g.getWorldQuaternion(modelQuat);
|
||||||
|
return modelQuat;
|
||||||
|
}
|
||||||
|
modelQuat.identity();
|
||||||
|
return modelQuat;
|
||||||
|
};
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
const main = mainCameraRef.current;
|
const main = mainCameraRef.current;
|
||||||
const controls = mainControlsRef.current;
|
const controls = mainControlsRef.current;
|
||||||
@@ -94,6 +111,11 @@ function CubeMesh({ calibrating }: { calibrating: boolean }) {
|
|||||||
localCam.position.copy(dir.multiplyScalar(3));
|
localCam.position.copy(dir.multiplyScalar(3));
|
||||||
localCam.up.copy(main.up);
|
localCam.up.copy(main.up);
|
||||||
localCam.lookAt(0, 0, 0);
|
localCam.lookAt(0, 0, 0);
|
||||||
|
// Sync the cube group orientation with the active model so it always
|
||||||
|
// mirrors the piece's pose (rotation from Posicionar, calibration, etc).
|
||||||
|
if (groupRef.current) {
|
||||||
|
groupRef.current.quaternion.copy(getModelWorldQuat());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const onClick = (e: ThreeEvent<MouseEvent>) => {
|
const onClick = (e: ThreeEvent<MouseEvent>) => {
|
||||||
@@ -102,17 +124,21 @@ function CubeMesh({ calibrating }: { calibrating: boolean }) {
|
|||||||
if (idx == null) return;
|
if (idx == null) return;
|
||||||
const def = FACE_DEFS[idx];
|
const def = FACE_DEFS[idx];
|
||||||
if (!def) return;
|
if (!def) return;
|
||||||
const dirVec = new THREE.Vector3(...def.dir);
|
// Convert the local cube-face direction to world space using the model's
|
||||||
|
// current world quaternion — this keeps cube ↔ model coherent after any
|
||||||
|
// rotation/translation/reset of the piece.
|
||||||
|
const dirWorld = new THREE.Vector3(...def.dir).applyQuaternion(getModelWorldQuat()).normalize();
|
||||||
if (calibrating) {
|
if (calibrating) {
|
||||||
pushCubeFace(dirVec);
|
pushCubeFace(dirWorld);
|
||||||
} else {
|
} else {
|
||||||
requestView(dirVec);
|
requestView(dirWorld);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 70% of previous 1.4 → ~0.98
|
// 70% of previous 1.4 → ~0.98
|
||||||
const SIZE = 0.98;
|
const SIZE = 0.98;
|
||||||
return (
|
return (
|
||||||
|
<group ref={groupRef}>
|
||||||
<mesh
|
<mesh
|
||||||
ref={meshRef}
|
ref={meshRef}
|
||||||
material={materials}
|
material={materials}
|
||||||
@@ -126,6 +152,8 @@ function CubeMesh({ calibrating }: { calibrating: boolean }) {
|
|||||||
>
|
>
|
||||||
<boxGeometry args={[SIZE, SIZE, SIZE]} />
|
<boxGeometry args={[SIZE, SIZE, SIZE]} />
|
||||||
</mesh>
|
</mesh>
|
||||||
|
<AxisTripod />
|
||||||
|
</group>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,8 +241,7 @@ export function ViewCube() {
|
|||||||
dpr={[1, 2]}
|
dpr={[1, 2]}
|
||||||
>
|
>
|
||||||
<ambientLight intensity={1} />
|
<ambientLight intensity={1} />
|
||||||
<CubeMesh calibrating={isCalibrating} />
|
<CubeMesh calibrating={isCalibrating} activeModelId={activeModelId} />
|
||||||
<AxisTripod />
|
|
||||||
</Canvas>
|
</Canvas>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user