高斯泼溅 (Gaussian Splatting) 的 Three.js 实现

高斯泼溅 (Gaussian Splatting) 的 Three.js 实现

「33 高斯泼溅 (Gaussian Splatting) 的 Three.js 实现」

/~825b3YKMDE~:/

链接:https://pan.quark.cn/s/561494312803


这是一个基于 Three.js 的 3D 高斯泼溅渲染器实现,该技术源自论文《3D Gaussian Splatting for Real-Time Radiance Field Rendering》,用于从 2D 图像生成 3D 场景。原项目基于 CUDA 并需要在本地机器上运行,而我的目标是构建一个可通过网络访问的查看器。

3D 场景以类似点云的格式存储,可以实时查看、导航和交互。此渲染器兼容 INRIA 项目生成的 .ply 文件、标准 .splat 文件,以及我自定义的 .ksplat 文件(这是原始 .ply 文件的精简和压缩版本)。

当我开始这个项目时,已经有基于 Web 的查看器可用------来自 antimatter15 的 WebGL 查看器和来自 cvlab-epfl 的 WebGPU 查看器------但当时还没有 Three.js 版本。我以这些版本作为我初始实现的起点,但截至目前,本项目包含的所有代码均为我独立编写。

⚠️ 正如大家注意到的,此仓库目前没有积极的开发活动。它更像是一个副业项目,我目前没有足够的时间投入有意义的开发。我建议您将 Spark 作为替代方案------它由 World Labs 的才华横溢的团队和开源社区积极开发,并包含许多高级特性和功能。

亮点

  • 渲染完全通过 Three.js 完成

  • 代码组织为现代 ES 模块

  • 内置查看器自成一体,加载和查看场景只需极少代码

  • 查看器可导入 .ply 文件、.splat 文件或我自定义的压缩 .ksplat 文件

  • 用户可将 .ply 或 .splat 文件转换为 .ksplat 文件格式

  • 允许与 Three.js 场景或物体组一同渲染

  • 内置 WebXR 支持

  • 支持用于视点相关效果(view-dependent effects)的 1 阶和 2 阶球谐函数

  • 专注于优化:

    • 使用自定义八叉树在排序和渲染前剔除泼溅点

    • WASM 泼溅点排序:使用 WASM SIMD 指令的 C++ 实现

    • 部分 GPU 加速的泼溅点排序:使用变换反馈(transform feedback)预计算泼溅点距离

提示

  • 渐进式加载的 .ply 和 .splat 文件不会应用某些优化,例如缓存优化的泼溅点排序。为了获得最佳性能,请将这些文件类型转换为 .ksplat 或非渐进式加载。

  • 将场景转换为 .ksplat 会获得最快的加载时间,因为其格式与泼溅点数据的内部格式匹配。

  • 具有大尺寸或高泼溅点密度的场景可能会导致默认设置出现问题。对于这些场景,您可以尝试以下方法:

    • 将查看器参数 integerBasedSort设置为 false以强制使用较慢的、基于浮点数的泼溅点排序。

    • 尝试为查看器参数 splatSortDistanceMapPrecision设置更大的值,以调整泼溅点排序中距离图的精度。更大的精度值会导致性能下降,但通常可以缓解精度过低时出现的视觉伪影。

已知问题

  • 泼溅点排序在 CPU 上运行------希望能找到一种基于 GPU 的方法

  • 移动或旋转过快时会出现视觉伪影(由于基于 CPU 的泼溅点排序)

  • 移动设备上性能欠佳

  • 自定义的 .ksplat 文件格式仍需改进,特别是在压缩方面

  • 尺寸非常大的场景可能会崩溃(通常出现泼溅点排序的"索引越界"错误)。在这些情况下,更改 splatSortDistanceMapPrecisionintegerBasedSort可能没有帮助。

限制

目前可渲染的泼溅点数量存在限制,这些限制主要取决于所需的球谐函数阶数。限制如下:

球谐函数阶数 最大泼溅点数量
0 ~ 16,000,000
1 ~ 11,000,000
2 ~ 8,000,000

未来的工作将包括优化泼溅点数据打包到数据纹理的方式,这将有助于提高这些限制。

未来工作

这仍然是一个进行中的项目!仍有一些事情需要完成:

  • 改进泼溅点数据打包到数据纹理的方式

  • 继续优化基于 CPU 的泼溅点排序------也许可以尝试某种增量排序?

  • 支持超大场景(流式加载区块和 LOD)

在线演示

https://projects.markkellogg.org/threejs/demo_gaussian_splats_3d.php

控制

鼠标

  • 左键点击​ 设置焦点

  • 左键点击并拖动​ 环绕焦点旋转

  • 右键点击并拖动​ 平移相机和焦点

键盘

  • C​ 切换网格光标,显示鼠标投影射线与泼溅网格的交点

  • I​ 切换信息面板,显示调试信息:

    • 相机位置

    • 相机焦点/观察点

    • 相机上向量

    • 网格光标位置

    • 当前 FPS

    • 渲染器窗口大小

    • 已渲染泼溅点与总泼溅点的比例

    • 上次泼溅点排序耗时

  • U​ 切换调试对象,显示相机控制的方向。它包括一个代表相机轨道轴的绿色箭头和一个代表相机仰角为 0 的平面的白色方块。

  • 左箭头​ 将相机的上向量逆时针旋转

  • 右箭头​ 将相机的上向量顺时针旋转

  • P​ 切换点云模式,其中每个泼溅点被渲染为一个实心圆

  • **=**​ 增加泼溅点比例

  • **-**​ 减小泼溅点比例

  • O​ 切换正交模式

从源代码构建并本地运行

进入代码目录并运行:

复制代码
npm install

接下来运行构建。对于 Linux 和 Mac OS 系统,运行:

复制代码
npm run build

对于 Windows,我添加了一个兼容 Windows 的构建命令:

复制代码
npm run build-windows

要在本地运行演示场景,运行:

复制代码
npm run demo

演示将在本地访问:http://127.0.0.1:8080/index.html。您需要下载演示场景的数据并将其解压到:

复制代码
<代码目录>/build/demo/assets/data

演示场景数据可在此处下载:https://projects.markkellogg.org/downloads/gaussian_splat_data.zip

作为 NPM 包安装

如果您不想从源代码构建库,它也可以作为 NPM 包使用。NPM 包不包含源代码存储库中的源代码和演示。要安装,运行以下命令:

复制代码
npm install @mkkellogg/gaussian-splats-3d

基本用法

要运行内置查看器:

复制代码
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('<.ply、.ksplat 或 .splat 文件的路径>', {
    'splatAlphaRemovalThreshold': 5,
    'showLoadingUI': true,
    'position': [0, 1, 0],
    'rotation': [0, 0, 0, 1],
    'scale': [1.5, 1.5, 1.5]
})
.then(() => {
    viewer.start();
});

查看器参数

参数 用途
cameraUp 查看场景的固有"上"向量(仅在与轨道控制一起使用且查看器使用其自身相机时有效)。用作相机将围绕其旋转的轴,并用于确定场景相对于相机的方向。
initialCameraPosition 相机的初始位置(仅当查看器使用其自身相机时使用)。
initialCameraLookAt 相机的初始焦点和相机轨道的中心(仅当查看器使用其自身相机时使用)。

addSplatScene()的参数

参数 用途
format 强制加载器在加载泼溅场景时假定指定的文件格式。这在从没有文件扩展名的 URL 加载时很有用。有效值在 SceneFormat枚举中定义:PlySplatKSplat
splatAlphaRemovalThreshold 告诉 addSplatScene()忽略 Alpha 值小于指定值的任何泼溅点(有效范围:0 - 255)。默认为 1。
showLoadingUI 在场景加载时显示加载旋转器和/或加载进度条。默认为 true
position 场景的位置,作为其默认位置的偏移量。默认为 [0, 0, 0]
rotation 以四元数表示的场景旋转,默认为 [0, 0, 0, 1](单位四元数)。
scale 场景的比例,默认为 [1, 1, 1]
progressiveLoad 渐进式加载场景的泼溅点数据,并允许在泼溅点加载时渲染和查看场景。此选项仅对 addSplatScene()有效,对 addSplatScenes()无效。

查看器还可以通过 addSplatScenes()函数同时加载多个场景:

复制代码
import * as GaussianSplats3D from '@mkkellogg/gaussian-splats-3d';

viewer.addSplatScenes([{
        'path': '<第一个 .ply、.ksplat 或 .splat 文件的路径>',
        'splatAlphaRemovalThreshold': 20
    },
    {
        'path': '<第二个 .ply、.ksplat 或 .splat 文件的路径>',
        'rotation': [-0.14724434, -0.0761755, 0.1410657, 0.976020],
        'scale': [1.5, 1.5, 1.5],
        'position': [-3, -2, -3.2]
    }
])
.then(() => {
    viewer.start();
});

addSplatScene()addSplatScenes()方法将接受原始的 .ply 文件、标准的 .splat 文件以及我自定义的 .ksplat 文件。

集成 THREE.js 场景

如果您希望由查看器处理渲染,可以将您自己的 Three.js 场景集成到查看器中。只需将 Three.js 场景对象作为 threeScene参数传递给构造函数:

复制代码
import * as GaussianSplats3D from '@mkkellogg/gaussian-splats-3d';
import * as THREE from 'three';

const threeScene = new THREE.Scene();
const boxColor = 0xBBBBBB;
const boxGeometry = new THREE.BoxGeometry(2, 2, 2);
const boxMesh = new THREE.Mesh(boxGeometry, new THREE.MeshBasicMaterial({'color': boxColor}));
boxMesh.position.set(3, 2, 2);
threeScene.add(boxMesh);

const viewer = new GaussianSplats3D.Viewer({
    'threeScene': threeScene,
});
viewer.addSplatScene('<.ply、.ksplat 或 .splat 文件的路径>')
.then(() => {
    viewer.start();
});

目前,这仅适用于写入深度缓冲区的对象(例如标准不透明物体)。支持透明物体将更具挑战性 :)

还支持查看器的"即插即用"模式。DropInViewer类封装了 Viewer,可以像任何其他可渲染对象一样添加到 Three.js 场景中:

复制代码
import * as GaussianSplats3D from '@mkkellogg/gaussian-splats-3d';
import * as THREE from 'three';

const threeScene = new THREE.Scene();
const viewer = new GaussianSplats3D.DropInViewer({
    'gpuAcceleratedSort': true
});
viewer.addSplatScenes([{
        'path': '<.ply、.ksplat 或 .splat 文件的路径>'
        'splatAlphaRemovalThreshold': 5
    },
    {
        'path': '<.ply、.ksplat 或 .splat 文件的路径>',
        'rotation': [0, -0.857, -0.514495, 6.123233995736766e-17],
        'scale': [1.5, 1.5, 1.5],
        'position': [0, -2, -1.2]
    }
]);
threeScene.add(viewer);
相关推荐
代码北人生1 小时前
agent时代,我们都低估了这个 23k Star 的 Claude Code Skills 项目!
javascript
成都渲染101云渲染66661 小时前
云渲染全面支持3dsMax 2027,高效渲染体验升级
开发语言·前端·javascript
zs宝来了2 小时前
微前端架构:qiankun 沙箱隔离与样式冲突
前端·javascript·框架
M ? A2 小时前
Vue 的 scoped 样式穿透 React 不支持?用 VuReact 编译就行
前端·javascript·vue.js·react.js·面试·开源·vureact
zs宝来了2 小时前
Vue 3 Composition API:响应式系统与依赖追踪
前端·javascript·框架
向往着的青绿色2 小时前
Java反序列化漏洞(持续更新中)
java·开发语言·计算机网络·安全·web安全·网络安全·网络攻击模型
村上小树2 小时前
非常简单地学习一下slate.js的原理
前端·javascript
web打印社区2 小时前
[特殊字符] 开源好物:web-print-pdf,让 Web 打印像调用接口一样简单!
前端·javascript·vue.js·electron
小短腿的代码世界2 小时前
Qt跨进程通信在交易系统中的应用:让策略引擎与风控模块在毫秒级握手
开发语言·qt