开始 3D 高斯渲染

相比于之前的点云光栅化,3DGS 有些不一样。我们的基本单位不再是没有体积的“点”,而是带有范围和透明度的“高斯球”。

在之前的点云渲染中,我们主要依赖两个参数:位置(Position)和颜色(Color)。

但在 3DGS 中,除了相机坐标系下的坐标 x, y, z 外,我们还需要引入几个全新的参数:

  • Color (颜色)
  • Opacity (透明度):控制这个高斯球是实心的还是半透明的。
  • Sigma (\Sigma, 协方差矩阵):决定了高斯球的形状和大小。

代码实现

我们要实现函数 gaussian_rasterization

  1. def gaussian_rasterization(pos, colors, opacity_raw, height, width, fx, fy, cx, cy, camera2world, near=2e-3, far=100, pixelGuard=64)

第一步,我们需要将三维空间中的高斯球投影到二维屏幕上,得到它们的 UV 坐标。

  1. # 1. 投影 3D 点到 2D 屏幕坐标
  2. uv, x_cam, y_cam, z_cam = project_points(pos, height, width, fx, fy, cx, cy, camera2world)
  3. u = uv[:, 0]
  4. v = uv[:, 1]

接着我们引入视锥剔除。在计算机图形学中,渲染那些根本不在屏幕视野内的物体是极度浪费算力的。如果我们用 3DGS 建模了一栋巨大的豪宅,当前可能只看到了 10% 的区域。直接丢弃剩下 90% 不在屏幕内的点,这就是我们提升渲染性能的法宝。

对于普通的点云,如果一个点越过了屏幕边界,我们可以直接忽略它。但是,高斯球是有体积的。即使高斯球的中心点(均值)在图像边界之外,它庞大的“身躯”(方差范围)依然可能会覆盖到屏幕边缘的像素,对画面产生贡献。

为了解决这个问题,我们引入了一个非常关键的超参数 pixelGuard

我们默认设定 pixelGuard = 64。这意味着我们在图像的四周额外拉起了一道 64 像素的缓冲区。只要高斯的中心落在这个带状区域内,我们就保留它。

  1. # 2. 软边缘视锥剔除 (pixelGuard): 在图像边缘扩展 pixelGuard 像素的保护带
  2. mask = (u > -pixelGuard) & (u < width + pixelGuard) & \
  3.        (v > -pixelGuard) & (v < height + pixelGuard) & \
  4.        (z_cam > near) & (z_cam < far)
  5.  
  6. # 3. 过滤出有效的高斯点
  7. u_v = u[mask]
  8. v_v = v[mask]
  9. colors_v = colors[mask]
  10. opacity_raw_v = opacity_raw[mask]

现在,我们拿到了在屏幕范围内的高斯球的原始透明度 opacity_raw_v

在深度学习和梯度下降优化中,参数 opacity_raw 的取值范围是负无穷到正无穷 (-\infty, +\infty)。但在物理世界和渲染逻辑中,透明度必须严格限制在 01 之间(0 代表完全透明,1 代表完全不透明)。

我们需要对其进行重参数化(Reparameterization)。

  1. # 4. 透明度重参数化 (Sigmoid & Clamp 到 0.999 避免梯度消失)
  2. opacity_v = torch.sigmoid(opacity_raw_v)
  3. opacity_v = torch.clamp(opacity_v, min=0.0, max=0.999)