ํฐ์คํ ๋ฆฌ ๋ทฐ
๐ Three.js์์ 3D ๋ชจ๋ธ ์ ๋๋ฉ์ด์ ๋ถ๋ฌ์ค๊ธฐ & ์ ์ดํ๊ธฐ
octo54 2025. 3. 28. 11:46๐ Three.js์์ 3D ๋ชจ๋ธ ์ ๋๋ฉ์ด์ ๋ถ๋ฌ์ค๊ธฐ & ์ ์ดํ๊ธฐ
์ด์ ๊ธ์์๋ GLTFLoader๋ฅผ ์ฌ์ฉํ์ฌ 3D ๋ชจ๋ธ์ ๋ถ๋ฌ์ค๊ณ , Three.js ์ฌ์ ๋ฐฐ์นํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์ ์ต๋๋ค.
์ด๋ฒ ๊ธ์์๋ ์ ๋๋ฉ์ด์
์ด ํฌํจ๋ GLTF ๋ชจ๋ธ์ ๋ถ๋ฌ์ค๊ณ , ์ฌ์/์ ์ง/์๋ ์กฐ์ ๋ฑ์ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃน๋๋ค.
๐ 1. Three.js์์ ์ ๋๋ฉ์ด์ ์ ์ฉํ๋ ๋ฐฉ๋ฒ
GLTF ๋ชจ๋ธ(.gltf ๋๋ .glb)์๋ ์ ๋๋ฉ์ด์
์ด ํฌํจ๋ ์ ์์ต๋๋ค.
Three.js์์๋ AnimationMixer๋ฅผ ์ฌ์ฉํ์ฌ ์ ๋๋ฉ์ด์
์ ์ ์ดํ ์ ์์ต๋๋ค.
๐ ์ ๋๋ฉ์ด์ ์ ์ฉ ๋ฐฉ๋ฒ
- useGLTF()๋ฅผ ์ฌ์ฉํ์ฌ GLTF ๋ชจ๋ธ ๋ก๋
- AnimationMixer๋ฅผ ์์ฑํ๊ณ ์ ๋๋ฉ์ด์ ํด๋ฆฝ์ ์ค์
- useFrame()์ ํ์ฉํ์ฌ ์ ๋๋ฉ์ด์ ์ ์ ๋ฐ์ดํธ
- ๋ฒํผ์ ์ถ๊ฐํ์ฌ ์ฌ์ / ์ผ์์ ์ง / ์๋ ์กฐ์ ๊ธฐ๋ฅ ๊ตฌํ
๐ 2. ์ ๋๋ฉ์ด์ ์ด ํฌํจ๋ 3D ๋ชจ๋ธ ์ถ๊ฐํ๊ธฐ
โ 1) ์ ๋๋ฉ์ด์ ์ด ํฌํจ๋ 3D ๋ชจ๋ธ ๋ค์ด๋ก๋
์๋ ์ฌ์ดํธ์์ .glb ํ์ผ์ ๋ค์ด๋ก๋ํ์ฌ ํ๋ก์ ํธ์ public/models ํด๋์ ์ ์ฅํฉ๋๋ค.
๐น ๋ฌด๋ฃ GLTF ๋ชจ๋ธ ๋ค์ด๋ก๋ ์ฌ์ดํธ
์์ ํ์ผ:
๐ public/models/
โฃ ๐ animated_robot.glb
โ 2) Three.js์์ ์ ๋๋ฉ์ด์ ์ด ์๋ GLTF ๋ชจ๋ธ ๋ก๋
๐ src/components/AnimatedModel.jsx
import { useRef, useEffect } from "react";
import { useGLTF } from "@react-three/drei";
import { useFrame } from "@react-three/fiber";
import * as THREE from "three";
const AnimatedModel = ({ modelPath, animationIndex = 0, isPlaying = true }) => {
const { scene, animations } = useGLTF(modelPath);
const mixer = useRef(null);
useEffect(() => {
if (animations.length > 0) {
mixer.current = new THREE.AnimationMixer(scene);
const action = mixer.current.clipAction(animations[animationIndex]);
if (isPlaying) {
action.play();
} else {
action.stop();
}
}
}, [scene, animations, animationIndex, isPlaying]);
useFrame((_, delta) => {
if (mixer.current) {
mixer.current.update(delta);
}
});
return <primitive object={scene} scale={1.5} />;
};
export default AnimatedModel;
๐ ์ค๋ช
- useGLTF()๋ฅผ ์ฌ์ฉํ์ฌ 3D ๋ชจ๋ธ์ ๋ก๋ํฉ๋๋ค.
- AnimationMixer๋ฅผ ์์ฑํ์ฌ ์ ๋๋ฉ์ด์ ์ ์คํํฉ๋๋ค.
- useFrame()์ ์ฌ์ฉํ์ฌ ๋งค ํ๋ ์๋ง๋ค ์ ๋๋ฉ์ด์ ์ ์ ๋ฐ์ดํธํฉ๋๋ค.
๐ 3. ์ ๋๋ฉ์ด์ ์ ์ด ๊ธฐ๋ฅ ์ถ๊ฐํ๊ธฐ
์ ๋๋ฉ์ด์ ์ ์ฌ์ / ์ ์ง / ์๋ ์กฐ์ ํ ์ ์๋๋ก UI๋ฅผ ์ถ๊ฐํด๋ณด๊ฒ ์ต๋๋ค.
๐ src/components/AnimationControls.jsx
import { useState } from "react";
const AnimationControls = ({ onPlay, onPause, onSpeedChange }) => {
const [speed, setSpeed] = useState(1);
const handleSpeedChange = (e) => {
const newSpeed = parseFloat(e.target.value);
setSpeed(newSpeed);
onSpeedChange(newSpeed);
};
return (
<div style={{ textAlign: "center", margin: "10px" }}>
<button onClick={onPlay} style={{ margin: "5px" }}>โถ Play</button>
<button onClick={onPause} style={{ margin: "5px" }}>โธ Pause</button>
<label style={{ marginLeft: "10px" }}>Speed: </label>
<input
type="range"
min="0.1"
max="2"
step="0.1"
value={speed}
onChange={handleSpeedChange}
/>
</div>
);
};
export default AnimationControls;
๐ 4. ์ต์ข ์ ์ผ๋ก ์ ๋๋ฉ์ด์ ์ปจํธ๋กค๋ฌ ์ ์ฉ
์ด์ AnimatedModel๊ณผ AnimationControls๋ฅผ ModelViewer์ ๊ฒฐํฉํฉ๋๋ค.
๐ src/components/ModelViewer.jsx
import { useState } from "react";
import { Canvas } from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
import AnimatedModel from "./AnimatedModel";
import AnimationControls from "./AnimationControls";
const ModelViewer = () => {
const [isPlaying, setIsPlaying] = useState(true);
const [speed, setSpeed] = useState(1);
return (
<div>
<Canvas camera={{ position: [0, 2, 5], fov: 50 }}>
<ambientLight intensity={0.5} />
<directionalLight position={[5, 5, 5]} intensity={1} />
<AnimatedModel modelPath="/models/animated_robot.glb" isPlaying={isPlaying} />
<OrbitControls />
</Canvas>
{/* ์ ๋๋ฉ์ด์
์ปจํธ๋กค UI */}
<AnimationControls
onPlay={() => setIsPlaying(true)}
onPause={() => setIsPlaying(false)}
onSpeedChange={setSpeed}
/>
</div>
);
};
export default ModelViewer;
๐ฏ 5. App.jsx์์ ModelViewer ์ ์ฉ
๐ src/App.jsx
import ModelViewer from "./components/ModelViewer";
function App() {
return (
<div>
<h1 style={{ textAlign: "center", marginTop: "20px" }}>3D ์ ๋๋ฉ์ด์
๋ทฐ์ด</h1>
<ModelViewer />
</div>
);
}
export default App;
โ 6. ์ต์ข ๊ฒฐ๊ณผ
โ GLTF ๋ชจ๋ธ์์ ์ ๋๋ฉ์ด์
์ ๋ถ๋ฌ์ ์ฌ์
โ ์ ๋๋ฉ์ด์
์ฌ์ / ์ ์ง ๋ฒํผ ์ถ๊ฐ
โ ์๋ ์กฐ์ ๊ธฐ๋ฅ ์ ์ฉ
โ OrbitControls๋ก ๋ง์ฐ์ค๋ก 3D ๋ชจ๋ธ ์กฐ์ ๊ฐ๋ฅ
๐ ์ด์ npm run dev๋ก ์คํํ๋ฉด 3D ์บ๋ฆญํฐ๊ฐ ์์ง์ด๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค!
๐ฅ 7. ๋ค์ ๋จ๊ณ: ์กฐ๋ช & ๊ทธ๋ฆผ์ ์ ์ฉํ๊ธฐ
์ง๊ธ๊น์ง ์ฐ๋ฆฌ๋ ์ ๋๋ฉ์ด์
์ด ํฌํจ๋ 3D ๋ชจ๋ธ์ ๋ก๋ํ๊ณ , ์ฌ์ ๋ฐ ์ ์ง, ์๋ ์กฐ์ ๊ธฐ๋ฅ์ ์ถ๊ฐํ์ต๋๋ค.
๋ค์ ๊ธ์์๋ ์กฐ๋ช
๊ณผ ๊ทธ๋ฆผ์๋ฅผ ์ถ๊ฐํ์ฌ ๋์ฑ ์ฌ์ค์ ์ธ 3D ํ๊ฒฝ์ ๊ตฌ์ถํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃน๋๋ค.
โ
๋ค์ ํธ ์๊ณ :
"Three.js์์ ์กฐ๋ช
๊ณผ ๊ทธ๋ฆผ์ ์ ์ฉํ๊ธฐ – ๋ ํ์ค์ ์ธ 3D ์ฌ ๋ง๋ค๊ธฐ" ๐
'project' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
- Total
- Today
- Yesterday
- Python
- Docker
- Ktor
- ๋ฅ๋ฌ๋
- AI์ฑ๋ด
- SEO์ต์ ํ
- llm
- nextJS
- kotlin
- Prisma
- nodejs
- CI/CD
- ํ๋ก ํธ์๋
- Next.js
- ๋ฐฑ์๋๊ฐ๋ฐ
- PostgreSQL
- NestJS
- gatsbyjs
- fastapi
- ํ์ด์ฌ์๊ณ ๋ฆฌ์ฆ
- ์น๊ฐ๋ฐ
- JAX
- rag
- flax
- App Router
- SEO ์ต์ ํ
- REACT
- ๊ฐ๋ฐ๋ธ๋ก๊ทธ
- ํ๋ก ํธ์๋๋ฉด์
- seo ์ต์ ํ 10๊ฐ
์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |