刚接触三维重建和神经渲染的同学,一定对“高斯飞溅”(3D Gaussian Splatting,简称 3DGS)这个词不陌生。它在 2023 年 SIGGRAPH 上一经公开,就凭借“高清晰度、实时渲染、训练速度快”三个特点走红,被大量用在场景重建、数字人、自动驾驶仿真、VR/AR 展示等方向。本文我会从零开始,先讲清楚高斯飞溅的核心思路,再带你跑通一个完整的场景重建流程,最后汇总常见报错、调参方向和工程落地建议。无论你是刚入门想做一个小实验,还是在调研可用于生产的重建方案,这篇文章都可以作为一份带注释的实战参考。
1. 背景与核心概念
1.1 什么是三维高斯飞溅
三维高斯飞溅(3D Gaussian Splatting)是一种基于点的显式场景表示与渲染方法。它的基本思想是:用大量带有空间位置、形状、颜色和不透明度的三维高斯小“颗粒”来描述一个静态场景,然后把这些高斯颗粒从三维空间投影到二维图像平面上,再进行光栅化混合,得到最终的渲染画面。
这句话包含两个关键点:第一,场景表示是“显式”的,也就是每个高斯点都可以被单独读取和修改;第二,渲染方式是“投影 + 混合”,也就是先把三维高斯投到图像平面上,再按照深度和透明度一层一层合成像素。
“高斯飞溅”中的“飞溅”(splatting)指的就是这种从三维到二维的投影涂抹过程。你可以把每个三维高斯想象成一团有颜色、有大小、有一定半透明度的“彩色雾气”,渲染时将这些雾气从三维空间“拍”到图像平面上,像撒了一堆彩色颜料点,最终叠加成一幅完整画面。
1.2 它解决了什么问题:对比 NeRF 与传统网格
在讨论高斯飞溅之前,需要了解它出现之前的主流方案。
最热门的对比对象是神经辐射场(NeRF)。NeRF 用多层感知机(MLP)来隐式编码一个场景的颜色和密度,渲染时从相机发出光线,在光线上采样大量点,再通过神经网络计算每个点的颜色和透过率,最后积分得到像素颜色。NeRF 的优点是渲染质量高、细节丰富,但缺点是训练和渲染都很慢,因为每条光线要查询神经网络很多次,并且隐式表示很难直接编辑或分割场景。
传统网格(Mesh)方案则依赖多视角立体几何(MVS)生成点云和网格,优点是渲染速度快、能直接用于游戏引擎,但缺点是重建结果对纹理复杂、反光表面和弱纹理区域特别敏感,容易出现空洞、边缘断裂等瑕疵。
高斯飞溅用一种“折中”的方式同时绕开了两者的主要痛点:它把场景本身存储为一系列可解析的高斯基元,不需要为每条光线反复查询网络;它又保留了显式点云的优势,支持实时渲染、自由视角插值和逐点编辑。这也是它在短时间内被广泛接受的核心原因。
1.3 典型应用场景
从工程角度,高斯飞溅目前最成熟的几类应用包括:
- 实景三维重建:用手机或无人机拍摄一组照片,重建出可在任意视角实时浏览的逼真场景。
- 数字人与商品展示:重建人像、服装、鞋帽等物体,用于电商展示和虚拟内容制作。
- 自动驾驶与机器人仿真:把道路场景重建为高保真数据,供感知算法训练和仿真测试。
- 城市级大场景重建:结合航拍影像与地面影像,构建可交互的城市三维底座。
- 影视后期与游戏资产制作:从实拍视频中提取可编辑的三维场景素材。
这些场景有一个共同需求:既要视觉效果好,又要能在普通设备上流畅交互。这正是高斯飞溅的强项。
2. 核心原理拆解:3D 高斯如何描述和绘制场景
这一节我会尽量不堆公式,用直观语言解释 3D 高斯从“表示”到“渲染”再到“优化”的完整流程。
2.1 场景表示:每个高斯点包含什么
一个三维高斯本质上是一个带协方差矩阵的高斯分布。为了便于优化,每个高斯点通常由下面几组参数组成:
- 中心位置:三维点坐标。
- 旋转四元数:用来确定高斯椭球在空间中的姿态。
- 缩放向量:用来确定高斯椭球在三个轴向上的大小。
- 不透明度:控制当前高斯对最终像素颜色的贡献权重。
- 颜色与球谐系数:用于表达在不同视角下的颜色变化,低阶球谐可以表达简单的视角相关效果。
一组三维高斯点集合在一起,就构成了对场景的完整描述。场景中某个位置越复杂、颜色变化越剧烈,训练算法会自动在该位置附近放置更多且更小的高斯点;而大片颜色均匀的区域,则只需要少量大尺寸高斯点即可覆盖。
2.2 渲染流程:从三维高斯到二维像素
高斯飞溅渲染过程大致可以分为四步。
第一步,根据当前相机视角,将每个三维高斯的中心位置投影到图像平面。这一步与普通点云投影类似,需要用到相机的内参和外参。
第二步,根据高斯的协方差矩阵与相机位姿,把三维高斯的形状投影到二维平面上,得到一个二维高斯椭圆。这个椭圆代表了当前三维高斯在图像上“涂抹”出来的范围。
第三步,对所有可见的三维高斯,按照它们离相机的远近进行排序。因为三维空间中的高斯点可能相互交叠,排序之后才能从远到近依次混合,得到正确的遮挡关系。
第四步,以像素为单位,找出覆盖当前位置的所有高斯椭圆,依次累加它的颜色与不透明度。为了提高效率,渲染器会把图像切成许多小块(tile),每个小块只处理与该区域相关的高斯点,避免全局排序和全图扫描。
这套流程本质上就是一个可微的、基于光栅化的渲染管线,因此反向传播时梯度可以顺利回传到每个高斯的参数上,这也是训练能够收敛的关键。
2.3 自适应密度控制:从稀疏点云到稠密场景
高斯飞溅初始化时并不需要大量数据。通常做法是先用 COLMAP 等运动恢复结构(SfM)工具,从多张照片中恢复相机位姿和稀疏三维点云,然后用这些稀疏点云作为初始高斯点的位置。
训练过程中,除了通过梯度下降更新每个高斯的颜色、不透明度、旋转、缩放等参数,还引入了自适应密度控制策略。简单来说,当某个区域的高斯点无法覆盖当前场景细节时,算法会把这些高斯点“克隆”或“分裂”成多个;当某处高斯点过于密集但并无太多细节时,又会合并或删除低贡献的高斯点。
这样做的结果是:场景中每个位置的表达密度与细节复杂度自动匹配。墙面、天空等平坦区域会保留少量大高斯,而树枝、镂空结构、复杂纹理等区域则会自动增加高斯点密度。
2.4 训练损失:如何衡量渲染结果好坏
训练过程中,网络会把当前视角下的三维高斯渲染成一张二维图像,与真实拍摄的照片做对比。高斯飞溅论文中采用的损失是 L1 损失与 D-SSIM 损失的组合。
L1 损失衡量渲染图和真实图在每个像素上的绝对差异,适合保持整体亮度和颜色的一致;D-SSIM(结构相似性)损失则更关注局部结构、边缘和纹理是否清晰。两部分的权重通常大约在 0.8 和 0.2 左右,具体数值可以在配置文件中调整。
从工程角度看,这套损失设计既兼顾了整体色调的准确性,又保证了局部结构的锐利度,这也是最终重建结果看起来“又清晰又自然”的重要原因。
3. 环境准备与版本说明
3.1 硬件与软件需求
运行三维高斯飞溅训练,建议满足以下条件:
- 操作系统:Linux 或 Windows。多数生产环境使用 Linux,Windows 上也能运行,只是部分原生扩展需要额外编译。
- GPU:NVIDIA 显卡,支持 CUDA。显存大小直接影响能跑的场景规模。简单物体 6 GB 左右可以尝试,街景或大场景建议 24 GB 或更高。
- Python:建议使用 3.8 及以上版本。
- 依赖库:PyTorch、CUDA ToolKit、COLMAP、diff-gaussian-rasterization 等。
需要注意,不同操作系统、不同显卡驱动版本、不同 CUDA 版本之间的兼容关系复杂,如果环境不匹配,最常见的表现是编译 diff-gaussian-rasterization 扩展时失败,或者运行时报 CUDA 版本不匹配错误。因此下面给出的是通用流程,具体版本仍以官方仓库 README 的说明为准。
3.2 安装 COLMAP
COLMAP 是当前高斯飞溅流程中最常用的“前置工具”,它负责从照片中恢复相机位姿和稀疏点云。
COLMAP 的安装方式依赖你的操作系统:
- Windows:官方发布页提供了带图形界面的安装包,下载后解压即可。
- Ubuntu:可以用 apt 安装,也可以从源码编译。apt 版本可能偏老,但通常够用。
- macOS:可以通过 Homebrew 安装,但 GPU 加速能力有限,训练大场景时不推荐。
安装完成后,在终端执行colmap -h能显示帮助信息,就说明安装成功。
3.3 克隆官方项目
官方开源项目地址是graphdeco-inria/gaussian-splatting。克隆后,项目目录中一般包含训练代码、渲染代码、SIBR 实时查看器相关源码和数据集处理脚本。
git clone https://github.com/graphdeco-inria/gaussian-splatting cd gaussian-splatting后续训练使用的核心文件主要是train.py、render.py以及场景处理相关的脚本。训练基线算法会在这里集中体现,你添加自己的数据处理逻辑时,也建议从这里开始改造。
3.4 创建虚拟环境
官方通常推荐使用 conda 创建独立的虚拟环境。这是一种较好的隔离方式,避免不同项目之间的 Python 包版本互相干扰。
conda create -n gaussian_splatting python=3.8 conda activate gaussian_splatting激活环境后,再根据项目中的requirements.txt安装依赖。安装过程可能需要几分钟,如果网络速度慢,可以考虑配置国内 pip 镜像。
pip install -r requirements.txt接着需要安装子模块diff-gaussian-rasterization和simple-knn。这些扩展通常需要编译,安装时请确保 CUDA 环境变量正确。
pip install submodules/diff-gaussian-rasterization pip install submodules/simple-knn如果编译报错,第一步先确认当前 PyTorch 的 CUDA 版本与系统 CUDA 是否一致,再做进一步排查。
4. 完整实战:用一组照片重建一个可交互的三维场景
4.1 数据采集与目录结构
数据是整个重建流程的源头。无论使用什么设备,都建议遵循以下原则:
- 场景静止,不要有人、车辆、晃动树叶等明显动态元素。
- 相邻照片之间保持足够的重叠度,通常要求 70% 以上。
- 拍摄路径尽量围绕目标场景,从不同高度和角度覆盖完整,而不是只在一个平面上旋转。
- 避免强烈反光、过曝、过暗,尽量使用均匀光照。
采集完成后,需要把图片整理成项目可识别的目录结构。以官方的数据和 COLMAP 约定为例,一个标准数据集目录大致如下:
data/ └── my_scene/ ├── images/ │ ├── 00001.jpg │ ├── 00002.jpg │ └── ... └── sparse/ └── 0/ ├── cameras.bin ├── images.bin └── points3D.bin其中images目录存放原始照片,sparse/0目录存放 COLMAP 生成的稀疏重建结果。如果你是自己下载的示例数据,目录结构通常已经符合要求,可以直接跳过下一步。
4.2 使用 COLMAP 生成相机位姿与稀疏点云
如果你用的是自己的照片,则先要用 COLMAP 计算相机位姿和稀疏点云。下面是一段常见的命令行流程,适合 Linux 和 macOS 环境。
首先将图片整理到my_scene/images目录,然后执行特征提取:
cd data/my_scene colmap feature_extractor --database_path database.db --image_path images这一步会为每张图片提取局部特征点,得到可用于匹配的特征描述子。
接下来执行特征匹配:
colmap exhaustive_matcher --database_path database.db对于数据量较小的场景,exhaustive matcher 即可满足要求;如果图片数量非常多,可以考虑使用更高效的顺序匹配或词袋匹配方式。
然后执行稀疏重建:
mkdir sparse colmap mapper --database_path database.db --image_path images --output_path sparse完成后,sparse目录下会生成 0 号子目录,其中就包括后续训练需要的相机参数和稀疏点云。
如果你的照片数量很大或场景结构复杂,建议在图形界面 COLMAP 中检查重建是否完整,删除明显错误的关键帧,再继续后续流程。
4.3 转换数据格式
部分版本的高斯飞溅训练代码需要把 COLMAP 生成的结果转换成cameras.bin、images.bin、points3D.bin等文件。如果你的 COLMAP 版本默认输出为 TXT 格式,可以使用官方仓库中提供的转换脚本,也可以参考社区常用的colmap2nerf.py类工具进行格式转换。
转换过程本质上是把相机的内参、外参和三维点坐标从 COLMAP 的数据结构,重写为 3DGS 训练器认识的格式。这一步骤偶尔会因为 COLMAP 版本不同而产生字段缺失,遇到时报错信息一般比较明确,按提示补齐即可。
4.4 开始训练
确保数据集目录结构与前面一致后,进入项目根目录,执行训练命令。
python train.py -s data/my_scene -m output/my_scene这里的-s指定数据集路径,-m指定输出目录。训练过程中,你会看到终端不断输出当前迭代次数、损失值和耗时等信息。
训练默认迭代次数通常为 30000 次,具体数值可以在参数中调整。训练时间与图片数量、分辨率、场景复杂度、显卡性能都有关系。一个小型物体场景在 24 GB 显存的显卡上可能只需要十几分钟,而一个大型街景可能需要数小时。
如果显存不足,可以尝试降低训练图像分辨率或减少同时参与优化的采样点数;如果显存充足,也可以适当提高分辨率,以获得更细腻的纹理细节。
4.5 渲染与导出
训练完成后,可以使用项目中的渲染脚本,对训练好的模型进行指定视角或全部训练视角的渲染。
python render.py -m output/my_scene渲染结果通常会输出到output/my_scene/test/...或类似目录,生成一组渲染图片。你可以把它们与原始照片放在一起对比,直观感受重建效果。
官方还提供了实时查看器(SIBR Viewer),下载对应平台的客户端后,可以加载训练输出中的模型文件,用鼠标自由旋转视角,实时观察重建场景。
SIBR_viewers/bin/SIBR_real_time_app.exe -m output/my_scene不同平台的启动命令和文件名会有差异,具体以官方发布页说明为准。实时查看器会让你直观理解“高斯飞溅”这个名字的含义:画面中每一个高光点、每一条边缘,都是一颗颗可独立移动、旋转和缩放的高斯颗粒叠加而成的。
4.6 结果说明
训练完一个场景后,你通常会得到以下几类内容:
point_cloud目录:保存了所有三维高斯点的核心参数。cameras.json或类似文件:记录了训练时使用到的相机信息。- 渲染图片:用于离线评估重建质量。
- 训练日志:记录了每一轮迭代的损失和耗时。
整体重建效果如果理想,你会看到:从任意一个新视角渲染图片,都能保持准确定位和清晰纹理;从已训练视角渲染时,图片质量往往很高,甚至肉眼难以和真实照片区分。
5. 关键参数与调优思路
5.1 迭代次数
迭代次数是影响重建质量最直接的参数。迭代次数太少,高斯点尚未完全覆盖场景细节,容易出现模糊和空洞;迭代次数过多,则可能产生过拟合,导致在训练视角表现极好,但在新视角下出现闪烁或虚影。
一般建议先用默认迭代次数跑通流程,再根据损失曲线的变化决定增加还是减少。如果损失在接近训练末尾时仍在显著下降,说明还有继续提升的空间。
5.2 损失函数权重
训练时的总损失是 L1 与 D-SSIM 的加权组合。增大 D-SSIM 权重可以让边缘更锐利,但过大会导致颜色过度饱和或出现类似“数字绘画”的质感;增大 L1 权重则更贴合真实亮度,但局部结构可能偏软。
实际调参时,可以优先调整 D-SSIM 权重,数值变化范围通常在 0.1 到 0.3 之间。不过,不同版本代码对损失权重的定义方式有所不同,建议先查看源码中的损失计算部分再修改。
5.3 高斯点密度相关参数
场景中高斯点的数量由初始化点云和自适应密度控制共同决定。如果重建结果中某个区域始终模糊不清,你可以先检查该区域在稀疏点云中是否有足够的初始点。如果初始点就很少,即使训练中自动分裂,也很难弥补大范围的空白。
此外,控制高斯点分裂或克隆的阈值也会影响最终点数。点数越多,细节表现力越强,但显存占用和渲染开销也会随之上升。这里需要在画质与性能之间做平衡。
5.4 输入图像分辨率
输入图像分辨率对结果影响很大。低分辨率输入会损失纹理细节,尤其是远处广告牌、字体、建筑边缘等;高分辨率输入则可能让训练变慢,并显着增加显存占用。
因此,比较推荐的做法是先用较低分辨率快速验证数据和参数流程是否正确,确认没有问题后,再提高分辨率进行正式训练。这也是 GPU 资源有限时最常见的优化策略。
6. 常见问题与排查思路
6.1 问题速查表
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 扩展模块编译失败 | CUDA 版本与 PyTorch 不匹配 | 统一 CUDA 版本,检查环境变量 |
| COLMAP 重建结果为空或稀疏点过少 | 图像特征不明显或重叠度不足 | 增加图片数量,避免重复纹理和弱纹理 |
| 训练时显存不足 | 图像分辨率过高或高斯点增长过快 | 降低分辨率,减小初始点云范围 |
| 渲染结果有大量空洞 | 相机位姿不准或动态物体干扰 | 检查数据集,剔除错误关键帧 |
| 训练速度极慢 | 图像数量过大且硬件较弱 | 按批次训练,或先降采样 |
| 新视角渲染出现闪烁 | 部分高斯点过拟合到训练视角 | 降低迭代次数,增大 D-SSIM 权重 |
| 画面中出现长条状高光伪影 | 高斯的旋转或尺度参数异常 | 检查初始点云质量,降低学习率 |
6.2 编译失败的细致排查
diff-gaussian-rasterization扩展需要本地编译,最容易出错的就是 CUDA 路径找不到、PyTorch 版本与 CUDA 版本不匹配等问题。
排查时先运行:
python -c "import torch; print(torch.__version__, torch.version.cuda)"确认 PyTorch 的 CUDA 版本。接着运行:
nvcc --version确认系统 CUDA 版本。两者如果不兼容,通常需要重新安装 PyTorch 或调整 CUDA 环境变量。如果仍未解决,可以查看编译日志中的具体报错位置,它经常会直接告诉你缺少哪个头文件或哪一个版本符号未定义。
6.3 数据采集导致的画质问题
在实际项目中最常见的问题,往往不是代码 bug,而是数据采集导致的问题。比如拍摄时相机自移动范围过大、目标物体表面反光太强、软件去噪导致纹理细节被抹平、或者使用了带有超广角畸变的镜头而没有正确的相机参数,这些都会让重建质量大打折扣。
遇到这类情况,先不要急着调参,而是回溯数据质量。在 COLMAP GUI 中查看稀疏点云和相机位姿分布,确认相机轨迹是否平滑、覆盖角度是否完整,再考虑后续优化方案。
7. 最佳实践与工程建议
7.1 数据准备阶段
- 场景尽量固定,动态物体会造成训练扰动,表现为局部区域出现重影或模糊。
- 拍摄时设定固定曝光和白平衡,避免自动曝光导致同一场景在不同视角下亮度不一致。
- 保留较高像素的原始照片,但训练时按需降采样,这样可以在后期随时切换分辨率重新训练。
- 为不同场景建立独立目录,并在文件名中加入拍摄日期和批次信息,避免数据管理混乱。
7.2 训练与调参阶段
- 先跑通一个 2000 到 5000 次迭代的快速实验,确认数据、代码和渲染链路没有问题,再投入正式训练。
- 记录每一次实验的数据集、参数和结果,方便对比。训练日志和渲染图建议统一存放,不要散落在各个目录。
- 不要在验证集上反复调参,否则容易对特定视角产生过拟合。
- 定期保存训练中间结果,防止意外中断导致需要从头开始。
7.3 生产落地阶段
- 如果场景规模很大,建议先分块重建,再合并相邻块的点云或高斯场。直接一次性训练全场景,显存和时间的消耗都会成倍增加。
- 高斯飞溅生成的模型文件可能很大,动辄几百 MB 到几个 GB。上线前需要评估用户的下载带宽和渲染设备,必要时量化参数或简化场景。
- 如果需要与现有渲染管线(如 Unity、Unreal)结合,需要在导出阶段做格式转换。不同引擎对高斯点的存储和渲染实现不同,转换时要注意坐标轴方向、单位、球谐系数阶数等细节。
- 涉及生产环境的数据采集、模型上线和算法调整,都必须做好备份和版本管理。不要直接在生产数据上做破坏性实验,而应使用独立的测试环境验证后再合入。
7.4 安全与合规提醒
在使用高斯飞溅进行场景重建时,需要特别注意数据来源的合规性。不要擅自拍摄、重建或传播涉及私人场所、敏感区域的内容。如果使用他人采集的数据集,要遵守数据集的使用协议。模型文件本身也可能包含可被识别的环境信息,对外发布前需要评估是否含敏感内容。
8. 总结与下一步学习
这篇文章围绕“高斯飞溅”这个主题,介绍了三维高斯飞溅的基本原理,包括 3D 高斯如何表示场景、如何通过光栅化渲染、如何自适应控制密度,以及如何用 L1 和 D-SSIM 损失进行优化。在实战部分,我们一起走完了从照片采集、COLMAP 稀疏重建、数据格式转换、模型训练到渲染预览的全部流程,并整理了训练中常见的错误排查方法和调参建议。
对于刚入门的同学,下一步可以先拿一个公开的、已经处理好的数据集,复现一遍完整流程。不要一开始就追求复杂场景,先把每个环节跑通,理解每一步的输出是什么,再切换到自己的数据。对于想在项目中落地的开发者,建议优先关注大场景分块重建、模型压缩、Web 端实时渲染和现有渲染引擎的集成方案,这些方向目前都有大量活跃的社区讨论和开源尝试。
高斯飞溅还在快速发展,很多工具链和最佳实践仍在变化中。如果你在实际操作中遇到了新的报错,或者总结了更好的调参经验,欢迎在评论区分享出来,一起把踩坑经验沉淀下来。