假设你接了一个游戏开发任务:要在虚拟世界里造一座真实的古城。传统美术师会拿着游标卡尺测量、建模、雕刻纹理,忙上一个月。而如今新一代的“泡泡魔术师”处理方式完全不同——他们朝三维空间里吹出成千上万颗彩色半透明的小泡泡,每颗泡泡都有自己的位置、大小、颜色和透明度。调整完毕后,从任何角度看去,这些泡泡层层叠叠形成的画面,足以骗过玩家的眼睛。 这项技术叫“3D高斯泼溅”(3D Gaussian Splatting,简称3DGS)。“3D“指的是泡泡悬浮在三维空间中;”高斯“形容每颗泡泡的密度从中心向外呈钟形曲线衰减,中间实、边缘淡;”泼溅“则指渲染时像扔水球一样把泡泡快速”甩”到画布上合成图像。训练过程就像一位艺术家反复端详真实照片,不断微调每一颗泡泡,直到从任意视角看都真假难辨。这篇文章将带你完整看一看:泡泡从哪来、如何自动繁衍、怎么泼溅成画,以及如何让它真正住进游戏引擎。
对游戏AI与图形从业者而言,掌握3DGS意味着掌握一条从真实场景到实时可玩数字资产的完整生产力链路,是AIGC内容生成时代极具价值的硬技能。
可视化演示
演示3D Gaussian Splatting生成3D场景:多视角采集、高斯点云优化训练,新视角实时渲染,生成高质量游戏场景。
本节配有交互动效(进入视口后自动加载,约 3KB)。
采集 视点 图像 capture 多视角采集场景图像
3DGS基础原理
假如游戏美术师想用“吹泡泡”的方法造一棵树:他不是用三角网一块块拼接树皮和树叶,而是朝空中吹出几百颗彩色半透明的小气泡——深褐色的排成树干,翠绿色的聚成树冠,每一颗的位置、大小、颜色、透明程度都可以单独调节。整个三维场景,就是成千上万颗小气泡的集合。这,就是3D高斯泼溅最朴素的模样。
在数学家眼里,每颗气泡都有精确的“脾气曲线”:从中心向外,它的密度沿一条钟形曲线缓缓衰减——正中间最实在,越到边缘越淡。这条曲线就是统计学中赫赫有名的高斯分布。所以“3D高斯”并不是什么玄乎的高维概念,它只是说:每颗气泡的中心区域更厚实、边缘更透明。
具体到3DGS,每颗高斯小球用四个核心参数定义:位置均值μ、协方差矩阵Σ、颜色c、不透明度α。μ决定气泡飘在哪里;Σ由旋转矩阵R与缩放矩阵S组成,决定它胖瘦和朝向;c通常用一组球谐系数表达,让同一颗气泡从不同角度看有轻微颜色变化,这正是视差与光照效果的小秘密;α则控制透不透光。一颗气泡对空间任一点的影响力写作:
现在你再看任何一张游戏截图,不妨把它想象成无数颗半透明气泡的“集体合影”。理解了底层表示,后面所有环节——重建、繁衍、泼溅、优化——都只是围绕“怎么把几十万颗气泡调整到位”的舞蹈。
- 查询点x三维空间中任意一个坐标点,它是我们“询问”的对象——这个点是否落在某颗气泡的影响范围内。
- 中心位置μ气泡的中心坐标(均值),决定泡泡飘在场景的哪个位置。
- 协方差矩阵Σ描述气泡的形状、胖瘦与朝向,由旋转矩阵R与缩放矩阵S按Σ=RSS^T R^T组合而成。
- 指数衰减中心处指数为0、函数值为1(最亮),越往外指数越负,值越接近0(越透明),宛如泡泡边缘渐渐淡去。
- 整体含义g越接近1,说明该点与这颗气泡“融为一体”的程度越高,渲染时按这个权重混合颜色。
场景重建流程
想象你站在一片真正的森林前,掏出手机围着它绕上一圈,从各个角度按下快门。回家后,你把照片喂给一台“泡泡吹制机”,它从照片里猜出每颗气泡该在哪儿、该是什么颜色,一点点复刻出这片森林。真实世界通往电子世界的桥,就这样搭了起来。
这台“吹制机”的第一步不是乱吹,而是先请一位几何测量员——COLMAP。它用运动恢复结构(SfM)在多张照片间匹配特征点,既估计出每张照片拍摄时的相机位姿,又生成一片稀疏点云。这些稀疏点就是第一代气泡的种子:每颗点云点被直接当成一颗初始高斯,颜色取照片对应位置的平均色。
有了种子,训练才真正开始。优化器手持每一帧照片当作“标准答案”,不断调整每颗气泡的参数,同时通过相机投影关系把3D气泡映射到2D像素坐标。投影的数学形式简洁而经典:
整个过程就像一位画家先勾出草稿(稀疏点云),再反复对照照片填色、调位置,直到每个角度都无懈可击。对游戏团队来说,这意味着再复杂的实景建筑,只要镜头扫一圈,就能变成可进入游戏引擎的三维资产。
- 世界点P场景中一个三维点,比如树梢顶端在世界坐标系下的坐标。
- 旋转R与平移t相机外参,表示相机在哪儿、朝哪儿看,相当于相机的位置和转头角度。
- 坐标变换把世界坐标转到以相机为原点的相机坐标,是一步刚体变换。
- 内参K包含焦距f和光心(cx, cy)等参数,相当于镜头的焦距与传感器偏移。
- 像素坐标p投影结果,即“树的顶端最终落在照片的哪个像素上”。
密度化与优化
气泡吹出来后,不一定会一次到位。想象你吹了一颗巨大的泡泡盖住整棵树冠,树叶的凹凸细节全被模糊掉了。聪明的魔术师会凑近观察:发现某处“糊了”,就拿起手术刀把大泡一分为二,换成两颗小泡;发现某处漏了馅,就克隆一颗放到旁边。这个“边看边繁衍”的过程,学术上叫自适应性密度化。
怎么判断该给哪颗气泡做手术?靠的是“信号”——梯度。每轮训练,损失函数会把“哪里画错了、错多少”沿反向传播算到每颗气泡头上:梯度大,说明这颗气泡对误差负主要责任,也说明它的容量已经不足以刻画这片区域。
因此3DGS每训练若干轮就统计所有高斯的梯度模长,当某颗高斯的梯度模长超过阈值τ时触发机制:欠覆盖的小气泡执行克隆(clone),过覆盖的大气泡执行分裂(split)。同时,透明度过低或体积过大的“飞点”会被直接剪除。训练过程中损失函数取L1与SSIM的加权组合,记为L = (1−λ)L1 + λ·L_SSIM。密度化触发条件写作:
正因如此,3DGS训练像一场“优胜劣汰”的进化:气泡从一万起步,随着训练自动涨到几十万,该加密的地方密密麻麻,该空旷的地方稀稀落落。游戏场景里远处山体用大泡、近处草叶用小泡,这套自适应机制功不可没。
- 损失L衡量当前气泡画面与真实照片的差异,数值越小说明越逼真。
- 梯度算子对损失函数求关于气泡中心位置μ的偏导,指“往哪挪、挪多少能减少误差”。
- 梯度长度把三维梯度向量取模,表示该气泡对整体误差的影响总幅度。
- 阈值τ一个超参数,梯度超过它就认为该处细节严重不足,触发克隆或分裂。
- 自适应控制每N轮检查一次,让气泡总量随场景复杂度自动生长。
实时渲染管线
成品吹好后,玩家要看画面了。想象放映室里有一块空白银幕,气泡按“由远到近”排好队,依次被投到银幕上:最远的山先投,半透明的树再盖上,最后是面前的一朵花。因为后投放的会吸收前面透来的光,整体看上去就有了天然的立体层次。
计算机里的步骤与放映过程一一对应:第一步投影,3D高斯通过相机内外参变成2D屏幕上的椭圆;第二步排序,所有椭圆按到相机的深度排成由远到近的队列;第三步合成,把队列里的椭圆逐层alpha混合。原始3DGS论文把三步实现成高度并行的光栅化算法,GPU上千万颗高斯同时工作,因此能达到实时帧率。
合成时,屏幕每个像素的颜色由所有覆盖它的椭圆按透明度加权求和:
回到游戏的比喻:玩家觉得场景“立体又真实”,并不是因为模型雕刻得精细,而是每颗气泡都被放在了正确的深度上,层层叠叠地盖出了明暗与遮挡。这就是“泼溅”二字的由来——不是精雕细琢,而是高效地“撒”出整个世界。
- 图层总数N场景中覆盖该像素的高斯数量,比如几十颗。
- 第i层颜色c_i排序后第i颗气泡的颜色,由球谐系数决定。
- 不透明度α_i该气泡的透明度,1为完全不透,0为全透明。
- 累积透光率从第1到第i−1层都没挡住的光线比例,等于它们(1−α)的连乘。
- 加权求和把每一层的贡献累加起来,得到最终像素颜色,远处图层自然被近处遮盖。
游戏场景应用
有了这门手艺,游戏美术团队的工作方式彻底变了。以前做一座古建筑,需要测量、建模、贴图、烘焙,动辄几周;现在只要围着建筑拍一圈视频,交给3DGS训练一晚,第二天就能得到可在引擎里随意游走的建筑模型。
从图像到可交互场景,3DGS天然贴合游戏生产管线:输出是显式的高斯集合而非隐式网络,因此可以导出成自定义格式进入Unity、虚幻引擎。PBR光照、阴影、碰撞体可以围绕高斯集进一步生成,团队只需把它当作一种“新型几何资产”。
但这也不是零成本魔法。训练耗时的“账本”可用一个关系式粗略估算——它与视角数量、高斯数量、迭代轮数近似成正比:
对游戏工作室来说,3DGS像一台“时空复印机”:把真实景观复制成虚拟资产。开放世界里的城市街区、山川峡谷、博物馆内景,都能以极低成本批量生产,美术师得以解放出来,专注于角色、玩法和叙事。
- 正比符号∝表示训练耗时与右侧三因子大致呈线性关系,不是精确等式。
- 视角数量采集的照片或视频帧数,视角越密质量越好,时间也越久。
- 高斯数量当前场景中气泡总量,细节越丰富数值越大。
- 迭代轮数训练轮数,通常几千到几万步。
- 工程估算用这个关系式预判“拍多少素材、训练多久”才能满足项目排期。
性能特性与挑战
气泡虽妙,但吹得太满也会撑爆气球。一个中等规模的场景轻松攒出两三百万颗气泡,每颗都要记住位置、旋转、缩放、颜色和透明度,GPU显存与磁盘空间都面临不小的压力。
先讲优点:3DGS训练速度比NeRF这类神经辐射场快数倍到数十倍,渲染更是为实时而设计——不只是画质好,而是“快”得符合游戏引擎的脾胃。再讲缺点:每颗高斯约4.5KB参数(含球谐系数),两百万颗就是9GB显存,直接硬塞显卡对中小团队是不小的负担。
显存占用的估算公式简单得令人意外:
更大的隐患是“视角依赖”:拍过的角落泡泡认识,没拍过的背面泡泡只能瞎猜,画面发糊或出现漂浮碎片。游戏团队若把3DGS当成万能扫描仪,不做好采集规范和后期检查,验收时就会遭遇“正面精致、背面翻车”的尴尬。用好3DGS,既要知道它有多快,更要懂它的边界。
- 显存占用M整个高斯场景在GPU上占用的内存,单位通常为MB或GB。
- 高斯数量N训练收敛后场景中保留的气泡总数。
- 单颗开销每颗高斯存储位置、协方差、球谐颜色与透明度所需字节数。
- 线性放大气泡翻倍,显存直接翻倍,没有讨价还价的余地。
- 数量级验证200万×4.5KB≈9GB,这就是GPU显存警报的来源。
优化策略
既然气泡太多会撑爆显卡,那就给它做“瘦身计划”。跟整理衣柜一个道理:不穿的衣服扔掉,暂时用不到的收进高处,常穿的放在手边。3DGS的工程优化正是这个思路:分层、剪枝、压缩。
LOD(Level of Detail)是游戏引擎里成熟的手法:远处玩家看不清细节,就用少而大的气泡渲染;走近再切换成密集气泡。配合流式加载,只在相机周围加载高精度分区,内存占用可成数量级下降。同时,训练收敛后做一次高斯剪枝,把不透明度趋近于0、体积过大的飞点彻底删除,数量往往能砍掉20%~50%而画质几乎无损。
压缩率的选择需在显存和画质间权衡,压缩后保留的气泡数量:
把这些手段叠加起来,一座原本要9GB显存的山城,可能被压到1GB以内,同时保持60帧的流畅体验。到这一步,“吹泡泡”的魔法才真正在游戏引擎里落了地。从原理到工程,3DGS带来的不只是更快,更是更聪明的场景生产之道。
- 压缩后数量N'剪枝与压缩后保留下来的高斯总数。
- 原始数量N训练刚收敛时的气泡总量。
- 压缩率r被移除气泡的占比,0.5代表砍掉一半。
- 约束条件r不能等于1,否则场景被清空,画面完全消失。
- 工程实践量化位置与颜色为低精度类型、用八叉树组织空间,再把各手段叠加。
AI 应用场景
开放世界实景采风
阶段:AIGC游戏内容生成(场景资产训练与导出)
解决的问题:传统手工建模一座真实地貌需要美术组驻扎一个月;用3DGS只需无人机环绕拍摄视频,训练一夜即可得到可用场景资产,工期压缩到原来的一成。
具体案例:某开放世界团队要把张家界地貌搬进游戏。无人机以50米高度环绕拍摄4K视频约20分钟,COLMAP求取位姿与稀疏点云后,3DGS在8张A100上训练约6小时,输出200万高斯直接导入虚幻引擎。美术师只做少量修补和碰撞体标注,两周后玩家已可在其中自由奔跑。
虚拟制片实时预演
阶段:AI生成三维场景(影视预演与导演走位)
解决的问题:影视剧组拍摄前需要可交互的现场三维草稿,传统扫描设备昂贵且慢;3DGS用普通单反绕着片场拍一圈,快速生成可漫游的高斯场景。
具体案例:某虚拟制片棚扫描了800平方米的实景影棚。导演戴上VR头显在3DGS场景中调整机位、排练走位,灯光美术同步在引擎中预览光效,确定方案后再实拍,节省了大量现场调试时间。
数字孪生网游玩法
阶段:AI生成游戏资产(街道数字化与实时漫游)
解决的问题:智慧城市沙盘游戏需要海量真实街道模型;3DGS把无人机巡拍数据快速转成低显存场景,用LOD分级后可在移动端流畅漫游。
具体案例:某数字孪生项目扫描了一条3公里商业街。对每100米街区单独训练一个3DGS子场景,按玩家位置流式加载,剔除冗余气泡并量化压缩后,总显存从12GB降到1.2GB,手机端也能以30帧运行。
Python 演示
import numpy as np class SplatScene: """二维简化版高斯泼溅场景:用气泡合成一张低分辨率图。""" def __init__(self, count=40, seed=7): rng = np.random.default_rng(seed) self.count = count self.positions = rng.uniform(-1, 1, (count, 2)) self.radii = rng.uniform(0.06, 0.22, (count, 2)) self.colors = rng.uniform(0, 255, (count, 3)) self.alpha = rng.uniform(0.15, 0.6, (count,)) self.depth = rng.random((count,)) def render(self, width=28, height=14): canvas = np.full((height, width, 3), 240.0) ys, xs = np.mgrid[0:height, 0:width].astype(float) order = np.argsort(self.depth)[::-1] # 从远到近 for i in order: cx = (self.positions[i, 0] + 1) / 2 * (width - 1) cy = (self.positions[i, 1] + 1) / 2 * (height - 1) rx = max(self.radii[i, 0] * width, 0.5) ry = max(self.radii[i, 1] * height, 0.5) dist = ((xs - cx) / rx) ** 2 + ((ys - cy) / ry) ** 2 weight = np.exp(-0.5 * dist) * self.alpha[i] weight = np.clip(weight[..., None], 0.0, 1.0) canvas = (1 - weight) * canvas + weight * self.colors[i] return canvas.astype(np.uint8) @staticmethod def to_ascii(canvas): chars = " .:-=+*#%@" gray = canvas.mean(axis=2) idx = (gray / 255 * (len(chars) - 1)).astype(int) return "\n".join("".join(chars[v] for v in row) for row in idx) if __name__ == "__main__": scene = SplatScene(count=48) image = scene.render() print(scene.to_ascii(image))
self.positions = rng.uniform(-1, 1, (count, 2))随机撒出气泡中心,模拟稀疏点云初始化。self.depth = rng.random((count,))每颗气泡的深度值,决定泼溅顺序。order = np.argsort(self.depth)[::-1]按深度从远到近排序,这是正确合成的前提。dist = ((xs - cx) / rx) ** 2 + ((ys - cy) / ry) ** 2计算每个像素到气泡中心的椭圆归一化距离。weight = np.exp(-0.5 * dist) * self.alpha[i]二维高斯衰减乘以不透明度,得到该气泡对像素的贡献权重。canvas = (1 - weight) * canvas + weight * self.colors[i]alpha合成核心公式:新颜色按权重覆盖旧颜色。np.clip(weight[..., None], 0.0, 1.0)把权重限制在[0,1],防止数值越界。scene.to_ascii(image)把RGB画布转成字符画,便于在终端直接“看见”渲染效果。
常见误区
误区3DGS是不是和NeRF一样,用深层神经网络隐式表示场景?那训练一定很慢吧。
正解3DGS恰恰相反。它没有任何神经网络,场景就是一堆显式的高斯椭球参数。NeRF把场景塞进网络权重里,查询每个像素都要做繁重的体渲染;3DGS把参数摊在桌面上,排序后直接泼溅,所以训练快一两个数量级,渲染还能达到实时帧率。
为何常见:两者同为三维重建新方法且同期爆火,很多人自然把“AI重建”统一想象成神经网络魔法。
误区既然高斯越多细节越好,训练时就疯狂加高斯,数量翻倍画质肯定翻倍。
正解密度化不是无脑加:欠覆盖区域克隆,过覆盖区域分裂,透明度过低或体积过大的飞点会被剪掉。无限制增加高斯只会使显存、排序时间同步上涨,最终得到一份又糊又卡顿的场景,还可能过拟合训练视角。
为何常见:点云处理中“点数越多越精细”的直觉深入人心,但3DGS的显存与渲染开销是硬约束。
误区反正AI自动建模,我拿手机随便拍几十张照片,就能重建出完美的游戏场景。
正解相机位姿需要COLMAP等SfM先估计,视角覆盖决定质量:每处都被拍到的区域山清水秀,没拍到的背面一定发糊或飘浮。采集时必须保证环绕、重叠、光照均匀,重建结果才谈得上进入引擎。
为何常见:只看到演示视频里“照片秒变3D”的高光时刻,没看到背后严苛的采集规范与大量失败案例。
误区所有高斯一次性扔到屏幕上就行,反正都是半透明的,顺序无所谓。
正解顺序至关重要。alpha合成公式里,前面图层的累积透光率会乘到后面图层上;顺序错乱会出现“前面的草被后面的山盖住”的穿帮。因此每帧都要把高斯按深度重新排序,再逐层泼溅。
为何常见:平时看惯了不透明三角形的画家算法,忽略了半透明物体必须严格排序叠加。
误区3DGS能直接替代游戏建模,角色、武器、动画全部用它生成。
正解3DGS擅长从真实照片/视频复刻静态空间,如城市街区、建筑内景。需要绑骨骼、做动作的原创角色、程序化生成的赛道,仍走传统建模与动画管线。两者是互补关系,不是替代关系。
为何常见:技术宣传片总把“实景扫描”拍得像万能造物机,容易让人高估技术边界。
面试题
Q1. 3DGS中用来表示场景的基本单元是什么?
- A.体素网格
- B.三维高斯分布← 正确答案
- C.神经网络权重
- D.三角面片
答案:B。3DGS用显式三维高斯(半透明气泡)集合表示场景,每颗高斯有自己的位置、形状、颜色和透明度。体素网格是传统离散表示,神经网络权重是NeRF的思路,三角面片是传统网格建模,都不是3DGS的基本单元。
Q2. 3DGS相比NeRF的最大优势是什么?
- A.训练数据更少
- B.支持实时渲染← 正确答案
- C.不需要相机位姿
- D.无需任何训练
答案:B。3DGS采用显式高斯表达与光栅化渲染,摆脱了NeRF逐像素体渲染的沉重代价,GPU上可达到实时帧率。训练数据更少并非本质差异,相机位姿仍需估计,训练更是必不可少。
Q3. 3DGS训练时通常用什么来初始化高斯位置?
- A.随机撒点
- B.均匀网格
- C.稀疏点云← 正确答案
- D.深度图投影
答案:C。3DGS用COLMAP等SfM工具生成稀疏点云,每颗点直接作为初始高斯。随机撒点与均匀网格缺乏场景结构信息,深度图投影则需额外深度传感器,都不是标准方案。
Q4. 密度化过程中,当某颗高斯的梯度模长超过阈值时会发生什么?
- A.删除该高斯
- B.克隆或者分裂← 正确答案
- C.随机翻转位置
- D.缩小整个场景
答案:B。梯度超阈值说明该区域误差大、细节刻画不足,系统会执行克隆(小泡欠覆盖时复制)或分裂(大泡过覆盖时一分为二)。删除是针对于透明度过低的冗余飞点,随机翻转和缩放场景都不属于密度化机制。
Q5. 3DGS渲染时按什么顺序合成高斯才能得到正确图像?
- A.由近到远
- B.由远到近← 正确答案
- C.随机顺序
- D.按颜色排序
答案:B。alpha合成要求从远到近逐层叠加,远的先画、近的后盖,利用累积透光率形成正确的遮挡关系。由近到远会把远处气泡错误地盖在近处之上,随机顺序和按颜色排序更会产生严重穿帮。
Q6. 3DGS训练常用的损失函数是哪种组合?
- A.仅L1像素差
- B.仅SSIM结构差
- C.L1加SSIM联合← 正确答案
- D.交叉熵损失
答案:C。原始论文采用L1损失与SSIM结构损失的加权组合,兼顾像素级保真与人眼感知结构相似度。单独一种损失会顾此失彼,交叉熵针对分类任务,均不合适。
Q7. 每颗3D高斯通常由哪些参数描述?
- A.均值协方差颜色与透明度← 正确答案
- B.顶点法线与纹理贴图
- C.权重偏置与激活函数
- D.深度法线与光照参数
答案:A。3DGS每颗高斯的位置由均值μ描述,形状由协方差Σ(旋转+缩放)描述,加上颜色(球谐系数)与不透明度α,共四个核心要素。顶点法线纹理属于网格表示,权重偏置激活函数属于神经网络,深度法线光照是传统渲染属性。
Q8. 下列哪些属于3DGS在游戏场景应用中的优势?
- A.照片快速重建← 正确答案
- B.渲染实时进行← 正确答案
- C.显存占用极低
- D.训练无需GPU
答案:AB。3DGS从照片/视频快速重建场景,且光栅化渲染可实时运行,是游戏落地的两大优势。显存其实偏大(单颗约4.5KB),训练也需要GPU加速,所以C、D都不对。
Q9. 关于3DGS的密度化机制,下列说法正确的是?
- A.梯度大则克隆重建← 正确答案
- B.大而模糊会分裂← 正确答案
- C.数量训练中固定
- D.冗余高斯被剪除← 正确答案
答案:ABD。密度化按梯度阈值触发:欠覆盖的小泡克隆,过覆盖的大泡分裂,同时剪除透明度过低或尺寸过大的飞点。高斯数量在训练中动态变化而非固定,所以C错误。整个机制让气泡数量随场景复杂度自适应生长。
Q10. 针对3DGS落地游戏引擎的优化策略包括哪些?
- A.LOD分层调度← 正确答案
- B.量化压缩参数← 正确答案
- C.隐式辐射场替代
- D.剔除冗余高斯← 正确答案
答案:ABD。LOD按距离切换不同密度的高斯,量化压缩位置与颜色降低存储,剔除冗余高斯减少显存,都是3DGS工程落地常用手段。C选项的隐式辐射场是NeRF的技术路线,与3DGS显式表达背道而驰。