๐ Three.js์์ ์กฐ๋ช ๊ณผ ๊ทธ๋ฆผ์ ์ ์ฉํ๊ธฐ – ๋ ํ์ค์ ์ธ 3D ์ฌ ๋ง๋ค๊ธฐ
๐ Three.js์์ ์กฐ๋ช ๊ณผ ๊ทธ๋ฆผ์ ์ ์ฉํ๊ธฐ – ๋ ํ์ค์ ์ธ 3D ์ฌ ๋ง๋ค๊ธฐ
์ด์ ๊ธ์์๋ Three.js์์ 3D ๋ชจ๋ธ ์ ๋๋ฉ์ด์
์ ๋ถ๋ฌ์ค๊ณ , ์ฌ์ ๋ฐ ์๋๋ฅผ ์กฐ์ ํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์ ์ต๋๋ค.
์ด๋ฒ ๊ธ์์๋ ์กฐ๋ช
๊ณผ ๊ทธ๋ฆผ์๋ฅผ ์ถ๊ฐํ์ฌ 3D ์ฌ์ ๋์ฑ ์ฌ์ค์ ์ผ๋ก ํํํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃน๋๋ค.
๐ 1. Three.js์์ ์กฐ๋ช ์ด ์ค์ํ ์ด์
3D ์ฌ์์ ์กฐ๋ช
์ ์
์ฒด๊ฐ๊ณผ ์ฌ์ค๊ฐ์ ๊ฒฐ์ ํ๋ ํต์ฌ ์์์
๋๋ค.
Three.js๋ ์ฌ๋ฌ ์ข
๋ฅ์ ์กฐ๋ช
์ ์ ๊ณตํ๋ฉฐ, ์ด๋ฅผ ์ ์ ํ ์กฐํฉํ๋ฉด ๋์ฑ ๋ฆฌ์ผํ 3D ํ๊ฒฝ์ ๋ง๋ค ์ ์์ต๋๋ค.
โ Three.js์์ ์ง์ํ๋ ์กฐ๋ช ์ข ๋ฅ
์กฐ๋ช ์ข ๋ฅ ์ค๋ช
AmbientLight | ์ ์ฒด์ ์ผ๋ก ๋ถ๋๋ฌ์ด ๋น์ ์ถ๊ฐ |
DirectionalLight | ํ์๊ด์ฒ๋ผ ์ง์ ์ผ๋ก ๋น์ ์จ |
PointLight | ์ ๊ตฌ์ฒ๋ผ ๋ชจ๋ ๋ฐฉํฅ์ผ๋ก ๋น์ ๋ฐฉ์ถ |
SpotLight | ํน์ ๋ฐฉํฅ์ผ๋ก ๋น์ ์ง์ค์ํด |
HemisphereLight | ํ๋๊ณผ ๋ ์ ์์์ ๋ฐ์ํ๋ ์กฐ๋ช |
๐ 2. Three.js ์ฌ์ ์กฐ๋ช ์ถ๊ฐํ๊ธฐ
โ 1) ๊ธฐ๋ณธ ์กฐ๋ช ์ค์
๐ src/components/LightingScene.jsx
import { Canvas } from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
import { useRef } from "react";
import * as THREE from "three";
const LightingScene = () => {
const pointLightRef = useRef();
return (
<Canvas camera={{ position: [0, 3, 5], fov: 50 }}>
{/* ๊ธฐ๋ณธ ํ๊ฒฝ๊ด (Ambient Light) */}
<ambientLight intensity={0.3} />
{/* ํ์๊ด ๊ฐ์ ์กฐ๋ช
(Directional Light) */}
<directionalLight position={[5, 5, 5]} intensity={1} />
{/* ์ ๊ตฌ ์กฐ๋ช
(Point Light) */}
<pointLight ref={pointLightRef} position={[2, 2, 2]} intensity={1} />
{/* ๊ทธ๋ฆผ์ ํ์ฑํ */}
<mesh receiveShadow castShadow>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color="orange" />
</mesh>
{/* ๋ฐ๋ฅ ์ถ๊ฐ */}
<mesh receiveShadow rotation={[-Math.PI / 2, 0, 0]} position={[0, -0.5, 0]}>
<planeGeometry args={[10, 10]} />
<meshStandardMaterial color="gray" />
</mesh>
<OrbitControls />
</Canvas>
);
};
export default LightingScene;
๐ ์ค๋ช
- ambientLight๋ก ์ ์ฒด์ ์ธ ์กฐ๋ช ์ ์ถ๊ฐ
- directionalLight๋ฅผ ์ฌ์ฉํด ๊ทธ๋ฆผ์๊ฐ ์๊ธฐ๋๋ก ์ค์
- pointLight๋ก ์ ๊ตฌ ๊ฐ์ ํจ๊ณผ ๊ตฌํ
- receiveShadow์ castShadow ์์ฑ์ ์ถ๊ฐํ์ฌ ๊ทธ๋ฆผ์ ํ์ฑํ
๐ฏ 3. Three.js์์ ๊ทธ๋ฆผ์ ์ค์ ํ๊ธฐ
Three.js์์ ๊ทธ๋ฆผ์๊ฐ ์ ์์ ์ผ๋ก ๋ ๋๋ง๋๋ ค๋ฉด ๋ช ๊ฐ์ง ์ค์ ์ด ํ์ํฉ๋๋ค.
โ 1) ๊ทธ๋ฆผ์ ํ์ฑํ
Three.js์์๋ Renderer์ Light์์ ๊ทธ๋ฆผ์๋ฅผ ํ์ฑํํด์ผ ํฉ๋๋ค.
<Canvas shadows camera={{ position: [0, 3, 5], fov: 50 }}>
<directionalLight castShadow position={[5, 5, 5]} intensity={1} />
<mesh receiveShadow castShadow>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color="orange" />
</mesh>
โ 2) ๋ฐ๋ฅ์ ๊ทธ๋ฆผ์ ๋ฐ๊ธฐ
๋ฐ๋ฅ์ด ๊ทธ๋ฆผ์๋ฅผ ๋ฐ์ผ๋ ค๋ฉด receiveShadow๋ฅผ ์ค์ ํด์ผ ํฉ๋๋ค.
<mesh receiveShadow rotation={[-Math.PI / 2, 0, 0]} position={[0, -0.5, 0]}>
<planeGeometry args={[10, 10]} />
<meshStandardMaterial color="gray" />
</mesh>
๐ 4. ๊ทธ๋ฆผ์ ํ์ง ๊ฐ์ ํ๊ธฐ
๊ธฐ๋ณธ ๊ทธ๋ฆผ์๋ ํ๋ฆฌ๊ฒ ๋ณด์ผ ์ ์์ต๋๋ค. ๋ ์ ๋ช ํ๊ฒ ๋ง๋ค๋ ค๋ฉด ๋ค์ ์ค์ ์ ์ถ๊ฐํฉ๋๋ค.
๐ DirectionalLight ๊ทธ๋ฆผ์ ํด์๋ ๊ฐ์
const directionalLight = useRef();
useEffect(() => {
if (directionalLight.current) {
directionalLight.current.shadow.mapSize.width = 2048;
directionalLight.current.shadow.mapSize.height = 2048;
directionalLight.current.shadow.camera.near = 0.5;
directionalLight.current.shadow.camera.far = 50;
}
}, []);
์ด๋ ๊ฒ ์ค์ ํ๋ฉด ๊ทธ๋ฆผ์๊ฐ ๋ ์ ๋ช ํ๊ณ ์ฌ์ค์ ์ผ๋ก ํํ๋ฉ๋๋ค.
๐ 5. ์กฐ๋ช ๋ฐ ๊ทธ๋ฆผ์ ์ค์ ์ ์ฉ
โ 1) 3D ๋ชจ๋ธ๊ณผ ์กฐ๋ช ๊ฒฐํฉ
์ด์ ์กฐ๋ช ์ ์ถ๊ฐํ ์ฌ์์ 3D ๋ชจ๋ธ์ ๋ก๋ฉํด๋ณด๊ฒ ์ต๋๋ค.
๐ src/components/LightingModelViewer.jsx
import { Canvas } from "@react-three/fiber";
import { OrbitControls, useGLTF } from "@react-three/drei";
const Model = () => {
const { scene } = useGLTF("/models/robot.glb");
return <primitive object={scene} scale={1.5} />;
};
const LightingModelViewer = () => {
return (
<Canvas shadows camera={{ position: [0, 3, 5], fov: 50 }}>
<ambientLight intensity={0.3} />
<directionalLight castShadow position={[5, 5, 5]} intensity={1} />
<pointLight position={[2, 2, 2]} intensity={1} />
{/* 3D ๋ชจ๋ธ */}
<Model />
{/* ๋ฐ๋ฅ */}
<mesh receiveShadow rotation={[-Math.PI / 2, 0, 0]} position={[0, -0.5, 0]}>
<planeGeometry args={[10, 10]} />
<meshStandardMaterial color="gray" />
</mesh>
<OrbitControls />
</Canvas>
);
};
export default LightingModelViewer;
โ 6. ์ต์ข ๊ฒฐ๊ณผ
โ AmbientLight, DirectionalLight, PointLight ์ถ๊ฐ
โ 3D ์ค๋ธ์ ํธ ๋ฐ ๋ฐ๋ฅ ๊ทธ๋ฆผ์ ์ค์
โ ๊ทธ๋ฆผ์ ํ์ง ํฅ์ (mapSize ์ค์ )
โ 3D ๋ชจ๋ธ์ ์กฐ๋ช
๊ณผ ํจ๊ป ๋ฐฐ์น
๐ ์ด์ npm run dev๋ก ์คํํ๋ฉด ์กฐ๋ช ์ด ์ถ๊ฐ๋ 3D ์ฌ์ ๋ณผ ์ ์์ต๋๋ค!
๐ฅ 7. ๋ค์ ๋จ๊ณ: ์ฑ๋ฅ ์ต์ ํ & ๋ก๋ฉ ์๋ ๊ฐ์
์ง๊ธ๊น์ง ์ฐ๋ฆฌ๋ Three.js์์ ์กฐ๋ช
์ ์ถ๊ฐํ๊ณ , ๊ทธ๋ฆผ์๋ฅผ ์ค์ ํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์ ์ต๋๋ค.
๋ค์ ๊ธ์์๋ ์ฑ๋ฅ ์ต์ ํ ๊ธฐ๋ฒ (Lazy Loading, Draco ์์ถ, PostProcessing) ๋ฑ์ ํ์ฉํ์ฌ ๋์ฑ ๋ถ๋๋ฝ๊ณ ๋น ๋ฅด๊ฒ ๋ก๋ฉํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃฐ ์์ ์
๋๋ค.
โ
๋ค์ ํธ ์๊ณ :
"Three.js์์ ์ฑ๋ฅ ์ต์ ํ & ๋ก๋ฉ ์๋ ๊ฐ์ ํ๊ธฐ" ๐