高斯泼溅颜色计算
在这篇文章中,我们将经典的体渲染(Volume Rendering)数学模型转化为屏幕上的图像。数学公式初看可能有些令人生畏,但别担心,我们会一点点把它拆解。
在进入具体计算之前,我们需要明确当前所处的阶段:假设图像的“分块(Tiling)”已经完成。它将整个屏幕切分成若干个小块(通常是 16×16 像素),以便我们并行处理。
接下来,我们的终极目标是遍历这些 Tile(图像块),处理与每个 Tile 相交的高斯球,并计算出每个像素的最终颜色。
全局深度排序
渲染 3D 场景的第一直觉是什么?遮挡关系。离相机近的物体会遮挡远处的物体,因此我们必须对高斯球按照深度(
- # 6. 全局深度排序 (Global Depth Sorting)
- order = torch.argsort(z_cam_v, descending=False)
- u_sorted = u_v[order]
- v_sorted = v_v[order]
- colors_sorted = colors_v[order]
- opacity_sorted = opacity_v[order]
- sigma_camera_sorted = sigma_camera_v[order]
从体渲染到高斯分布
当我们进入单个 Tile 的处理循环时,核心任务是计算当前像素的颜色
传统的体渲染中,像素的最终颜色
这里的
而
基于神经点的方法通过混合重叠在该像素上的
在 3D Gaussian Splatting 中:
c_i 是每个高斯球的颜色(通过球谐函数计算得出)。\alpha_i 不再是传统体渲染的积分,而是通过计算具有协方差矩阵\Sigma 的 2D 高斯函数,并乘以学习到的“每点不透明度(per-point opacity)”得到的。
用公式直观理解就是:
在 2D 高斯的中心点,
透射率 T_i 的计算
它的物理意义非常直观:光线在穿透前面的高斯球后,还有多少能量能继续往下传?如果
- # 计算累积透射率 T_i = \prod_{j=1}^{i-1} (1 - \alpha_j)
- ti = torch.cumprod(1.0 - alpha, dim=0)
直接对
但是我们的数学公式中是连乘到
为了对齐数学公式,我们需要将 cumprod 的结果整体向后移动一位,并在最前面补上 1。
- # 错位偏置一位,首位补 1
- ti = torch.cat([
- torch.ones((1, alpha.shape[1]), device=alpha.device, dtype=alpha.dtype),
- ti[:-1]
- ], dim=0)
计算颜色与高阶广播机制
现在我们有了公式中的各个组件:
这个乘法是逐元素相乘,结果的形状依然是 [N, T*T]。最后一步是把权重
w 的形状是 [N, T*T]c_i 的形状是 [N, 3](N 个高斯球,RGB 3个通道)
这时候,PyTorch 的广播机制 (Broadcasting) 就成了我们的利器,我们需要通过添加虚拟维度 (unsqueeze) 让它们对齐。
最后,我们只需要将所有高斯球(沿着
- # 计算权重 w_i = alpha_i * T_i
- w = alpha * ti # (N, P)
- # 混合颜色:\sum_i w_i * c_i
- tile_colors = (w.unsqueeze(-1) * colors_tile.unsqueeze(1)).sum(dim=0) # (P, 3)