# VDB -> NanoVDB -> WebGPU 实施方案 更新时间:2026-08-14 ## 1. 范围与完成定义 VDB 重新纳入 N-015/N-019/N-023/N-026。产品链路固定为:桌面工具或受控服务端使用 OpenVDB 读取 `.vdb`,转换为 NanoVDB;浏览器只读取受校验的 `.nvdb` 分块,并由 WebGPU 执行稀疏树遍历、采样和体积积分。 浏览器 Blender WASM 必须继续保持 `WITH_OPENVDB=OFF`。`WITH_OPENVDB=ON` 或 `WITH_NANOVDB=ON` 只能证明编译/链接选项,不能证明以下能力: - 外部 VDB 的受限读取、分块上传、失败恢复和缓存淘汰; - NanoVDB 数据布局与 WGSL 遍历正确; - density/temperature/color/emission/velocity 的 Blender 材质语义; - `.blend` 保存、转换产物绑定、重开和资源丢失诊断; - 与 Blender 5.2 桌面图像/数值 golden 一致; - 大体积、损坏输入、取消和 Chromium WebGPU 性能门;resident/page-table 确定性 OOM 门已完成。 只有上述链路均有真实资源与自动测试证据时,VDB 才能从 `BLOCKED` 转为可发布能力。 ## 2. 架构和信任边界 ```text .blend + .vdb | | source SHA-256, grid allowlist, budgets v Desktop/Server Blender 5.2 + OpenVDB + NanoVDB | | deterministic .nvdb + manifest.json + converter identity v Project asset store / HTTP Range / OPFS content-addressed cache | | contiguous ranges, per-chunk SHA-256, whole-bundle SHA-256 v Chromium Storage/Render Worker | | bounded GPU pages, validated grid ranges and transforms v WebGPU storage buffers + WGSL NanoVDB traversal + volume integrator ``` 信任边界如下: 1. `.vdb` 是不可信输入,只允许进入桌面/服务端转换沙箱;浏览器不加载 OpenVDB。 2. 转换器输出也不直接信任。浏览器先校验 schema、路径、预算、连续 range、分块 hash 和整包 hash,再允许 GPU 上传。 3. manifest 是持久化真源,路径必须位于项目资源根;HTTP 必须返回精确 `206 Content-Range`, OPFS 必须使用 content-addressed key。 4. GPU resident set 独立受限,CPU/网络总包预算不能代替 GPU 预算。 5. Main 只保存源绑定、转换版本、产物 hash、grid/material 映射;不能把临时 URL 或未验证 GPU 状态写成已完成资源。 ## 3. 产物与协议 ### 3.1 转换请求 `VDBConversionRequestIR` 固定记录 schema、job、项目内 `.vdb` 路径、源字节数/hash、源 grid 清单、选择 grid、量化策略、分块大小和输出 `.nvdb` 路径。`VDBConverterIdentityIR` 固定记录 DESKTOP/SERVER、Blender/OpenVDB/NanoVDB 版本和转换器可执行文件 hash。 同一源 hash、转换器 identity、选择 grid、量化和 chunk size 必须产生相同的 bundle hash;分别生成 但语义相同的 OpenVDB fixture 允许因文件 UUID 而有不同源 hash,其 NanoVDB grid/bundle 应一致。 job ID 和输出路径不进入内容键;不能仅以文件名作为缓存键。 ### 3.2 NanoVDB bundle manifest `NanoVDBBundleManifestIR` schema 1 记录: - 源 `.vdb` 与 bundle `.nvdb` 的项目路径、长度和 SHA-256,以及包含 grid/量化/chunk 参数的 canonical conversion request SHA-256; - 每个 grid 的 value type/class/semantic、active voxel、标准 NanoVDB segment 范围、内部 grid payload 范围、index/world bounds、voxel size 和 4x4 index-to-world;文件内 payload 偏移不要求 对齐,上传到 GPU storage buffer 时另行满足 32-byte alignment; - density/temperature/color/emission/velocity 材质绑定和受限参数; - 32-byte 对齐、连续覆盖整个 bundle 的 chunks,以及每块 SHA-256; - `NANOVDB_STORAGE_BUFFER`、GPU page/resident budget 和 `volume-wgsl-v1` 语义版本。 首期 GPU value type 白名单为 Float32、Float16、Vec3f32、Vec4f32。Double、Bool、Int、Point Index、未知 grid class 返回 `NANOVDB_GRID_UNSUPPORTED`,不进行隐式转换。 ### 3.3 浏览器流送 `streamNanoVDBChunks` 串行执行 range read -> 分块 hash -> consumer upload,并在每块后报告字节 进度。串行是首期的确定性基线;通过内存峰值和取消测试后才能加入最多 4 路的有界并发。 `createHttpNanoVDBRangeSource` 只接受 HTTP 206,且 `Content-Range` 的起点、终点、总长度必须 与 manifest 精确一致。resumable adapter 对临时状态和网络异常做有界重试;response body 中断后 保留已收字节,以相同 ETag 的 `If-Range` 从精确偏移续传,干净结束的短响应仍直接拒绝。 OPFS 适配器以 `bundleSha256/chunkIndex` 为 key 原子提交。所有块校验完成后才提交完整 bundle manifest;中断留下的 staging 数据不会被重开流程发现,重开后的每次 chunk 读取仍重新校验 SHA-256。 ## 4. 材质与渲染语义 首期声明 `Principled Volume` 有界子集: | Blender 语义 | NanoVDB/manifest | WebGPU 行为 | | --- | --- | --- | | Density | `densityGrid` + `densityScale` | 非负消光/散射密度 | | Temperature | `temperatureGrid` + scale | 只在 Blackbody emission 开启时采样 | | Color | `colorGrid` 或常量颜色 | 线性工作空间散射颜色 | | Emission | `emissionGrid` + scale | 线性辐射项;负值钳制并报告 | | Velocity | `velocityGrid` | 首期仅保留/报告,motion blur 未验证前不消费 | | Anisotropy | manifest scalar | Henyey-Greenstein,范围 `[-0.99, 0.99]` | 首期只开放单 Volume、单散射/吸收积分、线性/最近采样、对象变换和 scene exposure。多重散射、 体积阴影、烟火黑体、motion blur、多个 volume overlap、Cycles 等价保持独立阻断。 WGSL 实现必须包括 NanoVDB header/version/magic 检查、root/internal/leaf address 上界检查、空 节点跳跃、index-to-world/world-to-index、ray-box intersection、自适应步长上限、early transmittance termination 和 NaN 防护。shader 不能通过越界 buffer read 猜测无效节点。 ## 5. 保存与重开 保存流程分两层: 1. Blender Main 中的 Volume 保留项目相对 `.vdb` 引用和 grid/material 参数。 2. Web project manifest 保存 `sourceSha256 -> conversion request -> bundleSha256` 绑定、转换器 identity、chunk manifest 和 OPFS/object-store 定位信息。 重开时先比较 `.blend` Volume 引用、源 hash 和 bundle manifest。源改变、converter 改变、bundle 缺失、hash 不符或 shader semantic version 不符均返回结构化 `BLOCKED` 并要求重转;不能静默 复用旧缓存。保存成功标准包括:清空 Worker、重新打开 `.blend`、重新发现 bundle、逐块复验、 恢复同一 grid/material 映射并得到相同像素/采样摘要。 ## 6. 详细任务分解 ### Phase 0:能力声明与协议 - `VDB-001`:删除浏览器伪 decoder 入口,raw `.vdb` 浏览器解码固定返回 `VDB_CONVERSION_REQUIRED`。状态:`done_current_scope`。 - `VDB-002`:实现 source manifest、conversion request、converter identity、路径/hash/预算门。 状态:`done_current_scope`。 - `VDB-003`:实现 NanoVDB bundle/grid/material/GPU/chunk manifest、range plan、分块与整包 hash 校验。状态:`done_current_scope`。 - `VDB-004`:实现串行 range streamer 和严格 HTTP 206 适配器。状态:`done_current_scope`。 - `VDB-005`:能力门分别报告 desktop converter、server converter、stream、WebGPU renderer; 禁止单一布尔值概括全链路。状态:`done_current_scope`。 ### Phase 1:真实资源与转换器 - `VDB-010`:在本机资源库收录许可证明确的 tiny smoke、density+temperature、color、level-set、 大稀疏体积和损坏文件;记录来源 URL、许可证、原始 SHA-256。状态:`done_current_scope`; 资源库为 `/home/mes123456/resource-library/blender-web-vdb`,含 14 条受 hash 约束记录。 - `VDB-011`:建立 native/desktop CMake preset,OpenVDB 只在该目标开启;固定 Blender 5.2、 OpenVDB/NanoVDB 版本并生成可执行文件 hash。状态:`done_current_scope`;desktop target 实际 链接 OpenVDB 13.0/TBB 并生成 NanoVDB 32.9,浏览器仍保持 `WITH_OPENVDB=OFF`。 - `VDB-012`:实现 grid inventory 预扫、allowlist、active voxel/内存/输出预算和取消,调用官方 OpenVDB/NanoVDB API 写出确定性 `.nvdb`。状态:`done_current_scope`;inventory、allowlist、源/输出/ grid/active voxel 预算、LOSSLESS/FP16、report、确定性、cancel-file、timeout 和失败原子清理已验证。 - `VDB-013`:实现服务端 job API:content hash 幂等、上传/转换/下载、进度、超时、取消、日志、 不可信输入隔离和输出签名。状态:`done_current_scope`;当前以 bubblewrap、只读 root、资源限制、 HMAC 构件签名和原子输出为受控本地服务基线。 - `VDB-014`:桌面与服务端对同一 fixture 的 manifest/bundle hash 相同;版本变化必须导致缓存 key 变化。状态:`done_current_scope`;语义相同的 VDB、官方 sphere 重转及桌面/隔离服务端 转换均得到相同 NanoVDB hash。 ### Phase 2:存储与流送 - `VDB-020`:实现项目 asset manifest 和 source/bundle binding,支持 source hash 变化失效。 状态:`done_current_scope`。 - `VDB-021`:实现 OPFS range source、staging/journal/atomic commit、重启发现和 LRU page cache。 状态:`done_current_scope`;已验证真实 bundle、取消清理、Worker 重开、tamper gate 和 bundle LRU。 - `VDB-022`:实现 HTTP Range 重试、ETag/If-Range、断点续传、重复/乱序/短响应拒绝。 状态:`done_current_scope`;临时状态/网络异常重试、稳定 ETag、response-body 精确偏移续传、 ETag 改变、错位 `Content-Range`、短响应和逐块 hash 均有 Chromium 故障门。 - `VDB-023`:增加网络中断、Worker terminate、quota、tamper、manifest rollback 测试。 状态:`done_current_scope`;网络/body 中断、Worker terminate、真实 OPFS quota、chunk tamper、 manifest rollback、incomplete staging recovery 和旧 bundle 保持均已验证。 - `VDB-024`:在 512 MiB CPU、1 GiB bundle、512 MiB GPU 上限下验证峰值;不得整包复制到 JS heap。`planned`。 ### Phase 3:WebGPU NanoVDB - `VDB-030`:加入 Chromium WebGPU capability probe、adapter/device limits 和 device loss 状态机。 状态:`done_current_scope`;真实 adapter/device limit probe、device loss、device 重建和重传后 固定点 sample 一致已完成;生产视口资源重建仍归 `VDB-034`。 - `VDB-031`:实现 NanoVDB Float/Vec leaf traversal WGSL 和 CPU reference sampler;用固定 index 点比较值与 active/inactive 状态。状态:`in_progress`;Float32 CPU/WGSL 与 native sample 已逐点 一致,Float16/Vec 仍保持阻断。 - `VDB-032`:实现 GPU page allocator、storage buffer upload、indirection、resident LRU 和 dispose;每页上传前已通过 chunk hash。状态:`done_current_scope`;初始空驻留集、显式逐页 hash 校验装入、页表、确定性 LRU、数据级页替换、dispose 和多材质 grid 共享总驻留预算均已 通过 Chromium WebGPU 门。着色器自动回报缺页并驱动渐进重绘不属于本任务,继续由生产视口门阻断。 - `VDB-033`:实现对象 bounds raycast、front-to-back ray marching、步长/early exit 和深度合成。 状态:`in_progress`;有界正交 bounds、front-to-back integration、early exit 和确定性 96x96 Chromium 图像已完成,生产相机深度合成待接入。 - `VDB-034`:接入主线程/Offscreen renderer 的相同 volume scene delta;状态:`done_current_scope`; 双生产视口已消费相同 hash-bound asset 并输出非空像素。生产 Offscreen WebGPU device-loss 自动重建和 demand-page 恢复继续由故障门阻断。 ### Phase 4:材质、Main 与导出 - `VDB-040`:读取 Blender Volume/Principled Volume 节点并生成显式 material mapping/loss report。 状态:`in_progress`;density、常量 color/emission、anisotropy、nearest/linear 已映射, color/temperature/emission grid 和 velocity 明确生成 loss。 - `VDB-041`:density/temperature/color/emission/anisotropy 的 Main writer、undo/redo 和原子事务。 状态:`in_progress`;Volume source/display/interpolation/step/velocity Main 写回、undo/redo、保存重开 已完成,Principled Volume 完整节点事务仍阻断。 - `VDB-042`:保存 `.blend` 与 Web asset binding,清空 Worker 后重开并重新流送。 状态:`done_current_scope`;Main Volume、OPFS asset binding、Worker 重建与主线程/Offscreen 两个生产视口已在同一 revision/hash 闭环联合重开。 - `VDB-043`:GLB 明确报告 Volume 无核心映射;USD 仅在 desktop USD/OpenVDB 路径真实可用时 写入 field asset,不把 bounds proxy 当体积导出。`BLOCKED`。 ### Phase 5:真实验收与发布 - `VDB-050`:desktop OpenVDB -> NanoVDB grid count/name/type/transform/bounds/value sample golden。 - `VDB-051`:Blender 5.2 与 Chromium WebGPU 的至少 3 个视角像素 golden,分别比较 alpha、 transmittance、color,记录容差与色彩空间。状态:`done_current_scope`;OpenVDB 13 native density reference 与主线程/Offscreen WebGPU 的 X/Y/Z 三轴 RGBA8 逐通道比较均为零误差。 - `VDB-052`:64 MiB/512 MiB/1 GiB sparse bundle 的首帧、渐进清晰、峰值 CPU/GPU 和取消门。 状态:`in_progress`;64 MiB 实际 range、4 MiB 峰值工作集与中途取消已通过,512 MiB/1 GiB 仍按设备和 CI 预算保持阻断。 - `VDB-053`:损坏 magic/version/tree offset/hash、zip bomb 等价超预算、NaN transform、设备丢失、 网络中断和 OOM 门。状态:`in_progress`;resident/page-table 确定性 OOM、唯一释放和同设备 小 resident grid 恢复已完成,其余大 bundle 与联合故障矩阵仍阻断。 - `VDB-054`:保存重开、资源缺失、源变更重转、旧 schema migration、离线 OPFS 重开。 - `VDB-055`:N-026 证据记录包含真实转换器、资源、Chromium WebGPU、desktop golden 和构件 hash。 Phase 5 整体仍为 `BLOCKED`,不能由 Phase 0 的协议 fixture 代替;`VDB-053` 的确定性 resident OOM 子切片已有真实 Chromium WebGPU 资源证据,但不扩大为大 bundle 或完整 Phase 5 完成声明。 ## 7. 验收命令与停止条件 当前可运行门: ```bash npm --prefix web run typecheck npm --prefix web run test:vdb npm --prefix web run test:vdb-availability npm --prefix web run test:vdb-native npm --prefix web run test:vdb-server npm --prefix web run test:vdb-opfs npm --prefix web run test:vdb-webgpu npm --prefix web run test:vdb-viewport npm --prefix web run test:vdb-faults ``` 阶段停止条件: - 新增资源若无许可证/来源/hash:不得进入 VDB catalog 或 golden。 - desktop/server converter 已构建并有 hash 等价证据;未配置受控 endpoint 时运行时 `SERVER_CONVERSION` 仍保持 `BLOCKED`。 - 无 CPU reference sample 对照:WGSL traversal 不得进入 `READY`。 - 仅能显示 box/point proxy:体渲染仍为 `BLOCKED`。 - 未验证 material mapping、Main 保存重开或 desktop/Chromium golden:N-015 与 N-019 仍为 `BLOCKED`。 - Chromium 是当前唯一浏览器门;不配置 Firefox/WebKit,也不把未测浏览器写成兼容。