- 高斯泼溅简介
在辐射场渲染领域,高斯泼溅是一项相对较新但行之有效的方法。它凭借创新性的手段,能够以极高的效率和逼真度来描绘复杂的场景。
从本质上讲,高斯泼溅利用了高斯函数的数学原理,在"如何将三维空间点的信息投影并混合到二维图像平面"这一问题上实现了重大突破。这项技术在渲染充满复杂细节的场景时发挥着关键作用,能够实现前所未有的平滑度和视觉保真度。

这张图截取自高斯泼溅的原始论文,直观地展示了不同渲染方法在同一场景(一辆自行车)下的效果对比。
从左至右,我们依次可以看到 Instant-NGP 、Plenoxels 、Mip-NeRF360 以及两种变体的高斯泼溅方法(标记为"Ours")的渲染结果,并与真实参考图进行对照。
每种渲染方法都通过以下两个指标进行评估:
- 每秒帧数:用于衡量渲染速度。
- 峰值信噪比:用于衡量与真实参考图相比的图像质量。
此外,图中还列出了每种方法的训练时间,这充分展示了高斯泼溅的高效性------它能以显著减少的训练时间实现高质量的渲染结果。
高斯泼溅的起源可以追溯到 神经辐射场 的奠基性工作。这是一个具有范式转移意义的框架,彻底革新了我们从稀疏数据集中创建照片级真实感图像的能力。
神经辐射场利用深度学习,通过理解三维空间中光线和颜色的空间分布,来对复杂场景进行插值和渲染。高斯泼溅正是建立在这一框架之上,提供了一种不仅能与之互补,更能显著提升渲染过程的方法。
通过高效模拟光线与表面的相互作用,高斯泼溅使得生成的图像不仅具有视觉吸引力,而且在计算上也是可行的,即便是在那些极其复杂的场景中也是如此。

这张色彩鲜艳的泼溅图展示了一个三维空间中的高斯函数。它通过网格上的位置来定位,通过颜色来表示高斯函数的协方差(即扩散程度),并通过光影的相互作用来暗示其 Alpha 透明度。
高斯泼溅的精髓在于,它能够利用高斯函数,将颜色、密度等信息从三维点平滑地投影到二维平面上。这种平滑处理至关重要,它能消除渲染图像中常见的生硬边缘和伪影,从而确保视觉体验更加自然、连贯。
通过应用这项技术,研究人员实现了以往无法企及的细节水平和真实感,为虚拟现实、游戏开发和电影视觉特效等领域开启了全新的视野。

在这里,我们可以看到一簇泼溅点,每一个都遵循高斯分布原理,它们无缝融合,形成了一个连贯的整体结构。这张图展示了高斯泼溅的基本原理:独立的个体相互混合,使得彼此的边界难以分辨,最终融为一体。
此外,高斯泼溅的应用远不止于简单的图像增强。它代表了计算摄影和可视化领域的一大步,使得利用真实世界的数据重建场景成为可能,其精度和深度是过去无法企及的。
这不仅对娱乐和媒体行业影响深远,在建筑可视化、数字遗产保护甚至医学成像等领域也具有重要意义------在这些领域中,对复杂结构进行详细且逼真的呈现是至关重要的。

通过数百万个高斯泼溅点的集体渲染,一个复杂且有机的结构应运而生。这场色彩与形态的爆发,生动捕捉了大规模应用高斯泼溅的精髓,展示了无数简单的元素如何组合在一起,创造出错综复杂、细节丰富的视觉现象。
当我们深入探究高斯泼溅的机制与应用时,有必要向那些为该技术奠定基础的开创性研究和论文致敬。Mildenhall 等人撰写的关于神经辐射场的原始论文,向世界展示了深度学习在渲染领域的巨大潜力,从而为高斯泼溅等后续创新铺平了道路。随后,针对这项技术的进一步发展和探索从未止步,不断突破着可能性的边界。这也彰显了科学界在推动我们对计算机图形学的理解和能力提升方面所做出的共同努力。
- 高斯泼溅的数学基础
高斯泼溅基于将信息从三维点云投影到二维平面的原理。本节将阐明支配这一过程的关键数学结构。
2.1 泼溅中的高斯分布
高斯泼溅的核心是高斯分布函数,它在点的空间混合中起着关键作用。高斯分布的定义如下,它确保了在点的位置周围形成平滑的影响力梯度:

在这里, 𝑥代表距离点中心的距离, 𝜇是分布的均值或中心,而 𝜎则是决定分布扩散程度的标准差。

这张图表展示了经典的一维高斯分布"钟形曲线"。它凸显了该曲线围绕水平轴均值的对称特性,以及随着我们远离中心,数值呈现出的指数级衰减趋势。
2.2 三维高斯函数
将这一概念推广到三维空间,我们技术的核心便是一个三维高斯函数,其表示如下:

在这里, 𝑥是关注点(即均值),而𝛴是世界空间中的协方差矩阵,它定义了分布的扩散程度。

这里展示的是一个三维高斯函数,也被称为三维高斯钟形曲面。这种表现形式强调了分布沿所有轴线的平滑梯度和对称性,形成了一个类似山丘的表面,向平面方向平缓下降。
2.3 具有高斯影响的渲染方程
通过高斯泼溅进行图像渲染的过程,可以用一个积分公式来描述。该公式累积了每个点的颜色贡献,并根据它们的高斯影响以及场景中每个位置的透明度进行调制:

在这个方程中, I(x) 表示像素位置 𝑥处的强度, 𝐺是高斯分布, 𝑝𝑖是第𝑖个点的位置, 𝐿(p𝑖,w) 是来自 𝑝𝑖在方向 w上的辐射率,而𝑉(𝑝𝑖)则表示在𝑝𝑖处的可见性函数。
2.4 透明度与颜色混合
光线与材质属性的相互作用是通过颜色和透明度的混合来捕捉的。高斯泼溅通过叠加不同点的贡献并考虑它们各自的不透明度来实现这一点:

C(x) 是像素位置 𝑥处的最终颜色, 𝐶(𝑝𝑖)是第 𝑖个点的颜色贡献,而 𝜏(𝑝𝑖)表示 𝑝𝑖处的不透明度。分母确保加权颜色贡献的归一化,从而为渲染图像提供正确的强度和色调。
2.5 投影到 2D 空间
为了进行 2D 渲染,需要对这些 3D 高斯分布进行投影。这是通过将 3D 协方差矩阵𝛴变换到相机坐标系来实现的:

这里, 𝑊表示观察变换(viewing transformation),而 𝐽是投影变换仿射近似(affine approximation)的雅可比矩阵(Jacobian)。
2.6 椭球体配置
椭球体的配置提供了一种对𝛴的直观表示,其定义为:

其中 𝑆是缩放矩阵, 𝑅是旋转矩阵。
- 开启高斯泼溅技术实践之旅:基于 Python 搭建基础环境
接下来,我们将进入高斯泼溅的实践环节,从代码开始逐步实现。首先需要配置开发环境并导入必要的 Python 库,这是开展后续工作的基础。
所需工具库
我们将使用以下核心库:
先简单看看我们要用到的这些实用 Python 库:
import copyimport ipywidgetsimport jsonimport kaolinimport matplotlib.pyplot as pltimport numpy as npimport osimport torchimport torchvisionfrom utils.graphics_utils import focal2fovfrom utils.system_utils import searchForMaxIterationfrom gaussian_renderer import render, GaussianModelfrom scene.cameras import Camera as GSCamera
NumPy:用于数值计算
- matplotlib.pyplot:用于结果可视化
- torch:用于神经网络与张量计算
- Kaolin:用于 3D 深度学习相关操作
此外,还会用到若干专门用于高斯泼溅实现的工具库。
那列表最下方的那些特殊工具呢?它们是实现高斯泼溅 "法术" 的独门秘籍。后续我们会深入讲解这些工具的用法,不过现在你只需知道:在光追的复杂世界里,它们就像我们的地图和指南针一样关键。
为了方便调试与查看张量信息,我们定义一个辅助函数,用于输出张量的维度、数据类型等关键信息:
def log_tensor(t, name, **kwargs): print(kaolin.utils.testing.tensor_info(t, name=name, **kwargs))
该函数可以清晰展示张量信息,帮助开发者在开发过程中快速定位问题。环境准备完成后,即可开始高斯泼溅的核心实现。
4. 加载模型
好了,各位探索者!既然工具已经准备就绪,现在是时候拿出我们的魔法棒 ------** checkpoint** 了。我们预先训练好的模型就存放在这里,它满载着学到的知识,随时可以专业地完成高斯泼溅渲染。
def load_checkpoint(model_path, sh_degree=3, iteration=-1): # 定位并激活checkpoint的"魔法指令" checkpt_dir = os.path.join(model_path, "point_cloud") if iteration == -1: iteration = searchForMaxIteration(checkpt_dir) checkpt_path = os.path.join(checkpt_dir, f"iteration_{iteration}", "point_cloud.ply") # 将高斯体从"休眠状态"中唤醒 gaussians = GaussianModel(sh_degree) gaussians.load_ply(checkpt_path) return gaussians
这个函数会加载并激活我们的模型,使其准备好进行后续处理。如果你没有指定迭代轮次,它会自动查找最新的训练结果,确保我们使用的是最新的模型参数。
5. 相机设置
在任何渲染任务中,正确设置相机视角都是关键步骤。因此我们需要加载合适的相机参数,以正确渲染场景。
def try_load_camera(model_path): # 尝试查找相机配置文件 cam_path = os.path.join(model_path, 'cameras.json') if not os.path.exists(cam_path): print(f'未找到场景的相机配置文件,将使用默认参数。') # 默认相机参数 return GSCamera(...) with open(cam_path) as f: data = json.load(f) # 相机变换参数解析... return GSCamera(...)
6. 场景渲染
接下来,我们将 3D 模型渲染为 2D 图像。我们使用相机参数、高斯模型以及黑色背景来完成场景渲染。
# 执行渲染render_res = render(test_camera, gaussians, pipeline, background)rendering = render_res["render"]# 打印渲染结果中各张量的信息for k in render_res.keys(): log_tensor(render_res[k], k, print_stats=True)# 显示渲染结果plt.imshow((rendering.permute(1, 2, 0) * 255).to(torch.uint8).detach().cpu().numpy())

7. 相机转换方法
7.1 视场角计算
为确定数字场景的可视范围,我们首先实现视场角(FoV)的计算函数:
def compute_cam_fov(intrinsics, axis='x'): # 根据相机焦距计算视场角 aspectScale = intrinsics.width / 2.0 tanHalfAngle = aspectScale / (intrinsics.focal_x if axis == 'x' else intrinsics.focal_y).item() fov = np.arctan(tanHalfAngle) * 2 return fov
7.2 跨框架相机转换
以下函数实现 Kaolin 与 GS 框架间的相机参数转换:
def convert_kaolin_camera(kal_camera): # 将 Kaolin 相机转换为 GS 相机 R = kal_camera.extrinsics.R[0] R[1:3] = -R[1:3] # 反转指定轴 T = kal_camera.extrinsics.t.squeeze() T[1:3] = -T[1:3] # 反转指定轴 return GSCamera(colmap_id=0, R=R.transpose(1, 0).cpu().numpy(), T=T.cpu().numpy(), FoVx=compute_cam_fov(kal_camera.intrinsics, 'x'), FoVy=compute_cam_fov(kal_camera.intrinsics, 'y'), image=torch.zeros((3, kal_camera.height, kal_camera.width)), gt_alpha_mask=None, image_name='fake', uid=0)def convert_gs_camera(gs_camera): # 将 GS 相机转换为 Kaolin 相机 view_mat = gs_camera.world_view_transform.transpose(1, 0) view_mat[1:3] = -view_mat[1:3] # 反转指定轴 res = kaolin.render.camera.Camera.from_args( view_matrix=view_mat, width=gs_camera.image_width, height=gs_camera.image_height, fov=gs_camera.FoVx, device='cpu') return res
7.3 保证渲染结果一致性
最后,通过渲染验证相机转换后视角与原始视角的一致性:
# 渲染图像以测试相机转换效果kal_cam = convert_gs_camera(test_camera)test_cam_back = convert_kaolin_camera(kal_cam)rendering = render(test_cam_back, gaussians, pipeline, background)["render"]plt.imshow((rendering.permute(1, 2, 0) * 255).to(torch.uint8).detach().cpu().numpy())

8. 交互式视角交互实现
8.1 交互式渲染函数定义
场景配置与相机转换完成后,我们实现支持 Kaolin 相机的渲染函数,以实现视角灵活切换:
def render_kaolin(kaolin_cam): # 将Kaolin相机转换为GS相机 cam = convert_kaolin_camera(kaolin_cam) # 使用GS相机渲染场景 render_res = render(cam, gaussians, pipeline, background) # 预处理图像以适配可视化展示 rendering = render_res["render"] return (rendering.permute(1, 2, 0) * 255).to(torch.uint8).detach().cpu()
8.2 交互式探索环境搭建
将虚拟相机的焦点定位到场景指定位置,该位置将作为交互式视角的旋转中心:
# 确定相机聚焦的空间坐标点focus_at = (kal_cam.cam_pos() - 4. * kal_cam.extrinsics.cam_forward()).squeeze()# 基于Kaolin相机初始化交互式可视化工具visualizer = kaolin.visualize.IpyTurntableVisualizer( 512, 512, copy.deepcopy(kal_cam), render_kaolin, focus_at=focus_at, world_up_axis=2, max_fps=12)# 展示交互式场景visualizer.show()
完成上述配置后,即可通过鼠标拖拽或手指滑动操作探索 3D 场景。可实现场景旋转、缩放,直观查看渲染细节。
8.3 交互控制增强:精细化高斯泼溅筛选与查看
在基础交互功能之上,新增精细化交互控制能力,支持基于尺度筛选和查看高斯泼溅元素。
8.3.1 高斯尺度分析
首先分析高斯体的尺度参数,明确其对渲染结果的影响:
# 分析高斯体的尺度参数log_tensor(gaussians.get_scaling, '激活后的尺度参数', print_stats=True)log_tensor(gaussians._scaling, '原始尺度参数', print_stats=True)
8.3.2 选择性渲染函数实现
实现基于尺度筛选的选择性渲染函数,通过滑动条控件控制高斯体的筛选阈值:
def selective_render_kaolin(kaolin_cam): # 根据滑动条值筛选指定尺度范围内的高斯体 scaling = gaussians._scaling.max(dim=1)[0] mask = scaling < slider.value # 创建包含筛选后高斯体的临时模型 tmp_gaussians = GaussianModel(gaussians.max_sh_degree) # 将筛选掩码应用到所有高斯体参数 tmp_gaussians._xyz = gaussians._xyz[mask, :] tmp_gaussians._features_dc = gaussians._features_dc[mask, ...] tmp_gaussians._features_rest = gaussians._features_rest[mask, ...] tmp_gaussians._opacity = gaussians._opacity[mask, ...] tmp_gaussians._scaling = gaussians._scaling[mask, ...] tmp_gaussians._rotation = gaussians._rotation[mask, ...] tmp_gaussians.active_sh_degree = gaussians.max_sh_degree # 使用筛选后的高斯体渲染场景 cam = convert_kaolin_camera(kaolin_cam) render_res = render(cam, tmp_gaussians, pipeline, background) rendering = render_res["render"] return (rendering.permute(1, 2, 0) * 255).to(torch.uint8).detach().cpu()
8.3.3 滑动条控件实现
以下代码创建滑动条控件,支持动态调整高斯体筛选阈值,并实时重新渲染场景:
def handle_slider(e): # 清空当前输出并更新渲染结果 visualizer.out.clear_output() with visualizer.out: visualizer.render_update()# 控制高斯体尺度阈值的滑动条scaling = gaussians._scaling.max(dim=1)[0]slider = ipywidgets.FloatSlider(value=scaling.max().item(), min=scaling.min().item(), max=scaling.max().item(), step=0.1, description='最大尺度:', disabled=False, continuous_update=True, orientation='horizontal', readout=True, readout_format='.3f',)slider.observe(handle_slider, names='value')
8.3.4 可视化工具与滑动条集成
最终将选择性渲染函数与滑动条控件集成到交互式可视化工具中:
# 基于选择性渲染函数初始化可视化工具visualizer = kaolin.visualize.IpyTurntableVisualizer( 512, 512, copy.deepcopy(kal_cam), selective_render_kaolin, focus_at=focus_at, world_up_axis=2, max_fps=12)# 更新渲染结果以应用滑动条初始筛选阈值visualizer.render_update()# 展示可视化界面与滑动条控件,支持交互式控制display(visualizer.canvas, visualizer.out, slider)
集成滑动条后,可通过调整阈值筛选场景中的高斯体,直观查看不同尺度高斯体对渲染效果的影响,实现精细化的场景分析。