Changes
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { Suspense, useRef, useMemo } from 'react';
|
||||
import { Canvas } from '@react-three/fiber';
|
||||
import { OrbitControls, useGLTF, Grid, Environment, Html } from '@react-three/drei';
|
||||
import { Suspense, useRef, useMemo, useEffect } from 'react';
|
||||
import { Canvas, useFrame } from '@react-three/fiber';
|
||||
import { OrbitControls, useGLTF, Grid, Html } from '@react-three/drei';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import * as THREE from 'three';
|
||||
import { useModelStore } from '@/stores/useModelStore';
|
||||
|
||||
interface ModelViewerProps {
|
||||
url: string;
|
||||
@@ -22,6 +23,9 @@ function LoadingFallback() {
|
||||
function GLBModel({ url }: { url: string }) {
|
||||
const { scene } = useGLTF(url);
|
||||
const ref = useRef<THREE.Group>(null);
|
||||
const opacity = useModelStore((s) => s.opacity);
|
||||
const renderMode = useModelStore((s) => s.renderMode);
|
||||
const checklist = useModelStore((s) => s.checklist);
|
||||
|
||||
const modelInfo = useMemo(() => {
|
||||
const box = new THREE.Box3().setFromObject(scene);
|
||||
@@ -32,6 +36,41 @@ function GLBModel({ url }: { url: string }) {
|
||||
return { size, center };
|
||||
}, [scene]);
|
||||
|
||||
// Apply opacity, wireframe, and checklist color feedback
|
||||
useEffect(() => {
|
||||
// Determine overall inspection color
|
||||
const hasRejected = checklist.some(i => i.status === 'rejected');
|
||||
const allApproved = checklist.every(i => i.status === 'approved');
|
||||
|
||||
scene.traverse((child) => {
|
||||
if (child instanceof THREE.Mesh) {
|
||||
// Clone material to avoid shared mutations
|
||||
if (Array.isArray(child.material)) {
|
||||
child.material = child.material.map(m => m.clone());
|
||||
} else {
|
||||
child.material = child.material.clone();
|
||||
}
|
||||
const materials = Array.isArray(child.material) ? child.material : [child.material];
|
||||
materials.forEach((mat: THREE.Material) => {
|
||||
if (mat instanceof THREE.MeshStandardMaterial) {
|
||||
mat.transparent = opacity < 1;
|
||||
mat.opacity = opacity;
|
||||
mat.wireframe = renderMode === 'wireframe';
|
||||
mat.needsUpdate = true;
|
||||
// Color feedback
|
||||
if (hasRejected) {
|
||||
mat.color.setHSL(0, 0.7, 0.5); // red
|
||||
} else if (allApproved) {
|
||||
mat.color.setHSL(0.38, 0.7, 0.45); // green
|
||||
} else {
|
||||
mat.color.set(0x8899aa); // default steel
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}, [scene, opacity, renderMode, checklist]);
|
||||
|
||||
return (
|
||||
<group ref={ref} position={[-modelInfo.center.x, -modelInfo.center.y, -modelInfo.center.z]}>
|
||||
<primitive object={scene} />
|
||||
@@ -43,8 +82,16 @@ export function ModelViewerCanvas({ url }: ModelViewerProps) {
|
||||
return (
|
||||
<Canvas
|
||||
camera={{ position: [2, 2, 2], fov: 50, near: 0.001, far: 1000 }}
|
||||
gl={{ antialias: true, alpha: true }}
|
||||
gl={{ antialias: true, alpha: true, powerPreference: 'high-performance' }}
|
||||
frameloop="demand"
|
||||
className="!bg-background"
|
||||
onCreated={({ gl, invalidate }) => {
|
||||
// Target 72fps for Quest 3 compatibility
|
||||
gl.setPixelRatio(Math.min(window.devicePixelRatio, 1.5));
|
||||
// Continuous render for smooth interaction
|
||||
const loop = () => { invalidate(); requestAnimationFrame(loop); };
|
||||
loop();
|
||||
}}
|
||||
>
|
||||
<ambientLight intensity={0.6} />
|
||||
<directionalLight position={[5, 10, 5]} intensity={1} castShadow />
|
||||
@@ -76,4 +123,3 @@ export function ModelViewerCanvas({ url }: ModelViewerProps) {
|
||||
</Canvas>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user