打开这个 Demo,镜头缓缓推进,是一间真实拍摄过的房间——灯光、阴影、玻璃反射都在,可以用鼠标自由旋转。但这个场景里没有任何模型文件,没有贴图,没有 .glb,只有几百万个半透明的椭球体。
这是 3D Gaussian Splatting,一种 2023 年从学术界破圈的渲染技术。GaussianSplats3D 把它搬进了 Three.js,让这件事可以直接在浏览器里跑。


它和 NeRF、传统建模的区别
传统 3D 工作流是人工建模:艺术家画出网格、刷上贴图,渲染器计算光照。这条路质量可控,但成本高。
NeRF(Neural Radiance Field)是另一条路:用神经网络从一批照片里学出一个隐式场,推理时对每个像素射出光线,沿途采样颜色和密度再合成。质量不错,但慢——早期版本训练要几天,渲染一帧要几秒,实时完全没法做。
3D Gaussian Splatting(3DGS)解决的正是速度问题。它的核心思路:
- 从照片的稀疏点云出发,在空间中撒出大量三维高斯椭球
- 每个椭球有位置、旋转、缩放、不透明度、颜色(含视角相关的球谐系数)
- 渲染时把所有椭球投影到 2D,按深度排序后从后往前 alpha 合成
整个过程走的是 GPU 光栅化,不是光线步进。训练 15 分钟,实时跑 90fps——这就是它比 NeRF 快的原因。
在 Three.js 里跑起来
npm install @mkkellogg/gaussian-splats-3d最简单的用法,加载一个 .splat 或 .ply 文件:
import * as GaussianSplats3D from '@mkkellogg/gaussian-splats-3d';
const viewer = new GaussianSplats3D.Viewer({
cameraUp: [0, -1, -0.6],
initialCameraPosition: [-1, -4, 6],
initialCameraLookAt: [0, 4, 0]
});
viewer.addSplatScene('/scenes/room.ksplat', {
splatAlphaRemovalThreshold: 5, // 过滤掉 alpha < 5 的透明椭球
showLoadingUI: true,
position: [0, 1, 0]
})
.then(() => viewer.start());cameraUp 需要根据你的场景调整——不同的 3DGS 训练工具导出的坐标轴方向不一样,直接用 [0, 1, 0] 很可能场景是歪的。
嵌进已有的 Three.js 场景
GaussianSplats3D 支持接管已有的 Three.js 场景,把 Splat 渲染器当作场景里的一个对象:
import * as THREE from 'three';
import * as GaussianSplats3D from '@mkkellogg/gaussian-splats-3d';
const renderer = new THREE.WebGLRenderer({ antialias: true });
const camera = new THREE.PerspectiveCamera(65, width / height, 0.1, 500);
const scene = new THREE.Scene();
// 加其他 Three.js 对象
const light = new THREE.DirectionalLight(0xffffff, 1);
scene.add(light);
// 把 Viewer 挂在已有的 renderer / camera 上
const viewer = new GaussianSplats3D.Viewer({
selfDrivenMode: false, // 手动控制渲染循环
renderer,
camera,
useBuiltInControls: false,
threeScene: scene
});
viewer.addSplatScene('/scenes/garden.ksplat').then(() => {
function animate() {
requestAnimationFrame(animate);
viewer.update();
viewer.render();
}
animate();
});selfDrivenMode: false 是关键,它让你保留自己的 requestAnimationFrame 循环,Splat 渲染器只在你需要的时候更新。
球谐函数和视角相关颜色
初始化时有个参数 sphericalHarmonicsDegree,默认是 0。
这个参数控制颜色是否随视角变化。度数越高,材质的反射、金属感越真实,但单个 Splat 占的内存更多,能加载的总数量就少:
| 球谐次数 | 最大 Splat 数 | 效果 |
|---|---|---|
| 0 | ~1600 万 | 固定颜色 |
| 1 | ~1100 万 | 低频视角变化 |
| 2 | ~800 万 | 更完整的视角相关反射 |
对一般的室内场景,degree 0 已经够用。只有场景里有强反射材质(玻璃、金属)才值得开到 degree 1 或 2。
文件格式和 WASM 排序
3DGS 渲染的性能瓶颈在排序:每一帧都要把所有椭球按相机距离从远到近排好,才能正确做 alpha 合成。
GaussianSplats3D 的排序跑在 CPU 上,用 WebAssembly + SIMD 加速。.ksplat 是它自己的压缩格式,把 32 位浮点压成 16 位,文件体积减半,加载更快:
# 把 .ply 转成 .ksplat,压缩级别 1(32→16bit),过滤 alpha<5 的点
node util/create-ksplat.js input.ply output.ksplat 1 5压缩级别:
0— 不压缩1— 位置和缩放压到 16 位2— 球谐系数额外压到 8 位
现状和生态
这个仓库已经停止维护了。作者在 README 里直接说了,推荐去看 Spark (opens in a new tab)(World Labs 出的继任项目)。
但 GaussianSplats3D 的代码仍然可用,2.8k stars 的积累说明它在社区跑了很长时间。如果只是想在项目里嵌入一个 Splat 场景看效果,它是目前文档最完整的 Three.js 方案。
想要可视化编辑 Splat 场景(裁剪、调整、导出),PlayCanvas 的 Supersplat (opens in a new tab) 是目前最活跃的工具,8.5k stars,每周还在更新。
相关资源
- 仓库:https://github.com/mkkellogg/GaussianSplats3D (opens in a new tab)
- 在线 Demo:https://projects.markkellogg.org/threejs/demo_gaussian_splats_3d.php (opens in a new tab)
- 原始论文:3D Gaussian Splatting for Real-Time Radiance Field Rendering(Kerbl et al., 2023)
- Supersplat 编辑器:https://github.com/playcanvas/supersplat (opens in a new tab)