今日开源[第54期]Spark(@sparkjsdev/spark)源码解读
Spark(@sparkjsdev/spark)源码解读
项目主页:https://github.com/sparkjsdev/spark | 文档:https://sparkjs.dev/
版本:v2.1.0 | 许可:MIT | 语言:TypeScript + Rust/WASM | 依赖:three >=0.180.0
一、项目名称、作者及其介绍、作用与背景
1. 名称与作者
- 项目名:Spark(npm 包名
@sparkjsdev/spark,README 标题 "An advanced 3D Gaussian Splatting renderer for THREE.js",中文可译作"三维高斯泼溅的先进渲染器")。 - 作者/组织:由 World Labs( https://www.worldlabs.ai ,李飞飞创立的空间智能公司)官方构建并维护。GitHub 组织
sparkjsdev。 - 版本与许可:v2.1.0,MIT 许可,TypeScript 实现,核心解码与 LOD 用 Rust 编译为 WASM(
spark-rs)。
2. 作用
Spark 是一个深度集成进 three.js 渲染管线的高斯泼溅(Gaussian Splatting / 3DGS)渲染引擎。它的核心目标是:把"用多张照片重建出的三维点云(高斯泼溅)"当作与 mesh 同级的普通 three.js 物体来渲染、变换、编辑、动画,并能在 98%+ 的 WebGL2 设备上(包括低端手机)流畅运行。
3. 背景
高斯泼溅是 2023 年以来席卷三维重建界的表示法——用数百万个带协方差的"高斯_blob"来表示场景,比传统 mesh/NeRF 更轻、更真实。但它不在 WebGL 原生渲染栈内:
- 标准 three.js 没有"泼溅"这种基元;
- 排序(半透明正确叠加)、海量实例化、动态编辑、LOD 流式加载都是开放难题。
Spark 解决的就是"让 3DGS 在浏览器里成为一等公民"这件事。它和 PlayCanvas 的 spark/SuperSplat、gsplat.js 等是同一赛道,但 Spark 的差异化在于:完整的 dyno 着色器图(shader graph)系统——用户可以用 JS 像搭积木一样组合 GPU 着色逻辑,在 GPU 上实时生成/变形/着色泼溅。
4. 主要功能(README 摘录)
- 与 three.js 管线融合,泼溅与网格物体可同场渲染;
- 跨设备可移植,瞄准 98%+ WebGL2 支持,低端移动端也能快渲染;
- 多泼溅对象同场、正确排序;
- 支持主流格式:
.PLY(含压缩)、.SPZ、.SPLAT、.KSPLAT、.SOG、.RAD; - 多视点同时渲染;
- 完全动态:每个 splat 可变换、可编辑用于动画;
- 实时泼溅颜色编辑、位移、骨骼动画;
- dyno 着色器图系统:在 GPU 上动态创建/编辑泼溅。
二、安装与使用教程、依赖的软件/硬件条件
1. 软件依赖
- 运行(消费端):任意支持 WebGL2 的现代浏览器(Chrome/Edge/Firefox/Safari 15.4+);若为 HTTPS/localhost 之外场景需安全上下文;three.js
>=0.180.0(peerDependency)。 - 开发/构建:Node.js(用于 npm 脚本、vite、ts-node);Rust 工具链(
rustc/cargo,用于npm run build:wasm把spark-rs编译成 WASM);支持 WASM 的浏览器用于跑解码/LOD。 - 文档站构建(可选):Python +
mkdocs-material(pip install mkdocs-material或brew install mkdocs-material)。 - CI:GitHub Actions(
.github/workflows/下build-dist.yml、ci-linux.yml、ci-windows.yaml、deploy-site.yml)。
2. 三种使用方式
(a) CDN + importmap(最轻,零构建) —— 官方 Quick Start 示例,直接写一个 index.html:
<style> body {margin: 0;} </style>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.180.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.180.0/examples/jsm/",
"@sparkjsdev/spark": "https://sparkjs.dev/releases/spark/2.1.0/spark.module.js"
}
}
</script>
<script type="module">
import * as THREE from "three";
import { SparkRenderer, SplatMesh } from "@sparkjsdev/spark";
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(60, innerWidth/innerHeight, 0.01, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
const spark = new SparkRenderer({ renderer }); // 把 Spark 挂进 three 管线
scene.add(spark);
const butterfly = new SplatMesh({ url: "https://sparkjs.dev/assets/splats/butterfly.spz" });
butterfly.position.set(0, 0, -3);
scene.add(butterfly);
renderer.setAnimationLoop((time) => {
renderer.render(scene, camera);
butterfly.rotation.y += 0.01;
});
</script>
(b) NPM 安装(推荐,用于打包项目)
npm install @sparkjsdev/spark
随后 import { SparkRenderer, SplatMesh } from "@sparkjsdev/spark";,three 作为 peer 依赖自行安装。
(c) 源码开发/贡献
npm install
npm run build:wasm # 先编译 Rust -> WASM(spark-rs)
npm run build # 再构建 Spark 本体(vite 双产物)
# 可选:把远程示例资产下载到本地缓存,离线更快
npm run assets:download
npm start # 启动开发服务器,默认 http://localhost:8080/
排错时:npm run clean(清 dist/node_modules/rust/target + 资产)后重来。
3. 关键 npm 脚本(package.json)
| 脚本 | 作用 |
|---|---|
build:wasm |
node rust/build_wasm.js,把 spark-rs 编译为 spark-rs/pkg 的 WASM + JS glue |
build |
build:production + build:dev(vite 双模式,产出 dist/spark.module.js 与 spark.cjs.js 及 .min 版) |
dev |
构建 dev 版 + vite 热更(onchange 'src/**/*' 监听重编) |
start |
同 dev,跑示例服务器 |
test |
node --loader ts-node/esm --test test/**/*.test.ts |
lint / format |
Biome 检查/格式化(@biomejs/biome) |
build-lod |
cargo run --manifest-path rust/build-lod/Cargo.toml 运行独立的 Rust LOD 离线构建工具 |
assets:download / assets:compress |
下载示例资产 / 把 PLY 压缩成 SPZ |
docs / site:build / site:deploy |
MkDocs 文档站本地预览 / 静态构建 / 部署到 GitHub Pages(sparkjsdev.github.io) |
4. 硬件/运行条件小结
- 桌面 GPU 任意;移动端要求支持 WebGL2(几乎全覆盖),低端机靠内置三档画质(
low/medium/high,见src/quality体系,由enableLod、lodRenderScale等控制)与动态 LOD 降级保证流畅。 - 不需要专用 AI 加速;解码/LOD/排序在 Web Worker + WASM 中完成,主线程只做渲染。
三、工作流程与具体的执行步骤
1. 编译期:从源码到双产物
npm run build:wasm→rust/build_wasm.js调用wasm-pack风格流程,把rust/spark-lib编译为spark-rs/pkg/*.wasm与 JS 绑定;npm run build→ vite 以src/index.ts为入口,配合vite-plugin-glsl(内联.glsl)、vite-plugin-dts(生成dist/types/*.d.ts)、vite-plugin-arraybuffer(内联 WASM 二进制)打包出:- ESM:
dist/spark.module.js/.min.js - CJS:
dist/spark.cjs.js/.min.js - 类型:
dist/types/index.d.ts - 同时附带
dist/assets/worker-*.js(离屏 worker 包)。
- ESM:
2. 运行期:一次渲染帧的完整数据流
Spark 把自己实现为一个 THREE.Mesh 子类(SparkRenderer extends THREE.Mesh),从而无缝插入 three 的 render() 调用。每帧流程:
renderer.render(scene, camera)触发SparkRenderer.onBeforeRender(SparkRenderer.ts)。- 若
autoUpdate,调用updateInternal→ 进入异步driveSort+driveLod。 - 计算
renderSize、相机近/远平面。 - 把
SplatAccumulator的变换矩阵(renderToView…)写进 uniforms。 - 写入所有渲染 uniforms:最大标准差
maxStdDev、模糊、LOD 参数、排序纹理ordering、泼溅数据纹理等。 - 设
geometry.instanceCount = spark.activeSplats。
- 若
- LOD 驱动(
driveLod,worker 内):- 计算
pixelScaleLimit;比对相机位姿是否变化 →lodDirty。 - 收集带 LOD 的
SplatMesh,initLodTree分配lodId。 - 消费 Pager 分页更新;
updateLodTrees→traverseLodTrees得可见索引 →updateLodIndices写实例索引纹理(lodInstances中texture为UI32索引 DataTexture)。 - 每帧
traverseLodTrees生成raycastIndices供射线拾取。 - 超时 3s 未用的 LOD 树释放。
- 计算
- 排序驱动(
driveSort,worker 内):readbackDepth():用readRenderTargetPixelsAsync按层读回深度到Uint32Array。- 调
sortWorker.call("sortSplats32", {numSplats, readback, ordering})(由 Rust/WASM 实现的计数排序)。 - 得到
activeSplats与排序索引,上传/创建orderingTexture(RGBA32UI DataTexture,4096×N)。 - 标记 dirty,递归处理积压。
- GPU 实例化绘制:材质(
RawShaderMaterial,GLSL3)以ordering次序纹理 + 泼溅数据纹理(Packed/Ext)在着色器中texelFetch出每个 splat 的 center/scale/quaternion/rgba,计算协方差椭圆并光栅化。 - 离屏/环境模式复用同一管线:
renderTarget()渲到离屏WebGLRenderTarget(可双缓冲);renderCubeMap/renderEnvMap借助CubeCamera+PMREMGenerator生成环境贴图。
3. dyno 着色器图的组装流程(核心创新,详见第四节)
- 每个
SplatMesh/SplatGenerator持有一个GsplatGenerator(一个Dyno程序:输入index:int→ 输出gsplat:Gsplat)。 - 通过
objectModifiers/worldModifiers/SplatEdit注入的 dyno 节点(变换、重着色、SDF 编辑、骨骼等)被constructGenerator组合成一条管线。 DynoProgram在构造时把整张节点图编译成 GLSL 源码(graph.compile()→ 模板拼接{{GLOBALS}}/{{STATEMENTS}}),缓存为RawShaderMaterial。- 改
numSplats会让前后帧失去对应(需重排序);改generator会触发 GPU 着色器重编译(首次有可感知卡顿,之后按 identity 缓存)。
4. 加载一个 .SPZ/.PLY 文件的步骤(SplatLoader)
SplatLoader.load(url)→loadInternal;或用new SplatMesh({ url })自动走加载。getSplatFileType按魔数/扩展名判定格式(PLY=ply、SPZ=解压后NGSP、SOG=PKZip 内meta.json、RAD=RAD0;.splat/.ksplat只能靠扩展名)。- 把字节丢进
workerPool.withWorker,在 SplatWorker 内调用loadPackedSplats/loadExtSplats,其中 WASM 解码(Rustspark-rs的spz/ply/ksplat/sogs/rad解码器)返回{numSplats, packedArray/extArrays, extra, splatEncoding, lodSplats?}。 - 封装成
PackedSplats或ExtSplats,触发onLoad。 - 若
lodSplats存在,建 LOD 子PackedSplats供driveLod使用。
四、逐个介绍项目的各个文件的内容和作用(按模块)
4.1 根目录配置
| 文件 | 作用 |
|---|---|
package.json |
包元数据、依赖(fflate、three peer、spark-rs 本地包)、全部 npm 脚本、ESM/CJS/类型导出矩阵 |
biome.json |
Biome lint/format 配置 |
lefthook.yml |
Git 钩子(提交前 lint/format) |
mkdocs.yml |
文档站配置 |
CHANGELOG.md / LICENSE |
版本变更 / MIT 许可 |
index.html / examples.html |
仓库首页 / 示例入口 |
examples/、docs/ |
示例(40+ 个 HTML demo)与 MkDocs 文档源 |
.github/workflows/ |
CI(Linux/Windows 构建、dist 构建、站点部署) |
4.2 src/ —— TypeScript 运行时(核心)
入口与渲染:
src/index.ts:公共 API 聚合导出(SparkRenderer、SplatMesh、PackedSplats、ExtSplats、dyno、SplatLoader、XR、controls 等)。src/SparkRenderer.ts:引擎心脏。SparkRenderer extends THREE.Mesh,挂载渲染管线;负责onBeforeRender钩子、排序/LOD 驱动、离屏渲、环境贴图、多视点。含大量SparkRendererOptions(外观/裁剪/排序/动态 LOD/注视点/着色器覆盖等)。src/SparkXr.ts:WebXR 总控(SparkXr)、手部追踪(XrHand、JointEnum、25 关节常量)、JointSplats extends SplatMesh(把 25 个关节渲染成椭球 splat 手),支持 VR/AR。src/controls.ts:SparkControls+FpsMovement(WASD/手柄/XR 移动旋转)+PointerControls(鼠标拖拽/触摸捏合/双击移动/惯性)。
数据与网格:
src/PackedSplats.ts:内存与 GPU 数据封装。每个 splat 精确 16 字节(4×uint32):center(float16×3) + scale(uint8 对数, 范围 e-12~e9) + rgba(uint8×4) + 旋转(轴角八面体征 uint8×3)。提供pushSplat/getSplat/forEachSplat/ensureSplats、GPUDataArrayTexture(RGBA32UI,4096³ 上限)、DynoPackedSplats(可在着色器动态读)、与 Worker/GPU 的共享格式。src/ExtSplats.ts:扩展格式(float32 中心 + 各向异性协方差),用于需要更高精度或 CovSplat 的场景。src/SplatMesh.ts:场景中的泼溅物体(extends SplatGenerator)。持有packedSplats/extSplats/paged,构造时按优先级建立数据源;每帧update(FrameUpdateContext)写 time/recolor/transform/edits;支持objectModifiers/worldModifiers/skinning、LOD/分页、射线拾取raycast、资源释放dispose。src/SplatGenerator.ts:SplatGenerator extends THREE.Object3D(所有泼溅生成器的基类)。定义GsplatGenerator/CovSplatGenerator(index→gsplat 的 dyno 程序)、SplatModifier(带缓存地给生成器套修改器)、SplatTransformer/CovSplatTransformer(把 Object3D 的矩阵变成 dyno uniform 变换)、FrameUpdateContext与updateVersion()机制。src/SplatLoader.ts:THREE.Loader子类,多格式加载器。魔数/扩展名检测(getSplatFileType)、Web Worker 线程池解码、产出PackedSplats/ExtSplats。注:SPZ/PLY/SOG/RAD 的解码实际由 Worker 内的 Rust/WASM 完成(非纯 JS)。src/SplatWorker.ts:Worker 封装(SplatWorker)+ 池(NewSplatWorkerPool,默认 4 worker)。含tryExclusive(独占队列,避免长任务被打断)与call(name, args)的消息协议;构造时把WASM_MODULEpost 给 worker 完成 WASM 初始化。src/wasm.ts:WASM 胶水。用 Vite 的?arraybuffer&base64内联spark-rs.wasm,WebAssembly.compile后init_wasm({module_or_path})实例化,导出WASM_MODULEPromise 与isInitialized()。src/defines.ts:全局常量。LN_SCALE_MIN=-12/LN_SCALE_MAX=9(尺度编码范围,改此处须同步splatDefines.glsl)、SPLAT_TEX_*_BITS=11(2048³ 数组纹理上限,2D 数组纹理可达 8G splats)、WASM_SPLAT_SORT=true、SplatFileType枚举、SplatEncoding/PackedExtra/ExtExtra等类型。
dyno 着色器图系统(最大创新点):
src/dyno.ts:re-export 桶,聚合src/dyno/*。src/dyno/base.ts:图模型核心。Dyno<IOTypes, IOTypes>(节点:inTypes/outTypes +generate()产出 GLSL 片段)、DynoVal(带类型+变量名的边)、DynoBlock(子图,含visit()拓扑排序生成 statements)、dyno()/dynoBlock()工厂、UnaryOp/BinaryOp/TrinaryOp辅助、Compilation(收集 globals/statements/uniforms/updaters)。src/dyno/program.ts:图→GLSL 编译器。DynoProgram调graph.compile()把节点图编译成{{GLOBALS}}/{{STATEMENTS}}模板拼接出的着色器源码,用WeakMap缓存RawShaderMaterial(GLSL3)。DynoProgramTemplate解析模板三段。src/dyno/splats.ts:splat 专用节点。Gsplat/CovSplatGLSL 结构体定义、readPackedSplat/readExtSplat/readCovSplat(texelFetch +unpack*解包)、transformGsplat(缩放/旋转/平移/重着色)、splitGsplat/combineGsplat、法线/纹理坐标节点。src/dyno/{math,logic,trig,vecmat,transform,texture,convert,control,uniforms,util,value,types}.ts:标准库节点(加减乘除、比较逻辑、三角函数、向量矩阵、纹理采样、类型转换、uniform 绑定、字面量/值封装、类型定义)。
生成器、编辑、修饰、工具:
src/SplatGenerator.ts(见上)/src/SplatEdit.ts:实时编辑。SplatEditSdf(SPHERE/BOX/ELLIPSOID/CYLINDER/CAPSULE/CONE/PLANE 等形状)、SplatEdit(一次编辑操作,含SplatEditRgbaBlendMode的 MULTIPLY/SET_RGB/ADD_RGBA)、SplatEdits(把 SDF+编辑编码进 GPU 纹理,作为标准管线里逐点修改器,GPU 上实时改颜色+位移)。src/SplatSkinning.ts:骨骼双四元数变形(SplatSkinningMode)。src/SplatAccumulator.ts:跨场景累加所有SplatGenerator的 gsplat 到单一缓冲,供统一排序渲染。src/SplatGeometry.ts:实例化几何(每实例一个 splat)。src/SplatPager.ts:分页/流式加载(大场景按需取块)。src/Readback.ts:从 GPU 读回像素/深度(排序深度读回、cube targets 读回)。src/SparkPortals.ts:传送门效果(含DISK_PORTAL_FRAGMENT_SHADER)。src/generators.ts+src/generators/{static,snow}.ts:constructGrid/constructAxes/constructSpherePoints/imageSplats/textSplats程序化生成泼溅;generators.static/snow内置生成器。src/modifiers.ts+src/modifiers/{depthColor,normalColor}.ts:SplatModifier集合与按深度/法线着色修改器。src/splatConstructors.ts:程序化构造泼溅的工具。src/hands.ts:手部关节类型与辅助(与SparkXr协同)。src/RgbaArray.ts:RGBA 数组封装(readRgbaArray)。src/shaders.ts+src/shaders/*.glsl:共享 GLSL 片段(splatDefines.glsl、computeUvec4*.glsl等编码/解码辅助)。src/utils.ts:isMobile/isAndroid/isQuest2/isVisionPro、flipPixels、toHalf/fromHalf、floatToUint8、setPackedSplat/unpackSplat等底层工具。src/spz.ts:transcodeSpz/writeSpzSPZ 转码与写出。
4.3 rust/ —— Rust/WASM 核心
rust/spark-lib/:被编译成 WASM 的算法库(spark-rs)。lib.rs聚合模块:- 格式编解码:
ply/spz/ksplat/sogs/rad/antisplat/csplat/gsplat/tsplat(Gslpat/GsplatArray数据结构,含 SPZ 量化 roundtrip 测试)。 - LOD 聚簇:
sh_clustering(球谐聚簇)、bhatt_lod、quick_lod、tiny_lod、chunk_tree(分层分块树)。 - 排序:
ordering(sortSplats32 计数排序)、symmat3(对称阵)。 - 变换/射线:
splat_encode、decoder(流式ChunkReceiver)。 - 通过
wasm-bindgen暴露给 JS,供SplatWorker调用。
- 格式编解码:
rust/spark-rs/:独立的 Rust 消费端 crate(decoder、ext_splats、lod_tree、packed_splats、raycast、sort、transform),README 说明其用途,pkg 被package.json以file:rust/spark-rs/pkg本地引用。rust/build-lod/:离线 LOD 构建 CLI(main.rs+gpu_sh_clustering.rs),npm run build-lod触发。rust/build_wasm.js/build_rust_wasm.sh/build_rust_wasm.ps1/.cargo/config.toml:WASM 构建脚本(跨平台)。
4.4 scripts/ —— 工程脚本
download-assets.js(拉示例资产)、clean-assets.js、compress-to-spz.js(PLY→SPZ)、copy-site-files.js/clean-site-files.js/clean-site.js/serve-site.js/deploy-site.js/rename-assets-to-static.js/replace-urls.js(文档站构建与部署)。
4.5 dist/ —— 构建产物
ESM/CJS/.min、类型声明(dist/types/*.d.ts,含 dyno/ 子目录完整类型)、worker 包、版本 commit.txt。通过 .gitattributes/git update-index --assume-unchanged dist/* 避免误提交。
五、优势、不足、创新点与亮点
1. 优势
- 一等公民集成:
SparkRenderer直接是THREE.Mesh,SplatMesh是Object3D——泼溅与 mesh、灯光、相机、three 生态(OrbitControls、后处理、XR)自然融合。 - 跨设备高性能:瞄准 98%+ WebGL2,低端手机靠三档画质 + 动态 LOD + 注视点降级(foveation)保证流畅;排序/解码/LOD 全在 Worker+WASM,主线程只渲染。
- 格式覆盖广:PLY(含压缩)/SPZ/SPLAT/KSPLAT/SOG/RAD 全覆盖,自动魔数检测。
- 真正动态:每个 splat 可在 GPU 上被变换、重着色、SDF 编辑、骨骼动画——这是多数竞品只做到"静态查看到加载"的差距所在。
- 流式与 LOD:
SplatPager分页 + Rustchunk_tree/sh_clusteringLOD,支持超大场景按需加载与多分辨率。 - 生产级工程:MIT、完整类型声明、Biome lint、CI(Linux+Windows)、文档站、40+ 示例,易于二次开发。
2. 不足
- 学习曲线陡:dyno 着色器图是独特的编程模型,新手需同时理解 three.js、GLSL 与 dyno 节点图,门槛高于直接用 mesh。
- 包体与构建复杂:依赖 Rust 工具链构建 WASM,源码贡献门槛高;
dist体积与 WASM 初始化有成本。 - three 强绑定:peer
three>=0.180.0,锁定较新版本,与旧 three 项目不兼容。 - WebGL2 下限:不支持 WebGL1,极老设备无法运行(但作者宣称 98%+ 覆盖已足够)。
- 排序仍依赖深度读回:
readbackDepth每帧读回深度做 CPU 侧计数排序,理论上存在带宽与延迟开销(作者注释称 JS 与 WASM 排序耗时差异不大,故WASM_SPLAT_SORT默认开但影响有限)。
3. 创新点与亮点
- dyno 着色器图(Dyno Shader Graph)——项目最大亮点。用 TS 以"节点+边(带类型)"搭出计算图,
DynoProgram在运行时把图编译成 GLSL(RawShaderMaterial,GLSL3),并用WeakMap按程序身份缓存材质、按需重编译。这让"在 GPU 上动态生成/编辑泼溅"从"手写 GLSL"变成"搭积木",是 3DGS 领域少见的可组合 GPU 程序抽象。 - 16 字节紧凑编码 + 2048³ 数组纹理——center(float16)/scale(uint8 对数)/rgba(uint8)/旋转(八面体征)把每 splat 压到 16B,配合
DataArrayTexture(211×211×2^11,最高 8G splats),兼顾内存、缓存与上限。 - Rust/WASM 解码与 LOD 内核——SPZ/PLY/SOG/RAD 解码、
sh_clustering/bhatt_lod/chunk_treeLOD 聚簇、计数排序全用 Rust 编译成 WASM,在 Worker 内运行,性能与安全性俱佳,且spark-rs还能作为独立 Rust crate 复用。 - 统一累加 + 多线程驱动架构——
SplatAccumulator把全场景 gsplat 汇成单一缓冲,排序与 LOD 各自在独占 worker(tryExclusive队列)中异步驱动,主线程零阻塞。 - GPU 实时 SDF 编辑——
SplatEdit把多个 SDF 形状(球/盒/椭球/圆柱/胶囊/锥/平面)编码进纹理,在 dyno 管线里以 softmax 混合逐点实时改颜色+位移,支持风、火、水、变形等动画,无需回 CPU。 - 骨架动画与 XR 手部——
SplatSkinning双四元数骨骼变形;SparkXr+JointSplats把 WebXR 25 关节追踪渲染成椭球 splat 手,拓展到 VR/AR。 - 多格式 + 程序化生成——既能加载真实重建,也能用
textSplats/imageSplats/constructGrid等程序化生成泼溅,并内置 snow/static 生成器与 depth/normal 着色修改器,开箱即用。 - 多视点/离屏/环境贴图——同一管线复用为
renderCubeMap/renderEnvMap/renderTarget,支持多相机同时渲染与 splat 参与环境光照。
说明:本解读基于对仓库 README、
package.json、src/全部核心模块(SparkRenderer/PackedSplats/SplatMesh/SplatLoader/SplatWorker/wasm/defines/SplatGenerator/SplatEdit/SparkXr/controls)、src/dyno/*(图模型与 GLSL 编译器)、rust/spark-lib/src/lib.rs模块组织,以及示例/文档/CI 结构的实际抓取,关键结论均锚定在真实代码与文件上。

浙公网安备 33010602011771号