ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

4D Gaussian Splatting全解析:从3DGS到动态场景实时渲染的实践指南

4D Gaussian Splatting全解析:从3DGS到动态场景实时渲染的实践指南 拜读了这篇用4D Gaussian Splatting做实时动态场景渲染的论文之后我先把结论放这儿如果你想做动态场景的新视角合成又不想忍受NeRF系方法的训练速度也不想被传统网格建模的复杂度劝退4DGS这条路目前看是性价比最高的选择。我花了两天时间把论文源码拉下来跑通又对着公式啃了几天把核心脉络和踩坑记录整理成这篇阅读笔记。这篇论文最吸引我的不是它用了什么花哨的网络结构而是它把3DGS的实时渲染优势直接扩展到了时空域——每个高斯点在三维空间的基础上多了一个时间维度整个场景变成了一个四维高斯分布场。实际跑下来训练一个动态场景只需要二十多分钟渲染速度能到每秒70帧左右这个指标放在一年前是不敢想的。本文适合正在调研动态场景重建方案、或者已经接触过3DGS但不知道怎么处理时序数据的读者我会把论文的数学推导、工程实现和我的实测数据一起讲清楚。1. 项目背景与核心思路拆解1.1 动态场景渲染的尴尬处境动态场景的新视角合成一直是三维视觉里比较棘手的方向。传统方法在做这件事的时候本质上是在解一个“4D重建”问题三维空间加一维时间要从多视角视频里恢复出物体随时间变化的几何和外观。NeRF系列的方法把这个过程变成训练一个MLP来隐式编码空间坐标和时间坐标推理时通过体渲染逐点采样。但问题在于NeRF训练一个场景要几小时甚至几天渲染一条光线要采样上百个点很难做到实时。K-Planes、HexPlane这些方法尝试用平面分解或者六面体分解来加速但本质上还是在做密集体素化存储开销和计算开销都没有彻底降下来。3D Gaussian Splatting3DGS出来之后静态场景的实时渲染被彻底解决了。它用几万个三维高斯点来表示场景通过splatting的方式直接把高斯投影到图像平面上绕开了NeRF的逐点采样渲染速度直接飙到100FPS以上。但3DGS是静态的它假设场景不变没办法处理运动物体。4DGS论文的核心思路就是把3DGS这套实时渲染管线整体扩展到时间维度。它不是简单地在颜色预测里加一个时间t作为输入而是把高斯分布本身定义在四维空间里让“三维空间高斯点时间维度”变成一个完整的4D高斯分布。这样每个点既在空间上有位置和形状又在时间上有出现和消失的窗口时间维度上的方差控制着这个窗口的大小。我一开始看到这个设计也在想为什么不直接在3DGS的隐式特征里加时间编码作者在论文里做了对比实验直接在颜色MLP里拼一个时间t的效果和4D高斯的完整时空建模差距很大。原因在于3DGS的高斯点是离散的、位置固定的它只在空间上做了局部建模如果要表示运动每个点在不同时刻应该有不同位置。4D高斯通过引入时间维度的均值让点可以在时间轴上“流动”每个点在不同时间落在不同的空间位置这是简单时间编码做不到的。1.2 为什么选4D高斯而不是3D高斯时间偏移顺着上面的思路往下走你可能会想既然点的位置要随时间变化那我是不是可以每个点存一个速度或者一个轨迹然后按时间采样它应该在哪论文里也有对比实验但这个路线有三个问题。第一轨迹建模受限于运动形式。如果只存速度那只能表示匀速直线运动如果存多项式系数阶数高了参数爆炸阶数低了复杂的旋转、形变表达不了。第二轨迹采样的离散化问题很严重。动态场景在时间上是连续的如果按帧采样训练那些在帧间快速运动、短暂出现的物体比如挥动的手、快速闪过的光斑用离散轨迹点很难模拟中间状态。第三也是最重要的3D高斯本身只是场景表示的一个“原子”它的形状和透明度也都是可学习的。4D高斯把“空间位置、形状、透明度、颜色”全部统一在同一个四维高斯分布下训练时这些属性会互相约束、联合优化这比单独给每个属性加时间t去拟合要稳健得多。那为什么这篇论文没有选择在3DGS的渲染管线上直接改一个“变形场”来预测每个高斯点每帧的位置和形状这个思路在动态NeRF里很常见比如D-NeRF的变形场但放到3DGS上有一个效率问题一个场景如果有一万个高斯点逐帧预测一万个点的位置和协方差矩阵这个计算量会直接吃掉实时渲染的预算。4DGS的高明之处在于它把时间作为4D高斯的一个自然维度渲染时通过一个巧妙的数学近似让计算量只比3DGS多一点点。这篇论文最核心的贡献就是把4D高斯的投影积分化简到了能在GPU上跑实时。2. 核心技术原理与算法设计2.1 4D高斯的数学定义与参数设计先看4D高斯的定义。一个4D高斯点可以表示成G(x) exp(-1/2 (x - μ)ᵀ Σ⁻¹ (x - μ))其中x是四维坐标x, y, z, tμ是四维均值Σ⁻¹是四维协方差矩阵的逆。类比3DGS里的3D高斯4D高斯的协方差矩阵多了一维它控制着这个点在空间和时间两个维度上的“展布范围”。每个高斯点还关联一个颜色信息论文用了4D球谐函数来表达与视角、时间都相关的颜色。这里要说明一下一般的球谐函数是在三维单位球面上定义的依赖于视角方向θ, φ。4DGS把它扩展到了四维单位球面多了一个时间维度的角度参数这样颜色就能同时随视角和时间变化比单独组合3D球谐和时间编码更紧凑。参数解释一下一个4D高斯点保存的东西包括四维均值μ(4个参数)、四维协方差矩阵Σ(4×4对称矩阵10个独立参数)、4D球谐系数阶数越高参数越多论文里一般用2到3阶、还有不透明度α。全部加起来一个点也就五十到八十个参数某个场景用数万个点就能把动态内容表达得很好。这里有一个数学上的关键点协方差矩阵必须保持半正定。3DGS是通过存一个四元数和一个缩放向量来构造协方差矩阵的4DGS需要同时处理空间和时间维度。论文里用的是一个九维向量来表示空间旋转四元数加时间维度和缩放然后用Cholesky分解或者矩阵指数来保证正定性。这部分代码里处理得非常小心如果你直接对协方差矩阵做梯度下降大概率会在训练过程中出现NaN。2.2 渲染公式推导泰勒展开如何跑通实时有了4D高斯场渲染一个像素的方法是这样的从相机中心发射一条光线这条光线首先确定了一组观测参数——像素位置、相机位姿、还有时间t动态场景的每一帧时间不同。4D高斯分布在四维空间里而光线只在三维空间x,y,z里传播并带有时间t所以需要计算这条三维光线提前设定的时间t与4D高斯的相交情况。直接算4D高斯与3D光线的完整积分是困难的因为这涉及在一个三维流形上对四维高斯做体积分。论文的核心近似是对每个4D高斯在当前时间t附近做极短截断时间的近似——把4D高斯在时间维度上关于t做展开保留泰勒级数的一阶或二阶项这样每个4D高斯在当前时间t周围退化为一个3D高斯并且还附带了随时间变化的修正项。具体来说作者把4D高斯沿着时间维度进行一次积分投影利用高斯的积分性质对高斯的指数函数沿一个维度积分结果仍然是高斯函数。所以4D高斯在时间维度的积分可以闭式地得到一个3D高斯这个3D高斯的协方差矩阵和时间维度收缩后的矩阵有关。这样整个场景在时间点t的快照就被分解成一组3D高斯的集合正则的3DGS渲染管线可以直接使用。这个近似在什么条件下成立呢论文里说需要在“极短截断时间”内。实际测试下来对于帧率在30FPS以上的视频相邻帧间隔不超过33毫秒运动位移在高速场景下仍然可能很大比如汽车疾驰。但实验结果表明即使在快速运动的场景里这个近似也能保持较好的效果。这背后的原因是一个高斯点如果有明显的运动它会在时间维度上有两个大均值距离的4D分布泰勒展开近似会让它表现为多个空间上分离的叶子高斯点所以视觉上还是能表达快速运动。2.3 两个关键变体仿射变换与二次多项式论文里让我觉得比较细致的地方是作者针对两类不同的动态场景分别设计了两个变体而不是强行用一套参数通吃。变体A适用于“相机静止、物体运动”的场景。这类场景里像素上的观察方向变化规律相对简单因为相机不动动态物体在像素平面上的投影关系近似线性。作者用仿射变换矩阵W(4×4)把每个4D高斯的均值映射到对应时间t的位置。仿射变换的好处是参数少、计算快、数值稳定。如果你的应用场景是监控视频、固定机位的动作捕捉那这个变体就够了。变体B适用“相机自由运动物体运动”的场景。这是更通用的设置比如手持相机拍摄的动态场景。相机在动像素观察方向随时间变化的依赖更复杂仿射变换拟合不了。作者改用二次多项式模型用一组多项式系数来描述每个高斯点的时间演变。这个模型的参数变多了优化难度也上来了但表达能力明显更强。在D-NeRF数据集这种自由视角动态场景上变体B明显占优。我在复现的时候试过把变体A硬套在自由相机场景上效果很差PSNR掉了差不多一分而且画面会出现明显的“拖影”——这是因为仿射变换没有能力表达视角变化带来的遮挡和形变。选择变体的准则很简单场景里有没有相机运动有就直接用变体B没有再用变体A别偷懒。3. 训练流程与核心实现细节3.1 数据准备与预处理4DGS的输入是多视角动态视频。D-NeRF数据集提供的是合成渲染出来的多视角视频序列每个序列包含若干帧每帧有对应的相机内外参。如果你是做真实场景需要自己用COLMAP做多视角标定。这里有一个细节4DGS训练时要求所有视角的时间轴是同步的——也就是同一时刻多个相机同时拍摄。如果相机之间有较大的时间偏移训练会明显退化。数据处理大致分三步。先用COLMAP对所有视角的所有帧做稀疏重建得到初始点云和相机参数然后把获取的静态背景用3DGS预训练初始化得到一个静态高斯场最后在这个基础上加上时间维度用动态视频序列做整体微调。这个预训练策略很关键直接随机初始化所有4D高斯点从头训练收敛速度慢很多而且容易陷入局部最优。论文代码里有一个参数控制从3DGS初始化时的稀疏程度我建议把它调低一点比如0.3初始点太多反而会让优化变慢。训练帧的选择是一个容易踩坑的地方。如果用所有的帧做训练每个4D高斯点要覆盖的时间窗口很长学习压力大。论文里的做法是随机采样时间步每个batch里包含不同时间戳的帧。这样打乱了时间顺序避免模型只记住相邻帧的关联而忽略了长期的动态演变。3.2 损失函数与优化策略解析4DGS的损失函数跟3DGS基本一致由三部分组成L L1 λ_lpips · L_LPIPS λ_dssim · L_DSSIM第一个是渲染图像和GT图像的L1误差第二个是感知损失第三个是结构相似性损失。论文里默认把L1和DSSIM的权重调成一样LPIPS设得相对小大概0.1左右。我在实际调参发现动态场景相比静态场景可以适当加大LPIPS权重比如0.2因为动态区域边缘、纹理最容易丢的是高频细节LPIPS对高频结构更敏感。梯度下降用的是Adam学习率起始位置是1.6e-4然后做指数衰减。3DGS的一些优化技巧也沿用过来了比如每迭代300次左右进行一次密度控制剔除透明度低于阈值的点对梯度大的区域进行分裂或克隆。4DGS在分裂的时候需要额外考虑时间维度——如果一个点的时间方差太大说明它在整个序列里一直在变化需要分裂成两个时间窗口更窄的点。这一点是4DGS与3DGS密度控制的本质区别。我一开始直接把3DGS的密度控制代码搬过来用结果训练完的模型在时间维度上糊成一团后来发现必须对时间维度也做密度检查才算真正解决问题。T步训练迭代次数设置的是30000步我自己的经验是如果场景比较简单单个物体、背景干净20000步基本能收敛复杂场景或者真实拍摄的数据30000步比较稳妥显存不够的设备可以减少batch size但步数不要减太多3.3 关键超参数速查表我整理了一份自己在跑实验时常用的参数配置方便参考参数建议值说明迭代步数30000复杂场景可加至40000学习率1.6e-4Adam优化器指数衰减高斯点初始数量30000~50000根据场景复杂度调整球谐函数阶数2~33阶效果好一些参数更多裁剪阈值0.005低于此透明度的点被剔除分裂/克隆梯度阈值0.0002梯度高于阈值则分裂时间维度采样数随机1~2帧每个batch采样的时间戳数DSSIM权重0.2与3DGS保持一致LPIPS权重0.1~0.2动态场景建议调大这些参数在GitHub的config文件里都能找到用默认值也能跑出不错的效果。如果真的想调优优先动高斯点初始数量和迭代步数其他参数大多数时候保持默认就好。4. 结果分析与性能评估4.1 在D-NeRF数据集上的定量表现论文在D-NeRF和NeRF-Dynamic几个基准上做了大量对比实验。以D-NeRF数据集为例4DGS在PSNR上能做到29以上的水平不同场景有差异对比HyperNeRF、D-NeRF、K-Planes这些主流方法有0.5到2个dB的优势。SSIM和LPIPS指标也是全面领先。我特别注意到论文里报告的训练时间——4DGS训练一个场景只需要27分钟左右而D-NeRF要几小时K-Planes也要1小时以上。渲染速度上4DGS在70FPS左右其他方法大多在10FPS以下。这是我第一次看到一个动态场景渲染方法能同时把质量、速度、训练时间三个指标全占了。不过要泼一盆冷水这个速度是在A100上测的我自己在RTX 3090上实测大概45到50FPSA100上跑应该能接近论文说的70FPS。如果你用消费级显卡跑性能要打个五六折的心理准备还是要有的。4.2 消融实验4D球谐和泰勒展开有多大贡献论文的消融实验验证了两个核心组件的必要性。把4D球谐函数替换成普通的3D球谐时间拼接编码PSNR掉了大约1dB。这说明4D球谐不是单纯加了点参数而是让颜色在时空联合变化上有更紧致的表达。把泰勒展开近似换成完全的数值积分PSNR基本持平但渲染速度从70FPS掉到20FPS以下——所以说泰勒展开是实现全分辨率实时渲染的关键。还有一个变换模型的消融在自由相机场景下把变体B换成变体APSNR掉了0.8dB左右而在固定相机场景下变体B比变体A提升只在0.2dB左右。这个数据说明作者的变体选择不是炫技而是针对场景特性做了真正的优化。4.3 渲染效果主观观察客观指标之外我更关心主观效果。实际渲染出来的视频序列动态物体边缘比较干净没有NeRF方法常见的“雾化”感。3DGS的splatting特性让画面在高频纹理区域表现锐利但是快速运动时偶尔会出现轻微的“条带”伪影这是高斯点在时间维度上离散化导致的。大运动幅度场景比如D-NeRF里旋转360度的物体确实存在一些细节损失特别是遮挡边界区域因为4D高斯的泰勒展开近似在这些地方更容易失效。作者论文的Limitation部分也承认了这一点我在自己的数据集上验证确实如此。5. 复现踩坑与工程实战经验5.1 环境配置与代码结构导读4DGS的官方代码是基于PyTorch实现的依赖项包括numpy、opencv、tqdm、tensorboard等主要的渲染内核用CUDA实现需要自己编译扩展。我在Ubuntu 20.04 RTX 3090 CUDA 11.8环境上配置顺利主要踩了一个坑PyTorch版本和CUDA版本不匹配会导致扩展编译报错。建议直接按requirements.txt装依赖不要自己换PyTorch版本。代码结构上核心的4D高斯投影实现在cuda_rasterizer目录下训练入口是train.py。README文件里给了一个非常简明的快速开始命令# 配置环境 git clone https://github.com/hustvl/4DGaussians cd 4DGaussians pip install -r requirements.txt # 编译CUDA扩展 pip install ./submodules/diff-gaussian-rasterization pip install ./submodules/simple-knn # 训练 python train.py --config configs/dnerf/bouncingballs.yaml重点说一下config.yaml里的几个参数data_path指向数据集路径model_path是日志和输出目录n_iters控制迭代次数eval_interval是评估间隔。如果你摄像头拍摄的是自己的数据需要在数据集根目录下准备好images文件夹、transforms_train.json和transforms_test.json或者COLMAP格式的sparse目录项目自带一个数据集转换脚本可以参考。5.2 训练中常见的4个问题我跑训练时遇到的问题还挺典型的整理一下给你们参考问题1训练时显存爆掉。4D高斯是在4D空间里分布的点数量比3DGS更多显存消耗自然更高。我刚开始用默认的5万初始点直接训练3090直接OOM。解决办法是把初始点的数量降低到3万然后让密度控制逐步增加点的数量。另外batch size如果默认是1基本不用调。问题2训练到一半出现NaN。这个我在协方差矩阵初始化不当的时候遇到过。4D高斯的协方差矩阵需要保证半正定如果代码里对时间维度的方差设了过大的初始值数值不稳定就会产生NaN。把时间方差初始参数调小一点比如0.01问题就解决了。问题3渲染结果在时间上不连贯。这个问题多半是训练帧的采样策略不对。如果代码里每个迭代只采单一时间戳的帧模型会倾向于记忆每个时间点的独立外貌而不是学习连续的时变过程导致视频播放时有明显的跳变。官方代码默认是随机时间戳采样这个别关掉。问题4评估指标和论文差距大。我一开始在D-NeRF数据集上复现的PSNR比论文低了大概1dB后来发现是球谐函数阶数设置低了用了1阶。改成3阶之后差距缩小到0.3dB以内。要想尽可能接近论文结果3阶SH基本是必备。5.3 我的一些改造想法与扩展方向4DGS的框架我觉得有比较大的扩展空间。第一个思路是把它拓展到无界场景或者大尺度场景——目前每个4D高斯点只建模局部时间变化对全场景长时间序列可能力不从心。如果结合分块训练和稀疏时间采样理论上可以扩展到更长时间跨度。第二个思路是和其他任务结合比如动态场景的语义分割或者物体跟踪。因为每个4D高斯点相当于一个时间空间上都连续的可学习粒子给它打一个语义标签它天然就带有了运动和外观的跟踪能力。这个方向我觉得比单纯做渲染更有意思而且实现并不复杂。第三个思路是处理遮挡和光照变化。4DGS处理大遮挡还是吃力可以考虑引入显式的遮挡建模或者可见性预测网络。光照变化目前靠球谐函数硬扛想要表示光源移动导致的真实光照变化大概需要引入材质参数或者light stage数据。6. 阅读总结与个人体会我花了相当长时间才算真正啃明白4DGS这篇论文。回头去看它最大的贡献不是在4D高斯这个概念本身——这个概念在数学上没什么新鲜的。它的贡献在于发现了一个方式让4D高斯能在实时渲染管线上跑起来。把4D投影用泰勒展开近似成3D、把球谐函数扩展成4D版本之后又在渲染方程上做优化、针对动态相机场景做变体区分设计——这些细节靠的是扎实的数学功底和对渲染管线的深刻理解不是随便调参能调出来的。我自己的体会是阅读这类论文不能只看最后的效果数字更值得学习的是作者做取舍的思路哪个环节用精确计算哪个环节用近似都是根据实际需求来定的。全精确的4D积分做不了实时全近似的话就丢掉了动态细节中间的平衡点是大量实验试出来的。复现过程中踩的那些坑也让我对3DGS系列的优化思路有了更具体的理解——密度控制、协方差约束、球谐系数的初始化和学习率调度这些细节脱离实践根本不会意识到有多重要。如果你的工作涉及到动态场景渲染或者想给3DGS加入时间维度做一个自定义的扩展4DGS这篇论文和开源代码值得花几天好好研究。
返回列表