3D Gaussian Splatting学习笔记

相关文档

3DGS

NeRF 和 3DGS 的区别

什么是 Splatting

定义

  • 一种体渲染的方法:从 3D 物体渲染到 2D 平面
  • Ray-casting 是被动的(NeRF)
    • 计算出每个像素点受到发光粒子的影响来生成图像
  • Splatting 是主动的
    • 计算出每个发光粒子如何影响像素点

为什么选择 3D 高斯椭球

  • 很好的数学性质
    • 仿射变换后高斯核仍然闭合
    • 3D 降维到 2D 后(沿着某一个轴积分(z 轴))仍然为高斯
  • 定义:
    • 椭球高斯函数:

G(x)=12πkΣe12(xμ)TΣ1(xμ)G(x) = \frac{1}{\sqrt{2\pi^k|\Sigma|}}e^{-\frac{1}{2}(x-\mu)^T\Sigma^{-1}(x-\mu)}

  • 其中Σ\Sigma表示协方差矩阵,半正定,Σ|\Sigma|是其行列式,μ\mu表示均量

3D gaussian 为什么是椭球?

  • 对于椭球高斯函数:G(x)=12πkΣe12(xμ)TΣ1(xμ)G(x) = \frac{1}{\sqrt{2\pi^k|\Sigma|}}e^{-\frac{1}{2}(x-\mu)^T\Sigma^{-1}(x-\mu)}来说,2πkΣ{\sqrt{2\pi^k|\Sigma|}}始终是一个常数,变量只存在于12(xμ)TΣ1(xμ){-\frac{1}{2}(x-\mu)^T\Sigma^{-1}(x-\mu)}中,当(xμ)TΣ1(xμ)=constant{(x-\mu)^T\Sigma^{-1}(x-\mu)}=constant时,其可以展开为

constant=(xμ)TΣ1(xμ)=(xμx)2σx2+(yμy)2σy2+(zμz)2σz22σxy(xμx)(yμy)σxσy2σxz(xμx)(zμz)σxσz2σyz(yμy)(zμz)σyσzequalto:Ax2+By2+Cz2+2Dxy+2Exz+2Fyz=1\begin{align} constant &= (x-\mu)^T\Sigma^{-1}(x-\mu) \\ &= \frac{(x-\mu_x)^2}{\sigma_x^2} + \frac{(y-\mu_y)^2}{\sigma_y^2} + \frac{(z-\mu_z)^2}{\sigma_z^2} - \frac{2\sigma_{xy}(x-\mu_x)(y-\mu_y)}{\sigma_x\sigma_y}-\frac{2\sigma_{xz}(x-\mu_x)(z-\mu_z)}{\sigma_x\sigma_z}-\frac{2\sigma_{yz}(y-\mu_y)(z-\mu_z)}{\sigma_y\sigma_z} \end{align} \\ equal \quad to: Ax^2+By^2+Cz^2+2Dxy+2Exz+2Fyz=1

其中,

Σ=(σx2σxyσxzσxyσy2σyzσxzσyzσz2)\Sigma = \begin{pmatrix} \sigma_x^2 & \sigma_{xy} & \sigma_{xz} \\ \sigma_{xy} & \sigma_y^2 & \sigma_{yz} \\ \sigma_{xz} & \sigma_{yz} & \sigma_z^2 \end{pmatrix}

最终就是一个椭圆面的表示形式。而(xμ)TΣ1(xμ){(x-\mu)^T\Sigma^{-1}(x-\mu)}是有取值范围的,所以整体表现出来就是一个实心的椭球体

如何利用旋转和缩放计算协方差矩阵

对应于 cuda 代码中的 computeConv3D

  • 高斯分布:
    • xN(μ,Σ)\boldsymbol{x}\sim N(\mu, \Sigma)
    • 均值:μx,μy,μz\mu_x, \mu_y, \mu_z
    • 协方差矩阵:Σ=(σx2σxyσxzσyxσy2σyzσzxσzyσz2)\Sigma = \begin{pmatrix} \sigma*x^2 & \sigma*{xy} & \sigma*{xz} \\ \sigma*{yx} & \sigma*y^2 & \sigma*{yz} \\ \sigma*{zx} & \sigma*{zy} & \sigma_z^2 \end{pmatrix}
  • 高斯分布的仿射变换:
    • w=Ax+b\boldsymbol{w} = A\boldsymbol{x}+b
    • wN(Aμ+b,AΣAT)\boldsymbol{w} \sim N(A\mu+b, A\Sigma A^T)
    • 协方差和 b 没有关系
  • 标准高斯分布:
    • xN(0,I)\boldsymbol{x} \sim N(\bold{0}, I)

    • 均值:0\bold{0}

    • 协方差矩阵:Σ=(100010001)\boldsymbol{\Sigma} = \begin{pmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{pmatrix}

    • Σ=AIAT\boldsymbol{\Sigma} = \boldsymbol{A} \cdot \boldsymbol{I} \cdot \boldsymbol{A}^T 任意高斯可以看作是标准高斯通过仿射变换得到

  • A=RS\boldsymbol{A}=RS,其中R\boldsymbol{R}是旋转矩阵,S\boldsymbol{S}是缩放矩阵,因此

Σ=AIAT=RSSTRT\begin{align} \boldsymbol{\Sigma} &= \boldsymbol{A} \cdot \boldsymbol{I} \cdot \boldsymbol{A}^T\\ &=\boldsymbol{R}\boldsymbol{S}\boldsymbol{S}^T\boldsymbol{R}^T \end{align}

Splatting 过程介绍——从 3D 到像素

变换矩阵介绍

观测变换

  • 从世界坐标系到相机坐标系,仿射变换
  • w=Ax+b\boldsymbol{w} = \boldsymbol{A}\boldsymbol{x}+\boldsymbol{b}

投影变换

  • 3D 到 2D
  • 透视投影,和 Z 轴有关
  • 正交投影,和 Z 轴无关

正交投影

  • 对于一个立方体[l,r]×[b,t]×[f,n][l, r]\times[b, t]\times[f, n],将其平移到原点,然后缩放为[1,1]×[1,1]×[1,1][-1, 1]\times[-1, 1]\times[-1, 1]的正方体
  • 投影矩阵:

[2/(rl)00002/(tb)00002/(nf)00001][100(r+l)/2010(t+b)/2001(n+f)/20001]\begin{bmatrix} 2/(r-l) & 0 & 0 & 0 \\ 0 & 2/(t-b) & 0 & 0 \\ 0 & 0 & 2/(n-f) & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & -(r+l)/2 \\ 0 & 1 & 0 & -(t+b)/2 \\ 0 & 0 & 1 & -(n+f)/2 \\ 0 & 0 & 0 & 1 \end{bmatrix}

透视投影

  • 有远小近大的原则,投影出来是一个锥体。因此需要先把锥体压成立方体,然后再进行正交投影

  • 透视投影到立体的过程:

Mpersp>ortho=[n0000n0000n+fnf0010]\boldsymbol{M}_{persp->ortho} = \begin{bmatrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ 0 & 0 & n+f & -nf \\ 0 & 0 & -1 & 0 \end{bmatrix}

  • 注意:透视投影是非线性的,不是仿射变换

视口变换

  • 不管是透视投影还是正交投影,最终得到的都是[1,1]3[-1, 1]^3范围内的立方体,然后进行视口变换将其映射回图片的大小 height * width,恢复出原始比例

Mviewpoint=[w200w20h20h200100001]\boldsymbol{M}_{viewpoint} = \begin{bmatrix} \frac{w}{2} & 0 & 0 & \frac{w}{2} \\ 0 & \frac{h}{2} & 0 & \frac{h}{2} \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}

3D 高斯的观测变换过程,如何把物理坐标系的物体映射到像素空间

对应代码中的 computeCov2D

第一步:从物理坐标系到相机坐标系

  • 物理坐标系:
    • 高斯核的中心点:tk=[tx,ty,tz]T\boldsymbol{t}_k = [t_x, t_y, t_z]^T
    • 高斯核对应的高斯分布:rk,,(t)=GVk,,(ttk)r^{, , }_k(t) = G_{V_k^{, , }}(t-t_k)
    • 其中Vk,,V_k^{, , }是协方差矩阵
  • 相机坐标系:
    • 高斯核中心:μk=[μx,μy,μz]T\boldsymbol{\mu}_k = [\mu_x, \mu_y, \mu_z]^T
    • 高斯核对应的高斯分布:rk,(t)=GVk,(μμk)r^{, }_k(t) = G_{V_k^{, }}(\mu-\boldsymbol{\mu}_k)
    • 均值:μk=Wtk+d\boldsymbol{\mu}_k = Wt_k+d
    • 协方差矩阵:Vk,=WVk,,WTV_k^{, } = WV_k^{, , }W^T
  • 这一步就是简单做个仿射变换,3D 空间的坐标变换

第二步:从相机坐标系到像素空间

  • 相机坐标系:
    • 高斯核中心:μk=[μx,μy,μz]T\boldsymbol{\mu}_k = [\mu_x, \mu_y, \mu_z]^T
    • 协方差矩阵:$V_k^{, }
  • 投影变换:(非线性的变换,需要做泰勒展开做局部的线性近似)
    • 高斯核中心:xk=[xx,xy,xz]T\boldsymbol{x}_k = [x_x, x_y, x_z]^T
    • 高斯核对应的高斯分布:rk(t)=GVk(xxk)r_k(t) = G_{V_k}(x-\boldsymbol{x}_k)
    • 均值:xk=m(μk)\boldsymbol{x}_k = m(\mu_k)(对均值可以直接做非线性变换,不需要局部线性近似)
    • 协方差矩阵:Vk=JVk,JTV_k = \boldsymbol{J}V_k^{, }\boldsymbol{J}^T
    • 其中J=m(μk)μ\boldsymbol{J} = \frac{\partial m(\mu_k)}{\partial \mu},雅可比矩阵
    • 至此,协方差矩阵Vk=JWVk,,WTJTV_k = \boldsymbol{J}WV_k^{, , }W^T\boldsymbol{J}^T

如何求得雅可比矩阵?

  • 已知:

Mpersp>ortho=[n0000n0000n+fnf0010]\boldsymbol{M}_{persp->ortho} = \begin{bmatrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ 0 & 0 & n+f & -nf \\ 0 & 0 & -1 & 0 \end{bmatrix}

  • 视锥中一个点:[xyz1]T[x y z 1]^T对其应用投影变换后:

[x1x2x31]=[n0000n0000n+fnf0010][xyz1]=[nxny(n+f)znfz]=[nxznyz(n+f)nfz1]\begin{bmatrix} x_1 \\ x_2 \\ x_3 \\ 1 \end{bmatrix} = \begin{bmatrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ 0 & 0 & n+f & -nf \\ 0 & 0 & -1 & 0 \end{bmatrix} \begin{bmatrix} x \\ y \\ z \\ 1 \end{bmatrix} = \begin{bmatrix} nx \\ ny \\ (n+f)z-nf \\ z \end{bmatrix} = \begin{bmatrix} \frac{nx}{z} \\ \frac{ny}{z} \\ (n+f)-\frac{nf}{z} \\ 1 \end{bmatrix}

  • 由此,雅可比矩阵为:

J=[df1dxdf1dydf1dzdf2dxdf2dydf2dzdf3dxdf3dydf3dz]=[nz0nxz20nznyz200nfz2]\boldsymbol{J} = \begin{bmatrix} \frac{df_1}{dx} & \frac{df_1}{dy} & \frac{df_1}{dz} \\ \frac{df_2}{dx} & \frac{df_2}{dy} & \frac{df_2}{dz} \\ \frac{df_3}{dx} & \frac{df_3}{dy} & \frac{df_3}{dz} \\ \end{bmatrix} = \begin{bmatrix} \frac{n}{z} & 0 & -\frac{nx}{z^2} \\ 0 & \frac{n}{z} & -\frac{ny}{z^2} \\ 0 & 0 & -\frac{nf}{z^2} \\ \end{bmatrix}

3D 高斯球的颜色表示

这里是把高斯椭球的颜色表示成了一个颜色球,这个颜色球从不同角度观察,都可以看到不同的颜色。但是颜色球的颜色应该怎么描述呢?这里就是使用球谐函数来对其做近似,然后从不同角度对其做渲染

球谐函数介绍

  • 任何一个球面坐标的函数,都可以用多个球谐函数来近似
  • f(t)lm=llclmylm(θ,ϕ)f(t) \approx \sum_l\sum^l_{m=-l}c_l^my_l^m(\theta, \phi)
  • 其中,ll表示当前的阶数,clmc_l^m是各项系数,ylmy_l^m是基函数

f(t)lm=llclmylm(θ,ϕ)=c00y00+c11y11+c10y10+c11y11+c22y22+c21y21+c20y20+c21y21+c22y22+...\begin{align} f(t) &\approx \sum_l\sum^l_{m=-l}c_l^my_l^m(\theta, \phi) \\ = &c_0^0y_0^0 + \\ &c_1^{-1}y_1^{-1} + c_1^{0}y_1^{0} + c_1^{1}y_1^{1}+ \\ &c_2^{-2}y_2^{-2} + c_2^{-1}y_2^{-1} + c_2^{0}y_2^{0} + c_2^{1}y_2^{1} + c_2^{2}y_2^{2} +\\ &... \end{align}

  • 其中各个基函数为:

y00=14πy11=34πyry10=34πzr...y_0^0 = \sqrt{\frac{1}{4\pi}} \\ y_1^{-1} = \sqrt{\frac{3}{4\pi}}\frac{y}{r}\\ y_1^{0} = \sqrt{\frac{3}{4\pi}}\frac{z}{r}\\ ... \\

  • 由此,当 xyz 固定时,基函数就是固定的,但是系数是变化的。当系数维度为 3 时,共有 16 个系数,即一个高斯球,有 16 个颜色系数要估计

使用α\alpha -blending 计算像素的颜色

与 NERF 中公式相同

C=Tiαici=i=1NTi(1eσiδici)where:Ti=rj=1i1σiδj\begin{align} C &= T_i \alpha_i c_i \\ &= \sum_{i=1}^N T_i(1-e^{-\sigma_i\delta_i}c_i) \end{align} \\ where: T_i = r^{-\sum_{j=1}^{i-1}\sigma_i\delta_j}

  • 其中:
    • TiT_i:在 s 点之前,光线没有被阻挡的概率
    • αi\alpha_i:在 s 点处,光线被遮挡的概率。包含两点:1. 高斯椭球本身的不透明度;2. 该像素点距离高斯椭球中心越远,高斯椭球对其影响越小
    • cic_i:在 s 点处,高斯球的颜色。即通过球谐函数近似得到的颜色

注意,此时是在 2D 平面上计算像素值

  • 当一轮迭代之后,参数都固定了,此时就可以计算像素的颜色值。3D 高斯在投影到 2D 平面上后,还是一个高斯分布。利用之前的理论,当(xμ)TΣ1(xμ)=constant{(x-\mu)^T\Sigma^{-1}(x-\mu)}=constant时,在二维上表现为一个椭圆:(xμ1)2σ12+(yμ2)2σ222σxy(xμ1)(yμ2)σ1σ2=constant\frac{(x-\mu_1)^2}{\sigma_1^2} + \frac{(y-\mu_2)^2}{\sigma_2^2} - \frac{2\sigma_{xy}(x-\mu_1)(y-\mu_2)}{\sigma_1\sigma_2} = constant。此时μ1\mu_1μ2\mu_2为高斯中心点在像素平面上的坐标,σ1\sigma_1σ2\sigma_2为二维高斯协方差矩阵对角线上的元素。

高斯椭球的自适应密度控制

  • 这里使用 α 值来调控高斯函数的数量,以防止在优化过程中创建过多的高斯函数。α 值的调整基于一个预定义的阈值,当高斯函数的数量超过这个阈值时,就会使用剔除机制来移除那些贡献较小的高斯函数。(这里可以仔细在源码里找找)
  • 此外,为了处理小规模几何结构的不足重建问题,采用了复制(在重建不足的区域)和分裂(在过度重建的区域)高斯函数的策略。这些操作使得优化过程能够更精细地调整高斯函数的分布,以更精确地匹配场景的几何结构。具体地,这个过程包括以下步骤:
    • 在重建不足的区域,如果小尺度的几何特征没有被足够覆盖,算法会克隆现有的高斯函数,即复制一个相同的高斯函数以增加局部密度,从而更好地捕捉细微的细节。
    • 对于过度重建的区域,如果小尺度的几何被一个大的高斯函数所覆盖,算法会将其分裂为两个较小的高斯函数,这样可以减少单一高斯函数覆盖过多细节的情况,避免模糊和不必要的重叠。
  • 这种自适应的密度控制策略不仅可以增加细节的丰富性,也有助于避免过多的高斯函数对计算资源的消耗。α 值的动态调整和高斯函数的合理分布,使得模型在不同的迭代中逐渐收敛,最终得到一个既紧凑又精确的 3D 场景表示。
  • 优化过程中,通过增加 α 值来提高某些高斯函数的重要性,同时允许采用剔除方法来移除那些低于预设 α 阈值的高斯函数。尽管高斯函数可能会随着优化过程中的调整而增大或缩小,并与其他高斯函数产生重叠,但作者定期进行重建和调整,以确保在视觉空间中保留有重要贡献的高斯函数,同时优化整体的几何表现。
  • 通过这种方法,3D Gaussians 作为欧几里得空间中的基元,在所有时间内都保持一致,与其他方法(如基于投影或扭曲的策略处理大型高斯函数的方法)相比,这种方法避免了复杂的变换,使得渲染过程更加直接和高效。

代码解析

diff-gaussian-rasterization 解析

预处理

  • 批量并行处理高斯点,为光栅化做准备
1
2
3
4
5
6
7
8
9
10
11
12
// 共划分了P/256个线程块,每个线程块包含256个线程
// 创建的是一维线程块,每个高斯核对应一个线程
preprocessCUDA<NUM_CHANNELS> << <(P + 255) / 256, 256 >> > (

P, D, M,
means3D,
scales,
rotations,
opacities,
...
);

  • 每个线程中执行了以下步骤:

剔除视锥外的点

1
2
3
4
5
6
__global__ void preprocessCUDA(int P, int D, int M,
const float* orig_points,
const glm::vec3* scales,
...) {

}

计算高斯核对应的 tile

其他

名词解释:

  • EWA:
  • NDC 坐标系:Normalized Device Coordinates,标准化设备坐标系
  • footprint(足迹):椭球投影到 2D 平面上的扩散
  • NVS: novel view synthesis,新视角合成

常见疑问

  1. 为什么 3d 高斯降维到 2d?
    • 因为 splatting 算法就是要把 3d 的 voxel 投射到像素屏幕然后做叠加
  2. 怎么降到 2d?
    • 沿着 z 做积分
  3. 为什么选择高斯?
    • 因为高斯变成 2d 还是高斯,协方差矩阵直接拿掉 3 行 3 列即可(这个相当重要,直接省略了积分了!!!!)
  4. 为什么协方差矩阵不用做平移缩放?
    • 感觉应该是 splatting 在投影矩阵之后的那个空间里做,点要做视口变换是为了和后面的像素匹配,做后面的 tile 渲染

参考文档


3D Gaussian Splatting学习笔记
https://fansaorz.github.io/2024/04/13/3D-Gaussian-Splatting详解/
作者
Jiashi Zhang
发布于
2024年4月13日
许可协议