3D Gaussian Splatting(3DGS)은 장면을 흐릿한 타원체 수십만 개로 저장하고, 사진과 똑같아질 때까지 그 값을 고칩니다. 3D 장면을 돌려 보고, 가우시안 하나를 손으로 빚고, 쌓는 순서와 투영을 계산하고, 학습을 이 브라우저에서 직접 돌려 봅니다.
컴퓨터가 장면을 기억하는 방법은 크게 넷입니다. 메시는 삼각형을 이어 붙이고, 점군은 색 있는 점을 흩뿌리고, NeRF는 신경망이 '이 위치, 이 방향의 색과 밀도'를 대답하게 만듭니다. 3DGS는 점마다 크기·방향·투명도를 줘서 번지는 타원체로 만들고, 사진과 똑같이 보일 때까지 그 값을 학습합니다. 계산할 신경망이 없으니 그리기는 그래픽카드가 원래 잘하는 래스터화로 끝납니다. 그래서 NeRF보다 학습이 빠르고 실시간으로 돌아갑니다. 대가는 용량입니다.
끌어서 돌리기, 휠이나 두 손가락으로 확대, 두 번 눌러 처음으로. '점 구름처럼'은 같은 데이터의 크기만 줄인 것입니다. 점군과 3DGS의 차이는 점에 크기와 모양이 있느냐 하나입니다. 이 장면은 학습한 것이 아니라 코드로 배치한 것입니다.
Mip-NeRF360 데이터셋, Kerbl 외(2023) 표 1에서 옮김(A6000 GPU, †는 원 논문 값). 학습 시간과 용량은 로그 눈금.
가우시안 하나가 가진 값은 다섯 가지입니다. 위치 μ(3개), 크기 s(3개), 회전 q(쿼터니언 4개), 불투명도 o(1개), 색(구면 조화 계수 48개). 다 합쳐 실수 59개입니다. 모양을 정하는 공분산 Σ를 바로 학습하지 않고 크기 S와 회전 R로 나눠 저장합니다. Σ의 숫자를 마음대로 고치면 타원이 아닌 것(음수 분산)이 될 수 있지만, S와 R로 만들면 늘 올바른 타원이기 때문입니다.
그림을 누르거나 끌면 그 점의 α를 봅니다. 점선 고리는 1σ, 2σ, 3σ.
반짝이는 면은 보는 쪽에 따라 다르게 보입니다. 3DGS는 색을 구면 조화(spherical harmonics)로 저장합니다. 0차는 모든 방향에 한 색, 1차는 방향에 따라 완만하게 바뀌는 항을 더하고, 2·3차는 더 잘게 바뀝니다(RGB 모두 48개). 아래 고리는 가우시안 하나를 둘레의 각 방향에서 본 색입니다(2D 단면, 0·1차).
3D 타원체마다 화면 위 2D 타원으로 투영합니다(EWA 스플래팅). Σ′ = J W Σ Wᵀ Jᵀ에서 W는 카메라 회전, J는 원근 투영을 그 점 근처에서 직선으로 근사한 것입니다. 화면을 16×16 타일로 자르고, 가우시안마다 걸치는 타일에 적은 뒤 (타일, 깊이)로 GPU 기수 정렬을 한 번 하면 픽셀마다 앞→뒤 순서가 나옵니다. 그다음 앞에서부터 색을 쌓습니다. T는 아직 남은 빛이고, 0.0001 아래로 떨어지면 그 픽셀은 멈춥니다. 모든 단계가 매끄러워서 픽셀 오차를 그 픽셀에 닿은 모든 가우시안에 거꾸로 나눠 줄 수 있습니다.
색 점을 끌어 가우시안을 옮기고, 다른 곳을 눌러 픽셀(흰 고리)을 고릅니다. ↑ ↓로 깊이 순서를 바꿉니다.
진짜 3DGS는 카메라 위치를 아는 사진 수백 장으로 3D 가우시안을 학습합니다. 여기서는 같은 원리를 96×96 그림 한 장과 2D 가우시안에 적용해 이 브라우저에서 돌립니다. 그리기, 비교, 역전파, Adam을 수천 번. 100단계마다 위치 기울기가 계속 큰 가우시안은 작으면 복제하고 크면 분할하며, 거의 투명해진 것은 지웁니다. '타원'으로 바꾸면 경계와 무늬가 있는 곳부터 큰 덩어리가 작은 것으로 쪼개지는 것이 보입니다.
학습에는 사진과 함께 각 사진을 어디서 어느 방향으로 찍었는지가 필요합니다. COLMAP은 사진만 보고 이것을 계산합니다(structure from motion). 겹치는 사진들 사이에서 특징점을 짝짓고 삼각측량합니다. 덤으로 나오는 듬성듬성한 점이 가우시안의 출발점이 됩니다. 그래서 촬영이 거의 모든 것을 정합니다. 대상을 두세 높이로 한 바퀴씩 돌고, 옆 사진과 많이 겹치게, 노출·초점·화이트밸런스를 고정하고, 움직이는 것·거울·무늬 없는 벽은 피합니다.
# video → photos (2 per second) ffmpeg -i room.mp4 -vf fps=2 -qscale:v 2 room/input/%04d.jpg # COLMAP camera poses + undistortion (graphdeco-inria/gaussian-splatting) python convert.py -s room
물체 표면의 점이 서로 10° 이상 다른 방향의 사진 두 장 이상에 보이면 초록(삼각측량 가능), 한 장이면 주황, 안 보이면 빨강. 겹침: 사진 하나에 보이는 물체 중 옆 사진에도 보이는 몫.
CUDA GPU가 필요하고, 원 구현은 논문 품질에 VRAM 24 GB를 권합니다. 해상도를 낮추면 더 작은 카드에서도 돕니다. 문제 대부분은 학습이 아니라 사진에서 옵니다. 사진이 적은 방향의 공중 먼지(플로터), 흔들린 사진이나 카메라 위치 오차로 인한 흐림, 무늬 없는 면에서의 실패.
git clone https://github.com/graphdeco-inria/gaussian-splatting --recursive python train.py -s ../room # 30,000 iterations by default python render.py -m output/<id> && python metrics.py -m output/<id> pip install gsplat # lighter alternative (nerfstudio team)
원 구현 기본값: 위치 학습률 1.6e-4 → 1.6e-6(지수, 장면 크기를 곱함), 500~15,000단계에 100단계마다 밀도 제어, 3,000단계마다 불투명도 초기화, 1,000단계마다 SH 차수를 올려 3차까지.
가정값을 쓴 대략 추정: 매개변수, 기울기, Adam 두 모멘트로 4바이트 실수 4벌. 그리기 버퍼(투영 값, 타일 목록, 정렬 키)는 가우시안당 1 KB, 그림 버퍼는 실수 그림 12장으로 가정했습니다. 실제 사용량은 라이브러리, 장면, 부대 비용에 따라 다릅니다.
여기서 '최대 개수'와 밀도 제어를 바꿔 마지막 PSNR을 비교해 보세요. 개수 상한이 GPU 메모리 역할을 합니다.
학습한 PLY는 가우시안 하나에 실수 62개(위치 3, 법선 3, 색 48, 불투명도 1, 크기 3, 회전 4), 248바이트를 담습니다. 웹에서는 보는 방향에 따른 색을 흔히 버리고 숫자를 줄여 담습니다. .splat 형식은 32바이트입니다. 기여가 적은 가우시안을 빼고, 공중 먼지와 배경을 잘라 내면 더 줄어듭니다. 큰 장면은 객체 저장소(R2)에 두고 뷰어만 Pages에 둡니다. Pages는 파일 하나가 25 MiB까지입니다.
가우시안 하나의 바이트. PLY는 4바이트 실수(위치 3, 법선 3, 색 3·(차수+1)², 불투명도 1, 크기 3, 회전 4). .splat은 위치·크기 float32 각 3개, 색 RGBA 4바이트, 회전 4바이트. 머리말은 뺌.
2023년 논문 뒤로 갈래가 빠르게 늘었습니다. 확대·축소에 강한 품질, 정확한 표면, 움직이는 장면, 작은 파일, 장면마다 학습하지 않고 사진 몇 장에서 바로, 글이나 그림 한 장에서 만들기. 출발점은 모두 같은 래스터라이저입니다.
픽셀보다 작은 가우시안은 한 점에서만 재어지므로, 픽셀보다 작게 움직일 때 밝기가 튑니다. Mip-Splatting은 적어도 픽셀 하나 너비의 필터(학습 때 3D 평활 필터와 화면 위 2D 필터)를 더해서, 작은 가우시안을 픽셀 위에서 평균한 값으로 그립니다.
교육용 페이지입니다. 맨 위 3D 장면은 코드로 배치한 것이고(학습한 장면이 아님), 학습 체험은 같은 원리를 사진 한 장과 2D 가우시안에 적용한 축소판입니다. PSNR은 정답 그림과의 차이를 잰 값입니다.