From 512a6c8a9ca2d9b811b70b28fc3ea9a6c60bfe86 Mon Sep 17 00:00:00 2001 From: xfy Date: Wed, 21 May 2025 16:33:32 +0800 Subject: [PATCH] feat(3d): add camera animation --- components/models/home/bocchi.tsx | 1 + components/models/home/computer-desk.tsx | 20 ++++++----- components/models/home/computer-model.tsx | 9 +++-- components/models/home/desk-camera.tsx | 43 +++++++++++++++++++++++ package.json | 1 + pnpm-lock.yaml | 3 ++ 6 files changed, 66 insertions(+), 11 deletions(-) create mode 100644 components/models/home/desk-camera.tsx diff --git a/components/models/home/bocchi.tsx b/components/models/home/bocchi.tsx index 14ee59f..f5fe252 100644 --- a/components/models/home/bocchi.tsx +++ b/components/models/home/bocchi.tsx @@ -50,6 +50,7 @@ const BocchiRubbishBin = (props: JSX.IntrinsicElements['group']) => { dispose={null} position={position} rotation={[Math.PI / 10, Math.PI / 10, 0]} + scale={0.7} > import('components/models/home/desk-camera')); const ComputerModel = lazy( () => import('components/models/home/computer-model'), ); @@ -29,14 +29,16 @@ const ComputerDesk = () => { }> - + + + - + diff --git a/components/models/home/computer-model.tsx b/components/models/home/computer-model.tsx index 3e009df..ba7ce6c 100644 --- a/components/models/home/computer-model.tsx +++ b/components/models/home/computer-model.tsx @@ -61,6 +61,7 @@ export function Model(props: JSX.IntrinsicElements['group']) { const moniterTexture = useTexture('/texture/desk/monitor.png'); const screenTexture = useTexture('/texture/desk/screen.png'); + const tableTexture = useTexture('/texture/desk/table.png'); return ( @@ -107,13 +108,17 @@ export function Model(props: JSX.IntrinsicElements['group']) { receiveShadow geometry={nodes.Tv_tv_mat_0.geometry} material={materials.tv_mat} - /> + > + + + > + + { + const groupRef = useRef(null); + + const isMobile = useMediaQuery({ query: '(max-width: 768px)' }); + useFrame((state, delta) => { + easing.damp3(state.camera.position, [0, 0, 26], 0.25, delta); + + if (!isMobile && groupRef.current) { + const x = (() => { + const _x = state.pointer.y / 3; + if (_x < 0) { + if (_x <= -0.14) { + return -0.14; + } else { + return _x; + } + } else { + if (_x >= 0.14) { + return 0.14; + } else { + return _x; + } + } + })(); + easing.dampE( + groupRef.current.rotation, + [-x, -state.pointer.x / 5, 0], + 0.25, + delta, + ); + } + }); + + return {children}; +}; + +export default DeskCamera; diff --git a/package.json b/package.json index 7605f23..45d8c65 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "algoliasearch": "^5.25.0", "dayjs": "^1.11.13", "gsap": "^3.13.0", + "maath": "^0.10.8", "next": "15.3.2", "next-mdx-remote": "^5.0.0", "next-themes": "^0.4.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dea5bcb..5ef94c3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,6 +59,9 @@ importers: gsap: specifier: ^3.13.0 version: 3.13.0 + maath: + specifier: ^0.10.8 + version: 0.10.8(@types/three@0.176.0)(three@0.176.0) next: specifier: 15.3.2 version: 15.3.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.89.0)