FEATURED · 精选文章

Three.js原生支持3D Gaussian Splatting:从加载到渲染全指南

发布时间 / 2026/8/30 13:24:48
来源 / 创域科博编辑部
栏目 / 资讯中心
Three.js原生支持3D Gaussian Splatting:从加载到渲染全指南 早期接触 3D 高斯泼溅3D Gaussian Splatting时最大的痛点不是训练模型而是“模型训完之后怎么在网页里跑起来”。网上能搜到的方案要么是手写 WebGL/WebGPU 渲染器把排序、投影、alpha 混合全自己做一遍要么是挂在一些实验性第三方库上版本一更新代码就崩。Three.js 从 r170 开始正式引入原生 Gaussian Splatting 支持相当于把这一整套链路收编成了官方能力一个渲染器、一个网格类、一个加载入口就能把点云数据像加载普通模型一样放进三维场景里。本文会围绕 Three.js 原生支持 Gaussian Splatting 这条主线先解释这个功能解决什么问题再对比旧方案说明原理然后给出一份可直接运行的实战代码最后补充高频报错与工程化建议。适合已经具备 Three.js 基础、想尝试 3DGS 落地或者正在做数字孪生、实景三维、文物数字化展示的开发者阅读。1. 背景与核心概念1.1 什么是 3D Gaussian Splatting3D Gaussian Splatting3DGS是一种基于点云的三维场景表示与渲染方法。它的核心思路是用大量带属性的三维高斯体来描述一个场景。每个高斯体不仅记录位置还记录协方差矩阵决定椭球形状、颜色和不透明度。渲染时这些高斯体会被投影到二维平面上再按照深度排序逐像素做 alpha 混合最终生成一张照片级真实感的图像。这里可以对比两类常见方案来理解传统网格Mesh场景由三角形面片组成适合规整物体但重建复杂场景时三角面数量巨大且真实感依赖贴图。NeRF用神经辐射场隐式表示场景效果很好但训练和推理都慢实时渲染门槛高。3DGS介于两者之间。表示是显式的每个高斯体可独立操作渲染是实时的比 NeRF 快很多且训练速度也远快于 NeRF。在浏览器端3DGS 比同等画质的 mesh 更“轻”因为它不需要维护拓扑结构本质上就是一堆粒子的排序与混合。1.2 Three.js 原生支持解决了什么问题在 Three.js 原生支持之前要把 3DGS 放进网页通常有几条路使用社区贡献的 loaders例如mkkellogg/gaussian-splats-3d它能力全面但 API 与 Three.js 官方风格不完全一致升级 Three.js 时要额外关注兼容。自己基于 WebGPU 实现渲染管线包括粒子排序、协方差投影、alpha 混合等核心算法工作量很大。直接嵌入 viewer 项目比如 Antimatter15 的 Splat 客户端但它不是一个可扩展的三维引擎很难和业务场景、UI 交互、其他三维模型融合。Three.js 原生支持后带来的直接收益是官方维护会跟随 WebGPU 渲染器一起更新不用自己处理底层排序和投影细节。与 Three.js 现有场景体系打通可以像普通 Object3D 一样把高斯点云加进场景与网格、粒子、灯光、后期效果共存。加载流程更规范支持.splat、.ksplat、.ply等常见格式API 风格和 Three.js 其他加载器保持一致。1.3 典型应用场景Gaussian Splatting 的浏览器端渲染已经出现在多个真实业务中数字孪生把现实场景园区、厂区、室内空间扫描重建后在网页中叠加业务数据。文博数字化对文物、古建筑做高保真三维展示用户在网页端能 360 度旋转查看。电商与营销商品三维展示特别是鞋服、潮玩等需要质感呈现的品类。自动驾驶与测绘对小范围道路、街区场景做快速可视化。在这些场景中Three.js 作为成熟的三维引擎负责场景管理、交互、动画、后期而 Gaussian Splatting 负责提供高保真实景底图两者配合非常自然。2. 环境准备与版本说明2.1 硬件与浏览器要求Three.js 的 Gaussian Splatting 渲染依赖 WebGPU这是原生支持与早期 WebGL 方案最大的区别。WebGPU 能够执行计算着色器从而在 GPU 端完成高斯体的排序这是 WebGL 很难高效实现的能力。因此在开始之前需要先确认浏览器环境满足以下条件Chrome 113 及以上版本并且开启了 WebGPU 支持。Chrome 从 113 开始默认支持 WebGPU后续版本稳定性持续提升。Edge 与 Chrome 内核一致同样支持 WebGPU。Firefox 和 Safari 目前对 WebGPU 的支持属于实验阶段建议以 Chrome/Edge 作为开发调试首选浏览器。如果你的应用需要兼容不支持 WebGPU 的浏览器则需要考虑降级方案比如先展示静态截图或使用低精度点云模式。这一点在本文第 6 章会再次提到。2.2 Three.js 版本选择Three.js 从 r170 开始正式加入 Gaussian Splatting 原生支持。具体涉及的核心类包括GaussianSplattingMesh用于加载并渲染高斯点云的网格类。GaussianSplattingMaterial负责高斯点云渲染所需的着色器逻辑。GaussianSplattingLoader负责解析.splat、.ksplat、.ply等文件数据。建议直接使用 r170 之后的版本。本文示例以0.171.0为例如果你使用的版本不同部分导入路径和 API 可能略有差异这是 Three.js 处于快速迭代期的正常现象。版本需要根据你的项目实际情况调整本文示例以常见环境为例重点演示配置思路。2.3 环境准备清单推荐使用 Vite 或者任意静态服务器作为本地开发环境。如果只是快速测试也可以用 CDN 的 ESM 方式在单 HTML 文件中运行。在开始之前请确认已经安装Node.js 18 或更高版本用于 npm 包管理一个支持 ESM 的现代编辑器VSCode 即可Chrome 或 Edge 浏览器创建项目目录时建议结构如下three-gs-demo/ ├── index.html ├── package.json └── data/ └── sample.splatdata/sample.splat是你需要自行准备的训练结果数据本文第 4 章会说明如何获取和转换。2.4 安装依赖如果你使用 npm 管理项目在项目根目录执行npm init -y npm install three0.171.0如果你只是快速验证也可以不安装任何依赖直接在 HTML 中通过 importmap 引入 CDN 资源。第 4 章的示例会采用这一方式方便读者直接复制运行。3. 3D Gaussian Splatting 原理速通3.1 数据从哪来一个标准的 3DGS 流程通常包含以下步骤对真实场景拍摄多视角照片或者使用相机围绕物体连续采集视频帧。使用 COLMAP 等工具做运动恢复结构SfM生成每张照片的相机位姿和稀疏点云。将 COLMAP 的稀疏点云作为初始化使用 3DGS 训练管线迭代优化高斯体参数。导出训练结果常见导出格式是.ply也可以转换成.splat或.ksplat。最终的高斯点云数据包含每个高斯体的位置、旋转、缩放、颜色、不透明度等信息。.ply文件是标准格式体积最大.splat文件做了轻量化处理体积更小加载更快因此更适合 Web 端。3.2 渲染流程拆解在浏览器端GPU 渲染高斯点云的核心流程可以分为三个阶段排序将场景中的所有高斯体按照到相机平面的深度从远到近排序。由于相机可以任意旋转每一帧的排序结果都可能变化所以必须在 GPU 上每帧执行。投影把高斯体投影到二维图像平面形成二维椭圆形状。投影过程依赖高斯体的协方差矩阵和当前相机的投影矩阵。混合按深度顺序逐像素混合每个椭圆覆盖区域的颜色与透明度生成最终图像。这三个阶段中排序是计算量最大的部分。WebGL 时代很难高效完成大规模排序而 WebGPU 的计算着色器可以很好地承担这一任务。Three.js 原生支持正是建立在 WebGPU 渲染器之上的。3.3 Three.js 如何封装底层细节Three.js 把上述流程封装成了一个上层友好的接口。在用户视角你只需要关心创建一个GaussianSplattingMesh实例调用load()方法加载.splat文件把实例add到场景中用WebGPURenderer正常渲染至于高斯体排序、顶点缓冲、材质参数管理等细节都由GaussianSplattingMaterial和内部渲染模块处理。这意味着你不需要自己维护点云缓冲区也不需要关心 WebGPU 的状态绑定。不过理解原理仍然很有价值。当你遇到画面闪烁、加载失败、排序错误等问题时只有理解了排序和投影流程才能快速定位是数据问题、shader 问题还是渲染状态问题。4. Three.js 原生接入实战4.1 获取测试数据在动手编码之前需要一份可用的高斯点云文件。有三个途径可以获取使用官方训练仓库处理自己的照片导出.ply后再转成.splat。使用社区提供的在线转换工具将.ply转成.splat。使用公开测试数据集的样例文件。开发阶段建议使用.splat格式因为文件体积小加载快方便调试。将文件放入项目data目录下后记录好文件名下一步直接使用。4.2 创建项目骨架先创建一个index.html这是完整可运行的基础页面。为了简化依赖这里使用 CDN 方式引入 Three.js并且通过 importmap 管理模块路径。!DOCTYPE html html langzh-CN head meta charsetUTF-8 / meta nameviewport contentwidthdevice-width, initial-scale1.0 / titleThree.js 原生 Gaussian Splatting 示例/title style * { margin: 0; padding: 0; } body { overflow: hidden; background: #000; } #info { position: fixed; top: 16px; left: 16px; z-index: 10; color: #fff; font-family: system-ui, sans-serif; font-size: 14px; background: rgba(0, 0, 0, 0.5); padding: 8px 14px; border-radius: 8px; pointer-events: none; } /style /head body div idinfo加载中.../div script typeimportmap { imports: { three: https://cdn.jsdelivr.net/npm/three0.171.0/build/three.module.js, three/addons/: https://cdn.jsdelivr.net/npm/three0.171.0/examples/jsm/ } } /script script typemodule src./main.js/script /body /html注意importmap中的版本号需要与实际使用版本保持一致。如果你使用 npm 安装则本地导入路径会由打包工具自动解析不需要写 CDN 地址。4.3 编写加载与渲染逻辑创建main.js这是核心代码。整体步骤为创建 WebGPU 渲染器、创建场景与相机、添加轨道控制器、加载高斯点云文件、启动渲染循环。// 文件路径main.js import * as THREE from three; import { WebGPURenderer } from three/addons/renderers/webgpu/WebGPURenderer.js; import { OrbitControls } from three/addons/renderers/common/OrbitControls.js; import { GaussianSplattingMesh } from three/addons/renderers/webgpu/GaussianSplattingMesh.js; // 1. 创建渲染器 const renderer new WebGPURenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); document.body.appendChild(renderer.domElement); // 2. 创建场景 const scene new THREE.Scene(); scene.background new THREE.Color(0x111111); // 3. 创建相机 const camera new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.1, 100 ); camera.position.set(2, 1, 2); // 4. 添加轨道控制 const controls new OrbitControls(camera, renderer.domElement); controls.enableDamping true; controls.dampingFactor 0.05; // 5. 加载高斯点云 const splatMesh new GaussianSplattingMesh(); const splatURL ./data/sample.splat; const infoEl document.getElementById(info); splatMesh.load(splatURL).then(() { scene.add(splatMesh); // 根据包围球自动调整相机初始位置 const center splatMesh.boundingSphere.center; const radius splatMesh.boundingSphere.radius; camera.position.copy(center).add(new THREE.Vector3(radius * 0.8, radius * 0.5, radius * 0.8)); controls.target.copy(center); controls.update(); infoEl.textContent 加载完成拖拽或滚轮浏览; }).catch((err) { infoEl.textContent 加载失败请打开控制台查看错误; console.error(Gaussian Splatting 加载失败:, err); }); // 6. 渲染循环 renderer.setAnimationLoop(() { controls.update(); renderer.render(scene, camera); }); // 7. 窗口尺寸适配 window.addEventListener(resize, () { camera.aspect window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); });4.4 代码关键点说明重点解释几个容易被忽略的地方第一渲染器必须使用WebGPURenderer。普通WebGLRenderer无法渲染高斯点云因为底层依赖 WebGPU 计算排序。第二GaussianSplattingMesh在 r170 之后才存在且不同小版本的导入路径可能不同。如果你在某个版本中找不到renderers/webgpu/GaussianSplattingMesh.js可以进入node_modules对应目录自行确认实际文件位置。第三加载完成后不要急着把对象塞进场景。先根据boundingSphere调整相机位置否则相机可能在场景内部或者距离过远导致初始画面是一团色块或者空白。第四controls.target也需要同步到包围球中心否则旋转时视角会绕错中心点。4.5 运行与验证在项目根目录启动一个本地静态服务器npx vite或使用任意静态服务器工具例如python3 -m http.server 8000然后用 Chrome 打开页面。正常情况下你会在暗色背景中看到完整的高斯点云场景可以拖拽旋转、滚轮缩放。控制台输出加载失败信息时优先检查文件路径是否正确服务器是否正确启动浏览器是否支持 WebGPU文件是否完整如果页面底部出现WebGPU is not available之类的提示说明当前浏览器环境不支持 WebGPU需要更换浏览器或开启硬件加速。5. 进阶能力动画、交互与场景融合5.1 高斯点云的动画控制GaussianSplattingMesh本身也是Object3D所以你可以像操作普通网格一样对它做平移、旋转、缩放。下面代码让点云每帧缓慢旋转// 放在渲染循环中 splatMesh.rotation.y 0.002;这在商品展示场景中很实用用户无需手动拖拽就能自动浏览模型各个角度。如果你希望对点云做渐进式显示效果可以关注材质的不透明度参数。从 r170 开始材质支持opacity之类的通用属性你可以用线性插值控制点云淡入。5.2 与普通 Three.js 物体共存原生支持的最大优势之一就是高斯点云可以和普通三维模型放在同一个场景中。你可以把点云作为实景底图再叠加标注框、路径线、Mesh 建筑模型、CSS2D 标签等。这里有一个技术细节需要留意高斯点云本质上是大量半透明粒子与场景中其他半透明物体混排时渲染顺序可能不符合预期。遇到这种情况可以将普通物体的渲染顺序调整到点云之后或者适当降低点云的透明度减少遮挡感。如果你在点云场景中加入了普通 Mesh还需要注意相机近远裁剪面near、far的取值。点云场景的范围通常比普通模型大建议根据包围球半径动态调整far。5.3 点击拾取与业务交互高斯点云直接做射线拾取并不像 Mesh 那样简单因为Raycaster默认针对三角形几何体而高斯点云没有传统意义上的几何拓扑。要做点击交互通常有两种思路一种思路是借助一个隐藏的代理 Mesh。将点云的大致范围用一个低精度多边形包围盒表示点击时先检测代理 Mesh再把命中的坐标换算到点云局部坐标。这种方式适合点击区域判断例如点击某个物体区域弹出详情。另一种思路是使用 ID 缓冲区。离线训练时为每个物体或区域分配不同的 ID渲染时额外输出 ID 缓冲再通过像素颜色反查点击对象。这种方式精确度高但需要改动渲染管线工程成本也相对更高。5.4 Cesium 与 Three.js 共享 GL 上下文在数字孪生场景中经常需要把 Three.js 渲染的高斯点云叠加到 Cesium 的地球场景上。此时可以通过 Cesium 的useDefaultRenderLoop false关闭内置渲染循环然后手动控制 Cesium 与 Three.js 共用同一个 WebGL 上下文在每一帧中先渲染 Cesium 场景再渲染 Three.js 场景最后统一输出。需要特别说明的是高德点云渲染依赖 WebGPU而 Cesium 目前主要使用 WebGL两者如果分别创建各自的上下文浏览器内存占用会明显上升且透明叠加顺序很难控制。因此这类方案适合在桌面端和企业内网环境中使用移动端需要充分评估性能。如果你的实际需求只是“在 Three.js 中叠加地理坐标点”而不是完全的 Cesium 融合可以先把经纬度转换为局部平面坐标再换算到 Three.js 的右手坐标系同样能够实现点云与地图数据的对齐。6. 常见问题与排查思路6.1 高频问题清单下面是接入 Three.js 原生 Gaussian Splatting 过程中最常见的问题以及对应的排查方向。问题现象常见原因解决思路页面空白控制台提示 WebGPU 不可用浏览器版本过低或未开启 WebGPU使用 Chrome/Edge确认硬件加速开启加载 .ply 文件很慢ply 格式体积大转换为 .splat 或对点云抽稀后再加载模型渲染为乱点或噪点文件已损坏或文件格式与加载器不匹配校验文件头信息重新导出正确格式旋转视角时画面闪烁高斯体排序不稳定检查新版 Three.js升级到 r171点云与普通 Mesh 混合时半透明错乱渲染顺序冲突调整渲染顺序或把 Mesh 放在点云之前渲染相机初始位置不合理看不到模型未使用包围球初始化相机根据 boundingSphere 设置 camera 与 controls.target加载过程中内存占用过高点云数量过大离线裁剪、抽稀、量化压缩WebGPU 渲染模式下物体颜色异常颜色空间不一致检查 renderer.outputColorSpace 与材质颜色是否统一为 SRGB6.2 排查思路遇到问题不要先怀疑 Three.js 本身大部分情况下问题出在数据或环境。推荐按以下顺序排查确认浏览器环境。在地址栏访问chrome://gpu或使用WebGPU特性检测确认 WebGPU 可用。确认文件格式。检查文件后缀与二进制结构.splat与.ply的解析逻辑完全不同。确认 Three.js 版本。官方原生支持在 r170 才引入如果版本低请直接升级。确认路径。使用网络面板查看请求是否 404文件是否完整下载。最后再检查代码。重点看渲染器类型、加载回调、相机位置三个环节。如果画面能显示但表现异常建议先加载 Three.js 官方示例中的.splat文件做对照测试。如果官方示例正常说明问题出在你的数据文件上如果官方示例也异常则是环境或版本问题。6.3 相关地图场景的坑有读者在 Three.js 中结合 GeoJSON 制作 3D 地图时发现行政区名称标签总是偏移。这类问题与 Gaussian Splatting 本身无直接关系但在地理场景中叠加点云时会一起出现。根因通常是GeoJSON 经纬度坐标直接当作 Three.js 局部坐标使用导致坐标轴方向和缩放比例不对或者标签挂在球面而视角使用平面投影。正确做法是先将经纬度转换为墨卡托平面坐标或局部 ENU 坐标再映射到 Three.js 世界坐标系。标签偏移时优先检查坐标转换基准是否统一而不是调整标签位置偏移量。7. 最佳实践与工程建议7.1 数据侧优化3DGS 文件通常可以达到几十甚至上百 MB对于 Web 端并不友好。建议在数据进入前端之前完成以下几项处理优先使用.splat格式而不是.ply体积差异非常明显。对大场景做区域裁剪只保留用户需要关注的区域。对点云做抽稀在画质损失可接受范围内减少高斯体数量。对位置和颜色信息做量化压缩减小文件体积。你可以在服务端对点云做预处理也可以提供多种精度版本让用户根据网络条件动态选择加载。7.2 渲染性能优化WebGPU 渲染高斯点云已经比 WebGL 高效很多但性能仍与点云数量和像素填充率强相关。以下是几条工程建议限制pixelRatio移动端建议设置为 1避免高 DPR 下像素填充压力过大。使用renderer.setAnimationLoop而不是requestAnimationFrame保持与渲染器生命周期一致。当点云不在视野范围内时可以暂时从场景中移除或降低渲染频率。对于超大规模点云考虑在场景中动态管理多个GaussianSplattingMesh实例做视锥裁剪和 LOD 切换。7.3 WebGPU 兼容与降级策略目前 WebGPU 还不是所有浏览器都支持生产环境必须考虑降级方案。一种常见的策略是启动时检测 WebGPU 是否可用如果不可用则展示预渲染好的图片或视频而不是直接让页面崩溃。也可以用 WebGL 渲染器先加载场景中的普通物体当检测到 WebGPU 可用时再动态切换到 WebGPURenderer 并加载点云。以下是一个简洁的适配逻辑async function isWebGPUSupported() { if (!navigator.gpu) return false; try { const adapter await navigator.gpu.requestAdapter(); return adapter ! null; } catch (e) { return false; } } async function initRenderer() { if (await isWebGPUSupported()) { return new WebGPURenderer({ antialias: true }); } // 降级返回一个 WebGL 渲染器用于加载普通场景 return new THREE.WebGLRenderer({ antialias: true }); }注意降级方案中如果仍要展示点云效果只能在服务端预渲染点云图像再作为贴图或静态图展示无法在 WebGL 下实时渲染完整的 3DGS 内容。7.4 内存与资源释放点云数据占用内存较大在单页应用中尤其要注意资源释放。当用户关闭点云模块或切换场景时应手动释放相关资源scene.remove(splatMesh); splatMesh.geometry.dispose(); splatMesh.material.dispose();如果不释放浏览器内存峰值会持续累积最终导致页面卡顿甚至崩溃。7.5 生产部署建议生产环境部署时需要注意以下几点将.splat文件放在 CDN 上并开启 gzip 或 brotli 压缩虽然对二进制文件压缩率有限但配置成本低。对点云文件设置合理的缓存策略使用内容哈希命名避免版本更新后缓存不刷新。前端加载时显示进度条避免用户长时间等待无反馈。对大文件启用分片加载或流式解析不要阻塞主线程。如果你使用 Web Worker 做数据解析注意 Three.js 加载器的部分实现依赖 DOM 环境Worker 内解析时需要自行处理二进制数据不建议直接调用高层 API。8. 总结与后续学习路线到这一步你已经掌握了 Three.js 原生支持 Gaussian Splatting 的核心用法了解了 3DGS 的基本原理、为什么需要 WebGPU 渲染器、如何加载.splat文件并放入 Three.js 场景以及如何排查加载失败、渲染异常、半透明错乱等高频问题。接下来如果想深入可以按以下顺序继续学习阅读 Three.js 官方webgpu_gaussian_splatting示例源码观察完整场景配置和相机参数。自己采集几十张照片用 COLMAP 与 3DGS 训练仓库训练一个模型跑通完整数据链路。尝试修改GaussianSplattingMaterial的着色器加入自定义后处理或风格化效果。学习 WebGPU 计算着色器的基本写法理解 GPU 端排序的实现细节。在真实业务项目中测试 Cesium Three.js 共享上下文方案评估性能与内存表现。原生支持的意义在于降低了 3DGS 的接入门槛但离工程落地还有很长的路。数据规模控制、降级策略、交互反馈、内存释放这些环节都直接影响用户体验。如果你在跑代码时遇到问题先回到环境检查和数据格式校验这两步大多数坑都能迎刃而解。希望这篇教程能帮你少踩几个坑。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻