diff --git a/public/room.blend b/public/room.blend index c9bb0be..6ae3483 100644 Binary files a/public/room.blend and b/public/room.blend differ diff --git a/public/room.blend1 b/public/room.blend1 index 239a059..a09bcdd 100644 Binary files a/public/room.blend1 and b/public/room.blend1 differ diff --git a/public/room.fbx b/public/room.fbx index 934b5b7..901fb8f 100644 Binary files a/public/room.fbx and b/public/room.fbx differ diff --git a/public/room.glb b/public/room.glb new file mode 100644 index 0000000..a083327 Binary files /dev/null and b/public/room.glb differ diff --git a/src/App.tsx b/src/App.tsx index 739f70d..7703da0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,3 +1,5 @@ +// TODO: handle moving the camera vs actual click + import { useRef, useState, type ComponentRef } from "react"; import { Canvas, @@ -7,20 +9,23 @@ import { useLoader, } from "@react-three/fiber"; import { OrbitControls, useAnimations } from "@react-three/drei"; -import { FBXLoader } from "three/examples/jsm/Addons.js"; +import { GLTFLoader } from "three/examples/jsm/Addons.js"; import { LoopOnce, Vector3 } from "three"; import "./App.css"; const Room = () => { const controls = useRef>(null); - const room = useLoader(FBXLoader, "/room.fbx"); - const { mixer } = useAnimations(room.animations, room); + const room = useLoader(GLTFLoader, "/room.glb"); + const { mixer } = useAnimations(room.animations, room.scene); const [focus, setFocus] = useState(null); const cameraPosition = useRef(null); const cameraTarget = useRef(new Vector3(0, 1, 0)); const [windowState, setWindowState] = useState(false); + const [shadeState, setShadeState] = useState(false); + + const pointerDownCameraPos = useRef(new Vector3()); const { camera } = useThree(); @@ -42,22 +47,20 @@ const Room = () => { controls.current.target.lerp(cameraTarget.current, 0.1); }); - const handleClick = (e: ThreeEvent) => { + const handlePointerUp = (e: ThreeEvent) => { if (!controls.current) return; + if (pointerDownCameraPos.current.distanceTo(camera.position) >= 0.3) return; e.stopPropagation(); - if (e.object.name.includes("Window")) { - const clip = room.animations.find( - (x) => x.name === "LowerWindow|LowerWindowAction", - ); + const clip = room.animations.find((x) => x.name === "LowerWindowAction"); if (!clip) throw "no animation"; const action = mixer.clipAction(clip); if (action.isRunning()) return; action.clampWhenFinished = true; action.setLoop(LoopOnce, 1); - action.timeScale = windowState ? -1 : 1; + action.timeScale = (windowState ? -1 : 1) * 1.5; if (windowState) { action.paused = false; action.time = action.getClip().duration; @@ -69,6 +72,46 @@ const Room = () => { setWindowState(!windowState); } + if (e.object.name.includes("Shade")) { + { + const clip = room.animations.find((x) => x.name === "Cube.010Action"); + if (!clip) throw "no animation"; + + const action = mixer.clipAction(clip); + if (action.isRunning()) return; + action.clampWhenFinished = true; + action.setLoop(LoopOnce, 1); + action.timeScale = (shadeState ? -1 : 1) * 1.5; + if (shadeState) { + action.paused = false; + action.time = action.getClip().duration; + } else { + action.reset(); + } + action.play(); + } + { + const clip = room.animations.find( + (x) => x.name === "ShadeHandleAction", + ); + if (!clip) throw "no animation"; + + const action = mixer.clipAction(clip); + if (action.isRunning()) return; + action.clampWhenFinished = true; + action.setLoop(LoopOnce, 1); + action.timeScale = (shadeState ? -1 : 1) * 1.5; + if (shadeState) { + action.paused = false; + action.time = action.getClip().duration; + } else { + action.reset(); + } + action.play(); + } + setShadeState(!shadeState); + } + if (e.object.name.includes("Poster") && e.object.name !== focus) { const objectPos = new Vector3(); const objectDir = new Vector3(); @@ -106,8 +149,11 @@ const Room = () => { enablePan={false} /> - - + pointerDownCameraPos.current.copy(camera.position)} + onPointerUp={handlePointerUp} + > + );