ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

3D Gaussian Splatting 实战:在 GTA: San Andreas 中搭建可漫游高斯场景

3D Gaussian Splatting 实战:在 GTA: San Andreas 中搭建可漫游高斯场景 前阵子社区里流行起一段很特别的演示视频熟悉的 GTA: San Andreas 街景居然变成了由无数半透明“小椭圆”构成的立体影像。镜头可以贴着墙面飞行、从楼顶俯冲、绕着汽车缓慢旋转画面既像点云又像发光玻璃碎片带着一种奇特的体积感。其实这并不是某个 Mod 给原版游戏换了新渲染器而是 3D Gaussian Splatting简称 3DGS也常被称为 Gaussian Splat技术在经典游戏场景里做了一次很直观的落地展示。这篇文章会围绕“Gaussian Splat in GTA: San Andreas”这个主题从技术原理讲到复现思路先搞清楚 3DGS 是什么再看如何到游戏里采集数据、用 COLMAP 估计相机位姿、训练出可自由漫游的高斯场景最后聊一聊怎样把训练结果接到游戏画面里做实时渲染。内容对刚接触三维重建的读者比较友好也适合有渲染基础、想动手做类似技术演示的开发者参考。1. 背景与核心概念1.1 视频里的效果到底是什么如果你第一次看到 Gaussian Splat 做出来的画面很容易把它和“点云”、“雾化粒子”、“滤镜”这些概念混淆。从表面上看画面里所有的物体都像是由一颗颗半透明的光斑组成的边缘带有明显的颗粒感尤其是金属、玻璃、树叶这类材质会呈现出一种“流动的碎片感”。但严格来说视频里的效果并不是给原版游戏画面加了一层滤镜而是把 GTA: San Andreas 的某段游戏世界重新建模成了一组 3D 高斯原语3D Gaussian Primitives。这些高斯原语保存了场景中的空间位置、形状、颜色、透明度等信息。渲染时程序根据当前相机视角把这些高斯原语投影到图片平面上再逐像素进行透明度混合最终生成一帧与原场景视角一致、但质感完全不同的画面。这种做法的优势在于场景是连续的不再是网格模型因此镜头可以非常平滑地穿过物体缝隙。渲染速度快只要 GPU 足够强完全支持实时自由视角浏览。重建过程只需要一组普通照片或视频帧不需要昂贵的扫描设备。所以你在视频里看到的“在 GTA 里自由飞行”本质上是先采集游戏画面再用 3DGS 重建出另外一个“高斯世界”最后把相机控制权交给观察者。1.2 什么是 Gaussian SplatGaussian Splat 的完整名称是 3D Gaussian Splatting这是 2023 年 SIGGRAPH 上提出的一种场景表示与实时渲染方法。它的核心思路很有意思不再用三角形网格来描述一个三维场景而是用大量“3D 高斯分布”来填充场景。每一个 3D 高斯原语可以理解为一个带方向、带大小、带颜色的半透明小椭球。当无数个这样的小椭球组合在一起就能表现出墙壁、车辆、树木、行人等复杂的几何外观。渲染时GPU 把这些椭球按照深度排序后一次性“抛”到屏幕上再在像素层面做 alpha 混合生成最终图像。和 NeRF神经辐射场相比Gaussian Splat 最大的进步是渲染速度和训练速度。NeRF 通常需要隐式地发射射线并做体渲染训练时间动辄以小时甚至天计算实时渲染则需要大量工程优化。而 3DGS 把场景表示成显式的点基元借助传统图形管线里的光栅化思维训练时间可以压缩到几十分钟渲染速度可以跑到实时帧率。这也是它适合做游戏场景演示的原因游戏场景通常结构清晰、视角变化自由对实时性要求很高而这些恰好是 3DGS 擅长的地方。1.3 为什么选择 GTA: San Andreas 做试验场有人可能会问为什么不选一个画质更好的现代游戏做演示原因其实很实际。第一场景复杂度适中。GTA: San Andreas 是 2004 年发行的游戏原版场景的多边形数量远低于现代 3A 大作墙面、道路、建筑纹理大多是重复度较高的烘焙贴图。对于 3DGS 来说这种场景重建难度较低训练时不容易因为材质过于复杂而产生伪影。第二相机控制自由。在游戏里玩家可以步行、开车、切换视角这种自由度非常适合采集多视角数据。重建算法最需要的就是“同一个地方你从多个角度看过”而游戏内可以轻松做到。第三复古画风反而带来视觉冲击。原版游戏画质放到今天已经有些粗糙但一旦被 3DGS 重新表达以后那种带颗粒感的体积光效和特殊材质反射会形成一种“老游戏新视觉”的独特美感。这也是相关视频容易传播的原因之一。第四Mod 工具链成熟。GTA 系列生态里有大量玩家制作工具可以控制游戏内相机、屏蔽 HUD、切换天气、清理路人等。这些能力在做数据采集时非常关键。所以“Gaussian Splat in GTA: San Andreas”并不是一个随意的组合而是技术特点与场景特性高度匹配的结果。2. 3D Gaussian Splatting 核心原理在看实战之前有必要把 3DGS 的内部原理拆开讲一讲否则你在调整参数或排查训练问题时会不知道问题出在哪一层。2.1 场景表示一袋“3D 高斯”3DGS 对场景的表示非常直接场景由大量 3D 高斯原语组成。每个高斯原语包含这些参数位置高斯中心点的三维坐标类似点云中的点。旋转高斯椭球体的朝向用一个四元数表示。缩放高斯在三个轴方向上的尺度决定椭球的胖瘦。颜色通常用球谐系数表示既能表达固定颜色也能表达不同观察角度下变化的颜色。不透明度控制该高斯的透明程度多个高斯叠加后可以近似出复杂表面。如果用公式来表示每个高斯原语就是一个三维高斯分布G(x) exp(-1/2 * (x - μ)^T * Σ^(-1) * (x - μ))其中 μ 是中心位置Σ 是协方差矩阵。协方差矩阵直接控制高斯的形状和方向但直接用矩阵优化很难保证它保持半正定因此 3DGS 会把它拆成旋转矩阵和缩放矩阵来优化。从宏观来看一个训练好的 3DGS 场景一般包含几十万到数百万个高斯原语。高斯的数量不是固定的训练过程中算法会自动增删。2.2 可微光栅化从高斯到像素3DGS 的渲染过程可以被理解成“可微光栅化”。传统光栅化是把三角形投影到屏幕上然后填充像素3DGS 则是把 3D 高斯椭球投影到屏幕上生成一个 2D 高斯斑块再按深度排序从近到远做 alpha 混合。具体来说对于一张输出图像把所有 3D 高斯按当前相机参数投影到图像平面。把图像划分成许多小块tile每个高斯只影响它覆盖到的 tile。在每个 tile 内按高斯中心的深度值由近到远排序。对每个像素遍历覆盖到它的高斯做以下混合C Σ (ci * αi * Ti) Ti Π (1 - αj) j 在当前高斯之前其中 ci 是高斯颜色αi 是该高斯在像素位置的不透明度权重Ti 是前序高斯的累计透射率。这个过程和传统图形学里的“透明物体排序混合”非常像。也正是因为这种接近光栅化的设计3DGS 才能充分利用 GPU 并行能力实现高帧率渲染。2.3 训练过程与自适应密度控制3DGS 的训练目标是让渲染出来的图像尽可能接近真实图像。损失函数通常是两部分组合Loss (1 - λ) * L1 λ * D-SSIML1 损失保证像素颜色接近D-SSIM结构相似性损失保留局部边缘和纹理结构。λ 一般取 0.2 左右。训练中间算法会做一项非常关键的操作自适应密度控制。当某个区域的几何信息不够精细重建出的图像与真实图差异较大并且梯度信号强烈时算法会在该位置把高斯克隆或分裂成多个更小的高斯。当一个高斯的不透明度变得很低或者体积过大、几乎不参与有效渲染时算法会把它剪枝掉。这个机制使得一开始可能只需要几千个高斯初始化随着训练迭代场景会自动增加高斯数量最终达到精细还原的效果。这也是 3DGS 训练速度快的一个重要原因不需要像 NeRF 那样一直维持一个庞大的隐式神经网络。2.4 与 NeRF、传统网格重建的差异方法场景表示训练速度渲染速度适合场景传统网格重建显式三角形网格中快规则物体、室内、工业建模NeRF隐式神经场慢较慢需要大量优化复杂反射、透明物体、学术研究3DGS显式 3D 高斯集合快快接近实时实景重建、游戏场景、动态视频和 NeRF 相比3DGS 的优势是训练和渲染都快得多和传统网格重建相比3DGS 不需要做复杂的表面提取和贴图映射而是直接“用点堆出形状”因此在植被、布料、烟尘这类无规则物体上有更好的表现。3. 环境准备与实验设计3.1 硬件要求做 3DGS 相关实验硬件上首先要有一块 NVIDIA 显卡。这里不是搞品牌偏好而是 CUDA 生态下 PyTorch、COLMAP 的 GPU 加速、3DGS 的光栅化实现都最成熟。训练阶段建议 8GB 及以上显存。8GB 可以跑小场景16GB 以上会更从容。实时渲染阶段如果只做离线视频录制训练显卡即可如果要在游戏内实时运行推荐 RTX 4070 以上RTX 4080/4090 会舒服很多。内存16GB 起步数据较多时 32GB 更稳妥。硬盘图片、COLMAP 工程、模型文件都不小建议 SSD。如果你的显卡显存不大可以把输入图片分辨率压到 1280 或者 1600 再训练效果下降不明显但显存压力会小很多。3.2 软件依赖实际开发时可以用 Windows 也可以使用 Ubuntu 作为训练环境。如果是纯训练和渲染演示Windows 上也可以完成但如果你打算深入改渲染代码Ubuntu 环境编译调试会更方便一些。核心依赖如下Python 3.8 到 3.10具体以你使用的开源仓库要求为准。PyTorch建议 2.0 及以上CUDA 版本以本机驱动为准。COLMAP用于从图片序列中恢复相机位姿和稀疏点云。ffmpeg用于从游戏录屏中抽帧。NVIDIA CUDA Toolkit版本需要和 PyTorch 匹配。开源实现方面最主流的有以下几个方向官方 3DGS 仓库gaussian-splatting包含完整的训练和查看器代码。gsplat伯克利等团队维护的高性能 3DGS 库接口更轻量适合二次开发。Nerfstudio集成了多种神经渲染方法也支持 3DGS 数据流程适合做实验管理。这些仓库的依赖安装方式在各自 README 里都有说明。版本更新很快不要照搬旧博客的安装命令以仓库当前要求为准。3.3 项目目录与整体流程建议把实验目录规划成下面这种结构gta-splat-lab/ ├── data/ │ ├── raw_video/ │ │ └── gta_scene.mp4 │ ├── frames/ │ │ └── frame_0001.jpg │ └── gta_scene/ │ ├── images/ │ └── sparse/ ├── output/ │ └── gta_scene_run1/ └── envs/整体流程可以拆成四步在游戏内录制一段围绕目标场景的视频。用 ffmpeg 抽帧并做必要的去重和筛选。用 COLMAP 得到相机位姿和稀疏点云。用 3DGS 训练生成高斯场景最后做可视化或接入实时渲染。后面第 4 节会按这个流程一步步展开。4. 实战从 GTA 场景到 3D 高斯场景4.1 游戏内数据采集数据采集是整个流程里最容易影响最终效果的一步也是“Gaussian Splat in GTA: San Andreas”这类演示里最耗时的一步。在游戏里录制视频时需要注意几个原则选择静态场景。建筑、街道、公园这些不会动的物体最适合重建。行人、车辆、动物这类动态物体会在训练时产生重影尽量避开。固定天气和时间。GTA: San Andreas 的天气会变化光照方向和信息不一致会让重建结果变得很糊。建议把游戏时间锁住或者使用 Mod 固定为晴天白昼。控制移动速度。镜头移动太快会导致画面动态模糊影响 COLMAP 的特征匹配。最理想的是步行慢速环绕或者用 Mod 控制的固定轨道相机。保证画面干净。录制时建议隐藏 HUD、小地图和武器栏避免 UI 被当成真实场景数据。覆盖足够多的角度。同一个建筑最好从正面、侧面、背面、远处、近处都拍到这样重建出来的几何才完整。实际操作时可以先录一段 2 到 3 分钟的视频围绕一个街区或者一个特定建筑移动。一次不要贪多先从一个较小的场景跑通全流程。4.2 用 ffmpeg 抽帧录屏得到视频后第一步是抽帧。假设视频文件是gta_scene.mp4目标是每秒抽 10 帧图片mkdir -p data/frames ffmpeg -i data/raw_video/gta_scene.mp4 -vf fps10 -q:v 2 data/frames/frame_%04d.jpg参数含义-i输入视频文件。-vf fps10视频滤镜强制每秒输出 10 帧。-q:v 2JPEG 编码质量数值越小质量越高2 是一个比较安全的选择。frame_%04d.jpg输出文件名模板会生成frame_0001.jpg、frame_0002.jpg这样的文件。如果视频是 60 帧录制每秒抽 10 帧2 分钟视频大约可以得到 1200 张图片。这个数量对一个小场景是足够的但 COLMAP 跑起来会比较慢。可以先用fps5试跑验证全流程能通再增加密度。4.3 基于帧间相似度去重连续视频帧之间的视角变化往往很小如果直接全部丢给 COLMAP不仅浪费计算资源还可能因为特征点过于相似导致位姿估计退化。一个简单的做法是通过计算相邻帧之间的图像相似度把变化太小的帧过滤掉。下面给出一个用 Python OpenCV 实现的简化脚本import cv2 import os source_dir data/frames output_dir data/frames_filtered os.makedirs(output_dir, exist_okTrue) prev_gray None idx 0 for name in sorted(os.listdir(source_dir)): path os.path.join(source_dir, name) img cv2.imread(path) if img is None: continue gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray cv2.resize(gray, (320, 180)) if prev_gray is not None: psnr cv2.PSNR(prev_gray, gray) if psnr 30: continue prev_gray gray cv2.imwrite(os.path.join(output_dir, fframe_{idx:04d}.jpg), img) idx 1 print(f保留帧数: {idx})这里用 PSNR 作为相似度指标PSNR 越高表示两帧越接近。当 PSNR 大于 30 时说明变化太小就跳过。更严谨的做法是改用 SSIM但对游戏场景来说这个简化脚本已经能过滤掉大量冗余帧了。这里需要说明一下过滤掉的帧数如果太多可能导致相机轨迹不连续。建议第一次跑不要设置太严格先过滤到 300 到 600 张左右的量级再根据 COLMAP 结果调整。4.4 用 COLMAP 估计相机位姿3DGS 训练不能直接使用图片它需要知道每张图片对应的相机内外参数。这个任务通常交给 COLMAP 完成。COLMAP 的流程分为三步特征提取、特征匹配、稀疏重建。首先创建工程目录mkdir -p data/gta_scene/images mkdir -p data/gta_scene/sparse # 把筛选后的图片拷贝到 images 目录 cp data/frames_filtered/*.jpg data/gta_scene/images/然后运行特征提取colmap feature_extractor \ --database_path data/gta_scene/database.db \ --image_path data/gta_scene/images \ --ImageReader.single_camera 1--ImageReader.single_camera 1表示所有图片都来自同一台相机对游戏录屏场景来说非常合适因为游戏中通常只有一个固定视角相机。接着做特征匹配colmap exhaustive_matcher \ --database_path data/gta_scene/database.dbexhaustive_matcher会做全量匹配适合图片数量不是特别多的场景。如果图片数量超过 1000 张可以换成sequential_matcher它会根据相邻帧关系做匹配速度更快colmap sequential_matcher \ --database_path data/gta_scene/database.db最后做稀疏重建colmap mapper \ --database_path data/gta_scene/database.db \ --image_path data/gta_scene/images \ --output_path data/gta_scene/sparse成功后data/gta_scene/sparse/0/目录下会生成三个文件cameras.bin、images.bin、points3D.bin。它们分别保存相机内参、图像位姿、稀疏点云。如果使用的 COLMAP 是 Windows GUI 版本也可以通过界面依次点击“Feature extraction”、“Feature matching”、“Reconstruction”完成同样操作底层逻辑是一样的。4.5 训练 3D Gaussian Splatting 模型拿到 COLMAP 结果后就可以开始训练了。以官方 gaussian-splatting 仓库为例目录结构需要满足data/gta_scene/ ├── images/ │ ├── frame_0000.jpg │ └── ... └── sparse/ └── 0/ ├── cameras.bin ├── images.bin └── points3D.bin然后执行训练git clone https://github.com/graphdeco-inria/gaussian-splatting cd gaussian-splatting # 创建 conda 环境具体命令以仓库 README 为准 conda env create --file environment.yml conda activate gaussian_splatting python train.py \ -s ../data/gta_scene \ -m ../output/gta_scene_run1 \ --iterations 30000参数说明-s源数据目录包含images和sparse。-m模型输出目录训练日志、checkpoint、最终模型都会写到这里。--iterations总迭代次数默认 30000对游戏场景来说已经足够。训练过程中可以观察 loss 的变化。正常情况下loss 会在前几千步快速下降后期进入缓慢收敛阶段。显存占用也会随高斯数量增加而上升。如果你使用的是 gsplat 等轻量库训练入口通常是examples/simple_trainer.py参数略有不同但数据准备流程一致。不同仓库对数据格式的定义可能有差异动手前先读一下对应的 README。4.6 可视化与模型导出训练完成后在输出目录下会生成一个point_cloud.ply文件。这个文件里保存的并不是普通点云而是所有 3D 高斯的参数包括位置、旋转、缩放、球谐系数、不透明度。普通点云查看器虽然能打开.ply文件但通常只会显示坐标和颜色无法还原高斯渲染效果。正确的方式是使用专门支持 3DGS 的工具官方仓库自带的 SIBR 查看器能在本地加载训练好的模型并自由浏览。SuperSplat 这类网页工具可以直接把.ply或.splat文件拖进去预览。部分游戏引擎插件例如 Unity 和 Unreal Engine 社区中已经有一些 3DGS 插件可以直接导入导出的.ply文件。下图是可视化阶段最典型的验证方式加载模型后用鼠标旋转视角观察墙壁、路面、车辆是否稳定远处是否出现明显的漂浮噪点。如果确认效果可以可以进一步导出为.splat格式这个格式更紧凑适合 Web 端预览或后续引擎集成。5. 进阶让 Gaussian Splat 在游戏内“跑起来”搞定离线重建和查看器漫游之后下一个更有挑战性的目标是像视频演示那样让 Gaussian Splat 真正接入游戏画面或者至少像游戏一样可以自由交互。这一节讨论几条不同的技术路径。5.1 先想清楚你看到的视频是实时还是录播在看演示视频时一个容易被忽略的问题是画面是实时渲染还是离线录制3DGS 在高端显卡上确实可以实时渲染但帧率取决于高斯数量、渲染分辨率和光栅化实现。如果一个场景包含 300 万个高斯在 1080p 分辨率下RTX 4090 可能跑到几十到上百帧如果把分辨率升到 4K帧率会明显下降。视频里那种流畅丝滑的镜头运动有可能是实时渲染后录屏这种情况说明作者做了大量性能优化先渲染成图像序列或视频再剪辑成片这种情况对显卡要求不高。在动手之前先明确自己的目标。如果只是想复现视觉效果用独立查看器录制视频就够了如果想在游戏进程里实时看到高斯场景那需要走更复杂的渲染集成路线。5.2 路径一离线重建 独立查看器最稳妥、也最容易上手的方案是“重建一份高斯场景然后用独立查看器浏览”。具体做法很简单训练完成后使用官方 SIBR 查看器或 SuperSplat 打开模型用鼠标控制相机环绕漫游。虽然这不是严格意义的“在 GTA 游戏内”但视觉呈现上已经和视频里看到的非常接近了。这条路径适合只对重建效果感兴趣不想碰游戏引擎或逆向工程想快速验证不同场景的采集和训练参数需要把结果分享给其他人生成一段录屏演示。如果你希望做一些游戏化交互比如控制角色在高斯场景里走动可以把.ply导入 Unity 或 Unreal Engine。这个方案不碰原版游戏进程开发难度低得多也更安全。5.3 路径二导入游戏引擎做可交互场景Unity 和 Unreal Engine 社区目前已经有多个 3DGS 相关插件虽然不同插件的 API 和性能有差异但总体思路一致把训练好的.ply或.splat文件导入引擎资源目录。使用插件提供的渲染组件加载高斯场景。放入一个自由飞行相机或第三人称控制器。发布为独立程序。这种做法的最大优点是完全不依赖原版 GTA 程序不存在逆向工程和兼容性问题。你可以把重建后的圣安地列斯街景做成一个全新的“可漫游小场景”然后任意添加玩法逻辑。缺点是导入后的场景没有原版游戏的碰撞体、任务脚本和物理系统你需要自己定义可活动范围。如果只是做互动演示这个问题不大。5.4 路径三Mod / Render Hook 实时合成真正的“Gaussian Splat in GTA: San Andreas”大概率走的是第三条路径通过 Mod 或 Render Hook 技术把 3DGS 渲染结果与游戏原始画面合成或者直接替换掉游戏画面。这种方案的通用架构可以简化为# 伪代码每帧渲染流程仅用于说明思路 while running: # 1. 从游戏进程中获取当前相机参数 view_matrix game_hook.get_view_matrix() proj_matrix game_hook.get_projection_matrix() # 2. 把相机参数交给 3DGS 渲染器 gaussians load_gaussian_scene(gta_street.splat) gs_image gaussian_renderer.render( gaussians, view_matrix, proj_matrix, width1920, height1080 ) # 3. 获取游戏当前帧的后缓冲 game_image game_hook.get_back_buffer() # 4. 合成并输出 final_image compose(game_image, gs_image) game_hook.present(final_image)虽然这段代码是伪代码但它已经揭示了完整的链路。实际开发中比较常见的做法是用 D3D11/D3D12 或者 Vulkan 的 Hook 方式拦截游戏渲染线程从游戏内存中读取视图矩阵和投影矩阵或者通过 Mod 框架拿到相机数据在游戏画面渲染完成后把 3DGS 画面叠加到后缓冲上处理原始场景与高斯场景的遮挡关系例如用深度缓冲做混合。这条路线的工程难度不低而且涉及对游戏进程的内存读取、渲染管线 Hook、矩阵换算等问题。如果只是学习和研究建议把操作范围限制在本地单机环境不要破坏游戏的在线服务或绕过任何保护机制。这类技术实验的价值更多在于图形学实践本身。5.5 实时合成的几个关键工程点如果决定走实时合成路线下面几个问题是你绕不开的。第一坐标系统一。GTA: San Andreas
返回列表