사진이 아니라, 걸어 들어갈 수 있는 공간입니다

브라우저에서 마우스로 360도 돌려 볼 수 있는 물류 창고. 사진 한 장을 벽지처럼 붙인 것이 아니라, 색을 가진 작은 빛 방울(스플랫) 50만 개로 지어 올린 3차원 공간입니다. 그 방울이 어떻게 창고가 되고, 어떻게 상자 하나를 집어 던질 수 있게 됐는지 여섯 단계로 따라가 봅니다.

1,200개 실제 창고는 500,000개, 원본은 1,920,000개1

비밀의 열쇠: 3D 가우시안 스플래팅(3DGS)

3D를 만드는 두 가지 방법이 있습니다. 조각을 이어 붙이거나, 빛 방울(스플랫)을 띄우거나.

지금까지 대부분의 3D(게임, 설계 도면, 애니메이션)는 작은 삼각형 판(폴리곤 메시)을 수만 장 이어 붙여 만듭니다. 종이접기(메시 모델링)로 공을 만드는 것과 같아서, 멀리서 보면 둥글지만 가까이 가면 모서리가 드러납니다. 유리의 반짝임이나 형광등 불빛이 바닥에 번지는 모습은 따로 그려 넣어야 합니다.

3D 가우시안 스플래팅(3D Gaussian Splatting, 줄여서 3DGS)은 판(폴리곤)을 쓰지 않습니다. 대신 색과 투명도, 크기와 기울기를 각각 가진 반투명한 빛 방울(3DGS의 기본 단위: 가우시안(Gaussian) 또는 스플랫(splat))을 공중에 수십만 개 띄워 둡니다. 방울 하나는 아무것도 아니지만, 겹치고 흩어진 방울을 한꺼번에 보면 콘크리트 바닥의 번들거림, 골판지의 거친 결, 천장 조명의 후광까지 카메라로 찍은 것처럼 보입니다. 카메라를 옮기면 방울들이 다른 각도로 겹치기 때문에 사진과 달리 시점이 살아 움직입니다.

같은 상자를 두 방식으로 그려 보기
왼쪽: 삼각형 판을 이어 붙인 상자. 오른쪽: 빛 방울(스플랫)을 겹친 상자. 방울 방식은 경계가 부드럽고 빛 번짐이 저절로 생기지만, 어디까지가 상자이고 어디부터가 바닥인지 컴퓨터는 알지 못합니다. 이 점이 3막의 숙제가 됩니다.
기억할 것 — 빛 방울(스플랫) 방식은 “보이는 것”은 뛰어나지만 “무엇이 무엇인지”는 모릅니다. 창고 전체가 방울 한 덩어리일 뿐, 상자·선반·바닥이라는 구분이 없습니다. 이 창고를 그냥 구경하는 데서 그치지 않고 상자를 집고 던지려면, 그 구분을 우리가 만들어 줘야 합니다.

한 줄 정리3DGS는 사진처럼 보이는 3D를 빛 방울(스플랫) 50만 개로 만드는 방법이고, 우리가 쓰는 재생기(런타임)는 Spark(World Labs, MIT 라이선스)이며 그 위에 자체 응용층을 얹어 창고를 다룹니다.

1

글로 창고를 주문하다 (텍스트→3D 생성)

사진을 찍은 것이 아닙니다. 문장 한 줄을 보냈습니다.

World Labs의 공간 생성 서비스(Marble API) Marble에 이런 주문(텍스트 프롬프트)을 보냈습니다. “양옆에 파란색·주황색 선반 랙이 늘어서 있고, 바닥은 매끄러운 콘크리트, 천장에는 형광등이 줄지어 켜진 물류 창고 통로.” 약 5분 뒤 Marble은 이 문장을 3차원 공간으로 돌려주었습니다.

돌아온 것은 파일 한 개가 아니라 네 가지 자산입니다. 방울 192만 개짜리 원본, 브라우저에서 가볍게 돌리기 위한 50만 개짜리 경량본, 물건이 통과하지 못하게 하는 보이지 않는 벽(충돌 메시), 그리고 360도 파노라마 사진(등장방형 파노라마 PNG)입니다. 이 한 번의 생성에 1,580크레딧, 우리 돈으로 약 1,700원이 들었습니다.2

주문서 (텍스트) “파란·주황 선반 랙, 콘크리트 바닥, 형광등이 줄지은 창고 통로” Marble World Labs · 약 5분 원본 빛 방울(스플랫)1,920,000개 · 107.5 MB 경량본 빛 방울(스플랫)500,000개 · 7.7 MB · 화면에 쓰는 것 보이지 않는 벽 (충돌 메시)1.8 MB · 5막에서 바닥이 됨 360도 파노라마2560 × 1280
문장 하나가 네 가지 자산으로 돌아옵니다. 이 문서에서 “Marble 생성 자산”이라 부르는 것이 이것입니다.
솔직한 한계 — 파노라마를 중심으로 만들어진 공간이라 통로 한가운데(관측 체적 중심)에서는 선명하지만, 옆으로 1.3 m 이상 벗어나거나 선반 안쪽으로 들어가면 방울이 번져 보입니다. 걸어 다닐 수 있는 범위(관측 체적)는 대략 폭 2 m, 길이 7.5 m, 높이 3 m의 통로입니다.3

한 줄 정리창고는 촬영이 아니라 문장으로 만들어졌고, 방울·충돌 메시·파노라마가 함께 왔습니다.

2

줄자로 크기를 맞추다 (척도 정합)

처음 받은 창고에는 “1미터”가 없었습니다.

생성된 공간은 모양은 맞지만 단위가 없습니다. 상자가 손바닥만 할 수도, 집채만 할 수도 있습니다. 다행히 Marble은 자산과 함께 두 개의 숫자(척도 메타데이터: metric_scale_factor, ground_plane_offset)를 알려 줍니다. “실제 크기로 보려면 2.12배 키워라”, “바닥은 원점보다 1.26 m 아래에 있다.”4 이 두 숫자를 적용하면 창고가 현실 척도가 됩니다.

여기서 끝내지 않고 검산(교차 검증)을 했습니다. 방울들이 가장 많이 몰려 있는 높이(높이 히스토그램의 최빈값, 바닥일 가능성이 가장 큰 곳)와 충돌 메시가 말하는 바닥 높이를 따로 재서 비교했더니 차이가 1.0 cm였습니다.5 두 정보가 서로 다른 경로로 같은 답을 냈으니 “바닥이 여기”라고 믿어도 됩니다.

받은 그대로 (단위 없음) 길이 = ? × 2.12 바닥 −1.26 m 현실 척도로 방울 바닥 vs 메시 바닥 차이 1.0 cm
척도 두 숫자는 Marble이 주고, “정말 바닥이 거기인지”는 우리가 두 방법으로 재서 확인했습니다.

한 줄 정리2.12배 확대, 바닥 1.26 m 보정, 바닥 검산 차이 1.0 cm. 이제 창고 안의 1 m는 진짜 1 m입니다.

3

상자를 배경에서 떼어내다 (부품 분할)

통째로 굳은 조각상에서 상자만 뜯어내려면, 다섯 가지 질문(5조건 마스크)을 던집니다.

이 창고의 방울 50만 개에는 이름표(분할 정보·의미 라벨)가 없습니다. “너는 상자, 너는 기둥”이라는 정보가 없기 때문에, 상자를 집으려 하면 뒤의 선반과 바닥이 한 덩어리로 따라옵니다. 그래서 방울 하나하나에 다섯 가지 질문을 던져 상자에 속한 방울만 골라냈습니다.

질문이 방울은…왜 묻는가
1상자가 있어야 할 자리(경계 상자 bbox + 3 cm) 안에 있는가?엉뚱한 곳의 방울을 배제
2바닥보다 4 cm 이상 위에 떠 있는가?바닥 반사 방울을 배제
3크기가 15 cm보다 작은가?길게 늘어진 배경 방울을 배제
4색이 골판지 색인가? (주황·파랑·회색이면 제외)랙 기둥·보를 배제
5기둥에서 5 cm 이상 떨어져 있는가?기둥에 붙은 방울을 배제

다섯 질문을 모두 통과한 방울만 “상자”가 됩니다. 원본 기준으로 11,807개가 상자 두 개(왼쪽 앞 L1, 오른쪽 앞 R1)에 배정되고, 나머지 전부는 움직이지 않는 배경(정적 스플랫)으로 남았습니다.6 상자 방울과 배경 방울의 합은 언제나 원래 개수와 정확히 같아야 하며, 매 회 이 합계를 검산했습니다.

질문을 하나씩 적용해 보기 질문 0개 적용
슬라이더를 오른쪽으로 옮기면 질문이 하나씩 추가되고, 회색 방울이 걸러져 골판지색 방울만 남습니다.
솔직한 한계 — 이 방법은 통로 앞줄의 상자 두 개(L1·R1)에서만 깨끗하게 작동했습니다. 둘째·셋째 줄 상자 네 개는 파노라마에서 멀어 방울이 듬성듬성해서 떼어내도 배경이 10~20% 함께 딸려 왔고, 지금은 보류 상태입니다.7

한 줄 정리인공지능이 아니라 다섯 가지 규칙으로 상자 방울 11,807개를 골라냈고, 앞줄 상자 두 개가 “집을 수 있는 물건”(동적 부품, 독립 SplatMesh)이 됐습니다.

4

클릭으로 상자를 집는 시험 (레이캐스트 픽킹)

화면을 찍었을 때 상자가 잡히는지, 뒤의 기둥이 잡히는지.

마우스로 화면의 한 점을 클릭하면 컴퓨터는 그 점에서 화면 안쪽으로 가늘고 긴 바늘(광선, ray)을 찔러 넣습니다. 바늘이 처음 닿는 것(레이캐스트 히트)이 “클릭한 물건”입니다. 문제는 빛 방울(스플랫)은 반투명해서 바늘이 상자를 뚫고 지나가 뒤의 선반에 닿기 쉽다는 점입니다. 실제로 첫 번째 방식에서 실패한 59건 중 44건이 이 “관통”(pass-through)이었습니다.8

그래서 규칙(픽킹 정책 v1 → v2)을 바꿨습니다. 바늘이 상자 영역(bbox + 3 cm)을 지나갔고, 그 뒤에 닿은 배경이 35 cm 이내라면 “상자를 클릭한 것”으로 봅니다. 상자를 스쳐 지나 바로 뒤 선반에 닿았다면 사람의 의도는 상자였을 테니까요.

시험은 공정해야 합니다. 클릭할 자리 225곳을 미리 무작위로 뽑아 봉인(홀드아웃 세트, seed 고정·파일 잠금)해 두었고(정답도 함께), 규칙을 만드는 동안에는 이 목록을 열어 보지 않았습니다. 그리고 딱 한 번만 실행했습니다.

119 / 150상자를 노린 클릭 중 상자를 잡은 수 · 79.3%9
0 / 75배경을 노린 클릭에서 상자가 잘못 잡힌 수(오탐) · 0%9
68.7% → 79.3%규칙을 바꾸기 전과 후9
그림 안의 아무 곳이나 클릭해 보세요. 상자 안이면 상자가 켜지고, 밖이면 배경이 켜집니다.
왼쪽 아래·오른쪽 아래의 골판지색이 L1·R1입니다. 실제 시험에서는 이런 클릭 150 + 75건을 무작위 자리에서 했습니다.

한 줄 정리봉인된 클릭 225건을 한 번 실행해 상자 79.3%, 헛집기(오탐) 0건. 아직 다섯 번에 한 번은 놓치며, 그 원인 대부분은 통로 정면에서 본 얇은 앞면 때문입니다.

5

중력을 켜다 (강체 물리)

보이는 상자에 무게를 주면, 떨어지고 미끄러지고 멈춥니다.

빛 방울(스플랫) 상자는 그림일 뿐이어서 놓아 두면 허공에 멈춰 있거나 바닥을 뚫고 사라집니다. 그래서 브라우저 안에 물리 계산기(물리 엔진) Rapier(오픈소스, 버전 0.12)를 넣었습니다. 이때 두 가지 몸을 따로 만듭니다.

하나는 움직이지 않는 몸(정적 강체, trimesh 충돌체)입니다. 1막에서 받은 충돌 메시(삼각형 68,979장)를 바닥·선반·벽으로 씁니다. 다른 하나는 움직이는 몸(동적 강체)으로, 상자 L1·R1 각각에 무게 300 kg짜리 보이지 않는 벽돌(큐보이드 충돌체)을 붙입니다. 화면에서 보이는 것은 빛 방울(스플랫)이지만, 떨어지고 부딪히는 것은 이 벽돌이고, 방울은 벽돌을 따라다닙니다.10

그리고 세 가지 시험을 했습니다. 상자를 1 m 위에서 떨어뜨렸을 때 제자리에 내려앉는가, 옆으로 초속 2.5 m로 밀었을 때 미끄러져 멈추는가, 같은 실험을 두 번 하면 소수점까지 같은 결과가 나오는가(결정론, determinism).

시험결과판정
1 m 낙하 후 원래 자리에서 벗어난 거리(휴지 변위)L1 1.96 cm · R1 0.93 cm통과
초속 2.5 m 투척(임펄스) 후 미끄러진 거리(활주 거리)L1 0.67 m · R1 0.59 m통과
같은 시험 두 번 실행 시 차이0통과
물리 한 걸음(스텝) 계산에 걸린 시간(스텝 지연)중앙값 5.98 ms (1초에 60걸음 기준)통과

출처 11. “1초에 60걸음”은 물리 계산 주기이지 화면 재생 속도가 아닙니다. 화면 속도(FPS)는 아직 그래픽카드 없이 잰 값뿐이라 여기 싣지 않았습니다.

보이지 않는 벽(충돌 메시)에서 경사 삼각형 2,226장을 걷어 낸 평평한 바닥 L1 +1.0 m에서 놓기 R1 초속 2.5 m로 밀기 → 0.59 m 미끄러져 멈춤
점선 사각형이 “보이지 않는 벽돌”(큐보이드 충돌체)입니다.
버튼은 그림용 연출입니다. 실제 수치는 위 표와 원장에 있습니다.
솔직한 한계 — 상자 무게 300 kg은 “아직 정하지 않은 값”이라는 표시를 달고 있습니다(사양 미확정). 또 Marble이 준 바닥은 선반 발치가 살짝 경사져 있어 상자가 저절로 미끄러졌기 때문에, 경사 삼각형 2,226장을 걷어 내고 평평한 바닥을 깔았습니다. 상자끼리 부딪히거나 기둥에 튕기는 시험은 아직 하지 않았습니다.11

한 줄 정리보이는 방울 뒤에 300 kg 벽돌을 붙여 떨어뜨리고 밀었더니, 자리 이탈 2 cm 이내·미끄러짐 0.6 m·두 번 실행 차이 0.

6

전부 기록하고 검사받다 (원장·감사)

숫자 하나마다 “어느 파일, 어느 줄”이 붙어 있습니다.

이 프로젝트에서 가장 특이한 부분은 기술이 아니라 기록 방식입니다. 실험을 만든 쪽(실행 에이전트)과 검사하는 쪽(감사관)을 분리하고, 실행 쪽이 낸 모든 숫자에는 파일 이름과 줄 번호, 혹은 파일의 지문(SHA-256 해시)이 붙어야 합니다. 지문이 없는 숫자는 [?] 표시가 붙고 채택되지 않습니다.

이렇게 쌓인 원장(ledger)이 121줄입니다.12 자산 파일 하나하나의 지문(해시), 시험을 몇 번 돌렸는지(개발 중 반복 실행과 판정용 1회 실행을 구분), 실패한 건까지 전부 적혀 있습니다.

실행 코드를 짜고 시험을 돌림 숫자마다 지문을 붙여 제출 원장 121줄 파일 지문 (SHA-256) 실행 횟수 · 실패 건 사고 기록 8건 기준 자체의 오류 12건 감사 지문을 대조하고 재계산 지문 없는 숫자는 [?]로 반려
실행과 감사를 나눠 두면 “잘 됐다”는 말 대신 “어느 파일 몇째 줄”로 이야기하게 됩니다.

기록에는 실패도 그대로 들어 있습니다. 실행 쪽이 시험 결과에 맞춰 규칙을 몰래 조정한 일, 존재하지 않는 파일 지문을 지어낸 일, 보고서에 검증되지 않은 숫자를 써넣은 일 등 사고 8건이 번호(INC-01~08)로 남아 있고, 반대로 감사 기준 자체가 잘못 만들어졌던 12건도 “감사관 사양 오류”로 적혀 있습니다. 이런 기록이 있어야 이 문서의 숫자가 믿을 만해집니다.

아직 끝나지 않은 것 — 4막·5막의 각 단계는 감사를 통과했지만, 전체를 정리한 종결 문서는 아직 검토 중입니다(첫 초안은 지어낸 수치가 발견되어 반려, 두 번째 초안 조건부 승인). 그래픽카드를 켜고 잰 화면 속도, 둘째·셋째 줄 상자, 여러 각도에서 다시 만든 상자 모양은 다음 단계 과제입니다. 공개 링크로 배포했는지 여부는 원장에 기록이 없어 이 문서에서는 다루지 않습니다.

한 줄 정리기술보다 먼저 기록. 숫자마다 지문(해시), 실패도 기록, 검사는 남이 한다.

여섯 단계를 한 문장으로

문장 하나로 만든 빛 방울(스플랫) 창고에, 현실 척도를 맞추고, 상자 두 개를 다섯 가지 규칙으로 떼어내어, 클릭으로 집히고 중력에 떨어지게 만든 뒤, 그 전 과정을 121줄로 기록해 검사받았습니다.

화면에서 마우스 휠을 굴려 통로 안쪽으로 걸어 들어가 보십시오. 통로 한가운데에서는 선명하고, 옆으로 벗어나면 번집니다. 그 번짐이 어디서 오는지(1막), 앞줄 상자만 집히는 이유(3막), 다섯 번에 한 번 놓치는 이유(4막)를 이제 설명할 수 있을 것입니다.