feat(3d): add camera animation

This commit is contained in:
xfy
2025-05-21 16:33:32 +08:00
parent 73f6efadcd
commit 512a6c8a9c
6 changed files with 66 additions and 11 deletions

View File

@ -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}
>
<mesh
castShadow

View File

@ -1,12 +1,12 @@
'use client';
import { PerspectiveCamera } from '@react-three/drei/core/PerspectiveCamera';
import { Canvas } from '@react-three/fiber';
import { lazy, Suspense, useMemo } from 'react';
import Loading from './loading';
import { PerspectiveCamera } from '@react-three/drei/core/PerspectiveCamera';
import { useMediaQuery } from 'react-responsive';
import { useTexture } from '@react-three/drei';
import Loading from './loading';
const DeskCamera = lazy(() => import('components/models/home/desk-camera'));
const ComputerModel = lazy(
() => import('components/models/home/computer-model'),
);
@ -29,14 +29,16 @@ const ComputerDesk = () => {
<Suspense fallback={<Loading />}>
<ambientLight intensity={1} />
<directionalLight position={[10, 10, 10]} intensity={0.5} />
<ComputerModel
scale={scale}
position={[0.6, -7.2, 0]}
rotation={[0, -Math.PI, 0]}
/>
<DeskCamera>
<ComputerModel
scale={scale}
position={[0.6, -7.2, 0]}
rotation={[0, -Math.PI, 0]}
/>
</DeskCamera>
<Target />
<ReactLogo />
<PerspectiveCamera makeDefault position={[0, 0, 30]} />
<PerspectiveCamera makeDefault position={[0, 0, 36]} />
<Bocchi />
</Suspense>
</Canvas>

View File

@ -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 (
<group {...props} dispose={null}>
@ -107,13 +108,17 @@ export function Model(props: JSX.IntrinsicElements['group']) {
receiveShadow
geometry={nodes.Tv_tv_mat_0.geometry}
material={materials.tv_mat}
/>
>
<meshMatcapMaterial map={moniterTexture} />
</mesh>
<mesh
castShadow
receiveShadow
geometry={nodes.table_table_mat_0.geometry}
material={materials.table_mat}
/>
>
<meshMatcapMaterial map={tableTexture} />
</mesh>
<mesh
castShadow
receiveShadow

View File

@ -0,0 +1,43 @@
import * as THREE from 'three';
import { JSX, useRef } from 'react';
import { useFrame } from '@react-three/fiber';
import { easing } from 'maath';
import { useMediaQuery } from 'react-responsive';
const DeskCamera = ({ children }: { children: JSX.Element }) => {
const groupRef = useRef<THREE.Group>(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 <group ref={groupRef}>{children}</group>;
};
export default DeskCamera;

View File

@ -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",

3
pnpm-lock.yaml generated
View File

@ -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)