Files
pihkaal-me/src/App.tsx
2025-05-24 19:37:25 +02:00

98 lines
2.4 KiB
TypeScript

import { useRef, useState, type ComponentRef } from "react";
import {
Canvas,
useFrame,
useThree,
type ThreeEvent,
useLoader,
} from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
import { FBXLoader } from "three/examples/jsm/Addons.js";
import { Vector3 } from "three";
import "./App.css";
const Room = () => {
const controls = useRef<ComponentRef<typeof OrbitControls>>(null);
const room = useLoader(FBXLoader, "/room.fbx");
const [focus, setFocus] = useState<string | null>(null);
const cameraPosition = useRef<Vector3 | null>(null);
const cameraTarget = useRef<Vector3>(new Vector3(0, 1, 0));
const { camera } = useThree();
useFrame(() => {
if (!controls.current) return;
if (cameraPosition.current) {
camera.position.lerp(cameraPosition.current, 0.09);
if (camera.position.distanceTo(cameraPosition.current) < 0.012) {
if (!focus) {
controls.current.enableZoom = true;
controls.current.enableRotate = true;
}
cameraPosition.current = null;
}
}
controls.current.target.lerp(cameraTarget.current, 0.1);
});
const handleClick = (e: ThreeEvent<MouseEvent>) => {
if (!controls.current) return;
e.stopPropagation();
if (e.object.name.includes("Poster") && e.object.name !== focus) {
const objectPos = new Vector3();
const objectDir = new Vector3();
e.object.getWorldPosition(objectPos);
e.object.getWorldDirection(objectDir);
cameraPosition.current = objectPos
.clone()
.add(objectDir.multiplyScalar(-0.65));
cameraTarget.current = objectPos;
controls.current.enableZoom = false;
controls.current.enableRotate = false;
setFocus(e.object.name);
} else if (focus) {
cameraPosition.current = new Vector3(3, 3, -3);
cameraTarget.current = new Vector3(0, 1, 0);
setFocus(null);
}
controls.current.update();
};
return (
<>
<ambientLight intensity={Math.PI / 2} color={"#ffffff"} />
<directionalLight intensity={5} position={[5, 10, 5]} castShadow />
<OrbitControls
ref={controls}
target={[0, 1, 0]}
maxPolarAngle={Math.PI / 2}
enablePan={false}
/>
<mesh onClick={handleClick}>
<primitive object={room} />
</mesh>
</>
);
};
export default function App() {
return (
<Canvas camera={{ position: [3, 3, -3] }}>
<Room />
</Canvas>
);
}