diff --git a/app/home-modle.tsx b/app/home-modle.tsx index 7c612c6..ed5ea9c 100644 --- a/app/home-modle.tsx +++ b/app/home-modle.tsx @@ -1,11 +1,12 @@ 'use client'; -import { Canvas, useFrame, useLoader } from '@react-three/fiber'; -import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; -import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; -import { Environment, OrbitControls, useProgress } from '@react-three/drei'; -import { useRef, useState } from 'react'; +import { useProgress } from '@react-three/drei'; +import { Canvas, useFrame, useLoader, useThree } from '@react-three/fiber'; +import { frameArea } from 'lib/utils'; +import { useRef } from 'react'; import * as THREE from 'three'; +import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; +import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; const Model = () => { const mixer = useRef(null); @@ -19,16 +20,27 @@ const Model = () => { } ); - const [loading, setLoading] = useState(true); - useProgress((state) => { - if (state.progress >= 100) { - mixer.current = new THREE.AnimationMixer(gltf.scene); - gltf.animations.forEach((clip) => { - mixer.current?.clipAction(clip).play(); - }); - setLoading(false); - } + const camera = useThree((state) => state.camera); + const process = useProgress((state) => { + if (state.progress < 100) return state.progress; + // After model loaded. + mixer.current = new THREE.AnimationMixer(gltf.scene); + gltf.animations.forEach((clip) => { + mixer.current?.clipAction(clip).play(); + }); + + const box = new THREE.Box3().setFromObject(gltf.scene); + const boxSize = box.getSize(new THREE.Vector3()).length(); + const boxCenter = box.getCenter(new THREE.Vector3()); + frameArea( + boxSize * 0.8, + boxSize, + boxCenter, + camera as THREE.PerspectiveCamera + ); + camera.position.z += 0.15; + camera.position.y -= 0.15; return state.progress; }); @@ -46,13 +58,9 @@ const Model = () => { const HomeModel = () => { return ( - - + + - {/* - - - */} ); }; diff --git a/lib/utils/index.ts b/lib/utils/index.ts index 2eb3285..72ba2cc 100644 --- a/lib/utils/index.ts +++ b/lib/utils/index.ts @@ -1,3 +1,5 @@ +import * as THREE from 'three'; + export const sortByDate = ( { date: a }: { date: string }, { date: b }: { date: string } @@ -118,3 +120,34 @@ export const debounce: Debounce = (fn, ms) => { }, ms); }; }; + +export const frameArea = ( + sizeToFitOnScreen: number, + boxSize: number, + boxCenter: THREE.Vector3, + camera: THREE.PerspectiveCamera +) => { + const halfSizeToFitOnScreen = sizeToFitOnScreen * 0.5; + const halfFovY = THREE.MathUtils.degToRad(camera.fov * 0.5); + const distance = halfSizeToFitOnScreen / Math.tan(halfFovY); + // compute a unit vector that points in the direction the camera is now + // in the xz plane from the center of the box + const direction = new THREE.Vector3() + .subVectors(camera.position, boxCenter) + .multiply(new THREE.Vector3(1, 0, 1)) + .normalize(); + + // move the camera to a position distance units way from the center + // in whatever direction the camera was from the center already + camera.position.copy(direction.multiplyScalar(distance).add(boxCenter)); + + // pick some near and far values for the frustum that + // will contain the box. + camera.near = boxSize / 100; + camera.far = boxSize * 100; + + camera.updateProjectionMatrix(); + + // point the camera to look at the center of the box + camera.lookAt(boxCenter.x, boxCenter.y, boxCenter.z); +}; \ No newline at end of file