计算 G(x)

在 3D 高斯溅射的体积渲染过程中,计算每个高斯点在特定像素上的实际不透明度(即 \alpha_i)是渲染成败的关键。

简单来说,我们要实现的核心方程是:

\alpha_i = \text{opacity} \times G(x)

这里的 opacity 是每个高斯点自带的基础不透明度,而 G(x) 则是高斯函数在该像素位置上的衰减值。计算 G(x),我们需要先跨过一座名为 Q 值的数学大山。


计算协方差与距离:求出 Q

首先,我们来看看高斯函数中的指数部分 Q。它的标准矩阵形式是:

Q = x^T \Sigma^{-1} x

  • x:代表一个像素位置到高斯中心的距离(即偏移量)。我们可以用二维坐标表示为 x = [du, dv],其中 dudv 分别是像素坐标相对于高斯均值(mean)坐标的差值。
  • \Sigma^{-1}:这是二维高斯逆协方差矩阵。

由于 \Sigma^{-1} 只是一个 2 \times 2 的对称矩阵,我们可以直接将其元素提取为 a_{11}, a_{12}a_{22}(因为对称,a_{21} = a_{12})。

Q = a_{11} du^2 + 2 a_{12} du dv + a_{22} dv^2

直接在 PyTorch 中将公式写死,不仅数学结果完全一致,运算速度还会更快。

  1. # 计算 2D 高斯密度与透明度 alpha (Equation 2 核心物理公式实现)
  2. a11 = inv_cov_tile[:, 0, 0].unsqueeze(1)  # (N, 1)
  3. a12 = inv_cov_tile[:, 0, 1].unsqueeze(1)  # (N, 1)
  4. a22 = inv_cov_tile[:, 1, 1].unsqueeze(1)  # (N, 1)

在批处理时,不透明度张量 a 的形状是 N(代表 N 个高斯点)。但是距离矩阵 dudv 的形状是针对每个像素的,为 (N, T*T)。直接相乘会直接报错。必须通过增加维度来对齐。

  1. # 计算 Q 值(马氏距离的平方)
  2. Q = a11 * du**2 + 2.0 * a12 * du * dv + a22 * dv**2  # (N, P)

求出 G

有了 Q 之后,我们计算得到高斯衰减值 G

G = \exp(-0.5 Q)

  1. G = torch.exp(-0.5 * Q)  # (N, P)

99% 置信度裁剪

高斯函数是连续的,理论上一个高斯点对无限远的像素也有影响(尽管极其微弱)。如果对所有的影响都照单全收,计算量将不堪重负。因此,我们需要做一个截断(Clipping)。

我们算出的 Q 实际上代表的是马哈拉诺比斯距离(Mahalanobis distance)。在二维空间中,这个距离 Q 服从自由度为 2 的 \chi^2(卡方)分布。

如果希望保留 99% 的概率置信区间(即 99% 的高斯能量所在的椭圆范围内),查卡方分布表可知,对应的 Q 阈值刚好是 9.21。

  1. # 99% 置信区间裁剪:Q <= 9.21
  2. inside = Q <= 9.21
  3. G = torch.exp(-0.5 * Q)  # (N, P)
  4. G = torch.where(inside, G, 0.0)

torch.where(condition, x, y) 是条件过滤函数。它逐元素检查 condition:如果 insideTrue(距离在阈值内),就保留原来的 G 值。如果为 False(距离太远,影响微乎其微),就直接赋为 0