WebGL 을 기반으로 한 JavaScript 라이브러리로, 웹 브라우저에서 3D 그래픽을 쉽게 렌더링할 수 있도록 도와준다. 기본적인 원리로는 WebGL을 직접 다루는 복잡한 과정을 추상화하여 사용자가 간단한 코드로도 강력한 3D 환경을 구현할 수 있게 해준다.
Scene: 모든 3D 객체가 배치되는 공간Camera: 장면을 어떤 위치와 구조로 담아낼지 결정Renderer: 3D 장면을 캔버스에 그리는 역할Light: 3D 객체에 빛을 추가Mesh: 3D 모델을 구성하는 기본 단위로, Geometry와 Material로 구성Controls: 사용자 입력으로 카메라를 조작
📌 프로젝트에서 Three.js 활용
01. 3D 모델 불러오기
@react-three.drei의useGLTF훅을 활용했다.
Three.js를 React에서 더 쉽게 사용할 수 있도록 도와주는 유틸리티 라이브러리이다. useGLTF 뿐만 아니라 카메라 컨트롤, 환경 설정 등을 손쉽게 구현할 수 있다.
const { scene } = useGLTF(modelPath) as GLTFResult;
<primitive object={scene} scale={0.68} rotation={[0, -Math.PI / 4, 0]} />modelPath경로의 GLTF 모델을 로드하여scene으로 저장한다.primitive를 사용하여 GLTF 모델을Three.js의object형태로 변환 후 렌더링
3D 모델을 압축하여 웹에서 빠르게 로드할 수 있도록 도와주는 포맷이다.
02. 위치 및 그림자 설정
useEffect(() => {
if (scene) {
scene.position.set(0, 0, 0);
scene.traverse((object) => {
if (object.isMesh) {
object.castShadow = true;
object.receiveShadow = true;
}
});
}
}, [scene]);- 모델의 위치를 설정,
scene.traverse를 이용하여 모델 내의 모든 Mesh 요소에 그림자 설정을 적용
: scene 내부의 모든 객체를 순회하면서 특정 동작을 수행하도록 해준다.
castShadow: 해당 객체가 빛을 받아 그림자를 만들도록 설정receiveShadow: 해당 객체가 다른 객체의 그림자를 받을 수 있도록 설정- 이 두 속성을 모두 활성화해야 현실적인 그림자 표현이 가능하다
03. 모델 렌더링
<Canvas shadows camera={CAMERA_CONFIG}>
<RoomLighting />
<Suspense fallback={null}>
<Center>
<primitive object={scene} scale={0.68} rotation={[0, -Math.PI / 4, 0]} />
</Center>
</Suspense>
<OrbitControls enableRotate={false} enablePan={false} minDistance={5} maxDistance={12} />
</Canvas>Canvas컴포넌트를 사용하여 렌더링primitive를 통해 Three.js의scene객체를 직접 렌더링OrbitControls를 추가하여 카메라 이동 범위를 제한
Three.js 에서 제공하는 컨트롤러로, 사용자가 마우스로 카메라를 회전, 이동, 줌할 수 있도록 도와주며 다양한 속성들로 설정하거나 막을 수 있다.
enableRotate={false}: 회전 기능 비활성화enablePan={false}: 카메라 이동 비활성화minDistance및maxDistance: 줌 범위 조절
04. 조명 및 카메라 설정
재사용성과 관리의 용이성을 고려해서 별도의
constants파일로 분리해서 사용하였다.
카메라 설정
export const CAMERA_CONFIG = {
position: new Vector3(0, 4, 10),
fov: 30,
};Field of View로 즉, 카메라가 한 번에 볼 수 있는 시야각을 의미한다. 값이 클수록 넓게 보이고, 작을수록 좁게 보인다. 이를 통해 원근감을 조절할 수 있다.
조명 설정
렌더링에서 가장 중요한 건 조명이다. 왜냐하면 조명의 유/무의 차이로 퀄리티가 달라보이기 때문에, 조명 설정이 가장 중요했다.
export function RoomLighting() {
const { mainLight, ambient, fill } = LIGHT_CONFIG;
return (
<>
<ambientLight intensity={ambient.intensity} color={ambient.color} />
<directionalLight
position={[mainLight.position[0], mainLight.position[1], mainLight.position[2]]}
intensity={mainLight.intensity}
color={mainLight.color}
castShadow
shadow-mapSize-width={mainLight.shadowConfig.mapSize[0]}
shadow-mapSize-height={mainLight.shadowConfig.mapSize[1]}
shadow-camera-near={mainLight.shadowConfig.camera.near}
shadow-camera-far={mainLight.shadowConfig.camera.far}
shadow-bias={mainLight.shadowConfig.bias}
/>
<pointLight
position={[fill.position[0], fill.position[1], fill.position[2]]}
intensity={fill.intensity}
color={fill.color}
/>
</>
);
}ambientLight: 전체적인 기본 조명으로, 모든 방향에서 부드럽게 빛을 퍼뜨린다.directionalLighy: 태양빛과 유사한 조명으로, 특정 방향에서 평행하게 빛을 비춘다.pointLight: 특정 지점에서 모든 방향으로 빛을 방출하는 조명
05. 가구 모델링 분리 및 관리
방 내부에 배치되는 가구(책장, CD플레이어, 저금통, 방명록)은
useRoomItems훅으로 따로 만들어 관리하고 있다.
- 저금통, 방명록 : 사용자가 편집할 수 없는 가구 ❌
- CD 플레이어, 책장 : 사용자가 편집할 수 있는 가구 ⭕️

➡️ㅤ사용자는 가구 토글 기능을 이용해 CD 플레이어, 책장를 배치하거나 삭제할 수 있다.
const { items } = useRoomItems({ roomId, furnitures });- 방마다 배치된 가구의 종류가 다를 수 있기 때문에
roomId에 따라 동적으로 구성
{items.map((item) => (
<Suspense key={item.id}>
<Furnitures item={item} onInteract={handleInteraction} onHover={handleHover} />
</Suspense>
))}items배열을 순회하여Furnitures컴포넌트를 렌더링onInteract와onHover이벤트 핸들러를 통해 가구와의 상호작용을 구현

사용자가 원하는 테마로 변경 가능하다
06. 상호작용 구현 ( 가구 클릭 및 호버 이벤트 )




const handlePointerOver = (e: MouseEvent) => {
e.stopPropagation();
scene.traverse((object) => {
if (object.isMesh) {
object.material.emissive = object.material.color;
object.material.emissiveIntensity = 0.5;
}
});
};
const handlePointerOut = (e: MouseEvent) => {
e.stopPropagation();
scene.traverse((object) => {
if (object.isMesh) {
object.material.emissiveIntensity = 0;
}
});
};- 호버하면(onPointerOver), emissive 값을 변경하여 하이라이트 효과 적용
- 호버 해제 시(onPointerOut),
emissiveIntensity를0으로 설정하여 원래 상태로 복구
- 모델이 자체적으로 빛을 내는 효과를 줄 수 있도록 하는 속성
- 호버 시,
emissiveIntensity값을 높여 하이라이트 효과를 부여
💬ㅤ비하인드
처음 사이트에 모델링을 렌더링 했을 때는 보이지도 않아서 뭐가 잘못되었는지... 카메라 세팅 끝에 방을 정중앙에 불러올 수 있었다.

이제 가구들은 먼지처럼 그저 흩어져 있었다. 사실 이 부분은 노가다로 위치를 찾고 회전을 시키는 것 밖에는 없는 것 같아서 일일히 맞추었다.


