3D Gaussian Splatting for Real-Time Radiance Field Rendering (SIGGRAPH 2023)
paper :
https://arxiv.org/abs/2308.04079
project website :
https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/
code :
https://github.com/graphdeco-inria/gaussian-splatting
code review :
https://semyeong-yu.github.io/blog/2024/3DGScode/
referenced blog :
https://xoft.tistory.com/51
포스팅을 시작하기에 앞서…
본 글은 직접 논문을 읽으며 정리한 내용이고
더 깔끔한 핵심 정리만 보고 싶다면
3DGS 분석1, 3DGS 분석2 글 괜찮아보임
3DGS Code 리뷰한 내 포스팅도 있음 3DGS 코드분석
수많은 3D Gaussian이 모여 scene을 구성하고 있다!3D scene representation 방법
Mesh or Point NeRF method stochastic sampling for rendering 때문에 연산량이 많고 noise 생김orthogonality를 흐리기 때문에 high-freq. output을 잘 표현할 수 없어서 따로 미리 positional encoding을 수행3D Gaussian method orthogonality를 잘 살리기 때문에 high-freq. output 잘 표현 가능생략 (추후에 다시 볼 수도)
For unbounded and complete scenes,
For 1080p high resolution and real-time(\(\geq\) 30 fps) rendering,
input : MVS(Multi-View Stereo) data,SfM points for initializationsparse point cloud에서 시작해서empty space에서의 불필요한 계산을 하지 않도록 continuous volumetric radiance fields 정보를 저장optimization interleaved with adaptive density control : highly anisotropic volumetric splats는 fine structures를 compact하게 나타낼 수 있음!!spherical harmonics를 통해 directional appearance(color)를 잘 나타낼 수 있음!!real-time rendering :anisotropic splats respecting visibility orderGPU sorting algorithm and tile-based rasterization(projection and \(\alpha\)-blending)Gaussians 수에 제약 없이 빠른 backward pass도 가능빨간 박스 : initialization
파란 박스 : optimization
초록 박스 : 특정 iter.마다 Gaussian을 clone, split, remove
differentiable volumetric representation의 특성을 가지고 있으면서도 빠른 rendering을 위해 unstructured and explicit한 게 무엇이 있을까?
\(\rightarrow\) 3D Gaussian !!
a point를 a small planar circle with a normal이라고 가정하는 이전 Point-based rendering 논문들
SfM points는 sparse해서 normals(법선)를 estimate하기 어려울 뿐만 아니라, estimate 한다 해도 very noisy normals를 optimize하는 것은 매우 어렵
\(\rightarrow\) normals 필요 없는 3D Gaussians !!
k-dim. Gaussian : \(G(\boldsymbol x) = (2\pi)^{-\frac{k}{2}}det(\Sigma)^{-\frac{1}{2}}e^{-\frac{1}{2}(\boldsymbol x - \boldsymbol \mu)^T\Sigma^{-1}(\boldsymbol x - \boldsymbol \mu)}\)
scale vector \(s\) and quaternion \(q\) for covariance matrix spherical harmonics(SH) coeff. for color opacity \(\alpha\)3D position for mean scale vector(scale) and quaternion(rotation) for covariance matrix
\(\Sigma\) 가 symmetric and positive semi-definite이도록 \(\Sigma = R S S^T R^T\) 로 정의해서
\(\Sigma\) 대신 x,y,z-axis scale을 나타내는 3D vector \(s\) 와 rotation을 나타내는 4D quaternion \(q\) 를 optimize 하자!!
quaternion에 대한 설명은 Quaternion 블로그 참고!!
scale 3D vector \(s\) 초기값 :dist2 = torch.clamp_min(distCUDA2(torch.from_numpy(np.asarray(pcd.points)).float().cuda()), 0.0000001)
scales = torch.log(torch.sqrt(dist2))[...,None].repeat(1, 3)
scale 3D vector \(s\) activation function :
smooth gradient 얻기 위해 exponential activation function을 씌움
quaternion \(q\) 초기값 :rots = torch.zeros((fused_point_cloud.shape[0], 4), device="cuda")
rots[:, 0] = 1
anisotropic covariance는 다양한 모양의 geometry를 나타내기 위해 optimize하기에 적합!EWA volume splatting (2001)
[14] [15] :
world-to-camera 는 linear transformation 이지만,
camera-to-image (projection)는non-linear transformation이다!!
world coordinate (3D) : camera coordinate (3D) : viewing transformation affine matrix from world coordinate to camera coordinateimage coordinate (2D) : Local Affine (Linear) transform으로 Approx.하기 위해 \(\boldsymbol t = \boldsymbol t_{k}\) 에서의 Taylor Approx.를 이용하면,Jacobian(각 axis로 편미분한 matrix) of the affine approx. of the projective transformation from camera coordinate to image coordinateGaussian의 중심점을 \(\boldsymbol t_{k}\) 로 두면 그 주변의 \(\boldsymbol t\)에 대해서는 Jacobian을 이용한 affine(linear) transformation 가능!
Projectionof 3D Gaussiancovarianceto 2D
world coordinate :
\(\Sigma\) : 3 \(\times\) 3 covariance matrix of 3D Gaussian
image coordiante (z=1) :
\(\Sigma^{\ast} = J W \Sigma W^T J^T\) : covariance matrix of 2D splat
affine) :local affine approx.) :world-to-image covariance :covariance dimension reduction :param. gradient 직접 유도 (Appendix A.)
training할 때 automatic differentiation으로 인한 overhead를 방지하기 위해 param. gradient를 직접 유도함!
By chain rule, \(\frac{d\Sigma^{\ast}}{ds} = \frac{d\Sigma^{\ast}}{d\Sigma}\frac{d\Sigma}{ds}\) and \(\frac{d\Sigma^{\ast}}{dq} = \frac{d\Sigma^{\ast}}{d\Sigma}\frac{d\Sigma}{dq}\)
By covariance dimension reduction, \(\Sigma^{\ast}\) 는 \(U \Sigma U^T\) 의 좌상단 2-by-2 matrix
where \(U = JW\)
So, 편미분 값은 \(\frac{d\Sigma^{\ast}}{d\Sigma_{ij}} = \begin{bmatrix} U_{1, i} U_{1, j} & U_{1, i} U_{2, j} \\ U_{1, j} U_{2, i} & U_{2, i} U_{2, j} \end{bmatrix}\)
For symmetric and positive semi-definite property of covariance matrix, we set \(\Sigma = MM^T\)
where \(M = RS\)
So, \(\frac{d\Sigma}{ds} = \frac{d\Sigma}{dM} \frac{dM}{ds}\) and \(\frac{d\Sigma}{dq} = \frac{d\Sigma}{dM} \frac{dM}{dq}\)
where \(\frac{d\Sigma}{dM} = 2M^T\)
\(M = RS\)
where \(S = \begin{bmatrix} s_x & s_x & s_x \\ s_y & s_y & s_y \\ s_z & s_z & s_z \end{bmatrix}\)
So, \(\frac{dM_{i, j}}{ds_k} = \begin{cases} R_{i, k} & \text{if j=k} \\ 0 & O.W. \end{cases}\)
\(M = RS\) and \(R(q) = \begin{bmatrix} 1 - 2 \cdot (q_j^2 + q_k^2) & 2 \cdot (q_iq_j - q_rq_k) & 2 \cdot (q_iq_k + q_rq_j) \\ 2 \cdot (q_iq_j + q_rq_k) & 1 - 2 \cdot (q_i^2 + q_k^2) & 2 \cdot (q_jq_k - q_rq_i) \\ 2 \cdot (q_iq_k - q_rq_j) & 2 \cdot (q_jq_k + q_rq_i) & 1 - 2 \cdot (q_i^2 + q_j^2) \end{bmatrix}\)
where \(q = \begin{bmatrix} q_r \\ q_i \\ q_j \\ q_k \end{bmatrix}\)
So, \(\frac{dM}{dq_r} = 2 \begin{bmatrix} 0 & -s_y q_k & s_z q_j \\ s_x q_k & 0 & -s_z q_i \\ -s_x q_j & s_y q_i & 0 \end{bmatrix}\)
and \(\frac{dM}{dq_i} = 2 \begin{bmatrix} 0 & s_y q_j & s_z q_k \\ s_x q_j & -2 s_y q_i & -s_z q_r \\ s_x q_k & s_y q_r & -2 s_z q_i \end{bmatrix}\)
and \(\frac{dM}{dq_j} = 2 \begin{bmatrix} -2 s_x q_j & s_y q_i & s_z q_r \\ s_x q_i & 0 & s_z q_k \\ -s_x q_r & s_y q_k & -2 s_z q_j \end{bmatrix}\)
and \(\frac{dM}{dq_k} = 2 \begin{bmatrix} -2 s_x q_k & -s_y q_r & s_z q_i \\ s_x q_r & -2 s_y q_k & s_z q_j \\ s_x q_i & s_y q_j & 0 \end{bmatrix}\)
gradient for quaternion normalization is straightforward
Spherical Harmonics (SH) :각도 (\(\theta, \phi\))를 입력받아 구의 표면 위치에서의 값을 출력하는 함수SH coeff. 초기값 :
GaussianModel().create_from_pcd()
0-band SH (\(\theta, \phi\) 와 관계없는 view-independent color) 의 경우 SfM으로 얻은 point cloud의 RGB color값과 RGB2SH 이용하여 초기화
다른 band의 경우 0으로 초기화
smoothing 역할approx. 새로운 각도(view)를 rendering할 때 추가적인 MLP query 없이 SH func.으로부터 바로 color 정보 얻을 수 있음SH coeff.로 color 나타내는 법 :trainable parameter : SH coeff.인 \(k_{l}^{m}\)light source마다 SH coeff. \(k_{l}^{m}\) 다르므로 find optimal value)opacity \(\sigma\) 초기값 :
임의의 실수값으로 초기화
inverse_sigmoid(0.1 * torch.ones(…))
opacity \(\sigma\) range :
\(\sigma \in [0, 1)\) 위해
마지막에 sigmoid activation function을 씌워서 smooth gradient를 얻음
Tile Rasterizer
기능 : 3D Gaussians로 구성된 3D model을 특정 camera pose에 대해 2D rendering
input : Frustum Culling :Guard Band :view frustum의 near plane에 가까이 있는 Gaussian의 경우,nonlinearity가 심하기 때문에?????Create Tiles :CUDA 병렬 처리를 위해Parallelism :
tile마다 개별 CUDA thread block으로 실행하여
forward/backward processing, data loading/sharing을 병렬처리
(여러 threads가 Gaussian points를 shared memory에 collaboratively load)
(VRAM과 DRAM 사이의 이동은 overhead 발생하기 때문에 VRAM에서 모두 처리해버릴 수 있도록 CUDA Functions(.cu)를 직접 짬!)
Duplicate with Keys :
view-space-depth와 tile-ID를 이용하여 tile마다 각 Gaussian의 key를 생성CUDA 병렬처리 덕분에 2D Gaussian 하나가 3개의 tiles에 걸쳐 있다면, 3개의 2D Gaussians로 복제(instance화)되는 것처럼 작동Sort by Keys :처음에 한 번 sort 하고 나면 끝!! 추가로 per-pixel sorting 할 필요 없음splats가 각 pixel size 정도로 작기 때문에 해당 approx. 오차는 무시 가능! ??? from collections import deque
# 양방향에서 삽입/삭제 가능한 queue형 자료구조
# 1의 자릿수 기준으로 정렬한 뒤
# 10의 자릿수 기준으로 정렬한 뒤
# ...
def radixSort():
nums = list(map(int, input().split(' ')))
buckets = [deque() for _ in range(10)] # 각 자릿수(0~9)에 대응되는 10개의 empty deque()
max_val = max(nums)
queue = deque(nums) # 정렬할 숫자들
digit = 1 # 정렬 기준이 되는 자릿수
while (max_val >= digit): # 가장 큰 수의 자릿수일 때까지만 실행
while queue:
num = queue.popleft() # 정렬할 숫자
buckets[(num // digit) % 10].append(num) # 각 자릿수(0~9)에 따라 buckets에 num을 넣는다.
# 해당 정렬 기준 자릿수에서 buckets에 다 넣었으면, buckets에 담겨있는 순서대로 꺼내와서 정렬한다.
for bucket in buckets:
while bucket:
queue.append(bucket.popleft())
digit *= 10 # 정렬 기준이 되는 자릿수 증가시키기
print(list(queue))
Identify Tile Ranges : parallel하게 이루어짐Get Tile Ranges :
i-th tile에 대한 Gaussian list 범위 읽어옴
forward process) : 각 pixel에 대해color 및 opacity \(\alpha\) 값을 Gaussian list의 앞에서 뒤로 accumulateGaussian의 개수를 제한하지 않음으로써 scene-specific hyper-param. tuning 없이 arbitrary depth complexity를 가지는 scene을 커버 가능기존 기법들은 pixel마다 정렬이 필요해서 inefficient했지만Backward process : opacity 비율에 따라 뒤에서 앞으로 gradient update각 pixel에 대해pixel마다 global memory에 blended points list를 저장할 수도 있지만tile마다 구했던 range 및 sorted Gaussian list를 재사용 ????? Primitives :
본 논문의 Gaussians는 Euclidean space에 primitives를 남김 ?????
\(\rightarrow\)
primitives)를 미리 정렬(pre-sort)하여 primitives = Gaussians ?????Loss :
predicted image와 GT image를 비교하는
L1 loss 및 D-SSIM loss
D-SSIM : Directional Structural Similarity Index Measure
3D Gaussian의 xyz-mean에 대해서만 standard exponential decay scheduling 사용
low resol.부터 warm-up :stability 향상low band부터 warm-up :놓친 angular 영역이 있을 경우 SH의 0-band coeff. (base or diffuse color)가 부적절하게 만들어질 수 있어서optimization of 4 param.의 경우 매 iter.마다 update하지만,
Adaptive Density Control of Gaussians의 경우 100 iter.마다 update
Remove :Gaussians가 scene을 제대로 표현 못 하는 중
\(\rightarrow\) scene을 제대로 표현하기 위해선 Gaussian position을 크게 옮겨야 함
\(\rightarrow\) view-space positional gradient \(\Delta_{p} L\)가 큼
\(\rightarrow\) under/over-reconstruction 상황이므로 clone/split을 통해 정확한 위치에 Gaussian이 분포하도록 하자
Split :over-reconstruction의 경우 3D Gaussians split 2개로 분리하고 각 scale을 줄인 후 기존 3D Gaussian의 PDF에 따라 sampling하여 배치view-space positional gradient \(\Delta_{p} L\)의 avg. magnitude \(\geq\) threshold \(\tau_{pos}\)covariance가 큼Clone :under-reconstruction의 경우 3D Gaussians clone 같은 크기로 copy 후 positional gradient 방향에 배치view-space positional gradient \(\Delta_{p} L\)의 avg. magnitude \(\geq\) threshold \(\tau_{pos}\)covariance가 작음알파 값을 주기적으로 0으로 초기화 하면 전체 Gaussian 조절에 큰 도움이 됨! camera와 가까운 영역에서 많은 floater들이 생겨서 Gaussian density가 증가하는데, 이를 제거해주는 역할큰 Gaussian들이 중첩되어 있는 case를 제거해주는 역할custom CUDA kernel :
tile-based rasterization을 위해
custom CUDA kernel를 추가하여 사용 like
Radix Sort :
fast Radix Sort를 위해 NVIDIA CUB sorting routines
interactive image viewer :
open-source SIBR SIBR 이용해서
interactive image-rendering viewer 만듬 (frame rate 측정에 사용)
Quality : NeRF 계열 중 SOTA인 Mip-Nerf360 Speed : NeRF 계열 중 SOTA인 InstantNGP Plenoxels Space Carving :
- 설명 : 여러 camera에 대해 voxel-space에서 object 있는 부분만 남기고 깎아내는 기법
- 이유 : 3D reconstruction을 할 때 color 정보만으로 segmentation 가능할 정도로 background는 simple할수록 좋기 때문
- 한계 : 빛, 그림자 같은 정보는 사용하지 않기 때문에 fg/bg 판단만 가능하다. 따라서 lidar처럼 camera에 depth-detection 메커니즘이 없을 경우 물체 내부의 구멍 같은 건 reconstruct 불가능
Intialization (SfM) : background 퀄리티 저하floater 많이 발생Densification (clone, split) : background reconstruction에 중요한 역할thin structure reconstruction에 중요한 역할Unlimited depth complexity of splats with gradients : Anisotropic Covariance : align with surfaces 잘 하지 못해서 fine structure 잘 나타내지 못함Spherical Harmonics : view-dependent effect 담당training view가 부족한 영역에서는 여전히 floater, elongated(길쭉한) artifacts, splotchy(얼룩진) Gaussians 등 artifacts 발생 (Mip-NeRF360 등 prev. methods도 마찬가지)view-dependent appearance가 나타나는 영역에서는 large Gaussian 만들 때 guard band 등의 이유로 popping artifacts 발생depth-order 갑자기 바뀔 수 있음anti-aliasing으로 해결 가능large scene에 대해서는 position learning-rate를 줄이는 게 도움됨3D Gaussian :CUDA Implementation :real-time rasterization by GPU :Q1 :
tile-based rasterization과 parallelism의 관계를 간략히 설명해주세요
A1 :
tile(block)에 겹치는 2DGS들을 shared memory에 저장해서
(overlap 기준 : \(\Sigma^{\ast} = J W \Sigma W^T J^T\) 의 eigenvalue \(\times 3\))
그 tile 내에 있는 pixel(thread)들은 block shared memory(tile)에 있는 2DGS를 전부 쓰되
비교적 멀리 있는 2DGS라면 opacity의 \(e^{- \cdot}\) 항에 의해 그 pixel에는 덜 반영됨