从零到一:用 Aholo Viewer 在浏览器里渲染 3D 高斯泼溅小熊

传统 3D 模型用三角网格(Mesh)描述表面,而 3D Gaussian Splatting(3DGS) 用大量高斯椭球体「泼溅」出场景,能在浏览器里呈现照片级真实感,且文件往往比同等质量的 Mesh 更紧凑。

本项目是一个 最小可运行的 3D 入门 Demo:

  • 技术栈:Vite 6 + TypeScript + @manycore/aholo-viewer
  • 目标:从远程加载 .sog 格式的小熊模型,在 500×500 画布中实时渲染
  • 代码量:约 80 行 TypeScript,无框架依赖

整体流程可以概括为:

创建容器 → 初始化 Viewer → 加载 .sog 模型 → 解析为 Splat → 加入场景 → 配置相机与渲染管线 → 渲染循环

运行效果:


二、技术选型

组件 选择 作用
渲染引擎 @manycore/aholo-viewer 支持 Mesh 与 3DGS 的 Web 渲染器
构建工具 Vite 6 开发服务器、TypeScript 转译
语言 TypeScript 类型提示与工程化
模型格式 .sog Aholo 优化的 3DGS 格式,平衡性能与画质

Aholo Viewer 的核心概念(来自官方文档):

  • Scene:场景树,通过 add() 挂载对象
  • Splat:3DGS 的可渲染对象,不能直接 new,需通过 Loader 创建
  • PerspectiveCamera:透视相机,模拟人眼「近大远小」
  • Pipeline Config:背景、Splatting、TAA 等渲染管线配置

三、项目结构

3D-learn/

└── project/

└── aholo-first/

├── index.html # 页面入口

├── index.ts # 核心 3D 逻辑

├── vite.config.ts # Vite 配置(排除预构建)

├── package.json # 依赖与 Rollup WASM 覆盖

└── tsconfig.json

依赖极简:运行时只有 @manycore/aholo-viewer,开发时加 Vite 和 TypeScript。


四、核心实现拆解

4.1 创建渲染容器

javascript 复制代码
const container = document.createElement('div');

container.style.width = '500px';

container.style.height = '500px';

document.body.appendChild(container);

Viewer 需要挂载到一个 DOM 容器;宽高决定画布尺寸。

4.2 初始化 Viewer 与相机

javascript 复制代码
const viewer = createViewer('example-viewer', container, {});

const camera = new PerspectiveCamera(60, 1, 0.1, 2000);
  • createViewer:创建渲染实例,绑定容器
  • PerspectiveCamera(fov, aspect, near, far):60° 视场角,近平面 0.1,远平面 2000

4.3 加载并解析 3DGS 模型

javascript 复制代码
const SPLAT_URL = 'https://holo-cos.aholo3d.cn/aholo-opensource/gs_file/bear/bear.3d71a266.sog';

const resp = await fetch(SPLAT_URL);

const buffer = await resp.arrayBuffer();

const data = await SplatLoader.parseSplatData(

SplatLoader.SplatFileType.SOG,

new Uint8Array(buffer),

SplatLoader.SplatPackType.Compressed,

);

const splat = await SplatUtils.createSplat(data);

三步链路:

  1. fetch 拉取远程 .sog 二进制
  2. parseSplatData 解析(SOG 格式 + Compressed 打包),内部会用到 Web Worker(splat-worker.js
  3. createSplat 生成可渲染的 Splat 对象

4.4 相机坐标系:一个容易踩坑的细节

javascript 复制代码
// 模型使用 OpenCV 坐标系,-Y 向上

camera.up.set(0, -1, 0);

camera.position.set(-1.5, -0.5, 0);

camera.lookAt(new Vector3(0, 0, 0));

3DGS 模型常用 OpenCV 坐标(Y 轴向下),而 WebGL 默认 Y 轴向上。这里把 camera.up 设为 (0, -1, 0),并调整位置与朝向,才能正确看到小熊。

4.5 组装场景与渲染管线

javascript 复制代码
viewer.getScene().add(splat);

viewer.setCamera(camera);

setViewerConfig(viewer, {

pipeline: {

Background: { /* 黑色背景,关闭地面 */ },

Splatting: { /* 开启高斯泼溅,预计算、合成等 */ },

TAA: { enabled: false },

},

});
  • Background:纯黑背景,关闭地面
  • Splatting:核心 3DGS 渲染,含预计算、模糊、合成等
  • TAA:时间抗锯齿,Demo 中关闭以降低开销

4.6 渲染循环

javascript 复制代码
function render() {

viewer.render();

}

viewer.requestRenderHandler = function () {

requestAnimationFrame(render);

};

requestAnimationFrame(render);

按需渲染:Viewer 需要更新时通过 requestRenderHandler 触发下一帧,避免空转。


五、踩过的两个坑

5.1 Rollup 原生模块被 Windows 策略拦截

现象:

Error: Cannot find module @rollup/rollup-win32-x64-msvc

Application Control policy has blocked this file

原因: Vite 依赖 Rollup 的 .node 原生二进制,部分 Windows 环境会拦截。

解法: 在 package.json 中强制使用 WASM 版 Rollup:

javascript 复制代码
"overrides": {

"vite": {

"rollup": "npm:@rollup/wasm-node@^4.34.9"

}

}

5.2 splat-worker.js 路径失效

现象:

The file does not exist at ".../node_modules/.vite/deps/splat-worker.js"

原因: Aholo Viewer 用 new URL("./splat-worker.js", import.meta.url) 加载 Worker。Vite 预构建会把包打进 .vite/deps/import.meta.url 变了,相对路径就找不到 Worker。

解法: 在 vite.config.ts 中排除预构建:

javascript 复制代码
export default defineConfig({

optimizeDeps: {

exclude: ['@manycore/aholo-viewer'],

},

});

修改后需清除 node_modules/.vite 缓存再启动。


六、运行方式

cd 3D-learn/project/aholo-first

npm install

npm run dev

浏览器访问 http://localhost:5173/,即可看到 3D 高斯泼溅小熊。

相关推荐
用户2136610035721 小时前
Vue2组件化开发与父子通信
前端·vue.js
Momo__1 小时前
TypeScript satisfies 操作符——比 as 更安全的类型守门员
前端·typescript
用户2136610035721 小时前
Vue2事件系统与指令进阶
前端·vue.js
labixiong2 小时前
实现一个能跑的迷你版Promise(一)
前端·javascript·面试
Csvn3 小时前
`??` 和 `||` 搞混,线上用户头像全挂了
前端
kyriewen4 小时前
白宫前脚下了限制令,OpenAI 后脚就把 GPT-5.6 发了
前端·gpt·openai
用户40269244819085 小时前
CRMEB Pro 新增后台接口全链路:路由、权限、验证器、返回格式一次讲清
前端·后端
泉城老铁5 小时前
springboot+vue+ ffmpeg 实现视频的拉流播放
前端
PedroQue996 小时前
uni-router v1.8.0新增冷启动守卫补执行
前端·uni-app
xiaok6 小时前
部署之后,本地浏览器还在读取旧缓存导致页面一直显示loading中
前端