3DGS笔记

3dgs

Published on

在 3DGS 出现之前,隐式神经辐射场(NeRF)能够渲染出极其逼真的画面,但因为需要沿光线进行密集的体积采样(Volumetric ray-marching),渲染速度非常慢(通常只能按秒甚至分钟计算一帧).而传统的点云渲染虽然快,但容易出现破洞,走样,且缺乏连续性.

3DGS 结合了这两者的优点:它用连续的数学表达式保证了极高的图像质量,同时又采用了显式的,对 GPU 极其友好的数据结构,实现了真正的高清实时渲染(30\ge 30 fps,甚至超过 100 fps).

方法

表示法

在 EWA Volume Splatting 中,每个高斯核的位置和协方差矩阵是固定的死数据.但在 3DGS 中,它们变成了神经网络优化器里的 可学习参数 (Learnable Parameters).

这里有一个非常硬核的数学坑,也是 3DGS 论文在系统设计上的亮点:如果在代码里直接用梯度下降去硬更一个 3×33 \times 3 的协方差矩阵 Σ\Sigma,优化器极容易把它更成一个非正定矩阵.在概率论中,协方差矩阵一旦非正定,这个高斯椭球在物理上就崩溃了(变成了复数或负体积).

3DGS 放弃了直接优化 Σ\Sigma,而是把 Σ\Sigma 强行拆解成了两个独立的数据结构:一个 3D 缩放向量 ss (Scale) 和一个四元数 qq (Rotation/Quaternion).根据线性代数公式 Σ=RSSTRT\Sigma = R S S^T R^T,每次前向传播时临时把它们组装成协方差矩阵.这样,无论梯度下降怎么瞎更新 ssqq,算出来的 Σ\Sigma 永远是合法的正定矩阵!

密度控制

EWA 处理的医学 CT 数据是固定大小的体素网格.但在 3DGS 中,我们只有从运动恢复结构(SfM)算法中白嫖来的极少数稀疏特征点作为初始值.

随着梯度下降的进行,如果某个高斯核在屏幕上的位置梯度很大(说明它拼命想移动去填补某个缺失的画面细节,这叫”欠重建”),系统就会在代码层面直接 Clone 它,让它一分为二,去填补空缺.如果一个高斯核变得非常庞大,遮蔽了太多本该有精细纹理的地方(“过度重建”),系统就会把它 Split 成两个小一圈的高斯体.

光栅化

EWA 的原版代码是相对低效的,它需要为每个 Splat 计算包围盒,然后在屏幕上一个像素一个像素地累加.3DGS 面对的是现代 GPU(CUDA 架构),并且它不仅要正向渲染,还要能够把误差梯度反向传播给几百万个高斯核.如果用传统方法,显存会瞬间爆炸.

  • 图块化 (Tile-based):将屏幕切成 16×1616 \times 16 的小块.
  • 极速排序 (Radix Sort):不给像素排序,而是用 GPU 底层的基数排序算法,给所有跨越该图块的高斯核按深度 ZZ 进行极速排序.
  • 无锁并行 (Lock-free blending):每个图块分配一个 CUDA 线程块 (Thread Block).线程把排序好的高斯数据加载到极速的共享内存 (Shared Memory) 中,然后顺着视线从前向后做 Alpha 混合.一旦 α\alpha 累加到 1(说明这块区域的光已经被前面的高斯核挡死了),后面的高斯核直接扔掉不作计算(Early Stop).
  • 反向传播的内存魔术:为了求导,它不需要把每一步的中间状态存在显存里.正向算完后,反向传播只需按从后往前的顺序再遍历一次,利用数学恒等式就能算出每个高斯核的梯度,打破了以往方法对梯度计算数量的硬性限制.

3dgs怎么工作的?

输入

3dgs有三个输入

  1. 一堆照片:比如 50 张照片.这些是真实的监督信号(Ground Truth).
  2. 相机的位姿:系统需要知道每一张照片是在 3D 空间的哪个位置,朝哪个方向拍的.
  3. 稀疏点云:这是用来初始化高斯核的种子.

通常,把这 50 张照片扔进一个叫 COLMAP 的开源软件(这是一个标准的运动恢复结构 SfM 算法).COLMAP 跑完之后,会直接吐出需要的每张照片的精确相机位姿,以及一个附带生成的稀疏点云.

系统把 COLMAP 吐出来的稀疏点云加载进来.假设点云有 1 万个点,系统就在这 1 万个位置上,生成 1 万个初始的 3D 高斯核.每个高斯核有一个小小的初始体积和半透明度.

训练

3dgs不训练模型,而是优化参数.

可以把模型看作是一个巨大的 Excel 表格:

  • 每一行代表一个高斯核.
  • 每一列是它的参数:位置 (x,y,z)(x, y, z),缩放比例 (sx,sy,sz)(s_x, s_y, s_z),旋转四元数 (qr,qi,qj,qk)(q_r, q_i, q_j, q_k),不透明度 α\alpha,以及决定颜色的球谐函数系数.

训练循环 (Training Loop) 也就是前向传播和反向传播的交替:

  1. 抽取机位(前向传播):系统随机从那 50 个已知的相机位姿中挑出一个(比如第 10 张照片的机位).
  2. 渲染假照片:系统把当前的 3D 高斯核,通过 EWA 里的透视投影公式和那套极速的图块化光栅化算法,在这个机位上”画”出一张图.
  3. 计算误差:把刚画出来的”假照片”和那张真实的第 10 张照片进行逐像素的对比,算出一个误差值(通常是 L1L1 Loss 加上 D-SSIM 结构相似度度量).
  4. 反向传播:这是核心!计算误差对每一个高斯核参数的偏导数(梯度).这告诉系统:”如果我把这高斯核往左移一点,或者变得更红一点,误差会不会变小?”
  5. 更新参数:根据算出的梯度,微调每一个高斯核的参数.
  6. 自适应密度控制 (每 100 步触发一次):检查哪些高斯核的位置梯度太大(需要分裂/克隆),哪些高斯核太透明了(需要删除),动态改变表格的行数(高斯核的总数).

输出

输出的通常是一个 .ply 格式的文件,里面密密麻麻记录了几百万个高斯体的最终位置,最终缩放,最终旋转,最终透明度和最终颜色.

渲染

  • 设定任意机位:通过鼠标或键盘,在软件(比如一个基于 OpenGL 或 WebGL 的查看器)里随意设定一个虚拟摄像机的位置和朝向.
  • 运行光栅化:查看器读取那份 .ply 参数表,再次调用 3DGS 极速的图块化栅格化算法.
    • 把高斯核投影到当前屏幕.
    • 按 16x16 的图块进行极速排序(Radix Sort).
    • 在每个像素上,顺着视线把高斯核的颜色按 Alpha 混合累加起来(早期停止).
  • 输出帧:屏幕上立刻显示出当前视角的画面.