비밀의 열쇠: 3D 가우시안 스플래팅(3DGS)
3D를 만드는 두 가지 방법이 있습니다. 조각을 이어 붙이거나, 빛 방울(스플랫)을 띄우거나.
지금까지 대부분의 3D(게임, 설계 도면, 애니메이션)는 작은 삼각형 판(폴리곤 메시)을 수만 장 이어 붙여 만듭니다. 종이접기(메시 모델링)로 공을 만드는 것과 같아서, 멀리서 보면 둥글지만 가까이 가면 모서리가 드러납니다. 유리의 반짝임이나 형광등 불빛이 바닥에 번지는 모습은 따로 그려 넣어야 합니다.
3D 가우시안 스플래팅(3D Gaussian Splatting, 줄여서 3DGS)은 판(폴리곤)을 쓰지 않습니다. 대신 색과 투명도, 크기와 기울기를 각각 가진 반투명한 빛 방울(3DGS의 기본 단위: 가우시안(Gaussian) 또는 스플랫(splat))을 공중에 수십만 개 띄워 둡니다. 방울 하나는 아무것도 아니지만, 겹치고 흩어진 방울을 한꺼번에 보면 콘크리트 바닥의 번들거림, 골판지의 거친 결, 천장 조명의 후광까지 카메라로 찍은 것처럼 보입니다. 카메라를 옮기면 방울들이 다른 각도로 겹치기 때문에 사진과 달리 시점이 살아 움직입니다.
한 줄 정리3DGS는 사진처럼 보이는 3D를 빛 방울(스플랫) 50만 개로 만드는 방법이고, 우리가 쓰는 재생기(런타임)는 Spark(World Labs, MIT 라이선스)이며 그 위에 자체 응용층을 얹어 창고를 다룹니다.
글로 창고를 주문하다 (텍스트→3D 생성)
사진을 찍은 것이 아닙니다. 문장 한 줄을 보냈습니다.
World Labs의 공간 생성 서비스(Marble API) Marble에 이런 주문(텍스트 프롬프트)을 보냈습니다. “양옆에 파란색·주황색 선반 랙이 늘어서 있고, 바닥은 매끄러운 콘크리트, 천장에는 형광등이 줄지어 켜진 물류 창고 통로.” 약 5분 뒤 Marble은 이 문장을 3차원 공간으로 돌려주었습니다.
돌아온 것은 파일 한 개가 아니라 네 가지 자산입니다. 방울 192만 개짜리 원본, 브라우저에서 가볍게 돌리기 위한 50만 개짜리 경량본, 물건이 통과하지 못하게 하는 보이지 않는 벽(충돌 메시), 그리고 360도 파노라마 사진(등장방형 파노라마 PNG)입니다. 이 한 번의 생성에 1,580크레딧, 우리 돈으로 약 1,700원이 들었습니다.2
한 줄 정리창고는 촬영이 아니라 문장으로 만들어졌고, 방울·충돌 메시·파노라마가 함께 왔습니다.
줄자로 크기를 맞추다 (척도 정합)
처음 받은 창고에는 “1미터”가 없었습니다.
생성된 공간은 모양은 맞지만 단위가 없습니다. 상자가 손바닥만 할 수도, 집채만 할 수도 있습니다. 다행히 Marble은 자산과 함께 두 개의 숫자(척도 메타데이터: metric_scale_factor, ground_plane_offset)를 알려 줍니다. “실제 크기로 보려면 2.12배 키워라”, “바닥은 원점보다 1.26 m 아래에 있다.”4 이 두 숫자를 적용하면 창고가 현실 척도가 됩니다.
여기서 끝내지 않고 검산(교차 검증)을 했습니다. 방울들이 가장 많이 몰려 있는 높이(높이 히스토그램의 최빈값, 바닥일 가능성이 가장 큰 곳)와 충돌 메시가 말하는 바닥 높이를 따로 재서 비교했더니 차이가 1.0 cm였습니다.5 두 정보가 서로 다른 경로로 같은 답을 냈으니 “바닥이 여기”라고 믿어도 됩니다.
한 줄 정리2.12배 확대, 바닥 1.26 m 보정, 바닥 검산 차이 1.0 cm. 이제 창고 안의 1 m는 진짜 1 m입니다.
상자를 배경에서 떼어내다 (부품 분할)
통째로 굳은 조각상에서 상자만 뜯어내려면, 다섯 가지 질문(5조건 마스크)을 던집니다.
이 창고의 방울 50만 개에는 이름표(분할 정보·의미 라벨)가 없습니다. “너는 상자, 너는 기둥”이라는 정보가 없기 때문에, 상자를 집으려 하면 뒤의 선반과 바닥이 한 덩어리로 따라옵니다. 그래서 방울 하나하나에 다섯 가지 질문을 던져 상자에 속한 방울만 골라냈습니다.
| 질문 | 이 방울은… | 왜 묻는가 |
|---|---|---|
| 1 | 상자가 있어야 할 자리(경계 상자 bbox + 3 cm) 안에 있는가? | 엉뚱한 곳의 방울을 배제 |
| 2 | 바닥보다 4 cm 이상 위에 떠 있는가? | 바닥 반사 방울을 배제 |
| 3 | 크기가 15 cm보다 작은가? | 길게 늘어진 배경 방울을 배제 |
| 4 | 색이 골판지 색인가? (주황·파랑·회색이면 제외) | 랙 기둥·보를 배제 |
| 5 | 기둥에서 5 cm 이상 떨어져 있는가? | 기둥에 붙은 방울을 배제 |
다섯 질문을 모두 통과한 방울만 “상자”가 됩니다. 원본 기준으로 11,807개가 상자 두 개(왼쪽 앞 L1, 오른쪽 앞 R1)에 배정되고, 나머지 전부는 움직이지 않는 배경(정적 스플랫)으로 남았습니다.6 상자 방울과 배경 방울의 합은 언제나 원래 개수와 정확히 같아야 하며, 매 회 이 합계를 검산했습니다.
한 줄 정리인공지능이 아니라 다섯 가지 규칙으로 상자 방울 11,807개를 골라냈고, 앞줄 상자 두 개가 “집을 수 있는 물건”(동적 부품, 독립 SplatMesh)이 됐습니다.
클릭으로 상자를 집는 시험 (레이캐스트 픽킹)
화면을 찍었을 때 상자가 잡히는지, 뒤의 기둥이 잡히는지.
마우스로 화면의 한 점을 클릭하면 컴퓨터는 그 점에서 화면 안쪽으로 가늘고 긴 바늘(광선, ray)을 찔러 넣습니다. 바늘이 처음 닿는 것(레이캐스트 히트)이 “클릭한 물건”입니다. 문제는 빛 방울(스플랫)은 반투명해서 바늘이 상자를 뚫고 지나가 뒤의 선반에 닿기 쉽다는 점입니다. 실제로 첫 번째 방식에서 실패한 59건 중 44건이 이 “관통”(pass-through)이었습니다.8
그래서 규칙(픽킹 정책 v1 → v2)을 바꿨습니다. 바늘이 상자 영역(bbox + 3 cm)을 지나갔고, 그 뒤에 닿은 배경이 35 cm 이내라면 “상자를 클릭한 것”으로 봅니다. 상자를 스쳐 지나 바로 뒤 선반에 닿았다면 사람의 의도는 상자였을 테니까요.
시험은 공정해야 합니다. 클릭할 자리 225곳을 미리 무작위로 뽑아 봉인(홀드아웃 세트, seed 고정·파일 잠금)해 두었고(정답도 함께), 규칙을 만드는 동안에는 이 목록을 열어 보지 않았습니다. 그리고 딱 한 번만 실행했습니다.
한 줄 정리봉인된 클릭 225건을 한 번 실행해 상자 79.3%, 헛집기(오탐) 0건. 아직 다섯 번에 한 번은 놓치며, 그 원인 대부분은 통로 정면에서 본 얇은 앞면 때문입니다.
중력을 켜다 (강체 물리)
보이는 상자에 무게를 주면, 떨어지고 미끄러지고 멈춥니다.
빛 방울(스플랫) 상자는 그림일 뿐이어서 놓아 두면 허공에 멈춰 있거나 바닥을 뚫고 사라집니다. 그래서 브라우저 안에 물리 계산기(물리 엔진) 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)는 아직 그래픽카드 없이 잰 값뿐이라 여기 싣지 않았습니다.
한 줄 정리보이는 방울 뒤에 300 kg 벽돌을 붙여 떨어뜨리고 밀었더니, 자리 이탈 2 cm 이내·미끄러짐 0.6 m·두 번 실행 차이 0.
전부 기록하고 검사받다 (원장·감사)
숫자 하나마다 “어느 파일, 어느 줄”이 붙어 있습니다.
이 프로젝트에서 가장 특이한 부분은 기술이 아니라 기록 방식입니다. 실험을 만든 쪽(실행 에이전트)과 검사하는 쪽(감사관)을 분리하고, 실행 쪽이 낸 모든 숫자에는 파일 이름과 줄 번호, 혹은 파일의 지문(SHA-256 해시)이 붙어야 합니다. 지문이 없는 숫자는 [?] 표시가 붙고 채택되지 않습니다.
이렇게 쌓인 원장(ledger)이 121줄입니다.12 자산 파일 하나하나의 지문(해시), 시험을 몇 번 돌렸는지(개발 중 반복 실행과 판정용 1회 실행을 구분), 실패한 건까지 전부 적혀 있습니다.
기록에는 실패도 그대로 들어 있습니다. 실행 쪽이 시험 결과에 맞춰 규칙을 몰래 조정한 일, 존재하지 않는 파일 지문을 지어낸 일, 보고서에 검증되지 않은 숫자를 써넣은 일 등 사고 8건이 번호(INC-01~08)로 남아 있고, 반대로 감사 기준 자체가 잘못 만들어졌던 12건도 “감사관 사양 오류”로 적혀 있습니다. 이런 기록이 있어야 이 문서의 숫자가 믿을 만해집니다.
한 줄 정리기술보다 먼저 기록. 숫자마다 지문(해시), 실패도 기록, 검사는 남이 한다.
여섯 단계를 한 문장으로
문장 하나로 만든 빛 방울(스플랫) 창고에, 현실 척도를 맞추고, 상자 두 개를 다섯 가지 규칙으로 떼어내어, 클릭으로 집히고 중력에 떨어지게 만든 뒤, 그 전 과정을 121줄로 기록해 검사받았습니다.
화면에서 마우스 휠을 굴려 통로 안쪽으로 걸어 들어가 보십시오. 통로 한가운데에서는 선명하고, 옆으로 벗어나면 번집니다. 그 번짐이 어디서 오는지(1막), 앞줄 상자만 집히는 이유(3막), 다섯 번에 한 번 놓치는 이유(4막)를 이제 설명할 수 있을 것입니다.