📌 프로젝트 개요
실제 생활 공간은 이미 다양한 가구로 구성되어 있는 경우가 대부분이다. 그런데 IKEA Place, 오늘의집 등 기존 인테리어 앱들은 모두 빈 방에 새 가구를 배치하는 방향으로만 동작한다. 이미 보유한 가구를 활용해 레이아웃을 바꿔보는 기능은 지원하지 않는다. 그리고 기존의 인테리어 프로그램들은 빈 도면에서 시작하여 카탈로그 내 수많은 모델 중 자신의 가구와 가장 유사한 것을 일일이 찾아 배치해야 하는 번거로움으로 인하여 전문가가 아닌 일반 사용자가 사용하기에는 큰 어려움이 있다.
2D 가구 제거 웹앱에 이어, 이번에는 Meta SAM3D를 활용해 방 사진에서 가구를 추출하고 3D 메쉬로 변환하는 인테리어 시뮬레이션 시스템을 구축했다. 기존 2D 웹앱의 한계를 넘어, 실제 인테리어 디자이너가 사용하는 툴처럼 3D 공간 안에 가구를 자유롭게 배치할 수 있는 시스템 구현 목표다.
🛠 기술 스택
| 구분 | 사용 기술 |
| 3D 모델 생성 | Meta SAM3D (facebookresearch/sam-3d-objects) |
| 가구 인식 | SAM2 (Segment Anything Model 2) |
| 백엔드 | FastAPI (Python, sam3d 전용 conda 환경, 포트 8001) |
| 프론트엔드 | React.js + Three.js |
| 3D 렌더링 | Three.js (CDN r128) |
⚙️ 시스템 파이프라인
방 사진 업로드
↓
SAM2로 가구 클릭 인식 + 마스크 생성
↓
가구 누끼 추출 (Extract Service)
↓
Meta SAM3D로 가구 → 3D 메쉬 변환
↓
Three.js 3D 방에 가구 배치
Meta SAM3D란?
Meta SAM3D는 Facebook Research가 2025년 공개한 모델로, 단일 이미지 하나만으로 완성된 3D 메쉬를 직접 생성한다. 트랜스포머 기반 아키텍처로 DINO v2 임베딩을 거쳐 Sparse Structure를 생성하고, 이를 디코딩해 최종 메쉬를 출력한다.
Three.js란?
Three.js는 웹 브라우저에서 3D 그래픽을 구현할 수 있는 JavaScript 라이브러리다. WebGL을 직접 다루면 코드가 엄청 복잡해지는데, Three.js가 이걸 추상화해줘서 훨씬 간단하게 쓸 수 있다. 이 프로젝트에서는 SAM3D가 만들어준 3D 메쉬 데이터를 화면에 그려주는 용도로 사용했다. 사용자가 입력한 방 크기로 와이어프레임 방을 만들고, 가구 메쉬를 그 안에 배치한다. 마우스로 가구를 클릭해 바닥 위에서 자유롭게 드래그할 수 있고, 우클릭으로 카메라를 돌려가며 다양한 각도에서 볼 수 있다.
CDN 방식으로 사용해서 별도 빌드 설정 없이 window.THREE로 접근한다:
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
CDN란?
CDN(Content Delivery Network)은 라이브러리를 직접 설치하지 않고 인터넷에서 바로 불러오는 방식이다.
예를들어 npm install three 대신 <script src="https://..."> 한 줄로 Three.js를 사용하는 것!!
환경 구성
왜 별도 conda 환경을 만들었나?
기존 furniture 환경은 PyTorch 2.7.1+cu118로 구성되어 있었다. Meta SAM3D의 핵심 의존성인 pytorch3d가 CUDA 12.1 기반으로 빌드되어야 해서 CUDA 버전 충돌이 발생했다.
RuntimeError: The detected CUDA version (13.2) mismatches
the version that was used to compile PyTorch (11.8).
기존 환경을 건드리면 SAM2, LaMa 등 다른 모델들이 망가질 수 있어서 sam3d 전용 conda 환경을 새로 생성했다.
conda create -n sam3d python=3.11
conda activate sam3d
pip install torch==2.5.1+cu121 torchvision --extra-index-url https://download.pytorch.org/whl/cu121
주요 의존성 설치 과정
pytorch3d 빌드 시 g++ 컴파일러가 없어서 추가 설치가 필요했다.
conda install -c conda-forge gxx_linux-64 -y
pip install "git+https://github.com/facebookresearch/pytorch3d.git@stable" --no-build-isolation
이 외에도 spconv-cu121, kaolin, gsplat, utils3d, MoGe 등 다수의 패키지를 순차적으로 설치했다.
Troubleshooting
1. utils3d.numpy.depth_edge ImportError
SAM3D 임포트 테스트를 하는데 갑자기 이런 에러가 떴다.
from utils3d.numpy import depth_edge # ImportError!
처음엔 utils3d가 제대로 설치가 안 된 줄 알고 재설치를 반복했는데 계속 똑같은 에러였다. 알고 보니 utils3d 라이브러리가 버전업 되면서 함수명이 depth_edge에서 depth_map_edge로 바뀌어 있었다. SAM3D 코드는 구버전 기준으로 작성되어 있어서 생긴 충돌이었다. 패키지를 다운그레이드하는 방법도 있었지만, SAM3D 소스코드를 직접 한 줄 패치하는 게 더 깔끔했다.
sed -i 's/from utils3d.numpy import depth_edge/from utils3d.numpy import depth_map_edge as depth_edge/' \
~/sam-3d-objects/sam3d_objects/pipeline/layout_post_optimization_utils.py
2. mask_points.isfinite().max() RuntimeError
드디어 임포트까지 성공하고 3D 변환 버튼을 눌렀더니 이번엔 500 에러가 떴다.
RuntimeError: max(): Expected reduction dim to be specified
for input.numel() == 0.
에러 메시지만 봐서는 뭔 소린지 몰라서 한참 들여다봤다. SAM3D는 내부적으로 가구 이미지의 알파 채널(투명/불투명 정보)을 마스크로 사용해서 "여기가 가구 영역이에요"라고 인식한다. 그 영역에서 3D 좌표값들을 뽑아서 정규화하는 과정이 있는데, 뽑힌 좌표값이 하나도 없는 빈 상태일 때 .max()(최댓값 구하기)를 호출하니까 에러가 난 것이었다. 빈 상자에서 제일 큰 거 꺼내라는 격이었다.
# 문제 코드
if mask_points.isfinite().max() == 0: # numel()==0이면 에러!
해결 방법은 간단했다. 최댓값을 구하기 전에 먼저 "비어있냐?"를 체크하도록 조건을 바꿔주면 됐다.
# 수정 코드
if mask_points.numel() == 0 or (mask_points.numel() > 0 and not mask_points.isfinite().any()):
3. MeshExtractResult AttributeError
40~50분을 기다려서 드디어 3D 생성이 완료됐는데 이번엔 또 다른 에러가 떴다.
AttributeError: 'MeshExtractResult' object has no attribute 'verts_packed'
당연히 pytorch3d의 Meshes 객체겠지 싶어서 verts_packed()를 호출했는데 바로 에러였다. 알고 보니 Meta SAM3D는 자체 MeshExtractResult 클래스를 사용하고 있었고, 이 클래스는 verts_packed() 같은 메서드 없이 .vertices와 .faces 속성을 직접 가지고 있었다.
# inspect로 내부 구조 확인
print(inspect.getsource(MeshExtractResult.__init__))
# → self.vertices = vertices
# → self.faces = faces.long()
# → self.vertex_attrs = vertex_attrs ← 이게 나중에 색상 문제 해결의 열쇠가 됨
# 변경 전
vertices = mesh.verts_packed().cpu().numpy().tolist()
faces = mesh.faces_packed().cpu().numpy().tolist()
# 변경 후
vertices = mesh.vertices.cpu().numpy().tolist()
faces = mesh.faces.cpu().numpy().tolist()
4. 가구 3D 메쉬가 흰색으로만 렌더링되는 문제
드디어 3D 메쉬가 화면에 나타났는데... 소파가 완전히 하얗게 렌더링됐다. use_vertex_color=True 옵션까지 넣었는데 왜 색이 없지?

백엔드 코드를 보니 문제가 바로 보였다. 색상 데이터를 아예 추출하지 않고 그냥 회색으로 고정해버리고 있었다.
# 문제 코드 - 항상 회색으로 고정
colors = [[0.8, 0.8, 0.8]] * len(vertices)
위에서 inspect로 내부 구조를 확인할 때 봤던 vertex_attrs가 생각났다. 확인해보니 바로 거기에 버텍스별 색상 정보가 들어있었다.
# 수정 코드
if mesh.vertex_attrs is not None:
colors = mesh.vertex_attrs[:, :3].cpu().numpy().tolist()
else:
colors = [[0.8, 0.8, 0.8]] * len(vertices)
이 한 줄 수정으로 소파의 베이지색, 나무 다리의 갈색까지 실제 색상이 그대로 렌더링됐다. 뭔가 오래 걸렸는데 결과물 보니까 뿌듯했다 😊

⚡ 성능 이슈
Meta SAM3D는 RTX 4070 SUPER (12GB VRAM) 환경에서 가구 1개당 약 1시간이 소요된다. 사용자가 실시간 인테리어 툴로 활용하기엔 너무 느리다는 한계가 있다.
🗺️ 향후 계획
1. 속도 최적화
inference_steps를 25에서 10으로 줄이거나 float16 변환 등을 통해 처리 시간 단축을 검토할 예정이다.
2. 단일 사진으로 3D 방 자동 생성
현재는 사용자가 방 크기를 직접 입력하는 방식이다. 추후 업로드한 방 사진 한 장에서 Depth Estimation을 활용해 3D 방 구조를 자동으로 추출하는 기능을 개발할 예정이다.
'프로젝트' 카테고리의 다른 글
| Meta SAM3D 인테리어 시스템 개발 기록 (5) — SAM3D로 3D 방 만들기 도전!? (0) | 2026.06.07 |
|---|---|
| Meta SAM3D 인테리어 시스템 개발 기록 (4) — SAM3D 가구 복원 최적화 (0) | 2026.06.07 |
| Meta SAM3D 인테리어 시스템 개발 기록 (3) (0) | 2026.05.06 |
| Meta SAM3D 인테리어 시스템 개발 기록 (2) (0) | 2026.04.26 |
| SAM2 · LaMa · SD ControlNet으로 구현한 AI 인테리어 역방향 편집 시스템 (0) | 2026.04.19 |