3D Gaussian Splatting¶
메타 정보¶
| 항목 | 내용 |
|---|---|
| 논문 | 3D Gaussian Splatting for Real-Time Radiance Field Rendering |
| 저자 | Bernhard Kerbl, Georgios Kopanas, Thomas Leimkuhler, George Drettakis (Inria, Max Planck Institute) |
| 학회 | SIGGRAPH 2023 (Best Paper Award) |
| DOI | 10.1145/3592433 |
| 코드 | https://github.com/graphdeco-inria/gaussian-splatting |
| 분야 | Computer Vision, 3D Reconstruction, Neural Rendering |
1. 핵심 아이디어¶
3D Gaussian Splatting (3DGS)은 Neural Radiance Fields (NeRF)의 대안으로 제안된 3D 장면 표현 및 렌더링 기법이다. NeRF가 암묵적(implicit) 신경망 표현을 사용하는 반면, 3DGS는 명시적(explicit) 3D Gaussian primitives를 사용한다.
핵심 차별점¶
NeRF: 좌표 (x,y,z,theta,phi) --> MLP --> (색상, 밀도)
- 픽셀당 수백 번의 신경망 추론 필요
- 느린 렌더링 (수 초~수 분)
3DGS: 3D Gaussian 집합 --> Rasterization --> 이미지
- 신경망 추론 불필요
- 실시간 렌더링 (100+ FPS)
2. 3D Gaussian Primitive 정의¶
각 Gaussian은 다음 속성으로 정의된다:
| 속성 | 수학적 표현 | 설명 |
|---|---|---|
| 위치 (mean) | mu in R^3 | 3D 공간상 중심점 |
| 공분산 | Sigma in R^(3x3) | 형태와 방향 (타원체) |
| 불투명도 | alpha in [0,1] | 투명도 |
| 색상 | c (SH coefficients) | Spherical Harmonics로 표현된 view-dependent 색상 |
공분산 행렬 파라미터화¶
공분산 행렬 Sigma는 positive semi-definite 조건을 만족해야 한다:
최적화 시에는 (q, s)를 학습하여 유효한 공분산 보장.
3. 렌더링 파이프라인¶
┌─────────────────────────────────────────────────────────────────┐
│ 3D Gaussian Splatting Pipeline │
├─────────────────────────────────────────────────────────────────┤
│ │
│ [3D Gaussians] │
│ | │
│ v │
│ ┌─────────────────┐ │
│ │ 1. Projection │ 3D Gaussian --> 2D Gaussian │
│ │ (EWA) │ Sigma_2D = J * W * Sigma * W^T * J^T │
│ └────────┬────────┘ │
│ | │
│ v │
│ ┌─────────────────┐ │
│ │ 2. Tile-based │ 화면을 16x16 타일로 분할 │
│ │ Culling │ 타일별 Gaussian 할당 │
│ └────────┬────────┘ │
│ | │
│ v │
│ ┌─────────────────┐ │
│ │ 3. Depth Sort │ 타일 내 Gaussians를 깊이순 정렬 │
│ │ (per-tile) │ GPU radix sort 사용 │
│ └────────┬────────┘ │
│ | │
│ v │
│ ┌─────────────────┐ │
│ │ 4. Alpha │ front-to-back 순서로 블렌딩 │
│ │ Blending │ C = sum_i (c_i * alpha_i * T_i) │
│ └────────┬────────┘ T_i = prod_{j<i} (1 - alpha_j) │
│ | │
│ v │
│ [Rendered Image] │
│ │
└─────────────────────────────────────────────────────────────────┘
3.1 EWA (Elliptical Weighted Average) Splatting¶
3D Gaussian을 2D로 투영할 때, 원근 투영의 비선형성으로 인해 정확한 2D 공분산 계산 필요:
Sigma' = J * W * Sigma * W^T * J^T
where:
W: viewing transformation (world --> camera)
J: Jacobian of the projective transformation
Sigma': 2D screen-space covariance
3.2 Alpha Blending¶
깊이 순서대로 색상 합성:
C(x) = sum_{i in N} c_i * alpha_i * prod_{j=1}^{i-1} (1 - alpha_j)
where:
c_i: i번째 Gaussian의 색상
alpha_i: i번째 Gaussian의 기여도 (불투명도 x Gaussian 값)
4. 학습 (Optimization)¶
4.1 손실 함수¶
L = (1 - lambda) * L1 + lambda * L_D-SSIM
where:
L1: 픽셀별 L1 loss
L_D-SSIM: D-SSIM (structural similarity) loss
lambda: 0.2 (기본값)
4.2 Adaptive Density Control¶
학습 중 Gaussian 수를 동적으로 조절:
┌─────────────────────────────────────────────────────────────────┐
│ Adaptive Density Control │
├─────────────────────────────────────────────────────────────────┤
│ │
│ [Densification] 100 iteration마다 수행 │
│ │
│ 1. Clone (작은 Gaussian) │
│ - grad(position) > threshold │
│ - scale < scene_extent / 10 │
│ --> 같은 위치에 복사본 생성 │
│ │
│ 2. Split (큰 Gaussian) │
│ - grad(position) > threshold │
│ - scale >= scene_extent / 10 │
│ --> 2개의 작은 Gaussian으로 분할 │
│ │
│ [Pruning] │
│ │
│ 3. Remove │
│ - alpha < threshold (너무 투명) │
│ - scale > scene_extent (너무 큼) │
│ --> 제거 │
│ │
│ 4. Opacity Reset │
│ - 주기적으로 alpha를 낮은 값으로 리셋 │
│ --> 불필요한 Gaussian이 자연스럽게 pruning됨 │
│ │
└─────────────────────────────────────────────────────────────────┘
5. NeRF vs 3D Gaussian Splatting 비교¶
| 특성 | NeRF | 3D Gaussian Splatting |
|---|---|---|
| 표현 방식 | Implicit (MLP) | Explicit (3D Gaussians) |
| 렌더링 속도 | 느림 (수 초) | 실시간 (100+ FPS) |
| 학습 시간 | 수 시간 | 수십 분 |
| 메모리 사용 | 낮음 (MLP weights) | 높음 (수백만 Gaussians) |
| 편집 용이성 | 어려움 | 용이 (명시적 primitives) |
| 품질 | 높음 | 동등 또는 우수 |
| Anti-aliasing | 어려움 | 자연스러움 (Gaussian 특성) |
| View-dependent 효과 | MLP로 학습 | Spherical Harmonics |
6. Spherical Harmonics (SH) for View-Dependent Color¶
각 Gaussian의 색상은 보는 방향에 따라 달라질 수 있다 (반사, 광택 등):
c(d) = sum_{l=0}^{L} sum_{m=-l}^{l} c_{l,m} * Y_l^m(d)
where:
d: viewing direction
Y_l^m: spherical harmonic basis functions
c_{l,m}: learned coefficients
L: maximum degree (보통 3, 총 16개 계수)
SH Degree별 효과¶
| Degree | 계수 수 | 표현 가능한 효과 |
|---|---|---|
| 0 | 1 | Diffuse (단색) |
| 1 | 4 | 부드러운 방향성 |
| 2 | 9 | 반사 하이라이트 |
| 3 | 16 | 복잡한 광택 효과 |
7. Python 구현 예시¶
7.1 공식 코드 사용법¶
# 설치
git clone https://github.com/graphdeco-inria/gaussian-splatting.git
cd gaussian-splatting
# 환경 설정
conda create -n gaussian_splatting python=3.8
conda activate gaussian_splatting
pip install -r requirements.txt
# submodules 설치 (diff-gaussian-rasterization, simple-knn)
pip install submodules/diff-gaussian-rasterization
pip install submodules/simple-knn
7.2 학습¶
# COLMAP으로 카메라 파라미터 추출된 데이터 필요
python train.py -s <path_to_dataset>
# 주요 옵션
python train.py \
-s ./data/garden \ # 데이터 경로
--iterations 30000 \ # 학습 iteration
--sh_degree 3 \ # SH degree
--densify_until_iter 15000 \ # densification 종료 시점
--densification_interval 100 # densification 간격
7.3 렌더링¶
# 학습된 모델로 렌더링
python render.py -m <path_to_trained_model>
# 평가 (PSNR, SSIM, LPIPS)
python metrics.py -m <path_to_trained_model>
7.4 핵심 데이터 구조 (PyTorch)¶
import torch
import torch.nn as nn
class GaussianModel(nn.Module):
"""3D Gaussian Splatting 모델의 핵심 구조"""
def __init__(self, sh_degree=3):
super().__init__()
self.sh_degree = sh_degree
# 학습 가능한 파라미터
self._xyz = None # (N, 3) positions
self._features_dc = None # (N, 1, 3) DC component of SH
self._features_rest = None # (N, (D+1)^2-1, 3) higher order SH
self._scaling = None # (N, 3) log scale
self._rotation = None # (N, 4) quaternion
self._opacity = None # (N, 1) logit opacity
def create_from_pcd(self, pcd_points, pcd_colors):
"""Point cloud로부터 초기화"""
num_points = pcd_points.shape[0]
# 위치: point cloud 좌표
self._xyz = nn.Parameter(torch.tensor(pcd_points, dtype=torch.float32))
# 색상: RGB를 SH DC 성분으로 변환
# C0 = 0.28209479177387814 (SH 기저 함수의 첫 번째 계수)
fused_color = (pcd_colors - 0.5) / 0.28209479177387814
self._features_dc = nn.Parameter(
fused_color.unsqueeze(1).contiguous()
)
# Higher order SH: 0으로 초기화
num_sh = (self.sh_degree + 1) ** 2 - 1
self._features_rest = nn.Parameter(
torch.zeros((num_points, num_sh, 3), dtype=torch.float32)
)
# 스케일: 이웃 점들과의 거리 기반 초기화
dist = self._compute_nearest_neighbor_dist()
scales = torch.log(dist.unsqueeze(-1).repeat(1, 3))
self._scaling = nn.Parameter(scales)
# 회전: identity quaternion
rots = torch.zeros((num_points, 4), dtype=torch.float32)
rots[:, 0] = 1 # w=1, x=y=z=0
self._rotation = nn.Parameter(rots)
# 불투명도: inverse sigmoid(0.1)
opacities = torch.logit(torch.full((num_points, 1), 0.1))
self._opacity = nn.Parameter(opacities)
@property
def get_xyz(self):
return self._xyz
@property
def get_scaling(self):
return torch.exp(self._scaling) # log scale --> scale
@property
def get_rotation(self):
return torch.nn.functional.normalize(self._rotation, dim=-1)
@property
def get_opacity(self):
return torch.sigmoid(self._opacity)
@property
def get_covariance(self, scaling_modifier=1):
"""공분산 행렬 계산"""
scaling = self.get_scaling * scaling_modifier
rotation = self.get_rotation
# Quaternion --> Rotation matrix
r, x, y, z = rotation[:, 0], rotation[:, 1], rotation[:, 2], rotation[:, 3]
R = torch.stack([
1 - 2*(y*y + z*z), 2*(x*y - r*z), 2*(x*z + r*y),
2*(x*y + r*z), 1 - 2*(x*x + z*z), 2*(y*z - r*x),
2*(x*z - r*y), 2*(y*z + r*x), 1 - 2*(x*x + y*y)
], dim=-1).reshape(-1, 3, 3)
# S * S^T
S = torch.diag_embed(scaling)
# Sigma = R * S * S^T * R^T
covariance = R @ S @ S.transpose(-1, -2) @ R.transpose(-1, -2)
return covariance
def _compute_nearest_neighbor_dist(self):
"""KNN으로 최근접 이웃 거리 계산"""
from simple_knn._C import distCUDA2
dist2 = distCUDA2(self._xyz)
return torch.sqrt(torch.clamp(dist2, min=1e-7))
# 학습 설정 예시
def setup_optimizer(model):
"""파라미터별 learning rate 설정"""
params = [
{'params': [model._xyz], 'lr': 0.00016, 'name': 'xyz'},
{'params': [model._features_dc], 'lr': 0.0025, 'name': 'f_dc'},
{'params': [model._features_rest], 'lr': 0.0025 / 20, 'name': 'f_rest'},
{'params': [model._scaling], 'lr': 0.005, 'name': 'scaling'},
{'params': [model._rotation], 'lr': 0.001, 'name': 'rotation'},
{'params': [model._opacity], 'lr': 0.05, 'name': 'opacity'},
]
return torch.optim.Adam(params, lr=0.0, eps=1e-15)
7.5 Differentiable Rasterization (개념)¶
def render(viewpoint_camera, gaussians, bg_color):
"""
Differentiable Gaussian Rasterization
실제 구현은 CUDA 커널 사용 (diff-gaussian-rasterization)
"""
# 1. 3D Gaussian을 카메라 좌표계로 변환
means3D = gaussians.get_xyz
means2D = project_to_screen(means3D, viewpoint_camera)
# 2. 2D 공분산 계산 (EWA splatting)
cov3D = gaussians.get_covariance
cov2D = compute_cov2D(means3D, cov3D, viewpoint_camera)
# 3. 색상 계산 (SH evaluation)
view_dir = means3D - viewpoint_camera.position
view_dir = view_dir / view_dir.norm(dim=-1, keepdim=True)
colors = eval_sh(gaussians.sh_degree, gaussians.get_features, view_dir)
# 4. Rasterization (CUDA)
rendered_image = rasterize_gaussians(
means2D=means2D,
cov2D=cov2D,
colors=colors,
opacities=gaussians.get_opacity,
image_height=viewpoint_camera.image_height,
image_width=viewpoint_camera.image_width,
bg_color=bg_color
)
return rendered_image
8. 주요 확장 연구¶
| 프로젝트 | 설명 | 특징 |
|---|---|---|
| 4D Gaussian Splatting | 동적 장면 표현 | 시간 축 추가, deformation field |
| Gaussian-SLAM | SLAM에 적용 | 실시간 3D 재구성 + 위치 추정 |
| DreamGaussian | Text-to-3D 생성 | SDS loss + 3DGS |
| GaussianEditor | 3D 편집 | Gaussian 단위 편집, inpainting |
| Scaffold-GS | 구조화된 표현 | Anchor points + local Gaussians |
| Mip-Splatting | Anti-aliasing | 3D smoothing filter |
9. 하이퍼파라미터 가이드¶
9.1 주요 설정¶
| 파라미터 | 기본값 | 설명 |
|---|---|---|
| iterations | 30,000 | 총 학습 iteration |
| sh_degree | 3 | Spherical Harmonics 차수 |
| position_lr_init | 0.00016 | 위치 초기 learning rate |
| densify_until_iter | 15,000 | densification 종료 시점 |
| densification_interval | 100 | densification 주기 |
| opacity_reset_interval | 3,000 | opacity 리셋 주기 |
| densify_grad_threshold | 0.0002 | densification 기준 gradient |
| percent_dense | 0.01 | clone/split 비율 |
9.2 품질 vs 속도 트레이드오프¶
고품질:
- sh_degree: 3
- iterations: 30,000+
- densify_until_iter: 20,000
빠른 학습:
- sh_degree: 0-1
- iterations: 7,000
- densify_until_iter: 5,000
10. 한계 및 고려사항¶
| 한계 | 설명 |
|---|---|
| 메모리 사용량 | 수백만 Gaussian -> GB 단위 VRAM |
| 초기화 의존성 | COLMAP 등 SfM 결과 필요 |
| 동적 장면 | 기본 버전은 정적 장면만 지원 |
| 저조도/반사 | 극단적 조명 조건에서 품질 저하 |
| 큰 장면 | unbounded scene에서 추가 처리 필요 |
적합한 사용 사례¶
- 실시간 Novel View Synthesis
- VR/AR 콘텐츠 제작
- 게임/시뮬레이션 환경 구축
- 3D 스캔 및 재구성
- 디지털 트윈
11. 참고 자료¶
- 논문: https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/
- 공식 코드: https://github.com/graphdeco-inria/gaussian-splatting
- ACM DL: https://dl.acm.org/doi/10.1145/3592433
- Awesome 3D Gaussian Splatting: https://github.com/MrNeRF/awesome-3D-gaussian-splatting
- Radiance Fields: https://radiancefields.com/
최종 업데이트: 2026-02-16