Add Chromium-only Blender WebEngine parity work
This commit is contained in:
209
docs/BLENDER_5_2_WEB_FEATURE_PARITY.md
Normal file
209
docs/BLENDER_5_2_WEB_FEATURE_PARITY.md
Normal file
@@ -0,0 +1,209 @@
|
||||
# Blender 5.2 Web 功能对标与全量迁移台账
|
||||
|
||||
更新时间:2026-08-12
|
||||
|
||||
本文件以仓库内 `blender-5.2.0/source/blender/` 为基线,记录 Blender 功能域在 Web
|
||||
项目中的迁移方式和唯一领取顺序。`completed_current_scope` 只表示声明子集通过验收,
|
||||
不表示桌面 Blender 全量等价。任何未列入白名单的 operator、node、strip、physics
|
||||
类型或数据块都必须返回机器可读阻断,不能由 Three.js 静默近似。
|
||||
|
||||
## 完成定义
|
||||
|
||||
一个功能只有同时满足以下条件,才能从 `planned` 转为 `done_current_scope`:
|
||||
|
||||
1. 版本化协议和输入预算;linked/missing/corrupt/cycle 等安全门有稳定错误码。
|
||||
2. 修改 Blender Main,而不是只修改 React/Three.js 状态;支持 undo/redo。
|
||||
3. SceneIR/二进制 buffer/SceneDelta 可读回,保存、关闭、重开语义一致。
|
||||
4. Blender 5.2 desktop 与 WASM fixture/golden 比较通过。
|
||||
5. Chromium 主线程/OffscreenCanvas、Worker restart、OPFS quota、malformed input 和内存门通过。
|
||||
6. UI 只发命令并消费权威快照;不支持输入有可诊断状态。
|
||||
7. 导出前报告语义损失;不能映射时拒绝导出,不静默删除数据。
|
||||
|
||||
## 功能域矩阵
|
||||
|
||||
| Blender 5.2 功能域 | 当前 Web 状态 | Web 目标 | 后续任务 |
|
||||
| --- | --- | --- | --- |
|
||||
| `.blend` read/write、Main、undo、崩溃恢复 | `done_current_scope` | 浏览器本地 WASM + OPFS 权威闭环 | N-001/N-006/N-009/N-010 持续回归 |
|
||||
| Scene/Object/Collection/Parent/Transform | `done_current_scope` | 本地 Main 编辑和增量视口 | N-007 持续扩 fixture |
|
||||
| Mesh Object/Edit Mode | `done_current_scope` 有限 operator | 补选择历史、knife、rip、bridge、spin、normals、data transfer | N-007 后续矩阵 |
|
||||
| Modifier/Depsgraph | `done` 能力矩阵,求值为有限白名单 | 扩 modifier family、GN、simulation 和循环/目标资源门 | N-002/N-012 |
|
||||
| UV/Image/Material slot | `done_current_scope` | seam/unwrap/pack、多 UV、UDIM、paint image lifecycle | N-004/N-013/N-017 |
|
||||
| Sculpt | `in_progress` 有界 CPU/Main stroke | PBVH、四笔刷 desktop 等价、Mask/Face Set、恢复和 UI | N-011 |
|
||||
| Geometry Nodes | `in_progress` 协议/资源/cache | Blender lazy-function/field、实例、属性域和 group 闭包 | N-012 |
|
||||
| Simulation Zone | `in_progress` cache 安全层 | desktop bake 消费,再启用可取消的浏览器 bake | N-012 |
|
||||
| Shader Nodes | `in_progress` 七节点 Main 子集 | Mix/Mapping/TexCoord/Bump、受限 compiler、颜色空间 | N-013 |
|
||||
| Object Action/FCurve/Timeline | `done_current_scope` | handle/tangent、channel/group、driver 安全子集 | N-014/N-024 |
|
||||
| Armature/Pose/Constraint/Shape Key | `done_current_scope` 读取/求值 | edit bones、pose tools、weight paint、更多约束和驱动 | N-003/N-014/N-017 |
|
||||
| NLA | `in_progress` Action Clip/reverse/repeat 子集 | 多轨混合、Transition/Meta、Animated Time、UI 和导出 | N-014 |
|
||||
| Curve/Curves/Surface/Text/Metaball | `in_progress` reader/预览子集 | 数据块 IR、Main operator、tessellation 和保存闭环 | N-015 |
|
||||
| Point Cloud/Volume/Hair | `in_progress` 摘要/资源门 | 有界数据读取、分块 buffer、视口和资源预算 | N-015 |
|
||||
| Grease Pencil/Drawing | `planned` | layer/frame/drawing/stroke、onion skin 和基础 modifier | N-016 |
|
||||
| Vertex/Weight/Texture Paint | `planned` | Main/PBVH image transaction、颜色管理和恢复 | N-017 |
|
||||
| Rigid/Soft Body、Cloth、Fluid、Particles | `planned` | 优先消费 desktop bake;WASM 求值逐 family feature probe | N-018 |
|
||||
| Camera/Light/World/Color Management | `metadata/viewport subset` | SceneIR/Three/WebGPU 映射、阴影、曝光和差异报告 | N-019 |
|
||||
| Eevee/Cycles/Freestyle/Render Result | `planned` | WebGPU 实时子集;Cycles/硬件后端采用服务端 Blender | N-019 |
|
||||
| Compositor | `planned` | 受限 node graph + WebGPU/CPU executor;完整图可服务端执行 | N-020 |
|
||||
| Video Sequencer/Audio | `planned` | strip/time/edit proxy;codec 能力探测;最终编码可服务端 | N-021 |
|
||||
| Movie Tracking/Mask | `planned` | 数据/编辑协议和基础浏览器工具;重计算按能力门 | N-022 |
|
||||
| Asset Browser/Library/Override | `partial` | catalog、preview、append/link/override、路径与来源沙箱 | N-023 |
|
||||
| Import/Export formats | `GLB subset` | glTF/OBJ/PLY/STL/USD/Alembic 能力矩阵和 desktop round-trip | N-023 |
|
||||
| Blender editors/workspaces/keymap | `partial shell` | View3D/Outliner/Properties/UV/Node/Graph/Dope/NLA/Spreadsheet | N-024 |
|
||||
| Python Console/Text/Add-ons | `blocked_by_security` | 默认禁用;签名脚本沙箱或服务端 Blender,绝不执行任意代码 | N-025 |
|
||||
| Native window/GPU device/CUDA/Metal/HIP | `platform_not_equivalent` | 浏览器 API 适配或服务端执行,保持明确 capability report | N-025 |
|
||||
| 国际化、无障碍、输入设备、帮助系统 | `partial` | locale/keymap/accessibility 和可测试的偏好设置 | N-026 |
|
||||
|
||||
## 连续执行顺序
|
||||
|
||||
必须先完成当前运行时语义,再扩大数据块和编辑器:
|
||||
|
||||
```text
|
||||
N-011 PBVH Sculpt
|
||||
-> N-012 GN/Simulation
|
||||
-> N-013 Shader/compiler
|
||||
-> N-014 NLA
|
||||
-> N-015 非 Mesh 几何数据块
|
||||
-> N-016 Grease Pencil
|
||||
-> N-017 Paint/Weight
|
||||
-> N-018 Physics/Simulation
|
||||
-> N-019 Lighting/Render
|
||||
-> N-020 Compositor
|
||||
-> N-021 Sequencer/Audio
|
||||
-> N-022 Tracking/Mask
|
||||
-> N-023 Asset/IO
|
||||
-> N-024 Editors/UI
|
||||
-> N-025 Scripting/Platform adapters
|
||||
-> N-026 全域发布门
|
||||
```
|
||||
|
||||
UI 任务可以提前制作只读视图,但不得在对应 Main writer 和保存语义完成前开放编辑。
|
||||
|
||||
## N-015 非 Mesh 几何数据块
|
||||
|
||||
1. N-015-A(`done_current_scope`):`NonMeshDataIR` 和 WNM schema 1 已覆盖 Curve、Curves、
|
||||
Surface、Font、Metaball、PointCloud、Volume、Hair,提供 stable ID、状态、属性 domain、
|
||||
65,536 点 chunks、SHA-256、256 MB 场景预算和 1M 点性能门。
|
||||
2. N-015-B(`done_current_scope`):native reader 已读取真实 PointCloud/Curves position、
|
||||
radius、curve offset 和属性;depsgraph 对 Curve/Surface/Font/Metaball 输出真实 mesh、UV、
|
||||
材质槽和 source face mapping;Volume 保持项目路径与 VDB grid/decoder 安全门。
|
||||
3. N-015-C(`in_progress`):Curve/Surface control point/resolution、有界 cyclic/handle metadata、
|
||||
bounded Poly Curve create/delete、Poly/Bezier conversion、Curve/Surface/Font/Metaball 数据块 rename、
|
||||
Font body/geometry properties、逐字符样式/textbox、已有/packed VFont 四样式链接和
|
||||
Metaball element Main command 已支持并通过 undo/save/reopen;一维多 spline 创建/删除/重排、
|
||||
批量 handle/cyclic 和二维 Surface U/V topology/order/rational weight transaction 已通过
|
||||
undo/save/reopen 与 depsgraph 求值;多 handle 选择拖拽/gizmo UI 和任意外部路径字体导入仍推进。
|
||||
4. N-015-D(`in_progress`):Three.js 主线程和 OffscreenCanvas Worker 共享 WNM chunks,真实
|
||||
PointCloud/Curves 可预览,Point/Curve bounded raycast、Metaball proxy 与 evaluated mesh 分层;
|
||||
左右 handle identity raycast/单 handle 轴向 gizmo 已完成;WebGPU、跨对象 selection history、
|
||||
多 handle 拖拽和 SceneDelta range patch 仍待完成。
|
||||
5. N-015-E(`in_progress`):Blender 5.2 fixture、Chromium 双 renderer、depsgraph 真求值、GLB
|
||||
拒绝/映射和 USD loss report、Main roundtrip、desktop golden、7 对象 GLB/USD round-trip、
|
||||
1M binary gate、Worker restart 与 Chromium 真实 OPFS quota 已接入;VDB renderer 仍是
|
||||
当前阻断。后续浏览器验收仅覆盖 Chromium,不配置 Firefox/WebKit。
|
||||
|
||||
专项字段、验收命令和停止条件见 `docs/status/N-015.md`。
|
||||
|
||||
## N-016 Grease Pencil
|
||||
|
||||
1. N-016-A:Layer/Frame/Drawing/Stroke/Point/Attribute schema 与最大 layer/frame/point 预算。
|
||||
2. N-016-B:Main create/remove/reorder layer,insert/remove frame,draw/erase stroke transaction。
|
||||
3. N-016-C:material、onion skin、cyclic stroke、radius/opacity/color 和基础 modifier reader。
|
||||
4. N-016-D:Chromium 主线程/Offscreen 的 3D current-frame stroke preview 已完成;2D editor、
|
||||
stroke/point selection、timeline/dope integration、gizmo 和 worker restart 继续推进。
|
||||
5. N-016-E:desktop drawing hash、像素 golden、save/reopen 和 GLB/USD loss report。
|
||||
|
||||
## N-017 Paint 与权重
|
||||
|
||||
1. N-017-A:Vertex Color/Weight/Texture Paint stroke schema、PBVH/UV hit 和 brush 预算。
|
||||
2. N-017-B:vertex color 与 vertex group Main transaction、normalize/limit/mirror 权重。
|
||||
3. N-017-C:packed/UDIM image tile transaction、色彩空间、dirty tile 和原子保存。
|
||||
4. N-017-D:armature deform golden、seam bleed、mask/face selection 和 undo/redo。
|
||||
5. N-017-E:GPU texture upload/dispose、large image quota、malformed image 和 UI。
|
||||
|
||||
## N-018 Physics 与 Simulation
|
||||
|
||||
1. N-018-A:Rigid Body、Soft Body、Cloth、Fluid、Dynamic Paint、Particle/Hair 能力清单。
|
||||
2. N-018-B:每 family 的 settings/dependency/cache manifest;目标对象和 collection 防循环。
|
||||
3. N-018-C:先消费 Blender desktop deterministic bake,frame seek 不允许复用错误帧。
|
||||
4. N-018-D:逐 family 探测 WASM solver;初始化、线程或内存门失败时保持 bake-only。
|
||||
5. N-018-E:浏览器 bake start/cancel/commit、故障恢复、长任务进度和 100 帧 golden。
|
||||
|
||||
## N-019 灯光与渲染
|
||||
|
||||
1. N-019-A:Camera、Light、World、View Transform、Exposure、Mist、Shadow 的完整 SceneIR。
|
||||
2. N-019-B:Three/WebGPU 映射和 capability report;材质/灯光变化使用增量更新。
|
||||
3. N-019-C:Eevee 有限特性矩阵、shadow map、transparent sorting、probe 和后处理。
|
||||
4. N-019-D:Cycles/Freestyle/硬件 denoise 使用服务端 Blender job 协议与结果 hash。
|
||||
5. N-019-E:desktop/Web 像素误差、色彩管理、设备丢失和 1M 三角形性能门。
|
||||
|
||||
## N-020 Compositor
|
||||
|
||||
1. N-020-A:Compositor GraphIR、socket/link、image/render-layer 资源和 cycle 校验。
|
||||
2. N-020-B:Transform/Color/Alpha/Blur/Mix 等有限 node 的 CPU/WebGPU executor。
|
||||
3. N-020-C:viewer/composite output、frame cache、tile budget 和 worker cancellation。
|
||||
4. N-020-D:unsupported node 保留 metadata 并可提交服务端 Blender,不删图继续执行。
|
||||
5. N-020-E:desktop image golden、HDR/alpha/color-space 和 OOM/fault 门。
|
||||
|
||||
## N-021 Sequencer 与音频
|
||||
|
||||
1. N-021-A:Scene/Movie/Image/Sound/Effect/Meta strip schema、channel、range 和 proxy metadata。
|
||||
2. N-021-B:Main add/remove/move/trim/split、transition 和 modifier 白名单。
|
||||
3. N-021-C:WebCodecs/HTMLMedia capability probe、waveform/proxy 和精确 timeline seek。
|
||||
4. N-021-D:浏览器不支持的 codec/混音/编码提交服务端;资源路径必须沙箱化。
|
||||
5. N-021-E:A/V sync、frame hash、save/reopen、丢帧和损坏媒体测试。
|
||||
|
||||
## N-022 Tracking 与 Mask
|
||||
|
||||
1. N-022-A:MovieClip、Track/Marker、Plane Track、Mask Layer/Spline/Point schema。
|
||||
2. N-022-B:Main marker/mask edit、selection、keyframe 和 camera solve metadata。
|
||||
3. N-022-C:浏览器 tracking feature probe;完整 solve 可使用服务端 Blender。
|
||||
4. N-022-D:Clip/Mask editors、overlay 和 compositor/scene resource binding。
|
||||
5. N-022-E:desktop solve/error golden、媒体故障、保存和重开。
|
||||
|
||||
## N-023 Asset、Library 与 IO
|
||||
|
||||
1. N-023-A:Asset catalog、tag、preview、author/license/source hash 和 OPFS index。
|
||||
2. N-023-B:Append/Link/Library Override Main transaction、reload/relocate 和循环依赖门。
|
||||
3. N-023-C:glTF/OBJ/PLY/STL 首批本地 IO;USD/Alembic 按编译能力或服务端执行。
|
||||
4. N-023-D:每格式 import -> save -> reopen -> export -> desktop reimport 语义比较。
|
||||
5. N-023-E:zip bomb、路径穿越、外部 URI、许可证和大文件流式预算。
|
||||
|
||||
## N-024 Editors 与工作流
|
||||
|
||||
1. N-024-A:统一 Area/Region/Workspace context,不复制 Main state。
|
||||
2. N-024-B:Properties、UV/Image、Node、Graph、Dope Sheet、NLA、Spreadsheet 的只读面。
|
||||
3. N-024-C:对应 writer 完成后开放编辑、selection sync、operator search 和 context menu。
|
||||
4. N-024-D:Blender-compatible keymap、可配置 shortcut、gizmo、drag preview/commit。
|
||||
5. N-024-E:desktop/mobile layout、键盘/触控/笔、无重叠截图和 accessibility 门。
|
||||
|
||||
## N-025 Scripting 与平台适配
|
||||
|
||||
1. N-025-A:默认拒绝任意 Python、Text autorun、driver expression 和 add-on 安装。
|
||||
2. N-025-B:可选签名脚本 manifest、权限、CPU/内存/时间预算和无网络沙箱。
|
||||
3. N-025-C:需要 CPython/native module 的作业走服务端 Blender,结果绑定 source hash。
|
||||
4. N-025-D:CUDA/Metal/HIP/OptiX、native window、file watcher 等返回平台能力报告。
|
||||
5. N-025-E:恶意脚本、依赖混淆、逃逸、重放和审计日志发布门。
|
||||
|
||||
## N-026 全域发布门
|
||||
|
||||
1. 生成 machine-readable parity manifest:每个 Blender family 为
|
||||
`LOCAL_EXACT`、`LOCAL_BOUNDED`、`SERVER` 或 `BLOCKED`。
|
||||
2. 全部正例和阻断 fixture 在 Chromium 主线程/OffscreenCanvas、离线包和 Worker restart 下运行。
|
||||
3. 100k/1M/10M 几何、4k/8k texture、100/1000 frame、长媒体和 simulation cache 基准。
|
||||
4. `.blend`/image/media/script fuzz、OPFS quota、OOM、设备丢失、网络中断和恢复验证。
|
||||
5. 许可证/source offer/SBOM、确定性包、文档状态与测试报告一致后才能发布。
|
||||
|
||||
## 默认验收入口
|
||||
|
||||
新增任务必须把专项命令接入 `web/package.json`,并至少执行:
|
||||
|
||||
```bash
|
||||
source tools/web/emscripten-env.sh
|
||||
cmake --build build_web_blender6 --target web_engine -- -j8
|
||||
bash tools/web/install-web-engine-assets.sh
|
||||
npm --prefix web run typecheck
|
||||
npm --prefix web run lint
|
||||
npm --prefix web test
|
||||
npm --prefix web run test:authoring-roundtrip
|
||||
npm --prefix web run test:capability-gates
|
||||
npm --prefix web run test:e2e
|
||||
```
|
||||
196
docs/PBR_RENDERING_IMPLEMENTATION_PLAN.md
Normal file
196
docs/PBR_RENDERING_IMPLEMENTATION_PLAN.md
Normal file
@@ -0,0 +1,196 @@
|
||||
# Web Blender PBR 渲染实现与任务分解
|
||||
|
||||
更新日期:2026-08-09
|
||||
|
||||
## 1. 目标和声明边界
|
||||
|
||||
目标是在浏览器 3D Viewport 中提供与 Blender Principled 工作流一致、可保存、可重开的
|
||||
PBR 预览。材质参数必须来自 Blender Main,经 SceneIR 传输并由主线程和 OffscreenCanvas
|
||||
Worker 使用相同映射,禁止只修改 Three.js 临时状态。
|
||||
|
||||
当前能力称为 `physical-v1`,不是 Cycles、EEVEE 或 Blender Shader Node 的逐像素等价实现。
|
||||
它保证的是有界 Principled 参数、线性色彩输入、sRGB 输出、ACES Filmic tone mapping、
|
||||
World exposure、场景灯光和有界 PCF 阴影的一致 WebGL 渲染。未声明节点、谱渲染、光程、体积、
|
||||
次表面、多次散射和离线 path tracing 必须继续结构化阻断或降级并给出 warning。
|
||||
|
||||
## 2. 权威数据流
|
||||
|
||||
```text
|
||||
Blender Main
|
||||
-> .blend writer/save/reopen
|
||||
-> native blend reader
|
||||
-> SceneIR MaterialIR/LightIR/WorldIR
|
||||
-> transferable mesh buffers
|
||||
-> shared pbr.ts mapping
|
||||
-> main-thread WebGLRenderer
|
||||
-> OffscreenCanvas render Worker
|
||||
```
|
||||
|
||||
编辑链路为:Inspector 控件 -> `setMaterialPrincipled` -> EngineWorker -> Blender Main 节点
|
||||
socket -> 新 revision SceneIR -> 视口重建。任何新增参数必须同时通过命令校验、Main 写回、
|
||||
reader、SceneIR parser、保存重开和双后端验收。
|
||||
|
||||
## 3. Blender 到 Web 的材质映射
|
||||
|
||||
| Blender 5.2 Principled 输入 | SceneIR | Three.js | 范围/说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| Base Color | `baseColor` | `color` | 线性 RGB,alpha 独立处理 |
|
||||
| Roughness | `roughness` | `roughness` | `[0,1]` |
|
||||
| Metallic | `metallic` | `metalness` | `[0,1]` |
|
||||
| IOR | `ior` | `ior` | 当前限定 `[1,2.333]` |
|
||||
| Specular IOR Level | `specularIORLevel` | `specularIntensity` | Blender 中性值 0.5 映射到 Three 中性值 1.0;高半区有界截断 |
|
||||
| Transmission Weight | `transmissionWeight` | `transmission` | `[0,1]`,使用物理透射 pass |
|
||||
| Coat Weight | `coatWeight` | `clearcoat` | `[0,1]` |
|
||||
| Coat Roughness | `coatRoughness` | `clearcoatRoughness` | `[0,1]` |
|
||||
| Emission Color | `emissionColor` | `emissive` | 线性 RGB |
|
||||
| Emission Strength | `emissionStrength` | `emissiveIntensity` | `[0,1000000]` |
|
||||
| Alpha | `alpha` | `opacity/transparent/depthWrite` | alpha blend 时关闭 depth write |
|
||||
|
||||
材质选择高亮保存原始 emission 和强度,取消选择后恢复,不再破坏自发光材质。所有网格、
|
||||
实例和 LOD 都启用一致的 cast/receive shadow 标志。
|
||||
|
||||
## 4. 色彩、灯光和阴影
|
||||
|
||||
- Blender/SceneIR 数值按线性工作空间进入材质和灯光。
|
||||
- WebGL 输出固定为 `SRGBColorSpace`,tone mapping 固定为 `ACESFilmicToneMapping`。
|
||||
- `WorldIR.exposure` 按摄影 stop 转换为 `2 ** exposure`,并限制在 `[-8,8]`。
|
||||
- 无场景灯时使用低强度中性 Hemisphere fill 和有阴影的 key light,确保空场景可检查。
|
||||
- POINT、SUN、SPOT、AREA 均从 `LightIR` 创建。SUN/SPOT 根据 Blender 本地 `-Z`
|
||||
方向创建真实 Three target,不再错误地全部指向世界原点。
|
||||
- SUN、SPOT、POINT 使用 `PCFShadowMap`,第一质量档为 1024 平方 shadow map,并设置
|
||||
有界 bias、normal bias、near/far。AREA 受 Three WebGL 能力限制,当前不声明阴影等价。
|
||||
- 主线程与 Worker 暴露 `data-pbr-profile`、`data-tone-mapping` 和 `data-shadow-map`,供
|
||||
自动化测试核对真实后端配置。
|
||||
|
||||
## 5. 资产和纹理边界
|
||||
|
||||
当前 SceneIR 已表达 UV、Image Texture、Normal Map、packed image 和资源状态,但纹理像素
|
||||
进入 GPU 的链路必须继续遵守 EngineWorker/StorageWorker 权威模型。浏览器渲染器不得根据
|
||||
`.blend` 内路径自行访问文件系统或网络。
|
||||
|
||||
PBR-007 已建立 `GPUTextureAsset` 只读载荷:`assetId`、`imageId`、SHA-256、MIME、尺寸、
|
||||
颜色空间、用途、UDIM tile 和 `ArrayBuffer` 必须通过字节数、64 MiB 单图、16384 维度和
|
||||
SHA-256 校验后才可进入 `ImageBitmap`/Three `Texture`。主线程与 Offscreen Worker 共享同一
|
||||
`GPUTextureStore` 逻辑,载荷状态和拒绝字节数可观测;路径仍只能由 EngineWorker/StorageWorker
|
||||
解析,浏览器不得访问 `.blend` 内路径。当前不把 context-loss 自动恢复、mipmap/anisotropy
|
||||
策略和完整 UV Map 节点映射误报为完成。
|
||||
|
||||
## 6. 质量档和性能预算
|
||||
|
||||
| 档位 | 阴影 | DPR | 透射 | 目标 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Low | 关闭或 512 | 1 | 关闭 | 低内存移动设备 |
|
||||
| Medium | PCF 1024 | `min(device,1.5)` | 0.5 分辨率 | 默认移动/集显 |
|
||||
| High | PCF 1024/2048 | `min(device,2)` | 全分辨率 | 默认桌面 |
|
||||
|
||||
`physical-v1` 当前实现 High 的有界子集。后续自动降档的输入包括 GPU tier、draw call、
|
||||
transmission material 数、shadow caster 数、WASM/GPU 内存压力和帧时间 P95。质量切换只能
|
||||
改变表现质量,不得改变 Main 或保存语义。
|
||||
|
||||
## 7. 任务分解与执行顺序
|
||||
|
||||
### PBR-001 协议与安全门:done
|
||||
|
||||
- PBR-001-A:扩展 `MaterialIR` 五个物理参数,保持旧 snapshot 可解析。
|
||||
- PBR-001-B:对比例参数验证 `[0,1]`,对 emission strength 设硬上限。
|
||||
- PBR-001-C:扩展 `setMaterialPrincipled`,所有字段保持 optional 兼容旧客户端。
|
||||
- PBR-001-D:linked material 继续拒绝写回;NaN/Infinity 继续由 native 阻断。
|
||||
|
||||
### PBR-002 Blender Main authoring:done
|
||||
|
||||
- PBR-002-A:自建 Principled 节点补齐五个 Blender 5.2 socket。
|
||||
- PBR-002-B:命令写入 Base/Roughness/Metallic/IOR/Specular/Transmission/Coat/Emission。
|
||||
- PBR-002-C:native reader 从真实 socket 读取并生成 SceneIR。
|
||||
- PBR-002-D:Main round-trip 和 save/reopen 核对每个物理参数误差小于 `1e-5`。
|
||||
|
||||
### PBR-003 共享物理材质适配器:done
|
||||
|
||||
- PBR-003-A:用 `MeshPhysicalMaterial` 替代两条路径的 Standard/fixed material。
|
||||
- PBR-003-B:集中 clamp、默认值、透明深度策略和 selection emission 恢复。
|
||||
- PBR-003-C:主线程、Worker、实例和 LOD 使用同一映射。
|
||||
- PBR-003-D:Worker 恢复 UV、corner color 和多材质 triangle group。
|
||||
|
||||
### PBR-004 色彩管理和曝光:done
|
||||
|
||||
- PBR-004-A:线性输入、sRGB output、ACES Filmic。
|
||||
- PBR-004-B:World exposure 按 stop 映射并限制极端值。
|
||||
- PBR-004-C:通过 canvas profile 属性和像素非空门验证双后端。
|
||||
|
||||
### PBR-005 灯光和阴影:done_current_scope
|
||||
|
||||
- PBR-005-A:POINT/SUN/SPOT/AREA 类型映射。
|
||||
- PBR-005-B:修复 SUN/SPOT 方向 target。
|
||||
- PBR-005-C:SUN/SPOT/POINT PCF 阴影、bias 和 shadow camera 边界。
|
||||
- PBR-005-D:待补能量单位校准 fixture、级联太阳阴影、AREA 阴影替代和 caster budget。
|
||||
|
||||
### PBR-006 材质 Inspector:done_current_scope
|
||||
|
||||
- PBR-006-A:增加 IOR、Specular、Transmission、Coat、Coat Roughness、Emission Strength。
|
||||
- PBR-006-B:应用命令保留 alpha 和 emission color。
|
||||
- PBR-006-C:待补材质槽选择、emission color、alpha mode、双面和 blend mode 面板。
|
||||
|
||||
### PBR-007 纹理像素闭环:in_progress(AssetPayload/解码已完成,GPU 生命周期仍有安全门)
|
||||
|
||||
- PBR-007-A:done_current_scope;`render-assets.ts` 定义 schema v1、SHA-256、MIME/尺寸/字节预算和稳定错误码,App 从 `requestAsset` 生成载荷并同时写入 OPFS。
|
||||
- PBR-007-B:done_current_scope;Base Color/Emission 使用 sRGB,Normal/Data 使用 non-color/linear,主线程和 Worker 使用相同 `GPUTextureStore`。
|
||||
- PBR-007-C:in_progress;ImageBitmap 解码、旧 Texture dispose、状态回传已完成;mipmap、anisotropy、GPU context-loss 恢复和全局显存预算仍未开放。
|
||||
- PBR-007-D:Normal Map 切线空间、UV Map 选择、wrap/filter 和缺失纹理 fallback。
|
||||
- PBR-007-E:in_progress;双后端同一载荷正例已覆盖,context-loss/Worker crash 后重新上传仍属于 PBR-011 故障注入门。
|
||||
|
||||
### PBR-008 UDIM 与外部资源:in_progress(manifest/阻断已完成,多 tile 采样未声明)
|
||||
|
||||
- PBR-008-A:done_current_scope;`UDIMManifest` 校验 1001..1999、u/v 坐标、重复 tile、数量上限和 packed 状态;每个 tile 进入同一 SHA-256 载荷。
|
||||
- PBR-008-B:in_progress;当前只允许单 tile 安全上传,多 tile 返回 `UDIM_MULTI_TILE_UNAVAILABLE`,尚未实现分页、LRU 和 GPU atlas/array 采样。
|
||||
- PBR-008-C:done_current_scope;linked library、外部路径和缺 tile 使用结构化门,禁止任意路径读取。
|
||||
- PBR-008-D:done_current_scope;generated/sequence/movie 不生成静态 GPU 载荷,保持独立 capability。
|
||||
|
||||
### PBR-009 IBL 和 World Nodes:in_progress(有限 raster equirectangular IBL)
|
||||
|
||||
- PBR-009-A:in_progress;packed PNG/JPEG equirectangular 环境可经 GPU 载荷、PMREMGenerator 生成反射环境;HDR/EXR 解码尚未实现并返回 `IBL_FORMAT_UNSUPPORTED`。
|
||||
- PBR-009-B:in_progress;WorldIR 已携带 environment image/strength/rotation 字段,当前只消费 strength;旋转、跨场景缓存和完整 HDR 色域仍待安全门。
|
||||
- PBR-009-C:done_current_scope;`backgroundVisible` 与 `scene.environment` 生命周期分离,旧 PMREM target 会释放。
|
||||
- PBR-009-D:done_current_scope;任意 World Shader Node 不进入纹理上传,保持结构化阻断。
|
||||
|
||||
### PBR-010 GLB PBR 扩展:done_current_scope
|
||||
|
||||
- PBR-010-A:已导出 `KHR_materials_ior`、`transmission`、`clearcoat`、`specular`、`emissive_strength`,并保留无完整节点图时的有界 `imageIds` Base Color/Normal 路径。
|
||||
- PBR-010-B:桌面 Blender 再导入比较覆盖 8x8 packed texture、骨骼、shape key、动作和材质基础值。
|
||||
- PBR-010-C:不支持的 Blender 图返回 `SHADER_GRAPH_UNMAPPABLE`,禁止静默烘焙。
|
||||
- PBR-010-D:advanced extension fixture 已验证桌面 Blender 对 IOR、Specular IOR Level、Transmission、Coat 和 Emission Strength 的导入数值。
|
||||
|
||||
### PBR-011 性能、容错和跨浏览器:planned
|
||||
|
||||
- PBR-011-A:100k/1M 三角形下记录 CPU/GPU 帧时、draw call、shader compile 和显存。
|
||||
- PBR-011-B:Chromium 主线程/OffscreenCanvas 的 ACES、transmission 与 shadow 差异矩阵。
|
||||
- PBR-011-C:WebGL context loss、Worker crash、纹理解码失败和 GPU OOM 故障注入。
|
||||
- PBR-011-D:自动降档必须可观测且不修改权威数据。
|
||||
|
||||
### PBR-012 高级渲染:in_progress(能力查询/阻断协议,运行时家族仍未声明)
|
||||
|
||||
- PBR-012-A:done_current_scope;`queryRenderCapability` 明确返回 `WEBGPU_RENDERER_UNAVAILABLE`,没有 WebGPU renderer bundle 时不伪装为 WebGPU。
|
||||
- PBR-012-B:done_current_scope(安全门);BLOOM/SSAO/SSR/TAA/DOF/MOTION_BLUR 未有真实 pass 时返回 `POSTPROCESS_PASS_UNAVAILABLE`,未声明假实现。
|
||||
- PBR-012-C:done_current_scope(安全门);Volume/SSS 返回独立 `VOLUME_SHADER_UNAVAILABLE`/`SUBSURFACE_SHADER_UNAVAILABLE`,任意 Shader node 返回 `SHADER_NODE_UNSUPPORTED`。
|
||||
- PBR-012-D:浏览器 path tracer 若引入,作为独立 Render backend,不声称 Cycles 等价。
|
||||
|
||||
## 8. 当前验收
|
||||
|
||||
```bash
|
||||
source tools/web/emscripten-env.sh
|
||||
cmake --build build_web_blender6 --target web_engine -- -j8
|
||||
bash tools/web/install-web-engine-assets.sh
|
||||
npm --prefix web run typecheck
|
||||
npm --prefix web run lint
|
||||
npm --prefix web test
|
||||
npm --prefix web run test:authoring-roundtrip
|
||||
WEB_TEST_PORT=5209 npm --prefix web run test:e2e -- -g "PBR|Principled|local UV|packed raster|OffscreenCanvas"
|
||||
```
|
||||
|
||||
发布前还要运行完整 E2E、跨浏览器、GLB Blender round-trip 和离线包门。桌面与移动截图必须
|
||||
检查 canvas 非空、模型构图、材质高光/阴影可见、控件不遮挡以及页面无异常横向溢出。
|
||||
|
||||
## 9. 完成定义
|
||||
|
||||
一个 PBR 子任务只有在以下条件全部满足后才能标记 done:协议字段可验证;Main 可写;
|
||||
保存重开等价;主线程和 Worker 可渲染;资源可释放;错误稳定且结构化;至少一个正例和一个
|
||||
边界反例;桌面/移动像素与截图门通过;状态文档同步。仅识别 Blender socket、仅构造
|
||||
SceneIR 或仅显示 UI 控件都不构成完成。
|
||||
237
docs/PROJECT_STATUS_AND_NEXT_WORK.md
Normal file
237
docs/PROJECT_STATUS_AND_NEXT_WORK.md
Normal file
@@ -0,0 +1,237 @@
|
||||
# Web Blender 项目现状与后续连续任务
|
||||
|
||||
更新时间:2026-08-12
|
||||
|
||||
## 1. 当前结论
|
||||
|
||||
项目已经形成可运行的 Web 三维编辑器工程骨架,但还不是“Web 版完整
|
||||
Blender”。当前成熟度是:Web 基础设施和数据通路已成形,网格轻量化、骨骼
|
||||
数据、packed image 和 GLB 已有专项实现;完整 Blender Depsgraph、完整 modifier
|
||||
语义和 Blender 的全部工具仍不是当前承诺;已声明的 Mesh Edit、材质/UV、动画和对象层级
|
||||
工作流均经过 Blender Main、撤销、原子保存和重开闭环。
|
||||
|
||||
浏览器端技术边界保持不变:React 负责界面,Three.js 负责全部实时渲染,
|
||||
Blender C/C++ 子集编译为 WASM,OPFS 保存大文件,IndexedDB 保存小型元数据。
|
||||
SQLite WASM 和 Bitbybit/OCCT 均不在当前依赖范围内。Three.js、WASM 和其他
|
||||
运行时资源全部使用项目本地文件,不依赖 CDN。
|
||||
|
||||
## 2. 已完成并有测试覆盖的能力
|
||||
|
||||
| 能力 | 当前证据 | 状态 |
|
||||
| --- | --- | --- |
|
||||
| React + Blender 风格工作区壳 | Topbar、Viewport、Outliner、Properties、Timeline、状态栏和截图 golden | 已完成基础壳 |
|
||||
| Three.js 本地渲染 | 本地 vendor、SceneIR 适配、选择/相机/网格显示 | 已完成基础链路 |
|
||||
| Worker/C ABI/WASM 启动 | EngineWorker、错误协议、内存统计、离线 manifest 哈希 | 已完成 |
|
||||
| `.blend` 数据读取 | 场景、对象、Mesh、非 Mesh 摘要、材质、图片、相机、灯光、动画和稳定 ID | 已完成已声明子集 |
|
||||
| OPFS/IndexedDB | 项目、快照、LOD、SHA-256 资产、原子保存 journal 和 Worker 重启恢复 | 已完成当前存储链路 |
|
||||
| Decimate/LOD | native Collapse、多比例 golden、边界和非流形专项、LOD 缓存发现 | 已完成已声明子集 |
|
||||
| 蒙皮轻量化 | 四权重重映射、归一化、bind matrix 保留、shape key 重映射和策略阻断 | 已完成专项链路 |
|
||||
| Blender 变形 golden | Blender 5.2 shape key + armature 基准及 Web 误差检查 | 已完成当前 fixture |
|
||||
| Packed image | PackedFile、双 tile UDIM、generated、linked library、损坏签名、路径沙箱和 OPFS SHA-256 去重/重发现 | 已完成当前资源矩阵 |
|
||||
| GLB | 本地导出、严格解析,以及 Blender 5.2 回导比较网格/PBR/纹理/morph/skin/animation | 已完成当前 SceneIR 子集 |
|
||||
| Modifier/undo | modifier enable 状态、命令 revision、undo/redo 和专项 smoke | 已完成基础命令链路 |
|
||||
| Mesh Edit | 点/边/面选择,Merge/Dissolve/Extrude/Inset/Bevel/Loop Cut,Main 保存重开 | 已完成当前操作集 |
|
||||
| 材质与 UV | 材质槽/面分配、UV Map、planar/cube unwrap、限定 Principled/Image/Normal 图、图片打包 | 已完成当前节点集 |
|
||||
| 动画编辑 | TRS 关键帧、Timeline/Dope Sheet、插值、Action 选择和约束开关/影响 | 已完成当前操作集 |
|
||||
| 对象层级 | Parent/Unparent、Collection、rename、Join/Separate、Apply Transform、Origin | 已完成当前操作集 |
|
||||
| SceneIR 扩展 | tangent/split normal/seam/sharp/vertex group/attribute/UV,native WBG1、资源 Delta 和 mesh byte-range patch | 已完成当前数据契约 |
|
||||
| Sculpt 属性 | Mask/Face Set 的 SceneIR、WBG1 header v2、Delta、Main、undo 和保存重开 | 已完成属性子集;有界四笔刷 Main stroke 已开放,PBVH/完整求值未开放 |
|
||||
| Simulation cache | Blender 5.2/source blend/hash/frame manifest、OPFS 内容寻址、schema 6、重启逐帧复验 | 已完成缓存安全层;Simulation evaluator 未开放 |
|
||||
| Shader Main | RGB/Value/Principled/Image Texture/Normal Map/Output 整图事务、资源门和保存重开 | 已完成六节点写回子集;任意图/编译仍阻断 |
|
||||
| NLA Main | 单对象 Action Clip 整栈写回、SceneIR 重开和 native frame 求值 | 已完成有限 Action Clip 子集 |
|
||||
| 非 Mesh 数据块 | Curve/Surface/Font/Metaball Main 权威写回与保存重开、真实 evaluated mesh、PointCloud/Curves/Hair 属性、WNM chunks、双 viewport、desktop golden 与 7 对象 GLB/USD round-trip | 有界本地切片 in_progress;VDB renderer、完整 topology editor/跨对象 history/range patch、外部字体导入、跨浏览器 OPFS 性能仍阻断 |
|
||||
|
||||
## 3. 部分完成或仍有边界的能力
|
||||
|
||||
| 能力 | 已达到 | 尚未达到 |
|
||||
| --- | --- | --- |
|
||||
| Native Blender Depsgraph | Blender 5.2 full loader、ID 注册、viewport graph、tagged/frame 求值、复杂 rig 和 100 次重复门已在 wasm32 通过 | 新增 Blender 类型时继续扩大矩阵 |
|
||||
| Modifier dependency graph | Blender 5.2 类型 0–86 已完整识别;27 类 native 白名单,其余 60 类身份保留并结构化阻断 | 后续扩白名单必须逐类增加 Blender golden,不属于当前矩阵完成条件 |
|
||||
| 骨骼与层级 | Bone/parent/rest/pose、权重、joint ID、非单位 bind、四骨、父级缩放、IK、Copy Rotation 和 1/5/10/15 golden 已通过 | 新约束类型属于增量 fixture |
|
||||
| GLB round-trip | Web 严格解析与 Blender 5.2 importer 双门已覆盖网格、变换、PBR、PNG/sRGB、sampler、morph、双骨骼 skin 和动画帧 | 新增相机/灯光、插值和材质扩展时继续扩大独立摘要 |
|
||||
| `.blend` 保存 | 场景状态、modifier、Mesh Edit、材质/UV、动画/约束和对象层级命令均写 Main;历史、原子保存、快照和日志重放可恢复 | skin/shape-key decimate 保持结构化阻断 |
|
||||
| Blender UI 对标 | 默认区域、当前 Mesh Edit、raycast、多选、拖拽 gizmo、层级/材质/动画面板和核心快捷键已闭环 | Sculpt、Geometry Nodes 编辑器等未声明能力继续结构化阻断 |
|
||||
| 未声明能力扩展 | 四项协议/安全门均已细分;Sculpt 属性/有界 Main stroke、Simulation cache、六节点 Shader Main 和 Action Clip NLA Main 已有正例 | PBVH、GN lazy-function/Simulation 求值、其余 Shader Node、Web compiler、完整 NLA/UI/GLB 图映射仍 planned/结构化阻断 |
|
||||
| 非 Mesh 数据块 | 1M 点 reader budget、ID_MB/PT/VO/VF 注册、Main control-point/topology/body/element/Font style link commands、一维多 spline 与批量 handle/cyclic、二维 Surface topology transaction、undo/save/reopen、真实 evaluated mesh、WNM SHA chunks、handle raycast/gizmo、7 对象 GLB/USD 和 Chromium quota | 多 handle 选择拖拽/gizmo UI、跨对象 history/range delta、新外部字体导入、VDB renderer/voxel upload 仍 planned/阻断 |
|
||||
| 大场景 | Worker 二进制解码、per-mesh/range transferable、linked Mesh 实例化、LOD/OPFS cache、frustum culling、能力门 OffscreenCanvas Worker、100k/1M 内存门 | 超出当前 WBG1 的网络式渐进流送仍属于后续性能扩展 |
|
||||
| Decimate 全对标 | Collapse 的当前网格集合已覆盖,错误路径结构化 | Un-Subdivide、Dissolve、所有 delimiter/权重/对称组合及大模型性能矩阵未完成 |
|
||||
|
||||
## 4. 关键安全门
|
||||
|
||||
`web_engine_evaluate_depsgraph` 现在直接执行 Blender 5.2 native loader、viewport
|
||||
Depsgraph、tagged update 和 frame change。wasm32 DNA 重建器会递归恢复 64-bit
|
||||
字段的 8-byte ABI 对齐,避免 `Scene.master_collection` 等成员错位;Web ID 注册表
|
||||
覆盖 Scene、Collection、Object、Mesh、Material、World、NodeTree、Camera、Light、
|
||||
Lattice、Curves 和 Grease Pencil。
|
||||
空场景、基础场景和骨骼/Shape Key 场景均返回 `BlenderDepsgraph/EVALUATED`,并通过
|
||||
Blender 5.2 变形 golden。任何 loader、graph 或输出结构错误仍必须返回结构化错误,
|
||||
禁止伪造 Three.js 求值。
|
||||
|
||||
## 5. 后续连续执行顺序
|
||||
|
||||
以下任务按顺序领取。一个任务的验收未通过,不得把下一个任务标记为完成。
|
||||
|
||||
### N-001 恢复 native Depsgraph 安全求值(已完成,转入回归)
|
||||
|
||||
1. 建立最小 `empty/basic/rigged` full-loader fixture,单独验证 Main 所有权和释放。
|
||||
2. 补齐 headless 初始化闭包:ID/CPP type、task scheduler、RNA 必要子集、NodeTree
|
||||
数据类型、sequencer modifier 和 image runtime;禁止链接桌面 WindowManager/GPU。
|
||||
3. 修复 embedded NodeTree 的 ID/DNA 读取,加载阶段不得再产生 invalid embedded ID。
|
||||
4. 分别验证 graph build、tagged update、frame change、graph free 和 Main free。
|
||||
5. 连续求值 100 次,检查 live handles、WASM heap 增长和 Worker 重启恢复。
|
||||
6. 重新启用 native capability,并将重复求值和 golden 纳入持续回归。
|
||||
|
||||
验收:三个 fixture 无 trap;最终 positions/indices 合法;rigged 最大/RMS 误差通过;
|
||||
重复求值无持续泄漏。当前 fixture 已满足;frame/pose 回归已恢复,完整类型矩阵继续由
|
||||
N-002/N-003 覆盖。
|
||||
|
||||
### N-002 Modifier/Depsgraph 能力矩阵(已完成)
|
||||
|
||||
1. 建立 Blender modifier 类型清单和 Web 支持矩阵;原生报告已先覆盖 UID、堆栈顺序、模式开关、跨对象依赖边、`EVALUATED/DISABLED/BLOCKED` 以及稳定错误码/建议。
|
||||
2. 按数据依赖加入 Generate、Deform、Physics、Nodes 类,不按 UI 名称盲目链接;当前 27 类进入 native 白名单。simulation zone 无确定缓存时使用专项阻断;deterministic cache、更多节点、GP 和其余家族属于未来逐批扩白名单,不影响矩阵契约完成。
|
||||
3. 对 modifier 顺序、viewport/render/edit/cage 开关、对象 target 和循环依赖做 golden;当前 category golden 已覆盖顺序/模式/target,专项 fixture 已覆盖双对象循环和缺 target。
|
||||
4. modifier 参数编辑、apply、undo/redo、保存和重新打开必须使用同一 revision 协议。
|
||||
5. 不支持的 modifier 返回类型、对象、参数和建议处理方式,不得静默跳过。
|
||||
|
||||
验收:白名单内结果与 Blender 5.2 golden 一致;白名单外全部结构化阻断。
|
||||
|
||||
### N-003 骨骼、Shape Key 与变形误差扩展
|
||||
|
||||
1. 覆盖多骨骼、多权重、非单位 bind matrix、父级缩放和多个 shape key。
|
||||
2. 覆盖关键帧区间、Pose constraint、IK 前后的每帧矩阵和最终顶点。
|
||||
3. 验证简化前后 joint 映射、权重归一化、shape key 相对基准和误差预算。
|
||||
4. Blender desktop golden 与 native WASM 同时比较;Three.js 消费同一通过校验的 SceneIR/geometry buffer,并由跨浏览器非空像素门验证呈现链路。
|
||||
|
||||
验收:每个 fixture 同时满足拓扑、层级、bind matrix、最大误差和 RMS 误差门。
|
||||
|
||||
### N-004 Packed image 完整覆盖
|
||||
|
||||
1. 单 PackedFile、PackedFile 列表、UDIM/tile、generated image 和 library-linked resource 矩阵已覆盖。
|
||||
2. 校验 MIME、原始文件名、相对路径、SHA-256、重复资产去重和损坏字节错误。
|
||||
3. packed 数据进入 OPFS content-addressed asset,并验证刷新后可重新发现。
|
||||
|
||||
当前验收:`npm --prefix web run test:image-resources`,以及资产 E2E。SHA-256 去重、路径不可
|
||||
逃逸项目目录和 OPFS Worker 重启发现均已覆盖。
|
||||
|
||||
### N-005 GLB Blender 级 round-trip(当前 SceneIR 子集已完成)
|
||||
|
||||
1. 扩展材质、纹理 sampler/色彩空间、morph、skin、animation interpolation 和 hierarchy。
|
||||
2. 保留当前 Web 严格解析比较作为快速门。
|
||||
3. 使用桌面 Blender 5.2 导入导出的 GLB,生成独立语义摘要。
|
||||
4. 比较 node parent、mesh primitive/material、image、skin/joint/inverse bind、动画 channel。
|
||||
5. warning 分成阻断错误、可接受近似和信息,不允许一条字符串混合多种严重度。
|
||||
|
||||
验收:Web 快速门和 Blender 再导入门均通过;所有差异进入机器可读报告。当前命令为
|
||||
`npm --prefix web run test:glb-blender-roundtrip`,已覆盖显式 sampler、sRGB、morph、双骨骼
|
||||
层级/权重和帧 1/25 动画。
|
||||
|
||||
### N-006 `.blend` 真正回写与恢复
|
||||
|
||||
1. 把对象/层级/modifier/mesh/armature/animation 命令写入权威 Blender Main。
|
||||
2. 实现内存 `.blend` 写出、取消、OOM、OPFS 原子替换和校验和。
|
||||
3. 保存后清空 Worker,重新打开文件并比较 SceneIR、Depsgraph 和 GLB 摘要。
|
||||
4. 将 undo/redo 与保存点、自动保存和崩溃恢复统一到 revision 日志。
|
||||
|
||||
当前协议命令集已覆盖 frame/visibility/modifier、普通 decimate 的 Main 写入、内存保存和清空
|
||||
后重开比较;标准 write-file callback 不使用 undo MemFile,动画与 Pose constraint 已通过两代
|
||||
写出后 animation 1/5/10 与 pose 1/5/10/15 帧等价回归。历史栈恢复 Main,OPFS 以 staging/journal/manifest/SHA-256 原子提交,
|
||||
并在两个故障点完成新 Worker 恢复。skin/shape-key decimate 继续以
|
||||
`BLEND_WRITE_REQUIRES_MAIN_AUTHORITY` 阻断;N-007 的 primitive/duplicate/delete/TRS/顶点平移
|
||||
已复用同一 Main/history/save 契约。
|
||||
|
||||
验收:编辑不再只存在于 JSON snapshot;已支持命令重新打开 `.blend` 后语义一致,
|
||||
其余命令必须明确阻断,不能伪造成功。
|
||||
|
||||
### N-007 建模和 UI 对标扩展
|
||||
|
||||
当前验收切片已完成 primitive、duplicate、delete、TRS、点/边/面选择、Merge、Dissolve、
|
||||
Extrude、Inset、Bevel、Loop Cut、raycast、多选、拖拽 gizmo、层级/Collection/Join/Separate、
|
||||
Apply Transform/Origin 和核心快捷键,并通过 Main/history/save/reopen 门。
|
||||
|
||||
### N-008 质量与发布门
|
||||
|
||||
100k/1M 性能与内存、Worker 故障、OPFS quota、恶意 `.blend`、许可证、本地依赖和离线
|
||||
dist 门已完成。N-008 记录的多引擎结果只作为历史证据;后续验收统一以 Chromium 为唯一
|
||||
浏览器基线。
|
||||
|
||||
### N-009 快照、日志与崩溃重放
|
||||
|
||||
Schema 6(含 Simulation manifest)、SHA-256 快照保留、命令阈值、revision 排序、损坏隔离、保存点清理,以及提交后
|
||||
命令重放已完成。验收见 `docs/status/N-009.md`。
|
||||
|
||||
### N-010 可复现离线交付
|
||||
|
||||
确定性二进制包、对应源码包、source offer、license/notice、文件 manifest 和顶层
|
||||
`SHA256SUMS.txt` 已纳入连续两次生成摘要一致门。验收见 `docs/status/N-010.md`。
|
||||
|
||||
### N-011 至 N-014 未声明能力扩展(有限子集 in_progress)
|
||||
|
||||
Sculpt、Geometry Nodes/Simulation、Shader Node 图和 NLA 的详细任务分解、依赖顺序、
|
||||
协议字段、稳定错误码、停止条件和默认验收命令统一维护在
|
||||
`docs/UNDECLARED_CAPABILITIES_EXECUTION_PLAN.md`。当前四项均进入
|
||||
`in_progress`:四项都已超过纯协议阶段,但只开放经过 native/存储闭环验证的有限切片:
|
||||
Sculpt Mask/Face Set 与有界 Main stroke、GN 外部资源门与 deterministic cache 存储、七节点
|
||||
Shader Main 写回(含有限 Math)和常量 PBR 映射、单对象 Action Clip NLA Main/Depsgraph reverse/repeat 求值。详细完成项和 planned 项见专项计划;
|
||||
这些正例不扩大到 PBVH Sculpt、任意 GN/Simulation、任意 Shader Node/Web compiler 或完整 NLA。
|
||||
Blender 5.2 全域功能矩阵、浏览器/服务端边界和 N-015 至 N-026 后续顺序见
|
||||
`docs/BLENDER_5_2_WEB_FEATURE_PARITY.md`。
|
||||
|
||||
### N-015 非 Mesh 几何数据块(有界本地切片 in_progress)
|
||||
|
||||
`NonMeshDataIR`、native SDNA reader、Main 权威 Curve/Surface/Font/Metaball 写回、bounded Poly Curve create/delete、Poly/Bezier conversion、非 Mesh 数据块 rename、Curve 有界 topology/Font geometry、undo/redo、
|
||||
save/reopen、真实 legacy evaluated mesh、PointCloud/Curves 属性和 WNM 二进制分块已经接通。
|
||||
主线程与 OffscreenCanvas 消费同一 chunks;GLB 只接受真实 evaluated mesh,USD 提供
|
||||
`UsdGeomMesh`、`UsdGeomPoints`、`UsdGeomBasisCurves` 和 `OpenVDBAsset` 的机器可读映射/损失。
|
||||
VDB renderer、完整 Curve handle/cyclic topology editor、二维 Surface mutation、跨对象 history/range patch、新字体导入和跨浏览器 OPFS quota 仍按
|
||||
`docs/status/N-015.md` 的阻断项推进。
|
||||
|
||||
### PBR-001 至 PBR-012 模型物理渲染(核心切片 done_current_scope,资产/高级渲染安全门 in_progress)
|
||||
|
||||
`physical-v1` 已完成扩展 Principled 参数的 Main 写回/保存重开、双后端
|
||||
`MeshPhysicalMaterial`、ACES/sRGB、World exposure、场景灯方向和有界 PCF 阴影。PBR-007
|
||||
现已接通 SHA-256 GPU 纹理载荷、颜色空间、尺寸预算、ImageBitmap 解码和双后端状态;PBR-008
|
||||
现已接通 UDIM manifest/缺失资源/多 tile 结构化阻断;PBR-009 已支持有限 packed raster
|
||||
equirectangular PMREM/IBL 生命周期;PBR-012 已提供 WebGPU、任意 Shader、Volume/SSS 和
|
||||
高级后处理的能力查询门。HDR/EXR、多 tile 采样、context-loss 恢复、真实 WebGPU renderer、
|
||||
高级 pass 和未声明 Shader 家族仍不得声称完成。架构映射、细分状态、停止条件和验收命令统一维护在
|
||||
`docs/PBR_RENDERING_IMPLEMENTATION_PLAN.md`。
|
||||
|
||||
## 6. 当前验收命令
|
||||
|
||||
```bash
|
||||
source tools/web/emscripten-env.sh
|
||||
cmake --build build_web_blender6 --target web_engine -- -j8
|
||||
bash tools/web/install-web-engine-assets.sh
|
||||
bash tools/web/check-dual-engine.sh
|
||||
node tools/web/run-web-engine-smoke.mjs
|
||||
npm --prefix web run typecheck
|
||||
npm --prefix web run lint
|
||||
npm --prefix web test
|
||||
npm --prefix web run test:golden
|
||||
npm --prefix web run test:frame-evaluation
|
||||
npm --prefix web run test:pose-constraint-goldens
|
||||
npm --prefix web run test:main-roundtrip
|
||||
npm --prefix web run test:authoring-roundtrip
|
||||
npm --prefix web run test:modifier-goldens
|
||||
npm --prefix web run test:modifier-cycle
|
||||
npm --prefix web run test:modifier-matrix
|
||||
npm --prefix web run test:image-resources
|
||||
npm --prefix web run test:glb-blender-roundtrip
|
||||
npm --prefix web run test:depsgraph
|
||||
npm --prefix web run test:collapse-ratios
|
||||
npm --prefix web run test:topology-collapse
|
||||
npm --prefix web run test:capability-gates
|
||||
npm --prefix web run test:simulation-cache
|
||||
npm --prefix web run test:release-performance
|
||||
npm --prefix web run test:malicious-blends
|
||||
npm --prefix web run test:browser
|
||||
npm --prefix web run release:offline
|
||||
WEB_TEST_PORT=5193 npm --prefix web run test:e2e # 5173 被占用时指定可用端口
|
||||
WEB_TEST_PORT=5193 npm --prefix web run test:e2e -- -g "N-015|non-mesh"
|
||||
```
|
||||
|
||||
`test:depsgraph` 默认执行 `DEPSGRAPH_REPEAT=100`;本地快速迭代可显式设置为较小的
|
||||
正整数,但提交前必须使用默认值。
|
||||
|
||||
每次完成 N-001 至 N-015 的一个任务切片,都必须更新本文件、对应 `docs/status/`
|
||||
记录、fixture/golden 和验证输出。
|
||||
318
docs/UNDECLARED_CAPABILITIES_EXECUTION_PLAN.md
Normal file
318
docs/UNDECLARED_CAPABILITIES_EXECUTION_PLAN.md
Normal file
@@ -0,0 +1,318 @@
|
||||
# 未声明 Blender 能力执行计划
|
||||
|
||||
更新时间:2026-08-09
|
||||
|
||||
本计划把当前未声明的 Sculpt、Geometry Nodes/Simulation、任意 Shader Node 和完整
|
||||
NLA 拆成四个可独立验收的连续任务。每个任务都必须满足:Blender Main 是唯一写入
|
||||
权威;SceneIR 只承载通过校验的数据;Three.js 不执行 Blender 语义;不支持或不确定
|
||||
的输入返回稳定的结构化阻断。任务没有通过自己的 desktop golden、WASM golden、保存
|
||||
重开和故障门前,不得扩大下一阶段的能力白名单。
|
||||
|
||||
## 总体依赖
|
||||
|
||||
| 顺序 | 任务 | 依赖 | 交付物 |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | N-011 Sculpt 子集 | MeshIR 属性、BMesh/Main history、N-003 变形门 | 固定采样笔刷事务、Mask/Face Set、可重开的 Sculpt fixture |
|
||||
| 2 | N-012 Geometry Nodes 与 Simulation | Modifier graph、NodeTree reader、N-001 Depsgraph | 可证明的字段/实例闭包、内容寻址 simulation cache |
|
||||
| 3 | N-013 Shader Node 图 | MaterialIR、图片/色彩空间、W-080 节点写回 | 校验过的 ShaderIR、受限图编译与桌面材质 golden |
|
||||
| 4 | N-014 NLA | Action/FCurve、frame/pose 求值、N-006 保存日志 | Strip/Track 子集、跨 Action 评估和恢复 golden |
|
||||
|
||||
共享基础工作在 N-011 前先完成:capability manifest、协议版本、资源预算、错误码
|
||||
注册表、golden runner 模板和不支持输入 fixture。它们不改变任何既有白名单。
|
||||
|
||||
## N-011 Sculpt 子集
|
||||
|
||||
### 目标边界
|
||||
|
||||
第一版只承诺单对象、单用户 Mesh、Object Mode 到 Sculpt Mode 的受控笔刷事务。支持
|
||||
Draw、Inflate、Grab、Smooth 四种确定性笔刷,固定半径/强度/对称轴和离散 stroke
|
||||
采样;支持每顶点 Sculpt Mask 与每面 Face Set 的读写。多分辨率、Dyntopo、Voxel Remesh、
|
||||
cloth/pose/elastic deform、纹理笔刷、破坏性拓扑笔刷和雕刻贴图在本任务中继续阻断。
|
||||
|
||||
### 分解
|
||||
|
||||
1. **N-011-A 能力和资源门**
|
||||
- 增加 `SCULPT_STROKE`、`SCULPT_MASK`、`SCULPT_FACE_SET` 命令类型和 payload schema。
|
||||
- 校验 object/mesh 单用户、可编辑、无 linked library、无 shape-key/激活 modifier
|
||||
拓扑冲突;失败码分别为 `SCULPT_MESH_NOT_SINGLE_USER`、`SCULPT_TOPOLOGY_UNSUPPORTED`
|
||||
和 `LINKED_DATA_MUTATION_BLOCKED`。
|
||||
- 建立 stroke 点数、总位移、影响顶点数和每 revision 内存预算;超限不得部分提交。
|
||||
|
||||
2. **N-011-B MeshIR 属性**
|
||||
- SceneIR 增加 `sculptMask`(vertex float32)、`faceSets`(face int32)、active
|
||||
face set、mask revision 和 attribute domain。
|
||||
- WBG1 增加可选 mask/face-set字段,Worker 校验长度、有限值和域范围;旧 WBG1
|
||||
没有这些字段时保持兼容。
|
||||
- `MeshGeometryDelta` 支持上述属性的范围 patch,并将属性变化计入资源 hash。
|
||||
|
||||
3. **N-011-C Blender Main 笔刷事务**
|
||||
- 在 native Main writer 中建立一次 stroke 的临时 BMesh/PBVH 查询,按固定顺序处理
|
||||
sample,所有顶点写入在一个 history transaction 内完成。
|
||||
- Draw/Inflate 使用命中法线方向,Grab 使用投影平面位移,Smooth 使用固定邻接
|
||||
平均;算法参数和 Blender 5.2 desktop script 必须相同,不能由 Three.js 重新实现。
|
||||
- 每次 stroke 完成后更新 normals、split normals、tangents、bounds 和 SceneDelta。
|
||||
|
||||
4. **N-011-D UI 与恢复**
|
||||
- 增加 Sculpt Mode、brush selector、radius/strength、mask/face-set 操作和单击/拖拽
|
||||
stroke 收集;界面只发送 sample,不保存独立 Three 状态。
|
||||
- undo/redo、autosave、OPFS journal、Worker 重启和 `.blend` 下载都使用同一命令。
|
||||
- linked Mesh、shape-key topology、modifier evaluated mesh 必须显示结构化阻断而非灰掉后
|
||||
静默忽略。
|
||||
|
||||
5. **N-011-E 验收**
|
||||
- 新 fixture:平面、非均匀变换 Mesh、带 seam/sharp、带 mask/face set 的 1k/50k 网格。
|
||||
- desktop golden 比较 positions、normals、mask、face sets、bounds,门限为 max/RMS
|
||||
误差和精确属性 hash。
|
||||
- 多帧相同 stroke、重复打开、取消中途 stroke、OOM 和 malformed payload 都有测试。
|
||||
- 命令:`npm --prefix web run test:sculpt-goldens`、`test:sculpt-roundtrip`、
|
||||
`test:sculpt-faults`、`test:sculpt-e2e`。
|
||||
|
||||
### 停止条件
|
||||
|
||||
无法在 wasm32 headless 环境稳定初始化 PBVH/笔刷依赖时,PBVH Sculpt 能力保持 `BLOCKED`。
|
||||
当前有界 native Main CPU stroke 只能作为独立有限子集 C1a 验收,不能满足 C1、不能声明
|
||||
Blender PBVH 等价,也不能借由 Three.js 近似扩大能力。
|
||||
|
||||
## N-012 Geometry Nodes 与 Simulation
|
||||
|
||||
### 目标边界
|
||||
|
||||
先扩大无时间状态的字段和实例闭包,再处理 Simulation Zone。第一阶段承诺 Group Input/
|
||||
Output、Transform Geometry、Set Position、Join Geometry、Separate Geometry、Realize
|
||||
Instances、Store/Named Attribute、基础数学/比较/选择字段;不承诺任意 node group、外部
|
||||
对象资源、Python node、硬件依赖或隐式时间状态。
|
||||
|
||||
### 分解
|
||||
|
||||
1. **N-012-A GraphIR 和校验器**
|
||||
- 建立 node UUID、bl_idname、socket type/domain/default/link、group interface、
|
||||
node group 引用和 field dependency 的版本化 `GeometryNodeGraphIR`。
|
||||
- 解析时检查 duplicate UUID、悬空 link、socket 类型/域不匹配、group recursion 和
|
||||
anonymous attribute 生命周期,错误码包含 `GN_SOCKET_TYPE_MISMATCH`、
|
||||
`GN_GROUP_RECURSION`、`GN_EXTERNAL_RESOURCE_MISSING`。
|
||||
- 将 modifier stack order、viewport/render/edit 开关和 graph hash 纳入 depsgraph report。
|
||||
|
||||
2. **N-012-B 无时间字段求值**
|
||||
- native 只按 Blender lazy-function/field 语义执行声明闭包;输出 MeshIR 的 topology、
|
||||
instances、attributes 和 bounds。
|
||||
- 每个 node family 单独 desktop golden;域转换(point/edge/face/corner/instance)
|
||||
有固定 fixture,不允许把 unsupported socket 当常量 0。
|
||||
- Three.js 只消费 evaluated SceneIR;未求值 graph 返回 `METADATA_ONLY` 或 `BLOCKED`。
|
||||
|
||||
3. **N-012-C 实例和外部依赖**
|
||||
- 定义 object info、collection info、image/volume 等外部资源的 stable ID 和沙箱检查。
|
||||
- 先支持同文件、非循环、只读外部对象;linked library、循环 collection、缺失对象和
|
||||
非确定性数据返回 `GN_EXTERNAL_RESOURCE_MISSING` 或 `GN_DEPENDENCY_CYCLE`。
|
||||
- 实例变换和属性必须能进入 WBG1/GLB 摘要,不能在 Web 端展开后丢失 ID 语义。
|
||||
|
||||
4. **N-012-D Simulation cache**
|
||||
- 定义 `SimulationCacheManifest`:graph hash、source blend hash、frame range、inputs
|
||||
hash、Blender version、schema、每帧 byte range 和 SHA-256。
|
||||
- 只接受桌面 Blender 生成并校验过的 deterministic bake;Worker 按 OPFS content-addressed
|
||||
方式读取,frame seek 不得隐式重新计算。
|
||||
- cache 缺帧、hash 不符、版本不兼容、quota/OOM 和损坏字节都必须可恢复地阻断;禁止返回
|
||||
上一帧冒充当前帧。
|
||||
|
||||
5. **N-012-E 验收**
|
||||
- graph fixtures 覆盖每个支持 family、字段域、实例、group recursion、循环依赖和
|
||||
modifier 开关;simulation fixtures 覆盖 1/5/10/25 帧、seek、cache 重启和损坏。
|
||||
- 命令:`test-gn-goldens`、`test-gn-graph-validation`、`test-simulation-cache`、
|
||||
`test-gn-e2e`、`test-gn-blender-roundtrip`。
|
||||
|
||||
### 停止条件
|
||||
|
||||
Blender lazy-function runtime 或 simulation cache 不能在 wasm32 完整初始化时,只扩大
|
||||
metadata/graph validation,保持现有 simulation structured block,不得把输入几何复用成
|
||||
“求值成功”。
|
||||
|
||||
## N-013 Shader Node 图
|
||||
|
||||
### 目标边界
|
||||
|
||||
把当前 Principled/Image/Normal/UV 读写子集升级为可验证的 ShaderIR 图,而不是承诺任意
|
||||
Blender 节点。首批支持 RGB、Value、Mix、Math(限定运算)、Mapping、Texture Coordinate、
|
||||
Image Texture、Normal Map、Bump、Principled、Material Output;Volumetric、OSL、任意
|
||||
自定义 shader、Cycles-only 节点和未实现色彩管理继续阻断。
|
||||
|
||||
### 分解
|
||||
|
||||
1. **N-013-A ShaderIR**
|
||||
- node UUID/type/label/location、typed sockets/defaults, links、material output、
|
||||
image/sampler/color-space、group boundary 和 graph hash 全部版本化。
|
||||
- graph validator 检查单输出、无环、socket 类型、颜色/向量隐式转换、未连接输入和
|
||||
texture resource;错误码包含 `SHADER_NODE_UNSUPPORTED`、`SHADER_GRAPH_CYCLE`、
|
||||
`SHADER_SOCKET_TYPE_MISMATCH`。
|
||||
|
||||
2. **N-013-B Blender Main 写回**
|
||||
- 为每个支持 node family 建立最小 native node/socket/storage 注册和 create/update/remove
|
||||
command;操作在一个 Main history transaction 中完成。
|
||||
- linked material、library image、packed asset 和 color-management profile 经过同一
|
||||
资源/路径沙箱;无法写回的图返回稳定阻断。
|
||||
|
||||
3. **N-013-C Web 消费和编译**
|
||||
- 从 ShaderIR 生成受限 Three.js material/GLSL 或 WebGPU backend;编译结果必须带 graph
|
||||
hash 和 capability report。
|
||||
- Web 端不能把未知节点删掉后继续显示“成功”;未知节点显示阻断并保留原图 metadata。
|
||||
- 透明、alpha clip、normal/tangent、sRGB/Non-Color 和 sampler 状态分别测试。
|
||||
|
||||
4. **N-013-D 导出和回导**
|
||||
- GLB 只导出能映射到 glTF PBR 的闭包;不可映射节点进入机器可读 warning/error,不能
|
||||
静默烘焙。
|
||||
- Blender desktop 再导入比较节点摘要、材质值、纹理色彩空间、sampler 和渲染摘要。
|
||||
|
||||
5. **N-013-E 验收**
|
||||
- 命令:`test-shader-graph-goldens`、`test-shader-node-roundtrip`、
|
||||
`test-shader-compile`、`test-shader-glb-roundtrip`、`test-shader-faults`。
|
||||
- 每个 node family 至少一个正例、一个错误图和一个 save/reopen fixture;图 hash、
|
||||
asset hash、desktop/Web 语义报告必须可复现。
|
||||
|
||||
## N-014 NLA
|
||||
|
||||
### 目标边界
|
||||
|
||||
在现有 Action/FCurve 子集上增加单个对象的 Track/Strip、Action Clip、frame range、
|
||||
scale/repeat、blend in/out、influence、extrapolation 和 Replace/Add/Multiply/Combine
|
||||
四种有限混合。Drivers、完整 transition strips、meta strips、time warp 和复杂约束驱动
|
||||
仍然单独阻断。
|
||||
|
||||
### 分解
|
||||
|
||||
1. **N-014-A AnimationIR 扩展**
|
||||
- 增加 Action、slot、NlaTrack、NlaStrip、strip source range、scene range、blend/extend、
|
||||
muted/solo/active 和 stable owner IDs。
|
||||
- 校验 track/strip 排序、重叠、负 scale、repeat、循环引用和 FCurve path compatibility。
|
||||
|
||||
2. **N-014-B Blender Main 编辑**
|
||||
- 新增 track/strip create/remove/move/resize/blend/solo/mute commands,全部进入 Main
|
||||
history;Action 选择和已有 keyframe 命令共享 revision。
|
||||
- 保存后重新打开必须恢复 strip UUID、Action assignment、active track 和 frame state。
|
||||
|
||||
3. **N-014-C 原生求值**
|
||||
- 每帧交给 Blender Depsgraph/NLA evaluator,输出 object/bone matrices、FCurve values 和
|
||||
evaluated MeshIR;Three.js 不自行混合 Action。
|
||||
- 覆盖 strip 边界、负向播放、repeat、blend overlap、constraint order 和 frame seek。
|
||||
|
||||
4. **N-014-D UI 与导出**
|
||||
- Dope Sheet 增加 NLA track/strip lane、拖动边界、blend handles、mute/solo、Action menu。
|
||||
- GLB 导出只承诺可线性展开的 clip;不可展开的 NLA 结构返回 warning/error 并保留摘要。
|
||||
|
||||
5. **N-014-E 验收**
|
||||
- 命令:`test-nla-goldens`、`test-nla-frame-evaluation`、`test-nla-roundtrip`、
|
||||
`test-nla-faults`、`test-nla-glb-roundtrip`。
|
||||
- 以 frame 1/5/10/15/25 比较 transforms、pose matrices、vertex max/RMS error、strip
|
||||
metadata 和 save/reopen hash。
|
||||
|
||||
## 共享发布门
|
||||
|
||||
四个任务完成前,每个新能力必须补齐:
|
||||
|
||||
1. SceneIR/WBG schema 和 capability manifest 的版本迁移。
|
||||
2. native Main、undo/redo、save/reopen、OPFS journal、Worker restart 和 malformed input。
|
||||
3. Blender 5.2 desktop golden、WASM golden和 Chromium 主线程/OffscreenCanvas 非空像素。
|
||||
4. 100k/1M 内存预算、命令 payload 上限、超时/OOM/quota、恶意图/图形数据和路径沙箱。
|
||||
5. 对应 `docs/status/N-011.md` 至 `N-014.md`、fixture、默认 npm 验收命令和机器可读报告。
|
||||
|
||||
## 领取顺序
|
||||
|
||||
先做 N-011-A/N-011-B 与 N-012-A/N-013-A/N-014-A 这四个协议和安全门,随后按
|
||||
N-011 -> N-012 -> N-013 -> N-014 执行。任一任务的正例、阻断例、保存恢复或发布门失败,
|
||||
都只能修复当前任务,不得把下一任务的实现标记为完成。
|
||||
|
||||
## 当前执行切片(2026-08-09)
|
||||
|
||||
本轮把四个协议阶段再切成可独立回归的小步骤;每一步都先在 Worker 入口验证,再决定
|
||||
是否允许进入下一层:
|
||||
|
||||
| 切片 | 内容 | 状态 | 证据/下一步 |
|
||||
| --- | --- | --- | --- |
|
||||
| N-011-A1 | `SculptStrokeIR` schema、笔刷枚举、sample 数量/路径长度/数值/对称校验 | 已完成 | `web/protocol/sculpt.ts`;超 2048 点或路径预算返回 `SCULPT_STROKE_BUDGET_EXCEEDED` |
|
||||
| N-011-A2 | 单用户、linked、Shape Key、拓扑 modifier、空网格和 object-space mirror 能力门 | 已完成 | `gateSculptCapability` + Worker/native mirror gate;不满足条件结构化阻断 |
|
||||
| N-011-B1 | SceneIR Mask/Face Set 字段、域长度、范围、revision 校验 | 已完成 | `scene-ir.ts` 与 Worker binary validator |
|
||||
| N-011-B2 | WBG1/geometry delta 属性编码和 hash | 已完成 | WBG1 magic/header v2 向后兼容 v1;mask/face set 支持 binary transfer、replacement/range delta |
|
||||
| N-011-B3 | Mask/Face Set Blender Main 写回、undo、保存重开 | 已完成 | `setSculptMeshAttributes`;`test:authoring-roundtrip`;active Face Set runtime state 继续阻断 |
|
||||
| N-011-C1a | 有界 native Main 顶点 stroke(四笔刷、压力、Mask、对称、预算) | 已完成有限切片 | C++ Main 单事务;`test:authoring-roundtrip` 验证 save/reopen;明确不是 PBVH/BMesh 等价 |
|
||||
| N-011-C1 | Blender PBVH/BMesh 命中、法线/切线和桌面等价求值 | planned/阻断 | 当前只允许 C1a;PBVH、Dyntopo、多分辨率和 UI 仍返回结构化阻断 |
|
||||
| N-011-C2 | Draw/Inflate/Grab/Smooth desktop/WASM golden | planned | 依赖 C1;每种笔刷独立 max/RMS 门 |
|
||||
| N-012-A1 | GraphIR schema、节点白名单、typed socket/link/domain 校验 | 已完成 | `geometry-nodes.ts`;Worker cycle gate 已有 E2E |
|
||||
| N-012-A2 | 跨 group 的递归闭包、外部 object/collection/image ID 沙箱 | 已完成 | stable ID 类型、owner cycle、linked/missing/corrupt 资源门和 E2E 已覆盖 |
|
||||
| N-012-A3a | Simulation manifest/schema、Blender 版本、frame byte range | 已完成 | `simulation-cache.ts`;完整帧、连续范围、总/逐帧 SHA-256 |
|
||||
| N-012-A3b | committed blend 绑定、OPFS 内容寻址、schema 6 索引和 Worker 重启 | 已完成 | `simulation_manifest` + asset SHA-256;`test:simulation-cache` |
|
||||
| N-012-A3c | Blender desktop bake 生成、版本迁移、GN frame seek 消费 | planned | Simulation Zone 仍返回 `GEOMETRY_NODES_SIMULATION_UNAVAILABLE` |
|
||||
| N-012-B1 | 无时间 GN lazy-function/field Main evaluator | planned | 当前合法 GraphIR 仍返回 `CAPABILITY_MISSING` |
|
||||
| N-013-A1 | ShaderIR schema、单输出、typed socket/隐式转换、无环 | 已完成 | `shader-graph.ts`;未进入 writer 白名单的节点返回 `SHADER_NODE_UNSUPPORTED` |
|
||||
| N-013-A2 | material/image stable ID 与 linked/missing/corrupt 资源门 | 已完成当前子集 | packed image 可引用;linked/missing/corrupt image 在 Worker 阻断 |
|
||||
| N-013-B1 | RGB/Value/Principled/Image Texture/Normal Map/Output 整图 Main transaction | 已完成当前子集 | native create/remove/link/default、history、save/reopen 回归 |
|
||||
| N-013-B2a | Math 六运算 Main `custom1`、原生 socket identifier 和 operation reader | 已完成有限切片 | ADD/SUBTRACT/MULTIPLY/DIVIDE/MINIMUM/MAXIMUM;其他运算阻断 |
|
||||
| N-013-B2 | Mix/Mapping/TexCoord/Bump storage/property 写回 | planned | 未声明节点和 properties 仍 `SHADER_NODE_UNSUPPORTED` |
|
||||
| N-013-C1a | RGB/Value 常量到 glTF PBR factor 的严格映射 | 已完成有限切片 | 缺值、越界、重复输入和未知链接返回 `SHADER_GRAPH_UNMAPPABLE`;mapping E2E 覆盖 |
|
||||
| N-013-C1 | 受限 Web material compiler、graph hash、色彩空间/sampler | planned | C1a 不代表 Web shader compiler;任意图仍未启用 |
|
||||
| N-014-A1 | Track/Strip schema、Action/range/blend/time-warp 校验 | 已完成 | `nla.ts`;缺失 Action 返回 `NLA_ACTION_MISSING` |
|
||||
| N-014-A2 | strip 排序/重叠、owner/path compatibility、循环引用校验 | 已完成当前子集 | 同轨重叠、duration mapping、blend range 和 unsupported strip type 均阻断 |
|
||||
| N-014-B1 | Action Clip 整栈替换 Main transaction、reader、保存重开 | 已完成当前子集 | `setNLAStack`;Track/Strip/Action 摘要重开一致 |
|
||||
| N-014-B2 | 细粒度 create/remove/move/resize/active 命令 | planned | UI 前先扩命令和 revision 回归 |
|
||||
| N-014-C1 | 正 scale Action Clip native frame 求值 | 已完成当前子集 | authoritative Main bytes 进入 Blender depsgraph;frame 5 矩阵回归通过 |
|
||||
| N-014-C2a | Action Clip reverse Main 标志、reader、Depsgraph、保存重开 | 已完成有限切片 | `NLASTRIP_FLAG_REVERSE`;frame 5 反向矩阵回归 |
|
||||
| N-014-C2b1 | Action Clip repeat 与跨周期 frame seek | 已完成有限切片 | `repeat=2`;frame 5/14 native 矩阵一致 |
|
||||
| N-014-C2 | blend overlap、骨骼、约束顺序、transition/meta | planned | 未声明族继续 `NLA_*` 结构化阻断 |
|
||||
| 共享 | 四类命令联合类型、Worker 统一 gate、浏览器稳定错误码回归 | 已完成 | `web-engine.ts`、`web-engine.worker.ts`、`test:capability-gates` |
|
||||
|
||||
### 阻断家族的可领取细分
|
||||
|
||||
以下切片一次只扩大一个可证明的能力;前一切片未通过 Main/save-reopen/golden/fault 门时,
|
||||
后一切片不得转为 `in_progress`。
|
||||
|
||||
| Sculpt 切片 | 交付与验收 | 状态 |
|
||||
| --- | --- | --- |
|
||||
| N-011-C1b | wasm32 PBVH/session/context feature probe;初始化失败返回独立错误码且不修改 Main | planned/阻断 |
|
||||
| N-011-C1c | PBVH object-space 命中、半径查询、对称副本去重和最大影响顶点预算 | planned,依赖 C1b |
|
||||
| N-011-C1d | Draw/Inflate/Grab/Smooth 分别接 Blender brush kernel;每笔刷独立事务和取消回滚 | planned,依赖 C1c |
|
||||
| N-011-C1e | normals/split normals/tangents/bounds 与 mesh range delta;revision/hash 精确变化 | planned,依赖 C1d |
|
||||
| N-011-C2 | 1k/50k、非单位对象矩阵、Mask/Face Set、seam/sharp desktop/WASM max/RMS golden | planned,依赖 C1e |
|
||||
| N-011-D1 | Sculpt Mode、四笔刷、半径/强度和 object-space symmetry UI;UI 不保存副本 | planned,依赖 C2 |
|
||||
| N-011-D2 | undo/redo、取消、Worker restart、OOM/malformed stroke 和关闭重开故障注入 | planned,依赖 D1 |
|
||||
|
||||
| GN/Simulation 切片 | 交付与验收 | 状态 |
|
||||
| --- | --- | --- |
|
||||
| N-012-B0 | wasm32 lazy-function/field runtime feature probe、超时和内存上限 | planned/阻断 |
|
||||
| N-012-B1a | Group Input/Output + Transform Geometry 最小闭包,输出 topology/attributes/bounds | planned,依赖 B0 |
|
||||
| N-012-B1b | Set Position、Math/Compare/Selection field 及 point/edge/face/corner 域转换 | planned,依赖 B1a |
|
||||
| N-012-B1c | Join/Separate/Realize Instances 和 instance stable ID/transform | planned,依赖 B1b |
|
||||
| N-012-B1d | Store/Named Attribute 生命周期、anonymous attribute 泄漏和 deterministic graph hash | planned,依赖 B1c |
|
||||
| N-012-D1 | desktop bake 生成器、Blender 版本迁移和逐帧 cache 消费 | planned,依赖现有 A3b |
|
||||
| N-012-D2 | Simulation Zone wasm frame step、状态所有权和 frame seek feature probe | planned/阻断,依赖 B1d/D1 |
|
||||
| N-012-D3 | 浏览器 bake start/cancel/commit 原子事务;中断时不发布半成品 manifest | planned,依赖 D2 |
|
||||
| N-012-D4 | cache invalidation、缺帧/hash/version/quota/OOM/Worker restart 故障门 | planned,依赖 D3 |
|
||||
|
||||
| Shader 切片 | 交付与验收 | 状态 |
|
||||
| --- | --- | --- |
|
||||
| N-013-B2a | Math 白名单逐运算 Main 写回和 operation reader;GLB/Web 编译仍阻断 | 已完成有限切片 |
|
||||
| N-013-B2b | Mix 的 data type、factor clamp 和颜色/向量 socket 变体 Main 写回 | planned,依赖 B2a |
|
||||
| N-013-B2c | Texture Coordinate -> Mapping -> Image Texture,UV 名称/sampler/色彩空间闭环 | planned,依赖 B2b |
|
||||
| N-013-B2d | Normal Map/Bump 串联、强度/距离、切线前置条件和 desktop golden | planned,依赖 B2c |
|
||||
| N-013-C1b | 受限 Web compiler IR、graph hash cache、未知节点 fail-closed | planned,依赖 B2d |
|
||||
| N-013-C1c | sRGB/Non-Color、alpha、sampler、normal/tangent 和 WebGL/WebGPU 编译报告 | planned,依赖 C1b |
|
||||
| N-013-D1 | 可证明 PBR 闭包的纹理/常量完整映射;其余保持 `SHADER_GRAPH_UNMAPPABLE` | planned,C1a 已覆盖常量子集 |
|
||||
| N-013-D2 | 桌面 Blender GLB 再导入,比较 factor、节点摘要、图片、sampler 与渲染摘要 | planned,依赖 D1 |
|
||||
|
||||
| NLA 切片 | 交付与验收 | 状态 |
|
||||
| --- | --- | --- |
|
||||
| N-014-B2a | create/remove/move/resize/active 细粒度命令与 revision 冲突回归 | planned |
|
||||
| N-014-C2b1 | repeat 和跨周期 frame seek Main/Depsgraph/save-reopen | 已完成有限切片 |
|
||||
| N-014-C2b2 | strip 边界、NOTHING/HOLD/HOLD_FORWARD 和多周期 desktop golden | planned,依赖 C2b1 |
|
||||
| N-014-C2c | 多轨 overlap、blend in/out、influence 与四种 blend mode 的对象/骨骼 golden | planned,依赖 C2b2 |
|
||||
| N-014-C2d | constraint order、父级缩放和 pose matrix 的 NLA/Depsgraph 误差门 | planned,依赖 C2c |
|
||||
| N-014-C3 | Transition strip schema/Main/reader/evaluator;只连接兼容相邻 Clip | planned/阻断 |
|
||||
| N-014-C4 | Meta strip 递归深度、子 strip 所有权和循环检测 | planned/阻断,依赖 C3 |
|
||||
| N-014-C5 | Sound strip 资源沙箱、时间摘要;不伪装为几何/姿态求值 | planned/阻断 |
|
||||
| N-014-C6 | Animated Time、reverse+time-warp 组合、Drivers 依赖图和循环检测 | planned/阻断 |
|
||||
| N-014-D1 | NLA lanes、selection、drag/resize、blend handles、mute/solo 与 Action menu | planned,依赖 B2a/C2d |
|
||||
| N-014-D2 | 可线性展开 Clip 的 GLB 导出;其他 strip 返回机器可读错误并保留摘要 | planned,依赖 D1 |
|
||||
|
||||
当前默认验收命令:
|
||||
|
||||
```bash
|
||||
npm --prefix web run typecheck
|
||||
WEB_TEST_PORT=5200 npm --prefix web run test:capability-gates
|
||||
npm --prefix web run test:simulation-cache
|
||||
npm --prefix web run test:authoring-roundtrip
|
||||
```
|
||||
47
docs/decisions/000-baseline.md
Normal file
47
docs/decisions/000-baseline.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Web Blender Baseline
|
||||
|
||||
## Scope
|
||||
|
||||
This baseline fixes the source and toolchain for the first Web implementation. The
|
||||
Blender source tree remains an upstream dependency; Web-specific code belongs in
|
||||
new `web/`, `tools/web/`, `docs/`, and `tests/` paths.
|
||||
|
||||
## Source
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Web source directory | `blender-5.2.0/` |
|
||||
| Source archive | `blender-5.2.0.tar.xz` |
|
||||
| Source archive MD5 | `ec40a0ad895131a0fd3d360a59fd599a` |
|
||||
| Reference Git checkout | `blender/` |
|
||||
| Reference Git commit | `fbe6228777e7d9afefcd61a413844e790ae75db7` |
|
||||
| Reference checkout state | dirty before Web work; pre-existing changes are out of scope |
|
||||
| Existing native build | `build_blender_5.2.0/` |
|
||||
|
||||
The reference checkout is intentionally not clean. No existing Blender source,
|
||||
asset, or test file is reverted by the Web implementation.
|
||||
|
||||
## Toolchain
|
||||
|
||||
| Tool | Version |
|
||||
| --- | --- |
|
||||
| OS | Linux x86_64, kernel 6.12.95+deb13-amd64 |
|
||||
| CMake | 3.31.6 |
|
||||
| Ninja | 1.12.1 |
|
||||
| Emscripten | 3.1.69 |
|
||||
| Node.js | 20.19.2 |
|
||||
| npm | 9.2.0 |
|
||||
| pnpm | unavailable at baseline; npm is the bootstrap fallback |
|
||||
|
||||
## Build isolation
|
||||
|
||||
- Native builds use `build_blender_5.2.0/` or a separately named native build tree.
|
||||
- Web builds use `build_web/` and must not reuse native CMake cache files.
|
||||
- Browser packages are emitted under `web/dist/` and are not copied into the
|
||||
Blender source tree.
|
||||
|
||||
## Baseline checks
|
||||
|
||||
The baseline is accepted when the native binary reports Blender 5.2.0, the source
|
||||
and archive paths exist, and the Web toolchain versions above are recorded in the
|
||||
task status file.
|
||||
10
docs/status/N-001.md
Normal file
10
docs/status/N-001.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# N-001 Native Depsgraph 安全求值
|
||||
|
||||
状态:`done`(持续回归)
|
||||
|
||||
`empty.blend`、`basic_scene.blend`、`rigged_shape_scene.blend` 已通过 Blender 5.2
|
||||
headless full loader、WASM Depsgraph 和结构化 modifier 报告;frame/pose golden 已加入
|
||||
默认回归。重复求值和发布级内存门仍由 N-008 复核。
|
||||
|
||||
验收:`bash tools/web/check-dual-engine.sh`、`npm --prefix web run test:depsgraph`。
|
||||
|
||||
21
docs/status/N-002.md
Normal file
21
docs/status/N-002.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# N-002 Modifier/Depsgraph 能力矩阵
|
||||
|
||||
状态:`done`(能力矩阵契约)
|
||||
|
||||
当前报告覆盖 modifier UID、堆栈顺序、viewport/render/edit/cage 开关、目标对象依赖和
|
||||
`EVALUATED`/`DISABLED`/`BLOCKED` 结构化状态。跨对象循环返回
|
||||
`MODIFIER_DEPENDENCY_CYCLE`,缺目标返回 `MODIFIER_TARGET_MISSING`。native target 遍历覆盖
|
||||
Array、Mirror、Boolean、Lattice、Curve、Armature、Hook、Mesh Deform、Shrinkwrap、
|
||||
Surface Deform、Screw 和 Displace mapping object。
|
||||
|
||||
本轮继续加入受控 Displace:无纹理、无顶点组、Local Space 的常量 X/Y/Z/Normal 位移与
|
||||
Blender 5.2 golden 一致;纹理、RGB 和 mapping object 返回
|
||||
`MODIFIER_CONFIGURATION_UNSUPPORTED`。Geometry Nodes 白名单从 Transform Geometry 扩为
|
||||
constant-offset Set Position,二者都使用桌面 golden 比较。simulation zone/bake 不执行不确定
|
||||
状态,保留输入几何并返回 `GEOMETRY_NODES_SIMULATION_UNAVAILABLE`。机器门逐项覆盖 Blender
|
||||
5.2 的 0–86 共 87 个类型:27 类进入 native 白名单,60 类保留身份并使用 disabled sentinel,
|
||||
启用时结构化阻断。完整 lazy-function runtime、deterministic simulation cache、Grease Pencil
|
||||
求值不是该能力矩阵的隐含承诺;未来扩白名单必须新增 Blender golden。
|
||||
|
||||
验收:`npm --prefix web run test:modifier-goldens`、`npm --prefix web run test:modifier-cycle`、
|
||||
`npm --prefix web run test:depsgraph`、`npm --prefix web run test:modifier-matrix`。
|
||||
12
docs/status/N-003.md
Normal file
12
docs/status/N-003.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# N-003 骨骼、Shape Key、约束和多帧误差
|
||||
|
||||
状态:`done`
|
||||
|
||||
已修复 Web RNA 浮点属性默认 `0..0` 钳制、显式补齐 headless transform 更新,并统一
|
||||
SceneIR 矩阵为 Blender Python/glTF 使用的列主序展开;animation 和 pose constraint
|
||||
golden 已扩为 frame 1/5/10/15。当前 fixture 使用四根骨骼、独立 Auxiliary 分支、两骨 IK、
|
||||
Copy Rotation、非单位 mesh bind、Armature 对象变换和父级非均匀缩放;每帧同时比较全部
|
||||
pose matrix、constraint target/pole target 和最终蒙皮顶点的最大/RMS 误差。
|
||||
|
||||
验收:`npm --prefix web run test:frame-evaluation`、
|
||||
`npm --prefix web run test:pose-constraint-goldens`。
|
||||
18
docs/status/N-004.md
Normal file
18
docs/status/N-004.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# N-004 Packed Image 覆盖
|
||||
|
||||
状态:`completed_current_scope`
|
||||
|
||||
单 PackedFile 与 PackedFile 列表已覆盖。`image_resource_matrix.blend` 进一步覆盖两个独立
|
||||
asset ID 的 packed UDIM tile、generated image 元数据、缺失外部路径和 linked library;
|
||||
`corrupt_packed_image.blend` 验证 PNG 签名损坏返回 `PACKED_IMAGE_SIGNATURE_INVALID`。
|
||||
SceneIR 公开 `sourceKind`、`assetStatus`、tile、library 和稳定错误码,Worker 可按 tile asset
|
||||
ID 提取字节。
|
||||
|
||||
packed/tile 字节现按 SHA-256 写入
|
||||
`projects/<project>/assets/sha256/<prefix>/<digest>`;重复内容只保留一份,读取时复验长度和
|
||||
摘要,IndexedDB 保存项目级 asset metadata。Storage Worker 重启后可重新列举并读取 OPFS
|
||||
资产。Blender `//` 相对路径会规范化;绝对路径、URI、反斜杠、百分号编码和 `..` 逃逸均以
|
||||
`ASSET_PATH_INVALID`/`ASSET_PATH_OUTSIDE_PROJECT` 阻断。
|
||||
|
||||
验收:`npm --prefix web run test:image-resources`,以及 E2E
|
||||
`content-addresses assets, deduplicates them, and rediscovers them after worker restart`。
|
||||
11
docs/status/N-005.md
Normal file
11
docs/status/N-005.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# N-005 GLB Blender 级往返
|
||||
|
||||
状态:`completed_current_scope`
|
||||
|
||||
Web 严格 GLB 解析和 SceneIR 语义比较保留为快速门。独立回归现在调用项目 TypeScript
|
||||
exporter,随后使用桌面 Blender 5.2 headless importer,比较网格/对象变换、帧 1/25 动画、
|
||||
PBR、显式 sampler、嵌入 PNG/sRGB、morph、双骨骼层级、skin modifier、vertex group 和
|
||||
权重归一化。该门同时修复了 glTF 动画首帧被平移到 0 的问题。
|
||||
|
||||
验收:`npm --prefix web run test:glb-blender-roundtrip`。未来新增 interpolation、相机/灯光
|
||||
或材质扩展时,必须同步扩大该 Blender 语义摘要,不能退回仅解析 Web GLB。
|
||||
30
docs/status/N-006.md
Normal file
30
docs/status/N-006.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# N-006 Blender Main 权威回写与恢复
|
||||
|
||||
状态:`completed_current_scope`
|
||||
|
||||
`setFrame`、`setObjectVisibility`、`setModifierEnabled` 现在直接更新持久化
|
||||
Blender Main;保存通过非 undo 的标准 write-file callback 写出内存 `.blend`。动画与 Pose
|
||||
constraint fixture 已连续执行两代保存/重开,并在 1/5/10 帧比较网格、world matrix 和 bone
|
||||
pose matrix。权威 Main dirty 后的 Depsgraph 现在直接使用 writer 输出,不再回退原始 reader
|
||||
buffer。当前协议命令集中的 frame、visibility、modifier 开关和无 skin/shape-key 的
|
||||
`decimateMesh` 均回写 Main。decimate 会重建三角 Mesh,并保存 UV、corner color 和 material
|
||||
index;Collapse/Un-Subdivide/Dissolve 都经过保存门。带 skin/shape-key 的 decimate 继续保持
|
||||
snapshot-only,保存返回 `BLEND_WRITE_REQUIRES_MAIN_AUTHORITY`,不会丢失 Key/vertex-group 后
|
||||
伪造成功。
|
||||
|
||||
历史项现同时保存 SceneIR 与可重开的 Main buffer;Main 命令 undo/redo 后可立即保存,撤销
|
||||
snapshot-only 状态会恢复权威性。OPFS 保存使用 SHA-256、staging、journal、提交后复验和
|
||||
manifest;新 Worker 可从 staging 后或 scene commit 后两种故障点恢复,并串行化同项目的并发
|
||||
保存。AutosaveScheduler 复用同一事务。N-007/W-080 新增的 Mesh Edit、UV、材质、packed
|
||||
image、动画、约束、层级、Collection、Join/Separate、Apply Transform 和 Origin 已全部复用
|
||||
Main mutation、undo/redo、原子保存和保存重开契约。
|
||||
|
||||
验收命令:
|
||||
|
||||
```bash
|
||||
node tools/web/run-web-engine-smoke.mjs
|
||||
bash tools/web/check-dual-engine.sh
|
||||
npm --prefix web run test:main-roundtrip
|
||||
npm --prefix web run test:authoring-roundtrip
|
||||
WEB_TEST_PORT=5193 npm --prefix web run test:e2e -- --grep "atomic|journal|concurrent saves"
|
||||
```
|
||||
17
docs/status/N-007.md
Normal file
17
docs/status/N-007.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# N-007 建模和 UI 对标
|
||||
|
||||
状态:`completed_current_scope`
|
||||
|
||||
Cube/Plane primitive、独立 Mesh duplicate、delete、完整 TRS、Edit Mode 顶点平移,以及
|
||||
Merge/Dissolve/Extrude/Inset/Bevel/Loop Cut 均直接 mutation Blender Main。结构变化统一通过
|
||||
Main 内存写出再生成 SceneIR,失败会恢复前一历史项;shape key、linked data 和非法选择会
|
||||
结构化阻断。
|
||||
|
||||
UI 已接入视口 raycast、Shift/Ctrl 多选、隐藏对象过滤、删除清理、X/Y/Z 可拖拽 gizmo、
|
||||
Object/Edit Mode、点/边/面选择、Tab/Delete/Shift+D/Ctrl+Z/Ctrl+Y/G/R/S 快捷键。对象层级
|
||||
已覆盖 Parent/Unparent、Collection、新命名、Join/Separate、Apply Transform 和 Origin。
|
||||
材质/UV 与关键帧编辑复用相同 Main/history/save 契约。
|
||||
|
||||
验收:`node tools/web/run-web-engine-smoke.mjs`,以及 E2E
|
||||
`runs Main-authoritative object and edit-mode modeling workflows`,以及
|
||||
`npm --prefix web run test:authoring-roundtrip`。
|
||||
13
docs/status/N-008.md
Normal file
13
docs/status/N-008.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# N-008 发布门
|
||||
|
||||
状态:`done`
|
||||
|
||||
发布门现覆盖 100k 三角形 0.9 Collapse 与 1M 三角形 native 建网格/校验;本机结果分别为
|
||||
86.1s/64MiB 和 0.51s/346,554,368 bytes,默认门限 120s/180s 与 1.5GiB。Chromium、Firefox、
|
||||
WebKit(Safari engine)核心启动、离线资源、SceneIR、非空 WebGL 和 Main 建模全绿;OPFS、
|
||||
IndexedDB、quota 与 Worker commit 故障由 Chromium 专项覆盖。WebKit headless 不提供 Worker
|
||||
IndexedDB 时明确显示 `Storage: unavailable`,不影响引擎门。
|
||||
|
||||
五个恶意/截断 `.blend` 均返回有界错误;notice、GPL、GMP/OpenSubdiv、本地依赖和 dist 远程
|
||||
URL 扫描进入发布命令。验收:`test:release-performance`、`test:malicious-blends`、
|
||||
`test:cross-browser`、`test:release-package`。
|
||||
12
docs/status/N-009.md
Normal file
12
docs/status/N-009.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# N-009 快照、操作日志和崩溃重放
|
||||
|
||||
状态:`done`
|
||||
|
||||
Storage schema 5 加入 `operation_quarantine`;schema 6 新增经过哈希验证的
|
||||
`simulation_manifest`,不改变既有日志/快照语义。命令按 revision/时间/ID 确定排序,非法记录移入
|
||||
隔离区,revision 冲突结构化失败;显式保存后清理已提交日志。每 10 条命令写一份 SHA-256
|
||||
`.blend` 快照,默认保留 5 份且总量不超过 256MiB;保存点也写快照。恢复入口优先打开原子
|
||||
提交项目,缺失时使用最新快照,然后只重放提交 revision 之后的可重放 Main 命令。
|
||||
|
||||
验收:E2E `retains bounded snapshots and returns a validated operation replay plan`,以及原子恢复、
|
||||
并发保存和 quota 专项。
|
||||
11
docs/status/N-010.md
Normal file
11
docs/status/N-010.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# N-010 可复现离线发布包
|
||||
|
||||
状态:`done`
|
||||
|
||||
`release:offline` 生成 `release/blender-web-offline.tar.gz` 与
|
||||
`release/blender-web-corresponding-source.tar.gz`。二进制包包含同源 app、WASM、GPL、GMP、
|
||||
OpenSubdiv license、第三方 notice、文件 SHA-256 manifest 和 source offer;源码包包含 Blender
|
||||
5.2、Web app/protocol、锁文件、Web 构建脚本与状态/构建文档。tar 使用固定排序、mtime、owner
|
||||
和 `gzip -n`,连续生成两次后必须得到相同的两个 SHA-256;顶层 `SHA256SUMS.txt` 覆盖交付物。
|
||||
|
||||
验收:`npm --prefix web run release:offline`。
|
||||
20
docs/status/N-011.md
Normal file
20
docs/status/N-011.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# N-011 Sculpt 子集
|
||||
|
||||
状态:`in_progress(属性 + 有界 Main stroke 子集)`
|
||||
|
||||
详细分解、依赖、错误码、停止条件和验收命令见
|
||||
[`docs/UNDECLARED_CAPABILITIES_EXECUTION_PLAN.md`](../UNDECLARED_CAPABILITIES_EXECUTION_PLAN.md)。
|
||||
|
||||
本轮已交付 `SculptStrokeIR`、Mask/Face Set 校验、单用户/linked/Shape Key/拓扑
|
||||
modifier 能力门、点数和属性预算。SceneIR 及 WBG1 header version 2 可携带并校验
|
||||
`sculptMask` 和 `faceSets`,`MeshGeometryDelta` 可对两个字段执行 replacement/range patch。
|
||||
`setSculptMeshAttributes` 已通过 Blender Main 写入、undo 历史、保存重开和 WBG 二进制
|
||||
回归;非持久的 active Face Set 仍返回 `CAPABILITY_MISSING`。
|
||||
|
||||
`sculptStroke` 现在开放一个明确受限的 native Main 顶点事务:Draw/Inflate/Grab/Smooth、
|
||||
压力、Mask、对象空间对称、2048 samples/10000 path/250000 vertices 预算,以及 Shape Key、
|
||||
linked、单用户和启用拓扑 modifier 安全门。它不是 Blender PBVH/BMesh 等价求值,仍不声明
|
||||
动态拓扑、多分辨率、纹理笔刷、法线/切线 golden、Sculpt UI 或浏览器故障恢复;这些继续
|
||||
返回结构化阻断并由 N-011-C2/D/E 负责。
|
||||
|
||||
验收:`npm --prefix web run test:authoring-roundtrip`。
|
||||
20
docs/status/N-012.md
Normal file
20
docs/status/N-012.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# N-012 Geometry Nodes 与 Simulation
|
||||
|
||||
状态:`in_progress(资源/Simulation cache 安全层)`
|
||||
|
||||
详细分解、GraphIR、字段/实例闭包、deterministic simulation cache、错误码和验收命令见
|
||||
[`docs/UNDECLARED_CAPABILITIES_EXECUTION_PLAN.md`](../UNDECLARED_CAPABILITIES_EXECUTION_PLAN.md)。
|
||||
|
||||
本轮已交付版本化 `GeometryNodeGraphIR`、node/socket/link/domain 校验、支持节点白名单、
|
||||
循环依赖和自递归 group 检测。Object/Collection/Image Info 资源现在按 SceneIR stable ID、
|
||||
资源类型、owner cycle 和 linked/missing/corrupt 沙箱校验。合法图仍只通过协议门,native
|
||||
lazy-function evaluator 未启用时返回 `CAPABILITY_MISSING`。
|
||||
|
||||
`SimulationCacheManifestIR` 已绑定 graph/source blend/input hash、Blender 5.2、完整帧范围、
|
||||
连续 byte range、总 payload 和逐帧 SHA-256。StorageWorker schema 6 使用 OPFS 内容寻址资产
|
||||
和 `simulation_manifest` 索引,写入前核对当前 committed blend,Worker 重启后重新逐帧验证;
|
||||
缺失、版本不符和损坏均结构化阻断。
|
||||
|
||||
仍未声明:浏览器生成 bake、WASM Simulation Zone 求值、cache frame seek 接入 GN modifier、
|
||||
任意 lazy-function/field/instance graph。验收:`npm --prefix web run test:simulation-cache`、
|
||||
`npm --prefix web run test:capability-gates`。
|
||||
21
docs/status/N-013.md
Normal file
21
docs/status/N-013.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# N-013 Shader Node 图
|
||||
|
||||
状态:`in_progress(七节点 Main + 常量 PBR 映射子集)`
|
||||
|
||||
详细分解、ShaderIR、typed socket 校验、Main 写回、Web 编译、GLB 映射和验收命令见
|
||||
[`docs/UNDECLARED_CAPABILITIES_EXECUTION_PLAN.md`](../UNDECLARED_CAPABILITIES_EXECUTION_PLAN.md)。
|
||||
|
||||
本轮已交付版本化 `ShaderGraphIR`、单 Material Output、typed socket/隐式转换、图循环、
|
||||
Material/Image stable ID 以及 linked/missing/corrupt image 资源门。首个 native Main 写回
|
||||
子集开放 RGB、Value、有限 Math、Principled、Image Texture、Normal Map 和 Material
|
||||
Output;整图替换在一个 history transaction 中完成,并通过节点/链接及 RGB/Value
|
||||
defaultValue 保存重开回归。
|
||||
|
||||
Math 已开放 ADD/SUBTRACT/MULTIPLY/DIVIDE/MINIMUM/MAXIMUM 的 Main `custom1` 写回和
|
||||
operation 保存重开;其他运算继续结构化阻断。RGB/Value 到 Principled Base Color、
|
||||
Roughness、Metallic 的有限常量链接现可确定性映射为 glTF PBR factor;缺值、越界、
|
||||
重复输入和未知链接继续返回 `SHADER_GRAPH_UNMAPPABLE`。Mix、Mapping、Texture
|
||||
Coordinate、Bump 及任意节点仍返回 `SHADER_NODE_UNSUPPORTED`。node properties 仅开放
|
||||
Math operation;受限 Web 编译、完整色彩管理、完整 GLB 图映射和桌面渲染 golden 仍为 planned。
|
||||
验收:`npm --prefix web run test:authoring-roundtrip`、`npm --prefix web run test:capability-gates`
|
||||
以及 Shader GLB mapping E2E。
|
||||
20
docs/status/N-014.md
Normal file
20
docs/status/N-014.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# N-014 NLA
|
||||
|
||||
状态:`in_progress(Action Clip Main/求值 + reverse/repeat 子集)`
|
||||
|
||||
详细分解、AnimationIR strip/track、Main 编辑、原生 NLA 求值、UI、GLB 映射和验收命令见
|
||||
[`docs/UNDECLARED_CAPABILITIES_EXECUTION_PLAN.md`](../UNDECLARED_CAPABILITIES_EXECUTION_PLAN.md)。
|
||||
|
||||
本轮已交付 `NlaTrackIR`/`NlaStripIR`、Action 存在性、owner/path、稳定排序、不重叠、
|
||||
range/scale/repeat/influence 一致性、blend/extrapolation 和 time-warp 阻断。SceneIR reader
|
||||
可恢复 Track/Action Clip 摘要;`setNLAStack` 以整栈替换事务写 Blender Main,并经过
|
||||
undo 历史、保存重开和 frame 5 native depsgraph 求值。Action Clip `reverse` 已映射到
|
||||
Blender `NLASTRIP_FLAG_REVERSE`,reader 可恢复该标志;反向正例得到预期线性位置约
|
||||
`[0.555556, 1.111111, 1.666667]`。
|
||||
同一正例已扩为 `repeat=2`,frame 5 与第二周期 frame 14 的 native Depsgraph 矩阵一致。
|
||||
|
||||
当前只支持单对象 Action Clip、正 scale、Replace/Add/Multiply/Combine 和有限外插。
|
||||
Transition/Meta/Sound、Animated Time、Drivers、细粒度拖动/resize 命令、NLA UI、
|
||||
骨骼/约束混合矩阵及 GLB 展开仍为 planned/结构化阻断。
|
||||
|
||||
验收:`npm --prefix web run test:authoring-roundtrip`、`npm --prefix web run test:capability-gates`。
|
||||
113
docs/status/N-015.md
Normal file
113
docs/status/N-015.md
Normal file
@@ -0,0 +1,113 @@
|
||||
# N-015 非 Mesh 几何数据块
|
||||
|
||||
状态:`in_progress`(本地有界切片已落地,VDB renderer/完整交互仍阻断)
|
||||
|
||||
更新时间:2026-08-12
|
||||
|
||||
## 当前声明
|
||||
|
||||
当前声明覆盖 Blender 5.2 `.blend` 中有限非 Mesh 数据的稳定识别、Main 权威写回、undo/redo、
|
||||
保存重开、真实 evaluated mesh 报告和 WNM 二进制分块。Curve cyclic/handle 目前只有有界
|
||||
属性读写,未声明完整 topology editor、handle/cyclic gizmo、VDB 体渲染、完整 USD loss
|
||||
fixture 或跨浏览器性能等价。
|
||||
|
||||
| 数据族 | Reader | Web 预览 | 当前门 |
|
||||
| --- | --- | --- | --- |
|
||||
| legacy Curve | 控制点、spline offset、resolution | WNM 控制折线;depsgraph 真 mesh | `READY` |
|
||||
| legacy Surface | 控制点、spline offset、resolution | WNM 控制折线;depsgraph 真 mesh | `READY` |
|
||||
| Font | body、对齐、extrude/bevel/offset 与摘要 | depsgraph 真 mesh(源文本仍保留) | `READY`(无控制笼) |
|
||||
| Metaball | 元素类型、位置、半径、尺度 | bounded sphere proxy;depsgraph implicit mesh | `READY` |
|
||||
| PointCloud | position/radius/POINT 属性 | WNM 分块 Points | `READY`(空数据为 `summary-only`) |
|
||||
| Curves/Hair | position/radius/curve/POINT 属性 | WNM 分块 Points/curve line | `READY`(缺数据阻断) |
|
||||
| Volume | 项目内 OpenVDB path/grid metadata | 无 renderer;可取消 decoder API | `NON_MESH_RESOURCE_MISSING` 或预算阻断 |
|
||||
|
||||
## 已实现任务
|
||||
|
||||
1. `NonMeshDataIR` 加入 SceneIR schema 1,可选字段保持旧快照兼容。
|
||||
2. parser 校验类型、状态、有限数、三元控制点、spline offset、Metaball 元素和错误码。
|
||||
3. native reader 为数据块生成稳定 ID,并把对象 `dataId` 指向同一 ID;Web runtime 注册
|
||||
`ID_MB`、`ID_PT` 和 `ID_VO`,不再把三类对象降为 Empty。
|
||||
4. 单数据块最多读取 1M 点;越界或不完整数据返回
|
||||
`NON_MESH_DATA_BUDGET_EXCEEDED`。
|
||||
5. `NonMeshGeometryChunk` WNM schema 1 提供 65,536 点分块、SHA-256、属性 domain/storage、
|
||||
256 MB 场景预算和 1M 点性能门;Worker/主线程/Offscreen 均传输并消费分块。
|
||||
6. native reader 读取 PointCloud/Curves/Hair 的 position、radius、curve offset 和属性值,
|
||||
不以摘要计数伪造点;Volume 提供项目路径、OpenVDB grid metadata 和可取消 decoder。
|
||||
7. depsgraph 对 Curve/Surface/Font/Metaball 通过 `BKE_mesh_new_from_object` 输出真实位置、法线、
|
||||
边/三角索引、UV、材质槽和 source face/edge mapping,并在 1M/2M 拓扑预算处结构化阻断。
|
||||
Web ID registry 已注册 `ID_VF` 并在加载时恢复 Blender 未写入 `.blend` 的 `<builtin>` 字体
|
||||
引用;Curve/Surface/Font/Metaball 的几何计数、边界、面积和位置/索引矩均通过 Blender
|
||||
5.2 desktop golden。
|
||||
8. Main 已支持 Curve/Surface 控制点、resolution、有界 cyclic/handle 类型与 Bezier 左右 handle
|
||||
坐标、Font body/geometry/layout 标量属性(spacing、line distance、word space、shear、font
|
||||
size、x/y offset)、逐字符 kern/material/style flags 和最多 256 个 textbox、
|
||||
`.blend` 内已有/packed VFont 的 regular/bold/italic/bold-italic 四样式链接、
|
||||
Metaball element 写回,以及 bounded Poly Curve create、delete、1D Poly/Bezier/NURBS conversion、
|
||||
二维 Surface U/V dimensions/order/rational weight 网格替换和 Curve/Surface/Font/Metaball 数据块
|
||||
重命名;一维多 spline 创建/删除/重排和批量 handle/cyclic 已由单个原子 Main 事务覆盖。
|
||||
多 handle 选择拖拽/gizmo UI 仍阻断。单用户、undo/redo、save/reopen 由
|
||||
`check-nonmesh-roundtrip.mjs` 验证。
|
||||
9. 主线程与 OffscreenCanvas 对 PointCloud/Curve 控制点和 Bezier handle 代理提供 bounded raycast,并对 Mesh 的
|
||||
VERT/EDGE/FACE 使用一致的三角顶点、边索引解析,回传既有 selection callback;完整
|
||||
gizmo、跨对象 selection history 与精确范围 patch 仍未声明;新增 local bounded selection
|
||||
history 仅用于 revision/stale-hit 门和撤销栈验收。Bezier 左/右 handle 现以全局控制点映射
|
||||
独立拾取,轴向 gizmo 通过精确 Main 命令写回并通过 undo/redo、save/reopen;多选拖拽、跨对象
|
||||
history 和 range patch 仍未声明。
|
||||
10. `queryNonMeshCapability(dataId)` 返回 N-015 `READY/BLOCKED` 与机器可读错误码;GLB 对未求值
|
||||
非 Mesh 拒绝导出。Font/Metaball/二维 NURBS Surface 的 depsgraph 三角网格与 Curve 的
|
||||
evaluated edge line primitive 已通过 GLB 导出和 Blender 5.2 桌面回导几何校验;零三角且零边的结果仍返回
|
||||
`GLB_NON_MESH_UNMAPPED`,不生成空 primitive。确定性 USDA 1.0 序列化器将三角求值写为
|
||||
`UsdGeomMesh`、edge-only 求值写为 `UsdGeomBasisCurves`,缺 buffer/空场景结构化阻断;四对象
|
||||
已通过 USD-enabled Blender 5.2.0 LTS desktop reimport。PointCloud 使用 GLB `POINTS`/USD
|
||||
`UsdGeomPoints`,Curves/Hair 使用 GLB `LINES`/USD `UsdGeomBasisCurves`;radius 映射 USD
|
||||
widths,typed WNM 属性映射 primvars,GLB 属性损失结构化报告,7 对象 desktop reimport 已通过。
|
||||
Volume loss fixture 仍由 VDB 资源/renderer 阻断。
|
||||
11. Blender 5.2 fixture 已包含真实 PointCloud/Curves 属性;Chromium 主线程/Offscreen、真实
|
||||
depsgraph、WNM 1M 性能测试均接入。
|
||||
|
||||
## 后续分解
|
||||
|
||||
1. N-015-B3:接入真实 OpenVDB decoder 与体素纹理/射线步进;在此之前保持 Volume renderer 阻断。
|
||||
2. N-015-C1:多 handle 选择拖拽与 gizmo UI;多 spline 创建/删除/重排、批量 handle/cyclic
|
||||
editor transaction 和二维 Surface U/V topology/order/rational weight 网格替换已完成。
|
||||
3. N-015-C2:任意外部路径的新字体导入与资源沙箱;已有/packed VFont 的四 style link Main
|
||||
写回、字符级样式、kern/material 与 textbox 已完成并通过 PFB desktop/WASM golden。
|
||||
4. N-015-D1:跨对象 selection history、多 handle 拖拽和 SceneDelta range patch;左右 handle
|
||||
identity raycast、单 handle 轴向 gizmo/Main 写回已完成。
|
||||
5. N-015-D2:evaluated preview 与源控制笼分层显示、WebGPU 等价。
|
||||
6. N-015-E1:补齐 Volume 的完整 loss fixture;PointCloud/Curves/Hair、Curve line bake、真实
|
||||
4x4 NURBS Surface mesh、desktop geometry golden、7 对象 GLB 与 USDA desktop round-trip 已通过。
|
||||
7. N-015-E2:100k/1M WASM/GPU 内存、Worker restart 和 Chromium OPFS quota;Chromium
|
||||
64 KiB 真实 quota、失败后旧 revision 保持、Worker restart 恢复已通过。后续浏览器验收
|
||||
仅以 Chromium 为基线,不配置 Firefox/WebKit。
|
||||
|
||||
## 停止条件
|
||||
|
||||
- `summary-only` 不得进入 `READY`。
|
||||
- legacy 控制折线不得标记为 evaluated/tessellated curve。
|
||||
- Metaball sphere proxy 不得用于导出或保存为求值曲面。
|
||||
- Volume decoder/renderer、Hair 属性 buffer 缺失时不得生成占位几何。
|
||||
- Metaball sphere proxy 不得进入 GLB;GLB 只能消费 depsgraph evaluated mesh。
|
||||
- 任意新增 Main authoring 命令在 save/reopen 与 undo/redo 完成前不得开放 UI。
|
||||
|
||||
## 验收命令
|
||||
|
||||
```bash
|
||||
source tools/web/emscripten-env.sh
|
||||
cmake --build build_web_blender6 --target web_engine -- -j8
|
||||
bash tools/web/install-web-engine-assets.sh
|
||||
build_blender_5.2.0/bin/blender -b --factory-startup \
|
||||
--python tools/web/generate-nonmesh-fixture.py -- tests/files/web/nonmesh_scene.blend
|
||||
npm --prefix web run typecheck
|
||||
npm --prefix web run lint
|
||||
npm --prefix web run test:nonmesh-roundtrip
|
||||
npm --prefix web run test:nonmesh-desktop-golden
|
||||
npm --prefix web run test:nonmesh-glb-blender-roundtrip
|
||||
npm --prefix web run test:nonmesh-usd-serialization
|
||||
BLENDER_BIN=/path/to/usd-enabled/blender \
|
||||
npm --prefix web run test:nonmesh-usd-blender-roundtrip
|
||||
npm --prefix web run test:nonmesh-binary
|
||||
npm --prefix web run test:vdb
|
||||
WEB_TEST_PORT=5349 npm --prefix web run test:e2e -- -g "real OPFS quota|reports quota exhaustion"
|
||||
WEB_TEST_PORT=5201 npm --prefix web run test:e2e -- -g "N-015|non-mesh"
|
||||
```
|
||||
39
docs/status/N-016.md
Normal file
39
docs/status/N-016.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# N-016 Grease Pencil
|
||||
|
||||
状态:`BLOCKED`(协议、有限 reader 和有限 Main transaction 已落地;完整 2D/3D 编辑器、onion skin、modifier 语义和桌面 golden 仍阻断)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-016-A:SceneIR 中提供 Layer/Frame/Drawing/Stroke/Point/Attribute schema,校验
|
||||
finite position、radius、opacity、vertex color、cyclic、material index,并以
|
||||
1024 layer、100k frame、1M stroke、1M point、65,536 attribute 预算拒绝越界输入。
|
||||
超预算只允许 `blocked + GREASE_PENCIL_BUDGET_EXCEEDED` 摘要。
|
||||
2. N-016-A:Blender 5.2 Main reader 输出真实 Grease Pencil layer/frame/drawing/stroke
|
||||
数据,稳定映射 `grease-pencil:*` 与 `grease-pencil-layer:*` ID;对象 dataId 不再降级
|
||||
为 Empty。
|
||||
3. N-016-B:Main 支持有界 create/remove/reorder layer、insert/remove frame,以及整帧
|
||||
`setGreasePencilStrokes` transaction(空 stroke 数组用于擦除)。命令要求单用户数据块,
|
||||
使用既有 authoritative Main、undo/redo 和 save/reopen 流程。
|
||||
4. N-016-C(部分):radius、opacity、vertex color、cyclic stroke 和 material index
|
||||
已读写;onion skin 仅输出 layer 状态,不声明时间邻帧渲染。
|
||||
5. N-016-D(部分):共享 Three.js 适配器按当前 frame 选择每个可见 layer 最近的有效
|
||||
drawing,渲染真实 3D stroke/闭环;Chromium 主线程与 OffscreenCanvas 均通过非空像素门。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-016-C:material datablock 事务、onion skin preview 和完整 Grease Pencil modifier reader。
|
||||
- N-016-D:2D editor、stroke/point selection、timeline/dope integration、gizmo 和 worker restart;
|
||||
3D current-frame stroke viewport 已完成。
|
||||
- N-016-E:desktop drawing hash、Chromium 像素 golden、GLB/USD loss report 和 OPFS。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
npm --prefix web run typecheck
|
||||
npm --prefix web run lint
|
||||
npm --prefix web run test:grease-pencil
|
||||
WEB_TEST_PORT=5202 npm --prefix web run test:e2e -- --grep "N-016 Grease Pencil"
|
||||
```
|
||||
|
||||
`test:grease-pencil` 使用 `modifier_grease_pencil_scene.blend`,覆盖 reader、layer/frame/stroke
|
||||
Main transaction、undo/redo 和保存重开。它不替代桌面 drawing hash。
|
||||
33
docs/status/N-017.md
Normal file
33
docs/status/N-017.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# N-017 Paint 与权重
|
||||
|
||||
状态:`BLOCKED`(stroke/patch schema、Main 顶点色/权重 transaction 已落地;真实命中、texture paint 和 GPU/image 生命周期未实现)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-017-A(部分):`PaintStrokeIR` 覆盖 Vertex Color、Weight、Texture Paint,携带
|
||||
object/revision、radius/strength、pressure、PBVH face/barycentric hit 和 UV hit。
|
||||
2. N-017-A(部分):`WeightPatchIR` 覆盖有界 vertex index/value、normalize 和 mirror 意图。
|
||||
3. 预算限制为单 stroke 100k samples/64 MiB 估算、单 weight patch 1M entries、单 texture
|
||||
tile 256 MiB;非法 barycentric、pressure、color、weight 和非有限数会结构化拒绝。
|
||||
4. N-017-B(部分):`setVertexColors` 在单用户 Mesh 上创建/转换 `POINT` 或 `CORNER`
|
||||
`FLOAT_COLOR` 属性,并更新 active color;`setVertexWeights` 在真实 Object/Mesh 上创建顶点组、
|
||||
写入/移除 `MDeformWeight`,支持逐顶点 normalize。
|
||||
5. 顶点色和权重都已通过 Main undo/redo 与 `.blend` save/reopen;`mirror:true` 在没有已验证
|
||||
对称拓扑映射时返回 `CAPABILITY_MISSING`,不会伪造镜像结果。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-017-A:真实 PBVH/UV raycast 与 brush falloff 对桌面语义的对应。
|
||||
- N-017-B:limit/clean、已验证拓扑映射上的 mirror、桌面 brush/falloff 对照。
|
||||
- N-017-C:packed/UDIM tile transaction、色彩空间、dirty tile 和原子保存。
|
||||
- N-017-D/E:armature golden、seam bleed、mask/selection、GPU dispose、quota、坏图和 UI。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
WEB_TEST_PORT=5203 npm --prefix web run test:e2e -- --grep "N-017 paint"
|
||||
npm --prefix web run test:paint-roundtrip
|
||||
```
|
||||
|
||||
`test:paint-roundtrip` 覆盖 CORNER color、vertex group patch、normalize、mirror 错误门、
|
||||
undo/redo 与 save/reopen。
|
||||
30
docs/status/N-018.md
Normal file
30
docs/status/N-018.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# N-018 Physics 与 Simulation
|
||||
|
||||
状态:`BLOCKED`(family capability、settings/dependency/cache manifest 与错误帧门已落地;
|
||||
cache playback、WASM solver 和 bake job 未实现)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-018-A:Rigid Body、Soft Body、Cloth、Fluid、Dynamic Paint、Particle、Hair
|
||||
使用固定枚举能力清单;metadata/cache manifest 为 `LOCAL_BOUNDED`,cache playback、
|
||||
local solver、server job 均保持 `BLOCKED`。
|
||||
2. N-018-B(部分):`PhysicsSimulationManifestIR` 绑定 owner Object、settings SHA-256、
|
||||
有界设置摘要、依赖 stable ID 和 desktop bake cache;系统依赖环、重复依赖和超预算拒绝。
|
||||
3. N-018-C(门):cache 绑定 source blend/settings/input/cache SHA-256、帧范围和实际已缓存帧;
|
||||
`COMPLETE` 必须逐帧连续,frame seek 只返回精确命中帧,禁止复用相邻错误帧。
|
||||
4. 单 manifest 上限 4096 systems、每系统 1024 dependencies、256 settings/64 KiB、
|
||||
100k frames。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-018-A/B:从真实 Main 提取完整 family settings、collection/effector/collision 依赖。
|
||||
- N-018-C:desktop bake payload 的 family decoder、depsgraph frame playback 和 100 帧 golden。
|
||||
- N-018-D:逐 family WASM solver 初始化、线程、内存和确定性验证。
|
||||
- N-018-E:bake start/cancel/commit、服务端 job、故障恢复、进度与 UI。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
WEB_TEST_PORT=5204 npm --prefix web run test:e2e -- --grep "N-018 physics"
|
||||
npm --prefix web run test:simulation-cache
|
||||
```
|
||||
33
docs/status/N-019.md
Normal file
33
docs/status/N-019.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# N-019 灯光与渲染
|
||||
|
||||
状态:`BLOCKED`(Camera/Light/World/Scene metadata、Light/World 有界 Main 写回与
|
||||
Three exposure/shadow 映射已落地;完整 Camera/颜色管理 writer 和渲染等价未实现)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-019-A(部分):Camera 区分 Perspective/Orthographic/Panoramic/Custom,读取 sensor、
|
||||
shift、clip、panorama 和 DOF;Light 读取 energy/exposure/temperature/shadow/shape;World
|
||||
读取环境、exposure 和 mist;Scene 读取 render engine、display/view/look/exposure/gamma/白平衡。
|
||||
2. N-019-A(部分):Light 与 World 使用严格属性白名单写入真实 Main,覆盖 color、energy、
|
||||
exposure、temperature、shadow、World color/mist,已通过 undo/redo 与 save/reopen。
|
||||
3. N-019-B(部分):主线程和 OffscreenCanvas renderer 都优先使用 Scene color-management
|
||||
exposure,World exposure 仅作旧数据回退;Light exposure 转换为强度,`castsShadow:false`
|
||||
不再被 Three 强制打开。
|
||||
4. 白平衡读取有完整性门:Main Light/World 重写若导致 Blender 5.2 tint 序列化为异常近零值,
|
||||
不暴露垃圾数值而返回 `whiteBalanceStatus: BLOCKED`。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-019-A:Camera 与 Scene color-management writer;直接 DNA 写入会破坏 white balance,
|
||||
必须改接 Blender/RNA 颜色管理 API 后才能开放。
|
||||
- N-019-B/C:AgX/Standard/Raw 的视觉等价、temperature 颜色、Area spread、Mist、DOF、
|
||||
transparent sorting、probe 和高级 shadow 参数。
|
||||
- N-019-D:Cycles/Freestyle/denoise 服务端 job 协议与结果 hash。
|
||||
- N-019-E:desktop/Chromium 像素 golden、设备丢失和 1M triangles。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
npm --prefix web run test:lighting-roundtrip
|
||||
WEB_TEST_PORT=5319 npm --prefix web run test:e2e -- --grep "N-019 Scene exposure"
|
||||
```
|
||||
29
docs/status/N-020.md
Normal file
29
docs/status/N-020.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# N-020 Compositor
|
||||
|
||||
状态:`BLOCKED`(GraphIR 与有界 CPU executor 已落地;真实 Main graph、WebGPU、HDR golden
|
||||
和服务端执行未实现)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-020-A:版本化 `CompositorGraphIR` 覆盖 Image、Render Layer、Constant Color、
|
||||
Transform、Invert、Exposure、Alpha Over、Blur、Mix、Viewer、Composite 与 Unsupported;
|
||||
节点/资源 ID、重复 input socket、缺失引用和 graph cycle 会拒绝。
|
||||
2. N-020-B(CPU 子集):线性 sRGB Float32 RGBA executor 按拓扑序执行 Transform、颜色、
|
||||
Alpha Over、Blur、Mix,并返回 Composite 与多 Viewer 输出。
|
||||
3. N-020-C(部分):最大 4096 nodes、16384 links、4096 resources、8192 dimension、
|
||||
16M pixels、256 MiB image 和 100M blur operations;分配前检查,支持 worker cancellation。
|
||||
4. N-020-D(门):Unsupported node 保留 Blender type metadata,并返回
|
||||
`COMPOSITOR_NODE_UNSUPPORTED`,不会删节点后继续运行。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-020-A:从真实 Main 读取/写回 compositor node tree、socket defaults、Render Layer pass。
|
||||
- N-020-B/C:WebGPU executor、tile/frame cache、增量 invalidation 和 GPU dispose。
|
||||
- N-020-D:服务端 Blender job、source hash 和结果提交。
|
||||
- N-020-E:desktop HDR/alpha/color-space golden、OOM/fault/device-loss。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
WEB_TEST_PORT=5320 npm --prefix web run test:e2e -- --grep "N-020 CPU compositor"
|
||||
```
|
||||
31
docs/status/N-021.md
Normal file
31
docs/status/N-021.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# N-021 Sequencer 与音频
|
||||
|
||||
状态:`BLOCKED`(strip schema、确定性时间编辑和 codec 能力门已落地;真实 Main
|
||||
写回、媒体解码/渲染、音频波形和服务端编码仍未实现)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-021-A(部分):版本化 `SequencerTimelineIR` 覆盖 Scene、Movie、Image、Sound、
|
||||
Effect、Meta strip、channel、帧范围、source range、speed、proxy 和依赖;strip、
|
||||
image、dependency 数量以及帧范围都有预算,资源路径经过项目沙箱规范化。
|
||||
2. N-021-B(部分):`MOVE`、`TRIM`、`SPLIT` 以 revision 乐观并发控制作用于内存
|
||||
timeline;编辑后重新解析依赖和预算,锁定 strip 与 stale revision 会拒绝。
|
||||
3. N-021-B/C:`sequencerSourceFrame` 对 speed、trim、split 使用确定性的 source-frame
|
||||
映射,避免左右片段复用越界源帧。
|
||||
4. N-021-C/D(门):运行时只报告 WebCodecs/HTMLMedia 需要精确 probe;codec 必须
|
||||
出现在已验证 MIME 集合中才可放行,本地编码固定为 `BLOCKED`。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-021-A/B:从真实 Main 读取并写回 scene sequence editor 的 strip、transition、
|
||||
modifier、undo/redo、save/reopen。
|
||||
- N-021-C:WebCodecs 精确 seek/decode、音频 waveform、proxy 生成、A/V sync、丢帧和
|
||||
损坏媒体处理。
|
||||
- N-021-D:浏览器不支持的 codec、混音与最终编码的服务端 Blender job。
|
||||
- N-021-E:桌面/Chromium golden、OPFS 和大规模媒体性能门。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
WEB_TEST_PORT=5321 npm --prefix web run test:e2e -- --grep "N-021 sequencer"
|
||||
```
|
||||
28
docs/status/N-022.md
Normal file
28
docs/status/N-022.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# N-022 Tracking 与 Mask
|
||||
|
||||
状态:`BLOCKED`(资源 schema、marker/mask 有界事务和 solve 能力门已落地;真实 Main、
|
||||
跟踪/相机求解、编辑器 overlay 与桌面 golden 未实现)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-022-A:版本化 project schema 覆盖 MovieClip、Track/Marker、Plane Track、Camera
|
||||
Solve metadata、Mask Layer/Spline/Point 及 compositor/scene binding。
|
||||
2. N-022-A/B:clip 路径限制在项目内,source 与 solve 绑定 SHA-256;marker frame、
|
||||
plane track 引用、mask point/handle、资源 binding、重复 ID 与总量预算都严格校验。
|
||||
3. N-022-B(部分):marker upsert/delete、track selection、mask point 与 spline cyclic
|
||||
修改使用 revision 事务,锁定项和 stale revision 会拒绝,提交后再次完整解析。
|
||||
4. N-022-C(门):marker/mask schema edit 可用;browser tracking 只有显式 probe 成功后
|
||||
放行,camera solve 保持 `BLOCKED` 并要求受验证的服务端 Blender。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-022-A/B:真实 Blender Main MovieClip/Mask 读取、写回、undo/redo、save/reopen。
|
||||
- N-022-C:浏览器 tracking 实现、完整 camera/plane solve 与服务端 job/hash 提交。
|
||||
- N-022-D:Clip/Mask editor、overlay、selection/raycast 和 compositor/scene 实际绑定。
|
||||
- N-022-E:desktop solve/error golden、媒体故障和 Chromium 测试。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
WEB_TEST_PORT=5322 npm --prefix web run test:e2e -- --grep "N-022 tracking"
|
||||
```
|
||||
27
docs/status/N-023.md
Normal file
27
docs/status/N-023.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# N-023 Asset、Library 与 IO
|
||||
|
||||
状态:`BLOCKED`(asset catalog、来源/许可证元数据、库依赖与 IO 安全门已落地;真实
|
||||
Append/Link/Override Main、非 GLB 本地导入和跨桌面重导入未实现)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-023-A:版本化 manifest 覆盖 catalog、asset kind/tag、preview、author、license、
|
||||
source path/SHA-256、library source/dependency/read-only metadata;重复 ID、缺 catalog、
|
||||
缺许可证和哈希不匹配会拒绝。
|
||||
2. N-023-A/B(部分):catalog 与 library dependency 图做确定性拓扑检查并返回 load order;
|
||||
content-addressed index 报告 `LOCAL_BOUNDED`,OPFS 只在运行时 API 存在时报告 `PROBE_REQUIRED`。
|
||||
3. N-023-C(门):现有 GLB 导出与 USD semantic analysis 可放行;GLTF/OBJ/PLY/STL、
|
||||
USD/Alembic 实际导入保持 `IO_FORMAT_UNSUPPORTED`,库 mutation 需要真实 Main。
|
||||
4. N-023-E:项目路径、外部 URI、archive entry 数量/单项/总量、压缩展开比率均有边界。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-023-B:Append/Link/Library Override、reload/relocate 和真实 Main transaction。
|
||||
- N-023-C/D:GLTF/OBJ/PLY/STL、USD/Alembic import/export/save/reopen/desktop reimport。
|
||||
- N-023-E:zip fuzz、OPFS quota/recovery、license/source offer 发布审计和大文件流式性能。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
WEB_TEST_PORT=5323 npm --prefix web run test:e2e -- --grep "N-023 asset"
|
||||
```
|
||||
27
docs/status/N-024.md
Normal file
27
docs/status/N-024.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# N-024 Editors 与工作流
|
||||
|
||||
状态:`BLOCKED`(统一 context、只读 editor manifest、selection sync、keymap 和布局预算
|
||||
已落地;完整 Blender editor writer、gizmo/触控和跨设备 golden 未实现)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-024-A:版本化 workflow manifest 统一 workspace、area、region、active editor、mode、
|
||||
view layer、pinned data 与 revision;13 类 editor 可被明确识别。
|
||||
2. N-024-B(部分):只读 editor context、区域可见性、workspace/area 切换使用同一份
|
||||
workflow state,rect 边界与不可重叠布局经过校验。
|
||||
3. N-024-C(部分):selection sync 以 revision 事务更新 active object 与 selected IDs,
|
||||
active object 必须属于 selection,过期 revision 会拒绝。
|
||||
4. N-024-D(门):keymap 绑定和预算可验证;writer、gizmo 与 touch drag 保持能力阻断。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-024-B/C:Properties、UV/Image、Node、Graph、Dope Sheet、NLA、Spreadsheet 等真实
|
||||
Blender 数据读取/写回、selection history、operator search 和 context menu。
|
||||
- N-024-D/E:Blender-compatible keymap 执行、gizmo/drag preview/commit、桌面/mobile/笔
|
||||
触控布局、无重叠截图和 accessibility golden。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
WEB_TEST_PORT=5324 npm --prefix web run test:e2e -- --grep "N-024 editor"
|
||||
```
|
||||
28
docs/status/N-025.md
Normal file
28
docs/status/N-025.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# N-025 Scripting 与平台
|
||||
|
||||
状态:`BLOCKED`(默认拒绝策略、签名 manifest、权限/资源预算、平台报告和服务端 hash
|
||||
门已落地;本地隔离执行、真实 server job 与发布审计未实现)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-025-A:脚本默认拒绝网络、autorun、driver expression 和 add-on 安装;entry/dependency
|
||||
path 必须在项目内,未知权限和重复 ID 会拒绝。
|
||||
2. N-025-B(部分):脚本 manifest 要求 SHA-256、固定长度签名、publisher/keyId、权限
|
||||
allowlist、CPU/内存/墙钟预算,并检查脚本依赖图。
|
||||
3. N-025-C(门):合法脚本仍要求隔离 sandbox;server job 需要 script/source/input
|
||||
hash 一致,但当前 endpoint 未配置,返回 `SERVER_JOB_UNAVAILABLE`。
|
||||
4. N-025-D:Worker/WebGPU/OffscreenCanvas/OPFS 与 native/CUDA/Metal/HIP/OptiX capability
|
||||
报告只反映 API 存在或显式 `BLOCKED`。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-025-B/C:签名验证密钥管理、无网络 CPython/native sandbox、server Blender job 和
|
||||
output hash 提交。
|
||||
- N-025-D/E:真实 GPU/native window/file watcher 适配、恶意脚本/依赖混淆/逃逸/重放、
|
||||
审计日志和发布门。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
WEB_TEST_PORT=5325 npm --prefix web run test:e2e -- --grep "N-025 script"
|
||||
```
|
||||
37
docs/status/N-026.md
Normal file
37
docs/status/N-026.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# N-026 全域发布门
|
||||
|
||||
状态:`BLOCKED`(machine-readable parity manifest、依赖/状态检查、证据聚合和确定性
|
||||
序列化已落地;跨浏览器、离线包、OPFS、性能/故障、SBOM 与发布审计证据未齐)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-026-A:版本化 `ReleaseManifestIR` 为每个 family 记录 `LOCAL_EXACT`、
|
||||
`LOCAL_BOUNDED`、`SERVER` 或 `BLOCKED`、roadmap 状态、完成/阻断切片、验收命令和
|
||||
依赖;缺失 family、非法非阻断状态或依赖环会拒绝。
|
||||
2. N-026-B/C:Chromium 主线程/OffscreenCanvas、offline/Worker restart/OPFS recovery、
|
||||
1M/10M geometry、4K/8K texture、长媒体、simulation cache、OOM/device loss/网络
|
||||
中断/损坏 blend/zip bomb 等证据字段必须逐项为 true 才能放行。
|
||||
3. N-026-D/E:license、SBOM、source offer、deterministic package 为发布必需证据;
|
||||
manifest family 排序可确定性序列化,当前缺证据聚合为 `BLOCKED`,没有虚报发布通过。
|
||||
4. 当前 Chromium smoke 已通过引擎启动/Main 编辑与内容寻址资产恢复,并通过真实 64 KiB
|
||||
OPFS quota 下的失败保持旧 revision、Worker 重启恢复门。这只计为 partial evidence,不等于
|
||||
完整 suite 或其余 family 的桌面 golden。发布门 schema 2 仅接受 Chromium 浏览器证据。
|
||||
5. N-015 Curve/Surface/Font/Metaball 已通过 Blender 5.2 desktop geometry golden;这四类及
|
||||
PointCloud/Curves/Hair 共 7 对象已通过 GLB/USDA desktop round-trip。Volume/VDB 仍无 renderer
|
||||
与 loss fixture,这些证据也不替代其余 family 的 desktop golden。
|
||||
6. 当前发布包已通过本地 third-party notices、Blender/Three license 文件、无远程运行时依赖、
|
||||
非空 SHA-256 manifest、离线二进制/源码包确定性复建和 100k/1M decimate + 5 类损坏 blend
|
||||
拒绝门;这些是 partial evidence,不等于完整 SBOM/source offer、10M/长媒体或 OPFS quota。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- 完整跨浏览器矩阵、跨 family 桌面 golden、离线/OPFS quota、1M/10M/长媒体基准和 fault fuzz 尚未有
|
||||
真实证据;上游 N-015 至 N-025 的阻断能力会传递到发布门。
|
||||
- 完整 release package 审计、许可证/source offer/SBOM、10M/长媒体性能和 OPFS quota 发布流程仍未完成;
|
||||
当前离线包确定性检查只覆盖已有二进制/源码归档门。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
WEB_TEST_PORT=5326 npm --prefix web run test:e2e -- --grep "N-026 release"
|
||||
```
|
||||
17
docs/status/W-000.md
Normal file
17
docs/status/W-000.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# W-000 Status
|
||||
|
||||
status: done
|
||||
task: 固定源码和版本
|
||||
|
||||
## Evidence
|
||||
|
||||
- Blender source: `blender-5.2.0/`
|
||||
- Native binary: `build_blender_5.2.0/bin/blender`
|
||||
- Blender report: `Blender 5.2.0 LTS`
|
||||
- Toolchain: CMake 3.31.6, Ninja 1.12.1, Emscripten 3.1.69, Node 20.19.2, npm 9.2.0
|
||||
- Reference Git commit: `fbe6228777e7d9afefcd61a413844e790ae75db7`
|
||||
|
||||
## Risk
|
||||
|
||||
The reference `blender/` checkout was dirty before this work. It is not modified
|
||||
by the Web implementation.
|
||||
15
docs/status/W-001.md
Normal file
15
docs/status/W-001.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# W-001 Status
|
||||
|
||||
status: done
|
||||
task: 建立依赖和许可证清单
|
||||
|
||||
## Evidence
|
||||
|
||||
- Matrix: `docs/web/dependency-matrix.md`
|
||||
- Notices: `docs/web/third-party-notices.json`
|
||||
- No CAD kernel or Bitbybit/OCCT dependency is included.
|
||||
- Local runtime audit: `cd web && npm run check:local-deps` -> `local-dependencies-ok`.
|
||||
- Browser assets are vendored under `web/app/src/vendor/` and
|
||||
`web/app/public/vendor/`; no CDN/remote ESM URL is present in source or `dist/`.
|
||||
- Offline bootstrap check: `npm ci --offline --ignore-scripts` passed with the
|
||||
existing local npm cache.
|
||||
10
docs/status/W-002.md
Normal file
10
docs/status/W-002.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# W-002 Status
|
||||
|
||||
status: done
|
||||
task: 建立浏览器能力矩阵
|
||||
|
||||
## Evidence
|
||||
|
||||
- Capability implementation: `web/app/src/platform/capabilities.ts`
|
||||
- The probe is side-effect free and returns explicit false values when a browser
|
||||
API is unavailable. Browser screenshot validation is scheduled by W-015.
|
||||
11
docs/status/W-003.md
Normal file
11
docs/status/W-003.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# W-003 Status
|
||||
|
||||
status: done
|
||||
task: 建立 golden 场景目录
|
||||
|
||||
## Evidence
|
||||
|
||||
- Fixtures: `tests/files/web/empty.blend`, `tests/files/web/basic_scene.blend`
|
||||
- Manifest: `tests/files/web/manifest.json`
|
||||
- Golden manifest: `tests/golden/W-003/manifest.json`
|
||||
- Blender validation: empty scene has 0 objects; basic scene has 3 named objects.
|
||||
10
docs/status/W-004.md
Normal file
10
docs/status/W-004.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# W-004 Status
|
||||
|
||||
status: done
|
||||
task: 定义错误、进度和 revision 规范
|
||||
|
||||
## Evidence
|
||||
|
||||
- Error schema: `web/protocol/error.ts`
|
||||
- Progress schema: `web/protocol/progress.ts`
|
||||
- Protocol version: `web/protocol/schema-version` (`1`)
|
||||
10
docs/status/W-005.md
Normal file
10
docs/status/W-005.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# W-005 Status
|
||||
|
||||
status: done
|
||||
task: 规定数据坐标和颜色语义
|
||||
|
||||
## Evidence
|
||||
|
||||
- Contract: `docs/web/coordinate-color-contract.md`
|
||||
- Golden inputs: `tests/files/web/empty.blend`, `tests/files/web/basic_scene.blend`
|
||||
- Full adapter screenshot comparison is scheduled by W-051.
|
||||
11
docs/status/W-006.md
Normal file
11
docs/status/W-006.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# W-006 Status
|
||||
|
||||
status: done
|
||||
task: 建立任务状态和日志模板
|
||||
|
||||
## Evidence
|
||||
|
||||
- Status files are stored in `docs/status/`.
|
||||
- Golden manifests are stored under `tests/golden/<task-id>/`.
|
||||
- Baseline checker: `tools/web/check-baseline.sh`.
|
||||
- Task-card and validation rules: execution plan sections 4.1~4.3.
|
||||
21
docs/status/W-010.md
Normal file
21
docs/status/W-010.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# W-010 Status
|
||||
|
||||
status: done
|
||||
task: 创建 React 工程
|
||||
|
||||
## Evidence
|
||||
|
||||
- Package: `web/package.json`
|
||||
- Lockfile: `web/package-lock.json`
|
||||
- Build: `npm run build` passed with Vite 8.2.0.
|
||||
- Three.js: `0.185.1` vendored under `web/app/src/vendor/three/` (latest stable
|
||||
version selected from npm registry, then copied into the project).
|
||||
- Screenshot: `tests/golden/W-010/desktop-1440x900.png`
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run typecheck # passed
|
||||
npm run lint # passed
|
||||
npm run build # passed
|
||||
```
|
||||
15
docs/status/W-011.md
Normal file
15
docs/status/W-011.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# W-011 Status
|
||||
|
||||
status: done
|
||||
task: 建立应用布局和状态层
|
||||
|
||||
## Evidence
|
||||
|
||||
- App shell: `web/app/src/app/App.tsx`
|
||||
- UI styles: `web/app/src/app/app-shell.css`
|
||||
- Entry point: `web/app/src/main.tsx`
|
||||
- Screenshot: `tests/golden/W-011/layout-1440x900.png`
|
||||
|
||||
The first shell includes Blender-style Topbar, Workspace tabs, Viewport,
|
||||
Outliner, Properties, Timeline and StatusBar. Workspace selection and timeline
|
||||
frame state are local UI state; no geometry arrays are stored in React state.
|
||||
21
docs/status/W-012.md
Normal file
21
docs/status/W-012.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# W-012 Status
|
||||
|
||||
status: done
|
||||
task: 建立 EngineClient 和 Worker 通信
|
||||
|
||||
## Evidence
|
||||
|
||||
- Client: `web/app/src/engine-client/EngineClient.ts`
|
||||
- Worker: `web/app/src/workers/engine.worker.ts`
|
||||
- Protocol: `web/protocol/engine.ts`, `web/protocol/scene-ir.ts`
|
||||
- The browser status changes to `Mock Engine: r0` after init and snapshot.
|
||||
- Screenshot: `tests/golden/W-012/mock-worker-1440x900.png`
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run typecheck # passed
|
||||
npm run lint # passed
|
||||
npm run build # passed
|
||||
Chrome headless --virtual-time-budget=4000 # Mock Engine: r0
|
||||
```
|
||||
26
docs/status/W-013.md
Normal file
26
docs/status/W-013.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# W-013 Status
|
||||
|
||||
status: done
|
||||
task: 建立 Three.js 视口烟测
|
||||
|
||||
## Evidence
|
||||
|
||||
- Adapter: `web/app/src/three-adapter/viewport.ts`
|
||||
- Uses vendored Three.js `0.185.1` from `web/app/src/vendor/three/`,
|
||||
`WebGLRenderer`, `Scene`, `PerspectiveCamera`,
|
||||
`OrbitControls`, `GridHelper`, lights, resize observer and disposal.
|
||||
- No runtime CDN request is required; Playwright asserts all requests stay on
|
||||
the local dev origin.
|
||||
- Screenshot: `tests/golden/W-013/three-viewport-1440x900.png`
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run typecheck # passed
|
||||
npm run lint # passed
|
||||
npm run build # passed
|
||||
Chrome headless --use-gl=swiftshader --virtual-time-budget=60000 # rendered cube/grid
|
||||
```
|
||||
|
||||
The renderer failure path is contained in the viewport component, so browsers
|
||||
without a WebGL context keep the editor shell available.
|
||||
24
docs/status/W-014.md
Normal file
24
docs/status/W-014.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# W-014 Status
|
||||
|
||||
status: done
|
||||
task: 建立 StorageWorker 烟测(原生 IndexedDB)
|
||||
|
||||
## Evidence
|
||||
|
||||
- Client: `web/app/src/storage/StorageClient.ts`
|
||||
- Worker: `web/app/src/workers/storage.worker.ts`
|
||||
- Backend: browser-native IndexedDB in a dedicated Worker
|
||||
- Screenshot: `tests/golden/W-014/storage-viewport-1440x900.png`
|
||||
|
||||
The worker writes and reads a smoke record through IndexedDB and reports whether
|
||||
the Worker can also access OPFS. SQLite WASM is intentionally deferred because
|
||||
it is not required for the current project metadata and file workflow.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run typecheck # passed
|
||||
npm run lint # passed
|
||||
npm run build # passed
|
||||
npm run test:e2e # Storage: IndexedDB (or IndexedDB + OPFS)
|
||||
```
|
||||
20
docs/status/W-015.md
Normal file
20
docs/status/W-015.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# W-015 Status
|
||||
|
||||
status: done
|
||||
task: 建立 Playwright 冒烟测试
|
||||
|
||||
## Evidence
|
||||
|
||||
- Config: `web/playwright.config.ts`
|
||||
- Tests: `web/tests/e2e/smoke.spec.ts`
|
||||
- Browser: system Google Chrome with SwiftShader flags
|
||||
|
||||
The smoke suite covers editor startup, mock EngineWorker initialization,
|
||||
IndexedDB/OPFS capability status, Canvas presence, orbit input and Outliner
|
||||
scene content.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run test:e2e # 2 passed
|
||||
```
|
||||
23
docs/status/W-016.md
Normal file
23
docs/status/W-016.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# W-016 Status
|
||||
|
||||
status: done
|
||||
task: 建立资源 manifest 和 WASM 校验
|
||||
|
||||
## Evidence
|
||||
|
||||
- Manifest: `web/app/public/engine-manifest.json`
|
||||
- Protocol and loader: `web/protocol/manifest.ts`
|
||||
- App status reports `Manifest: verified r1`; the optional local `web_engine.wasm`
|
||||
resource is available for the real ABI worker path.
|
||||
|
||||
Version mismatch, malformed manifests, unavailable resources and digest
|
||||
mismatches reject before a required resource is accepted by the loader.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run typecheck # passed
|
||||
npm run lint # passed
|
||||
npm run build # passed
|
||||
npm run test:e2e # passed with manifest verification
|
||||
```
|
||||
18
docs/status/W-017.md
Normal file
18
docs/status/W-017.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# W-017 Status
|
||||
|
||||
status: done
|
||||
task: 完成 Web 壳里程碑
|
||||
|
||||
React + Three.js + EngineWorker + StorageWorker + versioned manifest now run
|
||||
together with the local minimal WebEngine ABI. The mock SceneIR remains the
|
||||
scene source in this milestone; Blender data libraries and `.blend` loading are
|
||||
deliberately deferred to W-030 and later.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run typecheck # passed
|
||||
npm run lint # passed
|
||||
npm run build # passed
|
||||
npm run test:e2e # 4 passed
|
||||
```
|
||||
21
docs/status/W-018.md
Normal file
21
docs/status/W-018.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# W-018 Status
|
||||
|
||||
status: done
|
||||
task: 定义 Blender 风格 UI 协议和上下文
|
||||
|
||||
## Evidence
|
||||
|
||||
- Protocol: `web/protocol/ui-schema.ts`
|
||||
- Golden: `tests/golden/W-018/ui-schema.json`
|
||||
- State includes versioned Workspace/Area/Region layout, active Editor,
|
||||
Blender mode, active object, selection, view layer, pinned data and revision.
|
||||
- `reduceUICommand()` keeps UI revisions separate from EngineWorker revisions.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run typecheck # passed
|
||||
npm run lint # passed
|
||||
npm run build # passed
|
||||
npm run test:e2e # 3 passed
|
||||
```
|
||||
23
docs/status/W-019.md
Normal file
23
docs/status/W-019.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# W-019 Status
|
||||
|
||||
status: done
|
||||
task: 实现 Blender 风格默认工作区和交互
|
||||
|
||||
## Evidence
|
||||
|
||||
- Shell: `web/app/src/app/App.tsx`
|
||||
- Styles: `web/app/src/app/app-shell.css`
|
||||
- Default areas: 3D Viewport, Outliner, Properties and Timeline.
|
||||
- Interactions: Layout/Modeling/Animation tabs, Object/Edit mode context and
|
||||
F3 Operator Search are wired through the UI command reducer.
|
||||
- Golden: `tests/golden/W-019/ui-layout-1440x900.png`
|
||||
|
||||
The current milestone implements the default shell and context routing. Area
|
||||
split/join and full OperatorRegistry commands remain later work, as specified
|
||||
by W-069 and the subsequent modeling packages.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run test:e2e # 3 passed
|
||||
```
|
||||
21
docs/status/W-020.md
Normal file
21
docs/status/W-020.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# W-020 Status
|
||||
|
||||
status: done
|
||||
task: 建立 Emscripten 工具链
|
||||
|
||||
## Evidence
|
||||
|
||||
- Environment: `tools/web/emscripten-env.sh`
|
||||
- Smoke runner: `tools/web/check-emscripten.sh`
|
||||
- Source: `web/engine/emscripten_smoke.c`
|
||||
- Golden: `tests/golden/W-020/toolchain.json`
|
||||
|
||||
The fixed toolchain is Emscripten 3.1.69. The smoke runner builds both a
|
||||
single-thread and pthread WASM module with ES module, Worker environment,
|
||||
memory growth and filesystem flags.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
tools/web/check-emscripten.sh # emscripten-toolchain-ok
|
||||
```
|
||||
22
docs/status/W-021.md
Normal file
22
docs/status/W-021.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# W-021 Status
|
||||
|
||||
status: done
|
||||
task: 添加 Web CMake 平台
|
||||
|
||||
## Evidence
|
||||
|
||||
- Platform policy: `blender-5.2.0/build_files/cmake/platform/web.cmake`
|
||||
- Standalone target: `web/engine/CMakeLists.txt`
|
||||
- Configure/build runner: `tools/web/configure-web-engine.sh`
|
||||
- Golden: `tests/golden/W-021/cmake-cache.json`
|
||||
|
||||
The Web platform fragment enforces Emscripten, disables desktop GHOST,
|
||||
Python, Cycles and optional desktop codecs, and sets ES module/Worker output
|
||||
flags. It is currently consumed by the isolated smoke target; the full Blender
|
||||
target integration remains the next C-stage task.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
tools/web/configure-web-engine.sh # web-cmake-ok
|
||||
```
|
||||
23
docs/status/W-022.md
Normal file
23
docs/status/W-022.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# W-022 Status
|
||||
|
||||
status: done
|
||||
task: 建立最小 web_engine target
|
||||
|
||||
## Evidence
|
||||
|
||||
- C ABI header: `blender-5.2.0/source/blender/web_engine/web_engine_api.h`
|
||||
- C ABI implementation: `blender-5.2.0/source/blender/web_engine/web_engine_api.cpp`
|
||||
- CMake target: `web/engine/CMakeLists.txt`
|
||||
- Golden: `tests/golden/W-022/web-engine-api.json`
|
||||
|
||||
The standalone target remains an ABI-only smoke target and links a test reader
|
||||
stub. The canonical Blender data target is `blender-5.2.0` with
|
||||
`WITH_WEB=ON` (`build_web_blender6/bin/web_engine.*`); it links BLO/DNA and the
|
||||
vendored zlib/zstd readers behind the same handle boundary.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
tools/web/configure-web-engine.sh # standalone ABI gate
|
||||
node tools/web/run-web-engine-smoke.mjs # web-engine-blend-ok
|
||||
```
|
||||
20
docs/status/W-023.md
Normal file
20
docs/status/W-023.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# W-023 Status
|
||||
|
||||
status: done
|
||||
task: 处理 Emscripten 运行参数
|
||||
|
||||
## Evidence
|
||||
|
||||
- Platform flags: `blender-5.2.0/build_files/cmake/platform/web.cmake`
|
||||
- Variant runner: `tools/web/build-web-engine-variants.sh`
|
||||
- Golden: `tests/golden/W-023/runtime-profiles.json`
|
||||
|
||||
Single-thread and pthread builds use `MODULARIZE`, `EXPORT_ES6`,
|
||||
`ENVIRONMENT=web,worker`, memory growth and filesystem flags. The pthread
|
||||
artifact is explicitly marked as requiring COOP/COEP at runtime.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
tools/web/build-web-engine-variants.sh # passed
|
||||
```
|
||||
21
docs/status/W-024.md
Normal file
21
docs/status/W-024.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# W-024 Status
|
||||
|
||||
status: done
|
||||
task: 固定内存和分配策略
|
||||
|
||||
## Evidence
|
||||
|
||||
- Memory ABI: `web_engine_get_memory_stats()` and scalar accessors
|
||||
- Golden: `tests/golden/W-024/memory-stats.json`
|
||||
- Node smoke: `tools/web/run-web-engine-smoke.mjs`
|
||||
|
||||
The ABI reports live handles and allocated bytes without exposing WASM heap
|
||||
pointers to React. Document memory is held inside the engine state and output
|
||||
buffers are explicitly freed after save; the first mesh snapshot also retains
|
||||
bounded arrays before the later transferable-buffer path.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
node tools/web/run-web-engine-smoke.mjs # blend open/save, then destroy
|
||||
```
|
||||
22
docs/status/W-025.md
Normal file
22
docs/status/W-025.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# W-025 Status
|
||||
|
||||
status: done
|
||||
task: 建立 Web C ABI
|
||||
|
||||
## Evidence
|
||||
|
||||
- Header: `blender-5.2.0/source/blender/web_engine/web_engine_api.h`
|
||||
- Implementation: `blender-5.2.0/source/blender/web_engine/web_engine_api.cpp`
|
||||
- Golden: `tests/golden/W-025/c-api.json`
|
||||
|
||||
The ABI now has stable POD pointer/length entry points for create/destroy,
|
||||
open, apply, snapshot, save and buffer release. Open accepts an empty input;
|
||||
command and full `.blend` serialization return an explicit not-implemented
|
||||
code until Blender libraries are linked.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
tools/web/build-web-engine-variants.sh # passed
|
||||
node tools/web/run-web-engine-smoke.mjs # passed
|
||||
```
|
||||
20
docs/status/W-026.md
Normal file
20
docs/status/W-026.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# W-026 Status
|
||||
|
||||
status: done
|
||||
task: 接入 Blender 报告系统边界
|
||||
|
||||
## Evidence
|
||||
|
||||
- Error ABI: `web_engine_last_error_code()` and
|
||||
`web_engine_last_error_message()`
|
||||
- Golden: `tests/golden/W-026/error-report.json`
|
||||
- Error codes are deterministic and do not expose raw WASM pointers to the UI.
|
||||
|
||||
The native Blender `ReportList` bridge is deferred until W-030 data libraries
|
||||
are linked; this task freezes the Web-facing error contract first.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
node tools/web/run-web-engine-smoke.mjs # explicit -3 not-implemented path
|
||||
```
|
||||
27
docs/status/W-027.md
Normal file
27
docs/status/W-027.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# W-027 Status
|
||||
|
||||
status: done
|
||||
task: 建立真实 WebEngineWorker ready 路径
|
||||
|
||||
## Evidence
|
||||
|
||||
- Worker: `web/app/src/workers/web-engine.worker.ts`
|
||||
- Client: `web/app/src/engine-client/WebEngineClient.ts`
|
||||
- Vendored runtime: `web/app/src/vendor/blender/web_engine.js` and
|
||||
`web/app/src/vendor/blender/web_engine.wasm`
|
||||
- Static deployment copies: `web/app/public/vendor/blender/`
|
||||
- Install script: `tools/web/install-web-engine-assets.sh`
|
||||
- Golden: `tests/golden/W-027/worker-ready.json`
|
||||
|
||||
The worker dynamically imports the local Emscripten glue, fetches the local
|
||||
WASM asset, initializes the ABI and returns deterministic memory stats. The UI
|
||||
reports this as `WASM ABI: ready`; `.blend` loading now uses the same real ABI
|
||||
and returns SceneIR snapshots. The legacy mock EngineClient remains only for
|
||||
protocol regression tests.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run test:e2e # 4 passed, including local web_engine worker
|
||||
npm run build # web-engine.worker and vendor/blender assets present
|
||||
```
|
||||
22
docs/status/W-028.md
Normal file
22
docs/status/W-028.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# W-028 Status
|
||||
|
||||
status: done
|
||||
task: 原生/WASM 双端回归
|
||||
|
||||
## Evidence
|
||||
|
||||
- Native runner: `web/engine/web_engine_native_smoke.cpp`
|
||||
- Dual runner: `tools/web/check-dual-engine.sh`
|
||||
- Golden: `tests/golden/W-028/dual-engine.json`
|
||||
|
||||
The same C ABI returns matching create, invalid-empty-open, and destroy
|
||||
results in native C++ and Emscripten builds. The WASM runner additionally
|
||||
opens local `.blend` fixtures, checks SceneIR, verifies an authoritative
|
||||
Main save/reopen, verifies ordinary decimate Main write/save/reopen, and verifies that the
|
||||
skin/shape-key decimate boundary blocks save with `BLEND_WRITE_REQUIRES_MAIN_AUTHORITY`.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
tools/web/check-dual-engine.sh # dual-engine-ok
|
||||
```
|
||||
23
docs/status/W-029.md
Normal file
23
docs/status/W-029.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# W-029 Status
|
||||
|
||||
status: done
|
||||
task: 完成最小引擎里程碑
|
||||
|
||||
## Evidence
|
||||
|
||||
- Gate: `tests/golden/W-029/min-engine-gate.json`
|
||||
- Local browser worker: `web/app/src/workers/web-engine.worker.ts`
|
||||
- Native/WASM check: `tools/web/check-dual-engine.sh`
|
||||
|
||||
The Web runtime has a reproducible Blender/Emscripten CMake target, local
|
||||
worker loading and a stable C ABI gate. The canonical target links the local
|
||||
Blender BLO/DNA reader and is vendored into both source and public asset trees;
|
||||
the UI opens `.blend` ArrayBuffers and displays the resulting SceneIR.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run build # passed
|
||||
npm run test:e2e # 5 passed
|
||||
tools/web/check-dual-engine.sh # passed, including empty/basic/save fixture
|
||||
```
|
||||
30
docs/status/W-030.md
Normal file
30
docs/status/W-030.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# W-030 Status
|
||||
|
||||
status: done
|
||||
task: 从内存读取 `.blend`
|
||||
|
||||
## Evidence
|
||||
|
||||
- Reader: `blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp`
|
||||
- ABI: `web_engine_open_blend(handle, data, length)` copies an `ArrayBuffer` into
|
||||
WASM memory and never receives a browser or POSIX path.
|
||||
- Worker: `web/app/src/workers/web-engine.worker.ts` reports started/progress/completed
|
||||
phases and maps malformed input to `BLEND_READ_FAILED`.
|
||||
- Golden: `tests/golden/W-030/manifest.json`
|
||||
|
||||
The reader accepts uncompressed, gzip and zstd Blender streams, validates the
|
||||
little-endian Blender header, decodes the embedded DNA1 schema and returns an
|
||||
empty or populated SceneIR snapshot. `empty.blend` and `basic_scene.blend` are
|
||||
both exercised by the WASM smoke.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
node tools/web/run-web-engine-smoke.mjs # empty + basic + save passed
|
||||
tools/web/check-dual-engine.sh # native ABI + WASM reader passed
|
||||
```
|
||||
|
||||
## Remaining risk
|
||||
|
||||
The first reader is deliberately bounded to a 1 GiB block and summary export;
|
||||
evaluated mesh buffers are W-033.
|
||||
29
docs/status/W-031.md
Normal file
29
docs/status/W-031.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# W-031 Status
|
||||
|
||||
status: done
|
||||
task: 定义 SceneIR v1
|
||||
|
||||
## Evidence
|
||||
|
||||
- TypeScript contract: `web/protocol/scene-ir.ts`
|
||||
- C++ serializer: `blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp`
|
||||
- Golden: `tests/golden/W-031/scene-ir-v1.json`
|
||||
|
||||
SceneIR v1 now carries versioned source metadata, Blender Z-up coordinate
|
||||
semantics, stable type/name IDs, nodes, collections, meshes, materials, images,
|
||||
cameras, lights, animations, scenes, frame bounds and active object. Browser
|
||||
validation rejects unsupported schema, coordinate, matrix and tuple shapes.
|
||||
IDs are generated from Blender ID names with deterministic duplicate suffixes;
|
||||
the wire format contains no raw WASM pointer.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run typecheck
|
||||
node tools/web/run-web-engine-smoke.mjs
|
||||
```
|
||||
|
||||
## Remaining risk
|
||||
|
||||
Image and animation arrays are schema-ready but are still empty until their
|
||||
datablock extraction tasks are implemented.
|
||||
28
docs/status/W-032.md
Normal file
28
docs/status/W-032.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# W-032 Status
|
||||
|
||||
status: done
|
||||
task: 导出场景树和集合
|
||||
|
||||
## Evidence
|
||||
|
||||
- C++ collection/object traversal: `web_engine_blend_reader.cpp`
|
||||
- Dynamic Outliner: `web/app/src/app/App.tsx`
|
||||
- Golden: `tests/golden/W-032/basic-scene-tree.json`
|
||||
|
||||
The reader resolves Scene root collections, linked collection objects, object
|
||||
parent/data links, active camera, local/world matrices, viewport visibility and
|
||||
selectability. Collection and node arrays are sorted by stable IDs before
|
||||
serialization; parent cycles fall back to the local matrix instead of recursing
|
||||
without a bound.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
node tools/web/run-web-engine-smoke.mjs
|
||||
npm run test:e2e # local basic_scene.blend appears in Outliner
|
||||
```
|
||||
|
||||
## Remaining risk
|
||||
|
||||
The fixture proves one nested collection. View-layer overrides and evaluated
|
||||
depsgraph visibility remain part of the later scene-context work.
|
||||
37
docs/status/W-033.md
Normal file
37
docs/status/W-033.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# W-033 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 导出 MeshIR
|
||||
|
||||
## Implemented
|
||||
|
||||
Mesh summaries export vertex, edge, face and corner counts. Blender 5.2
|
||||
`AttributeStorage` DATA blocks are now resolved by exact old-pointer matches
|
||||
and by SDNA pointer width. The reader exports position floats, normals,
|
||||
triangulated corner indices, corner UV/color attributes, triangle material
|
||||
indices, material slot IDs and object-space bounds with
|
||||
`geometryStatus: "available"`. The Three adapter applies Z-up conversion,
|
||||
uses exported normals, expands corner attributes into render vertices, and
|
||||
binds local material groups.
|
||||
|
||||
## Accepted bounded scope
|
||||
|
||||
The exporter now includes tangent and corner split-normal buffers, seam/sharp
|
||||
edge flags, custom attribute metadata, vertex groups and UV-layer selection.
|
||||
The native WBG1 C ABI carries these buffers without JSON construction and the
|
||||
Worker validates/transfers them to Three.js. Mesh Edit operations rebuild
|
||||
topology metadata through Blender Main and reject linked/shape-key topology
|
||||
changes with structured errors.
|
||||
|
||||
Evaluated buffers for unsupported modifier/simulation families remain blocked
|
||||
by the N-002 capability matrix; this is an explicit boundary rather than a
|
||||
claim of universal modifier evaluation.
|
||||
|
||||
The field and future transferable layout is documented in
|
||||
`docs/web/mesh-buffer-layout.md`.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
node tools/web/run-web-engine-smoke.mjs # basic + attribute fixtures
|
||||
```
|
||||
29
docs/status/W-034.md
Normal file
29
docs/status/W-034.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# W-034 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 导出材质、贴图和颜色
|
||||
|
||||
## Implemented
|
||||
|
||||
The SceneIR contract includes Principled-compatible base color, roughness,
|
||||
metallic, emission, alpha and IOR fields. The native reader walks embedded
|
||||
Principled node inputs, collects Image Texture IDs, and emits warnings for
|
||||
linked inputs or unsupported nodes. Blender Image datablocks export stable
|
||||
asset IDs, MIME guesses, generated dimensions and the original (possibly
|
||||
`//`-relative) source path without embedding base64 pixels. The EngineWorker
|
||||
exposes a local `requestAsset` metadata path for external and
|
||||
packed-unavailable assets. The Three adapter applies the exported material
|
||||
color, metalness, roughness, emission and alpha to local materials.
|
||||
|
||||
## Accepted bounded scope
|
||||
|
||||
Material slots can be created, removed and assigned to selected faces through
|
||||
Blender Main. The Web authoring surface writes Principled values and creates a
|
||||
limited `Principled -> Output`, `Image Texture`, `Normal Map` and `UV Map` graph.
|
||||
PNG/JPEG imports become packed Blender Image datablocks without allocating a
|
||||
headless ImBuf, and active UV-map/planar/cube unwrap operations round-trip.
|
||||
Packed bytes remain available through the asset API and are covered by the
|
||||
UDIM/generated/linked/corrupt resource matrix.
|
||||
|
||||
Arbitrary node graphs and renderer-specific shader execution are deliberately
|
||||
outside this bounded contract; unsupported nodes are reported by SceneIR.
|
||||
24
docs/status/W-035.md
Normal file
24
docs/status/W-035.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# W-035 Status
|
||||
|
||||
status: in_progress
|
||||
task: 导出相机和灯光
|
||||
|
||||
## Implemented
|
||||
|
||||
Perspective/orthographic camera fields, sensor/shift values, clip range and
|
||||
orthographic scale are read from the file and are visible in the SceneIR
|
||||
snapshot. Light type/color/energy, radius, spot cone, area dimensions and sun
|
||||
angle are exported. World background color and exposure are also versioned.
|
||||
The Three adapter creates local point/spot/directional/area light objects and
|
||||
applies the exported World color to the viewport background.
|
||||
|
||||
## Not yet accepted
|
||||
|
||||
Sensor fit is exported numerically, but exact sensor-fit projection math,
|
||||
camera replacement for orthographic view, light target direction, and complete
|
||||
world node settings remain pending.
|
||||
|
||||
## Golden fixture
|
||||
|
||||
`tests/golden/W-035/camera-light-world.json` covers the real
|
||||
`basic_scene.blend` camera, area light and world linkage.
|
||||
28
docs/status/W-036.md
Normal file
28
docs/status/W-036.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# W-036 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 导出动画和帧状态
|
||||
|
||||
## Implemented
|
||||
|
||||
Scene frame current/start/end and object transforms are exported from the
|
||||
serialized Scene block. Legacy FCurve lists and Blender 5.2 layered Actions
|
||||
(keyframe strips/channelbags) are decoded into target-scoped `AnimationIR`
|
||||
channels with RNA paths, scalar keyframes and bounded frame ranges. The
|
||||
Timeline uses scene bounds instead of a fixed 250-frame range after a `.blend`
|
||||
is opened.
|
||||
|
||||
## Accepted bounded scope
|
||||
|
||||
Timeline keyframe insertion/deletion for object location, Euler rotation and
|
||||
scale writes Blender layered Actions through Main. The UI exposes frame range,
|
||||
key dots, active Action and CONSTANT/LINEAR/BEZIER interpolation selection.
|
||||
Object constraint enable/influence is editable and node constraints plus pose
|
||||
constraints are exported in SceneIR. Frame/pose goldens cover 1/5/10/15 and
|
||||
save/reopen compares evaluated matrices and vertices.
|
||||
|
||||
The N-014 bounded extension now reads and atomically replaces single-object
|
||||
Action Clip stacks, and Blender's native depsgraph evaluates the saved Main at
|
||||
the requested frame. Transition/meta/sound strips, Animated Time, reverse,
|
||||
Drivers, complete blending matrices and arbitrary constraint types remain
|
||||
structured future extensions; Three.js does not approximate them.
|
||||
26
docs/status/W-037.md
Normal file
26
docs/status/W-037.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# W-037 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 实现场景完整快照
|
||||
|
||||
## Implemented
|
||||
|
||||
`get_scene_snapshot` remains a validated JSON compatibility ABI, including
|
||||
bounded positions/index/normals and optional
|
||||
UV/color/material-slot arrays for available meshes. The Worker validates that
|
||||
fallback snapshot, packs the geometry into little-endian `Float32Array`/`Uint32Array`
|
||||
buffers, strips the large arrays from the browser snapshot, and transfers the
|
||||
buffers to React/Three.js. Browser parsing is centralized in
|
||||
`parseSceneSnapshotIR` and failures become stable worker error reports. The
|
||||
envelope and chunk rules are documented in `docs/web/mesh-buffer-layout.md`.
|
||||
|
||||
## Accepted bounded scope
|
||||
|
||||
The preferred native WBG1 metadata/geometry ABI now emits positions, indices,
|
||||
corner attributes, material/face/edge indices, tangents and split normals as
|
||||
tightly packed little-endian buffers. The Worker validates lengths/bounds and
|
||||
keeps large arrays out of React state. Per-mesh envelopes, Worker processing,
|
||||
Three.js frustum culling, linked-data `InstancedMesh` groups and LOD cover the
|
||||
current large-scene contract. `?offscreen=1` capability-gates real canvas/WebGL
|
||||
ownership in a render Worker with orbit, selection and nonblank-pixel E2E;
|
||||
unsupported browsers retain the main-thread renderer.
|
||||
29
docs/status/W-038.md
Normal file
29
docs/status/W-038.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# W-038 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 实现场景增量
|
||||
|
||||
## Implemented
|
||||
|
||||
`web/protocol/scene-delta.ts` defines revisioned node add/update/remove, active
|
||||
object/frame changes and mesh/material/camera/light/animation resources.
|
||||
`diffSceneSnapshots` emits changed node and resource fields;
|
||||
`applySceneDelta` rejects stale base revisions and returns sorted immutable node
|
||||
arrays. The native C ABI computes the same minimal delta whenever a new
|
||||
`.blend` is opened, and the Worker exposes it through the `delta` request after
|
||||
validating the envelope. The command registry covers scene/frame state,
|
||||
modifier switches, mesh editing, material/UV authoring, keyframes/constraints
|
||||
and object hierarchy operations. Each command mutates Blender Main and returns
|
||||
the corresponding revisioned delta through `applyCommand`.
|
||||
|
||||
## Accepted bounded scope
|
||||
|
||||
SceneDelta now covers resource collections for meshes, materials, cameras,
|
||||
lights and animations in addition to nodes/frame/active object. Mesh payloads
|
||||
transfer separately so topology and attribute changes replace the associated
|
||||
resource envelope, while node-only changes stay in place. All declared
|
||||
authoring commands are Main-authoritative and covered by save/reopen. Fine-
|
||||
grained `MeshGeometryDelta` patches now transfer only changed byte ranges when
|
||||
field lengths stay stable; topology/attribute layout changes replace only the
|
||||
affected per-mesh envelope. The main-thread client applies patches immutably
|
||||
and retains unchanged mesh buffers.
|
||||
25
docs/status/W-039.md
Normal file
25
docs/status/W-039.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# W-039 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 完成场景数据里程碑
|
||||
|
||||
## Current gate
|
||||
|
||||
The `.blend` -> Blender Main/WASM -> binary SceneIR -> Three.js path is proven
|
||||
for basic, animation, pose, modifier, resource and authoring fixtures. The
|
||||
browser opens files, renders geometry, keeps Outliner/viewport selection linked,
|
||||
and applies Main edits with revisioned snapshot/delta responses.
|
||||
|
||||
## Accepted bounded scope
|
||||
|
||||
W-034 through W-038 are complete for the declared bounded contract: binary
|
||||
SceneIR, resource deltas, packed assets, animation editing and Blender Main
|
||||
authoring all have native and browser regression evidence. New Blender
|
||||
families must add independent goldens instead of reusing W-080.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm --prefix web run test:e2e
|
||||
npm --prefix web run test:authoring-roundtrip
|
||||
```
|
||||
14
docs/status/W-040.md
Normal file
14
docs/status/W-040.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# W-040 Status
|
||||
|
||||
status: in_progress
|
||||
task: 固定 OPFS 目录布局
|
||||
|
||||
`web/app/src/storage/opfs-files.ts` validates project IDs and file names,
|
||||
creates `projects/<id>/scene.blend`, `snapshots/`, `assets/`, `thumbs/` and
|
||||
`tmp/`, and writes a complete scene buffer through a temporary file before
|
||||
replacement. The standard `FileSystemHandle.move` path is used when available;
|
||||
the copy-and-remove fallback is bounded to the same project directory.
|
||||
|
||||
Large asset hashing, crash-recovery manifests and cross-browser atomic rename
|
||||
guarantees remain subsequent tasks.
|
||||
|
||||
12
docs/status/W-041.md
Normal file
12
docs/status/W-041.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# W-041 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 建立 IndexedDB schema 和 migration
|
||||
|
||||
`web/app/src/storage/migrations.ts` upgrades `blender-web-metadata` to schema
|
||||
version 4 while preserving the existing smoke store. It creates `project`,
|
||||
`asset`, `snapshot`, `operation_log`, `setting` and `migration` stores and
|
||||
records each schema migration. Schema 4 adds content-addressed asset metadata;
|
||||
StorageWorker `info`, project layout and Worker-restart discovery are covered by Playwright.
|
||||
|
||||
Downgrade/rollback across older deployed browser builds remains outside the current scope.
|
||||
16
docs/status/W-042.md
Normal file
16
docs/status/W-042.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# W-042 Status
|
||||
|
||||
status: done
|
||||
task: 保存 `.blend` 原子事务
|
||||
|
||||
StorageWorker `saveProject` accepts a transferable ArrayBuffer, creates the
|
||||
OPFS project layout, writes and SHA-256-verifies `scene.blend.<uuid>.stage`, records a
|
||||
recovery journal, and uses same-directory move (or a complete-copy fallback) before re-verifying
|
||||
`scene.blend`. Only then does it write the manifest, clear the journal and update the IndexedDB
|
||||
`project` record with revision, byte count, digest, backend and timestamp.
|
||||
The React Save command now submits this transaction before downloading the
|
||||
`.blend` Blob, and keeps the StorageClient alive for the project session.
|
||||
When OPFS is unavailable, the record stores the buffer in IndexedDB instead.
|
||||
Playwright injects failures after staging and after scene commit, restarts the Worker, and verifies
|
||||
exact bytes/revision/digest through `readProject`. Concurrent same-project saves are serialized and
|
||||
the last submitted revision wins without journal races.
|
||||
13
docs/status/W-043.md
Normal file
13
docs/status/W-043.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# W-043 Status
|
||||
|
||||
status: done
|
||||
task: 自动保存和快照策略
|
||||
|
||||
`AutosaveScheduler` debounces a dirty project and submits the current engine
|
||||
buffer through StorageWorker after 1.5 seconds without triggering a download.
|
||||
The React Save button reuses the same persistence path before exporting a
|
||||
download. A browser regression confirms the dirty marker returns to saved.
|
||||
|
||||
Every ten commands and every explicit save now retain a SHA-256 verified blend snapshot. The
|
||||
StorageWorker enforces count and total-byte limits and can list/read retained revisions. Large-file
|
||||
writes remain Worker-isolated and never block the renderer thread.
|
||||
16
docs/status/W-044.md
Normal file
16
docs/status/W-044.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# W-044 Status
|
||||
|
||||
status: done
|
||||
task: 记录操作日志和恢复
|
||||
|
||||
StorageWorker now validates and persists operation records with project id,
|
||||
revision, payload, inverse payload and timestamp in IndexedDB's
|
||||
`operation_log` store. StorageClient exposes `appendOperation`, and the
|
||||
operation/inverse path has a browser regression.
|
||||
|
||||
Project file recovery is now separate and complete for the current save path:
|
||||
an OPFS SHA-256 journal recovers interrupted staging/commit after Worker restart.
|
||||
|
||||
Schema 5 adds corruption quarantine. Recovery sorts validated operations by revision/time/ID,
|
||||
rejects revision conflicts, opens the committed project or latest retained snapshot, and applies
|
||||
only uncommitted replayable commands to the native Main. A successful save prunes committed rows.
|
||||
22
docs/status/W-050.md
Normal file
22
docs/status/W-050.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# W-050 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: SceneIR adapter
|
||||
|
||||
ViewportRenderer now tags imported meshes and lights with
|
||||
`userData.blenderId`, `userData.sceneNodeId` and `userData.revision`, keeps a
|
||||
Blender-ID object index, and exposes `applyDelta()`. Pure node visibility and
|
||||
transform updates mutate the existing Three object; node lifecycle changes
|
||||
fall back to a validated snapshot rebuild so geometry/material ownership stays
|
||||
correct.
|
||||
|
||||
The adapter now performs mesh raycast selection and applies multi-selection
|
||||
highlights, consumes binary WBG1 mesh resources, and installs validated LOD
|
||||
levels with hysteresis. Resource-aware SceneDelta entries trigger a validated
|
||||
resource rebuild while node-only deltas update existing Three objects.
|
||||
|
||||
The Worker keeps the previous geometry generation and emits byte-range patches
|
||||
or affected-mesh replacements. Objects sharing one Blender Mesh datablock are
|
||||
coalesced into a raycastable `InstancedMesh` with per-instance transform and
|
||||
selection. A capability-gated OffscreenCanvas Worker owns WebGL when requested;
|
||||
browsers without that capability retain the same main-thread renderer.
|
||||
11
docs/status/W-052.md
Normal file
11
docs/status/W-052.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# W-052 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 相机和输入系统
|
||||
|
||||
OrbitControls, resize handling and mouse orbit are active in the local Three
|
||||
viewport. Timeline transport controls now implement first/previous/play/next/
|
||||
last frame state transitions over the imported SceneIR range. Exact Blender
|
||||
camera basis conversion is preserved at the adapter boundary. Object/Edit mode keyboard dispatch
|
||||
and draggable X/Y/Z transform handles route to Main commands; additional view presets and touch
|
||||
gesture variants remain additive UI work.
|
||||
12
docs/status/W-053.md
Normal file
12
docs/status/W-053.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# W-053 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 选择和 Outliner 联动
|
||||
|
||||
Outliner rows are keyboard- and pointer-activatable and update
|
||||
`SceneSnapshotIR.activeObjectId`; the Three adapter consumes the new snapshot
|
||||
and highlights the active object's material. Stable Blender IDs are used for
|
||||
the binding.
|
||||
|
||||
Viewport raycast selection, Shift/Ctrl multi-select, hidden-object filtering and deletion cleanup
|
||||
are implemented. Selected IDs remain a UI-session concern while the active ID stays in SceneIR.
|
||||
34
docs/status/W-060.md
Normal file
34
docs/status/W-060.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# W-060 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 对象模式命令
|
||||
|
||||
The first native command registry slice is implemented end to end. The Worker
|
||||
serializes validated `WebEngineEditCommand` payloads into the local Blender
|
||||
WASM ABI, and the native engine currently supports:
|
||||
|
||||
- `setFrame`: updates the current timeline frame and emits a frame SceneDelta.
|
||||
- `setObjectVisibility`: updates an existing object node and emits a node update
|
||||
SceneDelta.
|
||||
- `setModifierEnabled`: updates the persistent modifier mode in Blender Main.
|
||||
- `decimateMesh`: commits ordinary mesh topology/UV/color/material output to Blender Main;
|
||||
skin/shape-key replacement remains structurally blocked from save.
|
||||
- `undo`/`redo`: restore both SceneIR and a reopenable Blender Main history entry.
|
||||
- `createPrimitive`, `duplicateObject`, `deleteObject`: mutate Main IDs and Collections, then rebuild SceneIR from the writer buffer; linked duplicate preserves the shared Mesh datablock for instancing.
|
||||
- `setObjectTransform`, `translateMeshVertices`: persist Object Mode TRS and the first Edit Mode vertex workflow.
|
||||
- `meshEdit`: Main-authoritative Merge, Dissolve, Extrude, Inset, Bevel and Loop Cut transactions.
|
||||
- UV/material/image commands: UV map lifecycle/projection, material slots/face assignment, bounded Principled graph and packed PNG/JPEG images.
|
||||
- animation/hierarchy commands: keyframes/interpolation/actions, constraints, parent/collection moves, rename, Join/Separate, Apply Transform and Origin.
|
||||
|
||||
The commands have native smoke coverage and browser E2E tests that check
|
||||
revision base/next values and the resulting snapshot. Unknown commands and
|
||||
malformed payloads return typed native errors.
|
||||
|
||||
The Blender-style UI now routes Timeline frame changes and Outliner eye-button
|
||||
visibility changes through the same command path. React SceneIR, transferable
|
||||
geometry state, Three visibility and the dirty marker are updated from the
|
||||
command response; the browser E2E suite covers the Outliner interaction.
|
||||
|
||||
Every declared command writes back to `.blend`, survives undo/redo and passes save/reopen
|
||||
regression. Unsupported modifier families, mutations of read-only linked-library IDs and topology
|
||||
changes that would invalidate shape keys remain structured native blocks.
|
||||
35
docs/status/W-073.md
Normal file
35
docs/status/W-073.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# W-073 Status
|
||||
|
||||
status: in_progress
|
||||
task: 定义 Blender 三角面简化和 LOD 协议
|
||||
|
||||
`web/protocol/simplify.ts` now defines versioned `SimplifyProfile`,
|
||||
`SimplifyResult` and `LODManifest` contracts. The profile validator keeps the
|
||||
Blender modifier modes separate:
|
||||
|
||||
- `COLLAPSE` requires `ratio` in `(0, 1]` and supports triangle budget,
|
||||
vertex-group weighting/inversion, triangulate, symmetry axis and tolerance.
|
||||
- `UNSUBDIV` requires a positive integer `iterations` and rejects collapse or
|
||||
dissolve-only parameters.
|
||||
- `DISSOLVE_PLANAR` requires `angleLimit` in `[0, PI]`, with explicit
|
||||
boundary delimit flags and dissolve-boundary handling.
|
||||
|
||||
The parser also enforces non-negative source revisions and error codes for
|
||||
missing vertex groups, unsupported cross-mode fields, invalid budgets and LOD
|
||||
manifests whose triangle budgets do not decrease. A browser E2E test covers a
|
||||
valid collapse profile, a two-level manifest and the missing-vertex-group
|
||||
failure.
|
||||
|
||||
The common profile now carries an explicit `attributePolicy`
|
||||
(`PRESERVE`/`RECOMPUTE_NORMALS`/`DROP`) and a validated `SkinSimplifyPolicy`
|
||||
with maximum influences, minimum weight, maximum position error and shape-key
|
||||
handling. Vertex-group and symmetry-only fields are conditionally optional, so
|
||||
the TypeScript contract and runtime validator no longer disagree when those
|
||||
features are disabled.
|
||||
|
||||
The protocol is now exercised end-to-end by the native/WASM command path:
|
||||
`decimateMesh` validates `sourceMeshRevision`, returns a new SceneIR revision,
|
||||
and the browser-facing smoke checks topology counts, index bounds and attribute
|
||||
buffer lengths. Native Blender/WASM golden parity for all parameter
|
||||
combinations remains part of W-079; implementation of the declared skin policy
|
||||
remains W-076.
|
||||
37
docs/status/W-074.md
Normal file
37
docs/status/W-074.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# W-074 Status
|
||||
|
||||
status: in_progress
|
||||
task: 编译并复用 Blender Decimate 实现
|
||||
|
||||
`web_engine_decimate.cpp` now wraps Blender's native BMesh decimate entry points
|
||||
(`BM_mesh_decimate_collapse`, `BM_mesh_decimate_unsubdivide` and
|
||||
`BM_mesh_decimate_dissolve`) behind the local `web_engine_decimate_apply`
|
||||
two-pass C ABI. The wrapper accepts triangle buffers, returns required output
|
||||
capacities on the first call, and leaves the input mesh untouched.
|
||||
|
||||
`web_engine_apply_command` now accepts `decimateMesh` with a versioned
|
||||
`SimplifyProfile`, validates the source revision, calls the native wrapper, and
|
||||
replaces the evaluated SceneIR mesh topology. The command allocates output from
|
||||
the input upper bounds and evaluates Decimate once; it does not run the
|
||||
modifier twice merely to query exact capacities. Normals are recomputed from
|
||||
the result, BMFace material indices are retained, and UV/float-color corners
|
||||
are transferred by the W-076 policy layer. Collapse now accepts boundary and
|
||||
non-manifold triangle meshes through the same BMesh bridge. The blend reader
|
||||
reconstructs corner vertices from `.corner_edge` and `.edge_verts` only after
|
||||
validating every face cycle, so it never treats edge indices as vertex indices.
|
||||
`npm run test:topology-collapse` independently opens and collapses an open quad,
|
||||
an open n-gon and a three-face shared-edge mesh; malformed cycles remain
|
||||
`summary-only`.
|
||||
|
||||
The WebEngine CMake target exports the ABI symbol and links a small archive-file
|
||||
group containing Blender BMesh, CustomData-capable BKernel objects, DNA/BLO,
|
||||
local zlib/zstd and allocator support; this avoids pulling the desktop
|
||||
editor/image dependency graph into the WASM module.
|
||||
|
||||
The local artifact is installed in both `web/app/public/vendor/blender/` and
|
||||
`web/app/src/vendor/blender/`, with the manifest SHA-256 updated. The native
|
||||
smoke covers all three modes, Collapse topology reduction, revision sequencing,
|
||||
SceneDelta and normal/UV/material attribute lengths. The browser regression
|
||||
suite covers the same local WASM command path, including native command,
|
||||
preview and isolated LOD workers. Modifier-stack transactions and full
|
||||
skin/seam/sharp preservation remain W-075/W-076.
|
||||
86
docs/status/W-075.md
Normal file
86
docs/status/W-075.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# W-075 Status
|
||||
|
||||
status: in_progress
|
||||
task: 实现三种模式和修改器堆栈求值
|
||||
|
||||
The React Properties editor now exposes a Blender-style Decimate inspector for
|
||||
all three native modes. Collapse has ratio, triangulate and optional symmetry
|
||||
axis controls; Un-Subdivide has bounded iterations; Dissolve Planar has angle,
|
||||
boundary handling and Normal/Material/Seam/Sharp/UV delimit toggles. A shared
|
||||
attribute-policy selector makes preservation or dropping explicit. Browser E2E
|
||||
switches through the mode-specific controls, while native probes confirm all
|
||||
three BMesh entry points execute against the local WASM artifact.
|
||||
|
||||
Applying the inspector commits a revisioned `decimateMesh` command. A
|
||||
`previewDecimateMesh` command now evaluates the profile in a separate WASM
|
||||
module instance, returns temporary geometry to the Three.js viewport, keeps
|
||||
the authoritative handle/revision unchanged and supports explicit cancellation
|
||||
from the inspector.
|
||||
|
||||
The SceneIR contract now carries modifier UUID/type/name/enabled state and a
|
||||
deterministic modifier-stack hash. The native `.blend` reader traverses each
|
||||
`Object.modifiers` list, uses Blender's persistent modifier UID for a stable
|
||||
UUID when available, and exports viewport/render modes plus common Subsurf,
|
||||
Mirror, Decimate and Bevel parameters. The generated
|
||||
`rigged_shape_scene.blend` fixture verifies the real Decimate modifier payload
|
||||
instead of a mock stack. The native command
|
||||
`setModifierEnabled` toggles a declared modifier, and the native history ring
|
||||
implements bounded undo/redo with revisioned snapshots. React exposes the
|
||||
modifier checkbox and top-bar undo/redo commands; browser E2E verifies that
|
||||
undo/redo changes the authoritative native snapshot rather than a Three.js
|
||||
shadow copy. Native smoke now covers the same modifier toggle and its
|
||||
undo/redo cycle against a local WASM engine.
|
||||
|
||||
`protocol/modifier-graph.ts` now builds a stable per-mesh topological order from
|
||||
stack order and explicit `dependsOn` edges. Cycles and unresolved external
|
||||
inputs produce `BLOCKED` with the offending IDs; declared but unexecuted
|
||||
modifiers remain `METADATA_ONLY`. The WebEngine Worker requires `EVALUATED`
|
||||
before Decimate preview, commit or LOD generation. Browser E2E checks the
|
||||
topological order, metadata-only handling and cycle blocking.
|
||||
|
||||
The WebEngine exposes `evaluateDepsgraph` and the native module executes
|
||||
Blender 5.2's `BLO_read_from_memory` loader, headless runtime bootstrap,
|
||||
view-layer sync, graph build, tagged update and frame evaluation. A wasm32 DNA
|
||||
alignment bridge and the Web ID registry for NodeTree/Camera/Light preserve the
|
||||
current C++ layout. The report contains evaluated mesh positions/triangles,
|
||||
source Mesh IDs, object world matrices and modifier counts. The report also
|
||||
contains ordered modifier entries with persistent UID, mode flags, stack
|
||||
dependencies and explicit `EVALUATED`, `DISABLED` or `BLOCKED` status with
|
||||
stable error codes and suggestions. Empty,
|
||||
basic and rigged/shape-key fixtures now pass without a WASM trap; the rigged
|
||||
positions match the Blender deformation golden. Broader modifier and constraint
|
||||
parity is tracked separately and unsupported cases remain structured errors.
|
||||
The lightweight reader's name table now covers all Blender 5.2 DNA modifier
|
||||
slots 0 through 86, including the Grease Pencil range, with a compile-time size
|
||||
check. Recognition remains separate from evaluated parity in
|
||||
`docs/web/modifier-support-matrix.md`.
|
||||
SceneIR now extracts target IDs and core parameters for Lattice, Curve,
|
||||
Armature, Hook, Mesh Deform, Shrinkwrap and Surface Deform, and appends their
|
||||
external objects to `dependsOn`; they deliberately remain `METADATA_ONLY`.
|
||||
|
||||
Six reproducible Blender 5.2 category goldens now cover Generate, Deform,
|
||||
legacy Curve, Physics/time, Geometry Nodes and Grease Pencil. The native report
|
||||
now includes non-Mesh objects, including all 26 Grease Pencil modifier types
|
||||
exposed by Blender 5.2 Python. Twenty-four category types now have evaluated Web
|
||||
goldens. Subdivision uses the local OpenSubdiv 3.7.0 CPU evaluator and matches
|
||||
the 26-vertex/48-triangle desktop result. Exact Boolean uses local GMP 6.3.0
|
||||
and matches the 12-vertex/20-triangle surface result; coplanar triangulation is
|
||||
compared by oriented surface area because wasm32 and desktop can select
|
||||
different valid diagonals. Curve now runs its native modifier and matches the
|
||||
desktop golden after the Web ID registry was extended for Curves data.
|
||||
|
||||
Geometry Nodes has bounded native implementations for a single constant
|
||||
Transform Geometry or Set Position node. Both topology/position results match
|
||||
Blender 5.2. Unknown graphs retain `BLENDER_MODIFIER_ERROR`; simulation zones
|
||||
and bake data preserve input geometry and return
|
||||
`GEOMETRY_NODES_SIMULATION_UNAVAILABLE`. The full node registration/lazy-function
|
||||
runtime is not claimed. Displace adds a bounded constant local-space closure;
|
||||
resource-dependent configurations return `MODIFIER_CONFIGURATION_UNSUPPORTED`.
|
||||
Grease Pencil modifiers remain disabled.
|
||||
Mesh and Surface Deform fixtures continue to serialize real bind caches and
|
||||
deform their cage/target after binding.
|
||||
|
||||
This is not yet complete native Blender dependency-graph parity. Unsupported
|
||||
external runtime resources and unsupported modifier/constraint types return
|
||||
structured errors; the lightweight SceneIR history remains separate and is not
|
||||
silently serialized as a full Blender undo stack.
|
||||
46
docs/status/W-076.md
Normal file
46
docs/status/W-076.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# W-076 Status
|
||||
|
||||
status: in_progress
|
||||
task: 属性、UV 和蒙皮安全简化
|
||||
|
||||
`SimplifyProfile` now requires an explicit attribute policy after parsing and
|
||||
defines `SkinSimplifyPolicy` limits for influences, weights, position error and
|
||||
shape keys. The native command currently implements this partial protection
|
||||
matrix:
|
||||
|
||||
- normals are recomputed from the evaluated triangle topology;
|
||||
- BMFace material indices and material slot IDs are retained;
|
||||
- existing UV and float-color corner values are transferred to output corners
|
||||
using a deterministic closest-source-triangle barycentric projection;
|
||||
- `DROP` is the only policy that removes these arrays intentionally;
|
||||
- Collapse validates and accepts open/non-manifold Mesh-to-BMesh topology;
|
||||
- the native reader exports Mesh `MDeformVert` CustomData as fixed four-slot
|
||||
`SkinWeightsIR` arrays, carries Mesh vertex-group names, and exports
|
||||
non-Basis `KeyBlock` positions as `ShapeKeyIR`; the local
|
||||
`rigged_shape_scene.blend` fixture validates both on a real `.blend` file;
|
||||
- a skinned or shape-key mesh requires explicit `skinPolicy`; omitting it is a
|
||||
structured `NOT_IMPLEMENTED` failure rather than silent attribute loss.
|
||||
|
||||
Native smoke and browser Worker E2E verify normal, UV, corner and material
|
||||
buffer sizes on the closed cube fixture. The WebEngine protocol validates
|
||||
`SkinWeightsIR` and `ShapeKeyIR`. After BMesh produces the authoritative
|
||||
topology, native code projects each output vertex onto the closest source
|
||||
triangle, merges and normalizes its joint influences, and reconstructs every
|
||||
shape-key position with the same barycentric weights. `maxInfluences`,
|
||||
`minWeight` and `maxPositionError` are enforced before committing the new
|
||||
SceneIR. Native smoke and Worker E2E verify output vertex counts, normalized
|
||||
weights, stable joint IDs, bind matrices and shape-key array lengths.
|
||||
`shapeKeys: REJECT` still returns `SHAPE_KEYS_REJECTED` before native work.
|
||||
|
||||
The reader now exports `ArmatureIR` bones with parent IDs, Blender `Bone.arm_mat`
|
||||
rest matrices and matching `PoseChannel.pose_mat` matrices. A mesh Armature
|
||||
modifier resolves its armature object, remaps vertex-group bone names to stable
|
||||
joint IDs, and records the mesh object TRS as its non-identity bind matrix. The
|
||||
generated rig fixture verifies all fields against local Blender data. This is
|
||||
sufficient for GLB inverse-bind generation and the current triangle-bridge
|
||||
remapping path.
|
||||
|
||||
UV seam and sharp-edge error metrics, tangent regeneration, native
|
||||
vertex-group name selection in profiles, Armature deformation comparison,
|
||||
seam/sharp constraints and Blender-evaluated shape-key error comparison remain
|
||||
required before this task can be marked done.
|
||||
46
docs/status/W-077.md
Normal file
46
docs/status/W-077.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# W-077 Status
|
||||
|
||||
status: in_progress
|
||||
task: 多级 LOD 生成、缓存和视口选择
|
||||
|
||||
The cache boundary is now implemented without changing the native WASM ABI:
|
||||
|
||||
- `buildLODCacheKey` creates a deterministic, path-safe key from object ID,
|
||||
source mesh revision, modifier-stack hash, profile hash and REST/POSE state.
|
||||
- IndexedDB schema v3 adds `lod_manifest`; the StorageWorker can put/get a
|
||||
validated manifest and writes transferable `.mesh` bytes to OPFS
|
||||
`projects/<id>/cache/lod/<cacheKey>.mesh`. Read, delete and byte-budget
|
||||
pruning update `lastAccessAt` and remove the least-recently-used entries.
|
||||
- `ThreeLODAdapter` selects pre-generated levels from projected pixel height,
|
||||
with a configurable hysteresis band, and is updated by the viewport render
|
||||
loop without rebuilding the imported scene.
|
||||
- `generateLOD` evaluates every requested profile independently from the source
|
||||
`.blend` in a fresh WASM module instance, returns a validated manifest and
|
||||
transferable geometry, and is exposed by the React inspector. A binary
|
||||
length-table container round-trips the level buffers before OPFS persistence;
|
||||
the React path reads that persisted container back before installing levels
|
||||
into the Three.js viewport, while preserving source transforms and materials.
|
||||
- Browser E2E covers the OPFS bytes, manifest round trip, stable key and
|
||||
hysteresis behavior, multi-level generation and binary geometry round trips.
|
||||
|
||||
The React open path now lists all `lod_manifest` rows for the project after a
|
||||
fresh application load, filters them by the authoritative SceneIR revision and
|
||||
object IDs, reads the OPFS `.mesh` container, validates the level mesh IDs and
|
||||
installs the cached levels into the Three.js LOD adapter. Applying any native
|
||||
scene command also removes manifests from older source revisions, so a stale
|
||||
cache cannot be selected after a mesh or modifier edit. Browser E2E covers
|
||||
generation, reload, discovery and reuse.
|
||||
|
||||
Pose-aware skin joints are still not exported into the LOD manifest. The native
|
||||
Collapse bridge now performs one Blender BMesh collapse pass at a time, creating
|
||||
a fresh heap for each pass and recalculating the quadric choice from the current
|
||||
mesh state. This removes the previous WASM memory failure at intermediate cube
|
||||
targets; the LOD Worker keeps per-level isolation as a general fault boundary.
|
||||
An active modifier stack must now have an `EVALUATED` dependency-graph report
|
||||
before LOD generation. Metadata-only and unresolved stacks return a structured
|
||||
capability error rather than caching output from an implicit base mesh.
|
||||
Each isolated LOD profile applies the same skin/shape-key preflight as direct
|
||||
Decimate, so a valid `skinPolicy` receives native remapping while a missing or
|
||||
rejecting policy cannot create a partial cache entry.
|
||||
Full Blender parity still requires pose-aware skin joints and broader Blender
|
||||
golden coverage, so the task stays `in_progress`.
|
||||
43
docs/status/W-078.md
Normal file
43
docs/status/W-078.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# W-078 Status
|
||||
|
||||
status: in_progress
|
||||
task: 轻量化预算和导出策略
|
||||
|
||||
`protocol/budget.ts` now validates explicit integer budgets for triangles,
|
||||
vertices, index bytes, material slots, texture bytes and estimated GPU bytes.
|
||||
`evaluateLightweightBudget` returns every violation with limit, actual value and
|
||||
excess while leaving the measured usage unchanged. Browser E2E covers a mixed
|
||||
triangle/GPU over-budget report.
|
||||
|
||||
`aggregateLightweightUsage` and `evaluateLightweightBudgets` now produce
|
||||
deterministic project, collection, object and LOD scopes. Project usage sums
|
||||
each source object once; collection membership is reported per collection and
|
||||
LOD usage is kept separate so generated levels are not double-counted. Browser
|
||||
E2E covers all four scope reports.
|
||||
|
||||
`analyzeGLBExport` now runs before the UI export action and returns structured
|
||||
warnings/errors for summary-only or missing geometry, unevaluated modifiers,
|
||||
external/packed images, linked material inputs and unavailable skin remapping.
|
||||
When no blocking condition is present, the local exporter writes a standards-
|
||||
shaped GLB 2.0 binary containing hierarchy, mesh positions/normals/UVs/colors,
|
||||
material groups, PBR material factors and shape-key morph targets. Blender
|
||||
shape-key positions are converted to glTF deltas in the Z-up to Three.js/glTF
|
||||
basis conversion. The top-bar action downloads this local binary; browser E2E
|
||||
checks the GLB header and a non-zero morph delta.
|
||||
|
||||
`exportGLB` now accepts caller-provided local asset buffers, embeds each image
|
||||
as a GLB buffer view, and connects it to exported PBR materials. It exports
|
||||
`JOINTS_0`/`WEIGHTS_0`, bone nodes, inverse bind matrices and supported object
|
||||
or bone animation channels for a resolved armature binding. The local test
|
||||
worker parses the emitted GLB JSON again; browser E2E embeds a real local PNG
|
||||
and verifies its byte length/signature, skin joints, MAT4 inverse-bind accessor,
|
||||
animation channels and skin attributes without a network fetch.
|
||||
|
||||
The native reader now extracts the exact bytes of both legacy and list-based
|
||||
Blender packed images through the local asset request ABI; the packed fixture
|
||||
checks PNG signature, MIME and byte length without a network request. The GLB
|
||||
worker strictly parses the emitted JSON/BIN chunks and compares mesh
|
||||
attributes, embedded image byte counts/MIME, skin joints/inverse-bind MAT4s,
|
||||
morph targets and grouped animation paths against the source SceneIR. The
|
||||
browser round-trip test has no semantic mismatches. Blender-side unsupported
|
||||
features remain explicit export warnings.
|
||||
57
docs/status/W-079.md
Normal file
57
docs/status/W-079.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# W-079 Status
|
||||
|
||||
status: in_progress
|
||||
task: 三角面简化和轻量化里程碑
|
||||
|
||||
The Blender golden fixture is checked by
|
||||
`tools/web/run-blender-golden.mjs`. It opens the local
|
||||
`tests/files/web/basic_scene.blend`, evaluates native Collapse in fresh WASM
|
||||
instances at ratios `1.0`, `0.9`, `0.5` and `0.25`, and compares source object
|
||||
identity, vertex counts and evaluated loop-triangle counts with
|
||||
`tests/golden/W-079/basic-scene-decimate.json`. The test is runnable offline as
|
||||
`npm run test:golden` and currently passes. The focused native memory regression
|
||||
gate `npm run test:collapse-ratios` starts an isolated WASM instance for each
|
||||
target and asserts a successful non-empty result. The matrix now also includes the
|
||||
previously unstable intermediate ratios `0.80`, `0.75`, `0.70` and `0.65`.
|
||||
|
||||
LOD generation evaluates each requested profile in an isolated Worker/WASM
|
||||
instance. A failure at one target records `requestedLevel`, `triangleBudget`
|
||||
and the diagnostic message in `WebEngineLODResult.errors`; the remaining levels
|
||||
are reindexed and cached. The native bridge now avoids the former multi-collapse
|
||||
heap lifetime failure by running one native Collapse pass per fresh heap, so the
|
||||
intermediate golden ratios no longer fault.
|
||||
|
||||
The reader retains 64-bit on-disk BHead pointer identities in WASM and resolves
|
||||
duplicate `BLEND_DATA` attribute arrays in the owning Mesh block range. This
|
||||
prevents a second mesh from inheriting the first mesh's attributes. The offline
|
||||
`npm run test:topology-collapse` regression confirms successful native Collapse
|
||||
for an open quad, an open n-gon and a non-manifold shared edge.
|
||||
|
||||
The rigged fixture also now runs Collapse with a preserving `skinPolicy`.
|
||||
Native output projects to the source triangles, remaps fixed four-slot weights
|
||||
and rebuilds shape-key positions, while a missing policy remains blocked. The
|
||||
same path is covered through the browser WebEngine Worker.
|
||||
|
||||
The deformation fixture now records an actual Blender 5.2 evaluated-depsgraph
|
||||
golden with shape-key value and armature pose applied. The Web deformation
|
||||
worker compares linear bind/rest/pose evaluation against the declared max and
|
||||
RMS error budget. Packed-image extraction, GLB semantic re-import and the Web
|
||||
deformation golden are covered by focused browser tests.
|
||||
|
||||
The native Blender Depsgraph path now completes full loader, view-layer sync,
|
||||
graph build, tagged update and frame evaluation in the headless WASM build for
|
||||
the empty, basic and rigged/shape-key fixtures. A wasm32-specific DNA layout
|
||||
adapter recursively restores 8-byte alignment for 64-bit members; this fixes
|
||||
the `Scene.master_collection` offset and prevents the former memory trap. The
|
||||
Web ID registry includes embedded NodeTree, Camera and Light data, and the
|
||||
rigged output matches the Blender 5.2 deformation golden within its max/RMS
|
||||
budgets. The report now exposes ordered native modifier entries, persistent UIDs,
|
||||
mode flags, target object IDs, stack dependencies and explicit Blender evaluation errors; the
|
||||
rigged fixture verifies Armature followed by a structured Decimate block on its
|
||||
two-triangle input. N-001 is complete for the declared fixtures and N-002 has
|
||||
started with this report contract; broader modifier, constraint and stress
|
||||
coverage remains tracked by N-002/N-003/N-008.
|
||||
|
||||
The broad Decimate mode/performance matrix and Blender round-trip warnings are
|
||||
still tracked as follow-up coverage; unsupported cases must remain structured
|
||||
errors and cannot be treated as parity.
|
||||
32
docs/status/W-080.md
Normal file
32
docs/status/W-080.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# W-080 Principled 材质映射
|
||||
|
||||
状态:`done_current_scope`
|
||||
|
||||
路线图中的 W-080 专指 Principled 材质映射。当前已完成默认输入、emission、alpha、IOR、
|
||||
Image Texture 元数据和 warning 证据;材质槽、选中面分配、UV Map 选择、限定
|
||||
Principled/Image Texture/Normal Map 节点创作及 packed PNG/JPEG 写回归属于 W-080 的
|
||||
bounded authoring slice。packed pixels、sRGB、基础 PBR/纹理 sampler 的 Blender GLB
|
||||
round-trip 由 N-004/N-005 覆盖。N-013 现可把 Principled、Image Texture、Normal Map、
|
||||
Material Output 四节点整图原子写回 Main 并保存重开;RGB/Value/Mix/Math/Mapping/TexCoord/
|
||||
Bump、任意节点求值和更多 Principled 扩展仍保持结构化边界。
|
||||
|
||||
2026-08-09 增加 `physical-v1` 渲染切片:Specular IOR Level、Transmission Weight、
|
||||
Coat Weight、Coat Roughness、Emission Strength 已贯通 Inspector、Blender Main、reader、
|
||||
SceneIR、save/reopen 和主线程/Offscreen `MeshPhysicalMaterial`。两条视口现在统一使用线性
|
||||
输入、sRGB 输出、ACES、World exposure、真实 SUN/SPOT 方向和有界 PCF shadow。
|
||||
详细映射、风险和 PBR-001 至 PBR-012 后续任务见
|
||||
`docs/PBR_RENDERING_IMPLEMENTATION_PLAN.md`。纹理像素 GPU 上传、UDIM、HDRI/IBL、任意
|
||||
Shader Node、AREA 阴影等仍是 planned,不包含在 `done_current_scope` 声明中。
|
||||
|
||||
`tests/golden/W-080/animation-depsgraph.json` 与 `pose-constraint-depsgraph.json` 是
|
||||
历史 fixture 目录,语义上属于 N-003 的 frame/pose 回归,不改变 W-080 的任务定义。迁移
|
||||
这些 fixture 前,验收脚本和 golden manifest 必须同步更新,禁止复用任务编号。
|
||||
|
||||
默认验收:
|
||||
|
||||
```bash
|
||||
npm --prefix web run test:golden
|
||||
npm --prefix web run test:frame-evaluation
|
||||
npm --prefix web run test:pose-constraint-goldens
|
||||
npm --prefix web run test:authoring-roundtrip
|
||||
```
|
||||
128
docs/status/parity-ledger.json
Normal file
128
docs/status/parity-ledger.json
Normal file
@@ -0,0 +1,128 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"updatedAt": "2026-08-12",
|
||||
"source": "docs/BLENDER_5_2_WEB_FEATURE_PARITY.md",
|
||||
"statusEnum": ["LOCAL_EXACT", "LOCAL_BOUNDED", "SERVER", "BLOCKED"],
|
||||
"families": [
|
||||
{
|
||||
"id": "N-015",
|
||||
"name": "Non-mesh geometry",
|
||||
"status": "LOCAL_BOUNDED",
|
||||
"roadmapStatus": "in_progress",
|
||||
"completedSlices": ["A1", "A2-malformed-binary-partial", "A2-integer-overflow-fixtures", "A2-multichunk-attribute-completeness", "B2", "B3-metadata", "C1-topology-partial", "C1-handle-points-partial", "C1-handle-preview-raycast-partial", "C1-handle-identity-gizmo-main-roundtrip", "C1-rename-partial", "C1-create-delete-poly-partial", "C1-poly-bezier-nurbs-1d-conversion", "C1-multispline-create-delete-bulk-handle-cyclic-transaction", "C1-surface-2d-topology-transaction", "C2-font-geometry-partial", "C2-font-layout-partial", "C2-font-character-style-textbox-roundtrip", "C2-existing-packed-vfont-style-links", "C2-builtin-font-evaluation-exact", "C3-roundtrip", "D1-raycast-partial", "D1-offscreen-vert-edge-partial", "D1-selection-history-partial", "D1-handle-identity-axis-gizmo", "D2-partial", "E1-partial", "E1-desktop-geometry-golden", "E1-true-2d-surface-desktop-golden", "E1-glb-evaluated-nonmesh-roundtrip-partial", "E1-glb-curve-line-surface-mesh-evaluated", "E1-usda-four-object-desktop-roundtrip", "E1-pointcloud-curves-hair-glb-usd-loss-fixture", "E2-1M-chromium", "E2-chromium-worker-recovery", "E2-opfs-quota-chromium"],
|
||||
"blockedSlices": ["B3-vdb-renderer", "C1-multi-handle-selection-drag-gizmo", "C2-new-external-font-import", "D1-cross-object-history-range-patch", "E1-volume-loss-fixture"],
|
||||
"acceptance": ["web:test:nonmesh-roundtrip", "web:test:nonmesh-desktop-golden", "web:test:nonmesh-glb-blender-roundtrip", "web:test:nonmesh-usd-serialization", "web:test:nonmesh-usd-blender-roundtrip", "web:test:nonmesh-binary", "web:test:vdb", "web:test:selection-history", "web:e2e:N-015|non-mesh", "web:e2e:real OPFS quota"],
|
||||
"dependencies": []
|
||||
},
|
||||
{
|
||||
"id": "N-016",
|
||||
"name": "Grease Pencil",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-schema-budget", "A-main-reader", "B-layer-frame-stroke-transaction-partial", "C-point-radius-opacity-color-cyclic-material-partial", "D-current-frame-stroke-preview-main-offscreen-chromium"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:test:grease-pencil", "web:e2e:N-016 Grease Pencil"],
|
||||
"dependencies": ["N-015"]
|
||||
},
|
||||
{
|
||||
"id": "N-017",
|
||||
"name": "Paint and weights",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-stroke-hit-weight-schema-budget-partial", "B-main-vertex-color-partial", "B-main-vertex-weight-normalize-partial"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:test:paint-roundtrip", "web:e2e:N-017 paint"],
|
||||
"dependencies": ["N-016"]
|
||||
},
|
||||
{
|
||||
"id": "N-018",
|
||||
"name": "Physics and simulation",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-family-capability-inventory", "B-settings-dependency-cache-manifest-partial", "C-exact-frame-selection-gate"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:e2e:N-018 physics", "web:test:simulation-cache"],
|
||||
"dependencies": ["N-017"]
|
||||
},
|
||||
{
|
||||
"id": "N-019",
|
||||
"name": "Lighting and render",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-camera-light-world-scene-reader-partial", "A-main-light-world-properties-partial", "B-three-exposure-shadow-mapping-partial", "A-white-balance-integrity-gate"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:test:lighting-roundtrip", "web:e2e:N-019 Scene exposure"],
|
||||
"dependencies": ["N-018"]
|
||||
},
|
||||
{
|
||||
"id": "N-020",
|
||||
"name": "Compositor",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-graph-resource-cycle-schema", "B-bounded-cpu-executor-partial", "C-image-operation-budget-cancel-partial", "D-unsupported-node-preservation-gate"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:e2e:N-020 CPU compositor"],
|
||||
"dependencies": ["N-019"]
|
||||
},
|
||||
{
|
||||
"id": "N-021",
|
||||
"name": "Sequencer and audio",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-strip-resource-schema", "B-deterministic-move-trim-split-partial", "B-source-frame-seek", "C-runtime-codec-probe-gate"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:e2e:N-021 sequencer"],
|
||||
"dependencies": ["N-020"]
|
||||
},
|
||||
{
|
||||
"id": "N-022",
|
||||
"name": "Tracking and masks",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-clip-track-plane-mask-schema", "B-revision-marker-mask-edit-partial", "B-source-hash-binding-validation", "C-browser-probe-solve-gate"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:e2e:N-022 tracking"],
|
||||
"dependencies": ["N-021"]
|
||||
},
|
||||
{
|
||||
"id": "N-023",
|
||||
"name": "Assets, libraries and IO",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-catalog-asset-license-source-schema", "A-content-addressed-opfs-capability", "B-library-dependency-order-partial", "C-glb-export-usd-analysis-gates", "E-archive-path-ratio-budget"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:e2e:N-023 asset"],
|
||||
"dependencies": ["N-022"]
|
||||
},
|
||||
{
|
||||
"id": "N-024",
|
||||
"name": "Editors and workflow",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-unified-area-region-context", "B-read-only-editor-manifest-partial", "C-selection-sync-revision-partial", "D-keymap-layout-budget-gates"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:e2e:N-024 editor"],
|
||||
"dependencies": ["N-023"]
|
||||
},
|
||||
{
|
||||
"id": "N-025",
|
||||
"name": "Scripting and platform",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-default-deny-script-policy", "B-signed-manifest-permission-budget", "C-server-source-hash-job-gate", "D-platform-capability-report"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:e2e:N-025 script"],
|
||||
"dependencies": ["N-024"]
|
||||
},
|
||||
{
|
||||
"id": "N-026",
|
||||
"name": "Release gate",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-machine-readable-parity-manifest", "A-dependency-status-validation", "B-chromium-runtime-evidence-gate", "B-chromium-smoke-partial", "C-performance-fault-provenance-gate", "C-performance-1M-malicious-input-partial", "C-release-package-notices-partial", "D-deterministic-manifest-serialization", "D-offline-reproducible-source-archive-partial"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:e2e:N-026 release", "web:test:browser-smoke", "web:test:release-package", "web:release:offline", "web:test:release-performance", "web:test:malicious-blends"],
|
||||
"dependencies": ["N-015", "N-016", "N-017", "N-018", "N-019", "N-020", "N-021", "N-022", "N-023", "N-024", "N-025"]
|
||||
}
|
||||
]
|
||||
}
|
||||
33
docs/web/coordinate-color-contract.md
Normal file
33
docs/web/coordinate-color-contract.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Coordinate and Color Contract v1
|
||||
|
||||
## Coordinate spaces
|
||||
|
||||
Blender scene data is the authority. The browser adapter performs one explicit
|
||||
conversion at the SceneIR -> Three.js boundary; React components never convert
|
||||
coordinates independently.
|
||||
|
||||
| Data | Blender source | Web representation | Rule |
|
||||
| --- | --- | --- | --- |
|
||||
| Object transform | local/world matrices | column-major `Float32Array(16)` | preserve parent inverse and negative scale |
|
||||
| Position/vector | Blender Z-up | Three.js Y-up adapter space | convert once in `three-adapter` |
|
||||
| Normal/tangent | evaluated mesh | normalized buffer attributes | inverse-transpose for object scale |
|
||||
| UV | mesh loop corner | `uv` buffer attribute | preserve V direction from source contract |
|
||||
| Distance | Blender unit | meters only at import/export boundary | do not silently rescale scene values |
|
||||
| Camera | Blender camera | Three.js camera | preserve perspective/orthographic parameters |
|
||||
|
||||
## Color spaces
|
||||
|
||||
- Base color and emission textures are decoded as sRGB unless Blender metadata
|
||||
explicitly says otherwise.
|
||||
- Metallic, roughness, normal, mask and weight textures remain linear data.
|
||||
- Vertex colors are converted according to their Blender color attribute domain and
|
||||
storage type; no implicit gamma conversion is allowed in the SceneIR serializer.
|
||||
- Exposure and tone mapping belong to the Three.js renderer settings, not to
|
||||
material data.
|
||||
|
||||
## Test fixtures
|
||||
|
||||
The contract is validated with an axis object, a non-uniformly scaled cube, a
|
||||
negative-scale mirror, a perspective camera, an orthographic camera, an animated
|
||||
object and an sRGB/linear texture pair. Every fixture records source values and
|
||||
adapter values in `tests/golden/coordinate-color/`.
|
||||
27
docs/web/dependency-matrix.md
Normal file
27
docs/web/dependency-matrix.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Web Dependency Matrix
|
||||
|
||||
This is the initial dependency decision for the browser build. A dependency may
|
||||
move from `待验证` only after a task adds a build or browser regression test.
|
||||
|
||||
| Dependency or module | Decision | Web role | Evidence or next task |
|
||||
| --- | --- | --- | --- |
|
||||
| `blenlib`, `guardedalloc` | 保留 | Blender base/runtime utilities | W-022 |
|
||||
| `makesdna`, `makesrna` | 保留 | DNA/RNA data and property schema | W-022 |
|
||||
| `blenloader`, `blenkernel` | 保留 | `.blend` read/write and data blocks | W-022, W-030 |
|
||||
| `bmesh` | 保留 | mesh editing and Decimate primitives | W-022, W-074 |
|
||||
| `depsgraph` | 保留 | hierarchy, modifiers, evaluated mesh | W-067, W-093 |
|
||||
| selected `modifiers` | 保留白名单 | Blender 5.2 types are identity-complete; evaluated parity remains fixture-gated | [modifier support matrix](modifier-support-matrix.md), W-066, W-074 |
|
||||
| `windowmanager`, `editors`, `ghost` | React replacement | Blender-style UI semantics, not desktop window backend | W-018, W-019 |
|
||||
| Blender `draw/gpu` viewport | 关闭首期 | Three.js is the browser renderer | W-013, W-050 |
|
||||
| Python runtime and automatic `.blend` scripts | 关闭首期 | security and package-size boundary | W-117 |
|
||||
| Cycles, CUDA/OptiX, Embree | 关闭首期 | server-side or native rendering only | roadmap non-goal |
|
||||
| OpenVDB, USD, FFmpeg | 关闭首期 | server-side or later format modules | W-021 |
|
||||
| React + TypeScript | 保留 | application UI and state | W-010 |
|
||||
| Three.js (vendored) | 保留 | WebGL2 viewport and scene adapter; runtime has no CDN dependency | W-013, W-050 |
|
||||
| Emscripten runtime | 保留 | Blender C/C++ to WebAssembly | W-020~W-025 |
|
||||
| zlib 1.3.1 (vendored) | 保留 | gzip `.blend` decompression in Blender file reader | W-030 |
|
||||
| zstd 1.5.7 (vendored) | 保留 | zstd `.blend` decompression in Blender file reader | W-030 |
|
||||
| IndexedDB | 保留 | project metadata and small persistent records in StorageWorker | W-014, W-041 |
|
||||
| OPFS | 保留 | large `.blend`, assets, snapshots and LOD cache | W-040, W-077 |
|
||||
|
||||
No CAD kernel or Bitbybit/OCCT module is part of this matrix.
|
||||
71
docs/web/depsgraph-evaluation-contract.md
Normal file
71
docs/web/depsgraph-evaluation-contract.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Blender Depsgraph Evaluation Contract
|
||||
|
||||
`evaluateDepsgraph` is an explicit WebEngine Worker command intended to evaluate
|
||||
the currently opened `.blend` with Blender 5.2's native loader and dependency
|
||||
graph. It does not reinterpret the SceneIR modifier metadata in TypeScript.
|
||||
|
||||
Current status: the native module executes Blender 5.2 full loading, view-layer
|
||||
synchronization, graph build, tagged update and frame evaluation in the headless
|
||||
WASM runtime for the declared fixtures. The wasm32 DNA bridge recursively aligns
|
||||
64-bit members, and the Web ID registry includes embedded NodeTree, Camera,
|
||||
Light, Lattice and Grease Pencil data. The command returns the native
|
||||
`BlenderDepsgraph/EVALUATED` report;
|
||||
loader, graph or schema failures remain structured errors and never become
|
||||
Three.js approximations.
|
||||
|
||||
The native evaluation sequence is:
|
||||
|
||||
1. Initialize Blender's headless data runtime once per WASM module.
|
||||
2. Load the saved buffer with `BLO_read_from_memory`.
|
||||
3. Synchronize view layers, build the viewport Depsgraph and apply tagged and
|
||||
frame evaluation.
|
||||
4. Return modifier identity/status for every evaluated object and final mesh
|
||||
vertex positions and triangle indices for every mesh
|
||||
object, keyed by stable SceneIR object/Mesh IDs. Each mesh also returns its
|
||||
original modifier stack in order. Entries carry Blender's persistent UID,
|
||||
registered type name, viewport/render/edit/cage flags, target object IDs,
|
||||
the previous-stack and cross-object dependency edges, and an explicit
|
||||
status: `EVALUATED`, `DISABLED` or `BLOCKED`. Blocked entries carry a stable
|
||||
`errorCode`, human-readable `error` and actionable `suggestion`; they are
|
||||
never silently treated as successful evaluation.
|
||||
|
||||
The result is validated by `parseDepsgraphEvaluation`. Every mesh must have a
|
||||
16-value world matrix, exactly `vertexCount * 3` position values and exactly
|
||||
`triangleCount * 3` in-range integer indices. A load, initialization or graph
|
||||
failure returns the existing structured WebEngine error; it must never fall
|
||||
back to a Three.js approximation.
|
||||
|
||||
The rigged fixture is checked against a golden written by desktop Blender 5.2.
|
||||
The golden disables the fixture's Preview Decimate modifier solely to isolate
|
||||
shape-key plus armature deformation. The current Web deformation evaluator
|
||||
already compares final positions under the declared maximum and RMS error
|
||||
budget. Native WASM Depsgraph evaluation must pass the same comparison and
|
||||
repeated memory-safety runs before this contract is considered complete.
|
||||
|
||||
The offline regression `npm --prefix web run test:depsgraph` checks this report
|
||||
schema for all declared fixtures and verifies the rigged stack order
|
||||
`Armature -> Decimate`, its stack edge, the Armature target object edge and
|
||||
Blender's structured "requires more than 3 input faces" Decimate block.
|
||||
Drivers and constraints remain separate matrix entries. Geometry Nodes now has
|
||||
two explicitly bounded native closures described below; it is not a claim of
|
||||
general node-graph evaluation.
|
||||
|
||||
The category fixture suite adds Generate, Deform, Physics, Geometry Nodes and
|
||||
Grease Pencil desktop goldens. Twenty-four category types execute native Web
|
||||
implementations and compare topology/positions, including serialized
|
||||
Mesh/Surface Deform bind caches and frame-6 Build/Wave output. Subdivision uses
|
||||
the locally linked OpenSubdiv 3.7.0 CPU evaluator; exact Boolean uses local GMP
|
||||
6.3.0; Curve evaluates through Blender's native modifier after registering the
|
||||
Curves ID type. Their category goldens now pass in wasm32.
|
||||
|
||||
Geometry Nodes is intentionally narrower than Blender's full lazy-function
|
||||
runtime. The evaluator accepts a three-node graph containing either Transform
|
||||
Geometry in Components mode with literal defaults, or Set Position with an
|
||||
unlinked constant selection/offset. Both use Blender mesh APIs and match desktop
|
||||
goldens. Other graph shapes produce `BLENDER_MODIFIER_ERROR`; simulation/bake
|
||||
state produces `GEOMETRY_NODES_SIMULATION_UNAVAILABLE` and preserves input geometry.
|
||||
|
||||
Other unsupported implementations retain their original DNA type code through
|
||||
a disabled placeholder and report `UNSUPPORTED_MODIFIER_TYPE`; they are not
|
||||
rewritten to `None`. Unsupported resource closures are validated before their
|
||||
implementation can mutate geometry or enter an unavailable runtime path.
|
||||
31
docs/web/local-dependencies.md
Normal file
31
docs/web/local-dependencies.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# 本地依赖策略
|
||||
|
||||
浏览器运行时禁止从 CDN、远程 ESM 或第三方脚本地址加载功能模块。依赖分为
|
||||
三类:
|
||||
|
||||
| 类别 | 当前模块 | 本地实现 |
|
||||
| --- | --- | --- |
|
||||
| 项目 vendored 运行时 | Three.js 0.185.1、OrbitControls、WebEngine glue/WASM | `web/app/src/vendor/`、`web/app/public/vendor/` |
|
||||
| WASM 构建压缩库 | zlib 1.3.1、zstd 1.5.7 | `blender-5.2.0/extern/zlib/`、`blender-5.2.0/extern/zstd/`,由 Web CMake 的本地静态 target 使用 |
|
||||
| npm 构建依赖 | React、ReactDOM、Vite、TypeScript | `web/package-lock.json` 锁定,Vite 打入本地 `dist/assets/index-*.js` |
|
||||
| 测试/工具依赖 | Playwright、ESLint、Emscripten | `web/node_modules`、系统 Emscripten 和本机 Chrome;不进入浏览器产物 |
|
||||
|
||||
`tools/web/check-local-deps.sh` 是发布前门禁:检查 runtime dependencies 在本地
|
||||
安装、Three.js 没有回退到 npm runtime import、vendor 资源存在,并扫描源码和
|
||||
`dist/` 中的 CDN/远程 ESM 地址,同时按 `engine-manifest.json` 校验本地 WASM
|
||||
SHA-256。npm registry 只发生在开发机首次安装阶段;发布/浏览器运行只提供
|
||||
`web/dist` 的同源静态文件。离线开发需要预先保留 `node_modules` 或 npm
|
||||
缓存,随后可用 `npm ci --offline` 重建,运行时不再访问 registry。
|
||||
|
||||
Blender Web CMake 不使用 `ExternalProject`、FetchContent 或构建时下载。zlib
|
||||
和 zstd 的源码、许可证和 CMake 输入已放入 `blender-5.2.0/extern/`;浏览器只
|
||||
加载 `web_engine.js` 与同源 `web_engine.wasm`,不加载 SQLite WASM、OCCT 或
|
||||
任何远程模块。
|
||||
|
||||
可复现的离线检查命令:
|
||||
|
||||
```text
|
||||
cd web
|
||||
npm ci --offline --ignore-scripts
|
||||
npm run check:local-deps
|
||||
```
|
||||
66
docs/web/mesh-buffer-layout.md
Normal file
66
docs/web/mesh-buffer-layout.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# MeshIR Buffer Layout
|
||||
|
||||
This document is the versioned boundary between the Blender reader and the
|
||||
Three.js renderer. The compatibility C ABI returns a JSON snapshot. The
|
||||
preferred ABI separates JSON metadata from a native WBG1 geometry stream, and
|
||||
the Worker transfers each typed mesh buffer without reconstructing large JSON
|
||||
arrays. JSON arrays remain a fallback for older engine binaries.
|
||||
|
||||
## Coordinate and topology contract
|
||||
|
||||
- Blender source coordinates are right-handed, Z-up, with forward `-Y`.
|
||||
- Positions and normals use packed little-endian IEEE-754 `float32` values.
|
||||
- `indices` are packed little-endian unsigned 32-bit integers and reference
|
||||
`positions` vertices.
|
||||
- `topology` is `triangles`; every three indices form one triangle.
|
||||
- `triangleCornerIndices` maps every index entry to the original Blender mesh
|
||||
corner. It is required when UV or color attributes are present because a
|
||||
single position can have multiple corner values.
|
||||
- `triangleMaterialIndices` has one non-negative integer per triangle and
|
||||
indexes `materialSlotIds`.
|
||||
|
||||
## SceneIR fields
|
||||
|
||||
| Field | Element count | Type | Domain |
|
||||
| --- | ---: | --- | --- |
|
||||
| `positions` | `vertexCount * 3` | `float32` | Point |
|
||||
| `normals` | `vertexCount * 3` | `float32` | Point, normalized |
|
||||
| `indices` | `triangleCount * 3` | `uint32` | Triangle corners |
|
||||
| `triangleCornerIndices` | `triangleCount * 3` | `uint32` | Blender Corner |
|
||||
| `uvs` | `cornerCount * 2` | `float32` | Corner, optional |
|
||||
| `colors` | `cornerCount * 4` | `float32` RGBA | Corner, optional |
|
||||
| `triangleMaterialIndices` | `triangleCount` | `uint32` | Face expanded to triangles |
|
||||
| `triangleFaceIndices` | `triangleCount` | `uint32` | Source face for edit selection |
|
||||
| `edgeVertexIndices` | `edgeCount * 2` | `uint32` | Edge endpoints |
|
||||
| `tangents` | `cornerCount * 4` | `float32` | Corner tangent/sign, optional |
|
||||
| `splitNormals` | `cornerCount * 3` | `float32` | Corner normal, optional |
|
||||
|
||||
`bounds.min` and `bounds.max` are three finite JSON numbers in source object
|
||||
space. `materialSlotIds` are stable SceneIR IDs and never contain embedded
|
||||
material data.
|
||||
|
||||
## Native WBG1 stream
|
||||
|
||||
The stream starts with `WBG1`, a little-endian schema version and mesh count.
|
||||
Each mesh contains an ID length, eleven element counts, UTF-8 ID bytes, then
|
||||
the following arrays in order:
|
||||
|
||||
```text
|
||||
positions:f32, indices:u32, normals:f32, triangleCornerIndices:u32,
|
||||
uvs:f32, colors:f32, triangleMaterialIndices:u32,
|
||||
triangleFaceIndices:u32, edgeVertexIndices:u32, tangents:f32,
|
||||
splitNormals:f32
|
||||
```
|
||||
|
||||
Every count is element-based and every scalar is 4 bytes, so array starts stay
|
||||
4-byte aligned. The decoder rejects truncation/trailing bytes, unknown mesh
|
||||
IDs, count/summary mismatches and indices outside `vertexCount`. Topology
|
||||
changes must regenerate triangle-face and edge mappings; stale source arrays
|
||||
are never accepted.
|
||||
|
||||
`geometryStatus: "binary"` means metadata references a transferred per-mesh
|
||||
buffer through `geometryBufferId`. `geometryStatus: "available"` is the JSON
|
||||
fallback. After the initial WBG1 generation, `MeshGeometryDelta` carries
|
||||
`meshId`, field, byte offset and transferable replacement bytes for stable-size
|
||||
changes; topology or attribute-layout changes replace only that mesh envelope.
|
||||
Network-style progressive sub-mesh streaming is not implied by WBG1.
|
||||
143
docs/web/modifier-support-matrix.md
Normal file
143
docs/web/modifier-support-matrix.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# Blender 5.2 Modifier Web Support Matrix
|
||||
|
||||
This matrix separates file recognition, dependency extraction and evaluated
|
||||
result parity. Loading a modifier type is not evidence that its Web result
|
||||
matches Blender desktop.
|
||||
|
||||
## Status levels
|
||||
|
||||
| Level | Meaning |
|
||||
| --- | --- |
|
||||
| `IDENTITY` | Type code/name, UUID, stack order and mode flags are preserved. |
|
||||
| `PARAMETERS` | Declared parameters are present in SceneIR. No evaluated mesh is implied. |
|
||||
| `TARGET_EDGE` | Cross-object target IDs are present in the native Depsgraph report. |
|
||||
| `NATIVE_FIXTURE` | Native WASM Depsgraph behavior is covered by a Blender fixture/golden. |
|
||||
| `COMMAND` | A revisioned Web command can execute and has undo/redo or isolated-preview coverage. |
|
||||
| `BLOCKED` | No parity claim. An enabled unsupported/invalid entry must return a structured block. |
|
||||
|
||||
## Current verified set
|
||||
|
||||
| Modifier | Identity | Parameters | Target edge | Native fixture | Command |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| Subdivision Surface | yes | levels/type | no | desktop/WASM topology and geometry parity through local OpenSubdiv 3.7.0 CPU evaluator | no |
|
||||
| Mirror | yes | axis/merge flags | optional mirror object | desktop/WASM geometry parity | no |
|
||||
| Boolean (Exact) | yes | operation/solver | target object | desktop/WASM surface parity through local GMP 6.3.0 | no |
|
||||
| Decimate | yes | mode/ratio/iterations/delimit | no | structured small-mesh error | Collapse/Un-Subdivide/Dissolve command |
|
||||
| Armature | yes | target/group/deform flags | yes | rigged shape-key golden | enable/disable + undo/redo |
|
||||
| Bevel | yes | width/segments/profile | no | desktop/WASM geometry parity | no |
|
||||
| Lattice | yes | target/group/strength/flags | yes | desktop/WASM geometry parity | no |
|
||||
| Curve | yes | target/group/axis/flags | yes | desktop/WASM topology and geometry parity | no |
|
||||
| Hook | yes | target/subtarget/group/falloff/force | yes | desktop/WASM geometry parity | no |
|
||||
| Mesh Deform | yes | target/group/grid/flags | yes | bound-cache desktop/WASM geometry parity | no |
|
||||
| Shrinkwrap | yes | targets/group/distance/type/mode/limit | primary/aux targets | desktop/WASM geometry parity | no |
|
||||
| Surface Deform | yes | target/group/falloff/strength/flags | yes | bound-cache desktop/WASM geometry parity | no |
|
||||
| Array/Solidify | yes | fixture parameters | object edges where used | desktop/WASM geometry parity | no |
|
||||
| Triangulate/Weld | yes | fixture parameters | no | desktop/WASM topology and geometry parity | no |
|
||||
| Build/Wave | yes | frame/time parameters | object/texture edges where used | frame-6 desktop/WASM geometry parity | no |
|
||||
| Geometry Nodes | yes | node group/default socket values | node-group edge | bounded Transform Geometry and Set Position closures match desktop | no |
|
||||
| Edge Split | yes | angle/sharp flags | no | desktop/WASM topology and geometry parity | no |
|
||||
| Screw | yes | axis/angle/steps/merge | optional axis object | desktop/WASM topology and geometry parity | no |
|
||||
| Displace | yes | direction/strength/mid-level/space | optional mapping object | constant local-space desktop/WASM parity; resource configurations block | no |
|
||||
|
||||
Native `targetObjectIds` currently covers Array, Mirror, Boolean, Lattice, Curve, Armature, Hook,
|
||||
Mesh Deform, Shrinkwrap, Surface Deform, Screw and Displace mapping objects.
|
||||
The ordered `dependsOn` list contains the prior stack entry followed by those
|
||||
external object IDs. These SceneIR entries remain `METADATA_ONLY`; the Worker
|
||||
still blocks topology/LOD commands until evaluated input is available.
|
||||
|
||||
## Complete Blender 5.2 identity coverage
|
||||
|
||||
The lightweight reader now covers every DNA slot from `0` through `86`; a C++
|
||||
`static_assert` fails the build when `NUM_MODIFIER_TYPES` grows without a table
|
||||
update. The category-golden native whitelist contains 24 evaluated types:
|
||||
`SUBSURF`, `MIRROR`, `ARRAY`, exact `BOOLEAN`, `BEVEL`, `SOLIDIFY`,
|
||||
`TRIANGULATE`, `WELD`, `LATTICE`, `HOOK`, `SHRINKWRAP`, `SIMPLE_DEFORM`,
|
||||
`MESH_DEFORM`, `SURFACE_DEFORM`, `CURVE`, `BUILD`, `WAVE` and the bounded
|
||||
`NODES` closures, plus `SMOOTH`, `CAST`, `WIREFRAME`, `EDGE_SPLIT`, `SCREW` and
|
||||
bounded `DISPLACE`.
|
||||
Armature, Shape Key and Decimate have earlier dedicated
|
||||
fixtures. The remaining identity-only types are:
|
||||
|
||||
`NONE`, `SOFT_BODY`, `UV_PROJECT`,
|
||||
`PARTICLE_SYSTEM`, `PARTICLE_INSTANCE`, `EXPLODE`, `CLOTH`,
|
||||
`COLLISION`, `FLUID_SIM`, `MASK`, `MULTIRES`, `SURFACE`, reserved slot `31`,
|
||||
`WARP`, `WEIGHT_VG_EDIT`, `WEIGHT_VG_MIX`, `WEIGHT_VG_PROXIMITY`,
|
||||
`OCEAN`, `DYNAMIC_PAINT`, `REMESH`, `SKIN`, `LAPLACIAN_SMOOTH`, `UV_WARP`,
|
||||
`MESH_CACHE`, `LAPLACIAN_DEFORM`, `DATA_TRANSFER`,
|
||||
`NORMAL_EDIT`, `CORRECTIVE_SMOOTH`, `MESH_SEQUENCE_CACHE`, `WEIGHTED_NORMAL`,
|
||||
`FLUID`, `MESH_TO_VOLUME`, `VOLUME_DISPLACE`, `VOLUME_TO_MESH`,
|
||||
`GREASE_PENCIL_OPACITY`, `GREASE_PENCIL_SUBDIV`, `GREASE_PENCIL_COLOR`,
|
||||
`GREASE_PENCIL_TINT`, `GREASE_PENCIL_SMOOTH`, `GREASE_PENCIL_OFFSET`,
|
||||
`GREASE_PENCIL_NOISE`, `GREASE_PENCIL_MIRROR`, `GREASE_PENCIL_THICKNESS`,
|
||||
`GREASE_PENCIL_LATTICE`, `GREASE_PENCIL_DASH`, `GREASE_PENCIL_MULTIPLY`,
|
||||
`GREASE_PENCIL_LENGTH`, `GREASE_PENCIL_WEIGHT_ANGLE`,
|
||||
`GREASE_PENCIL_ARRAY`, `GREASE_PENCIL_WEIGHT_PROXIMITY`,
|
||||
`GREASE_PENCIL_HOOK`, `GREASE_PENCIL_LINEART`, `GREASE_PENCIL_ARMATURE`,
|
||||
`GREASE_PENCIL_TIME`, `GREASE_PENCIL_ENVELOPE`, `GREASE_PENCIL_OUTLINE`,
|
||||
`GREASE_PENCIL_SHRINKWRAP`, `GREASE_PENCIL_BUILD`,
|
||||
`GREASE_PENCIL_SIMPLIFY`, `GREASE_PENCIL_TEXTURE`.
|
||||
|
||||
## Blocking contract
|
||||
|
||||
An enabled unregistered native modifier returns `UNSUPPORTED_MODIFIER_TYPE`.
|
||||
An enabled target-based modifier without a target returns
|
||||
`MODIFIER_TARGET_MISSING`. An error raised by Blender itself returns
|
||||
`BLENDER_MODIFIER_ERROR`. Resource/configuration-dependent Displace returns
|
||||
`MODIFIER_CONFIGURATION_UNSUPPORTED`; simulation/bake GN returns
|
||||
`GEOMETRY_NODES_SIMULATION_UNAVAILABLE`. A target path that reaches the owner returns
|
||||
`MODIFIER_DEPENDENCY_CYCLE`. All blockers include the modifier object/name/type,
|
||||
`error`, and an actionable `suggestion`. Viewport-disabled modifiers remain
|
||||
`DISABLED` and do not inherit stale evaluated errors.
|
||||
|
||||
## Category fixtures
|
||||
|
||||
| Category | Blender 5.2 golden | Current Web result |
|
||||
| --- | --- | --- |
|
||||
| Generate | Subdivision, Mirror, Array, Boolean, Bevel, Solidify, Triangulate, Weld | All eight execute native Blender code. Subdivision matches the 26-vertex/48-triangle OpenSubdiv golden; Exact Boolean matches the 12-vertex/20-triangle surface golden. |
|
||||
| Deform | Lattice, Hook, Shrinkwrap, Simple Deform, Mesh Deform, Surface Deform | All six match desktop geometry; Mesh/Surface fixtures contain real bind caches and target deformation. |
|
||||
| Curve | Curve target and evaluated output in a dedicated fixture | Native Curve evaluation matches desktop topology and positions within the declared floating-point tolerance. |
|
||||
| Physics/time | Build and Wave at frame 6; disabled Cloth, Soft Body and Collision | Build and Wave match desktop geometry at frame 6; simulation entries remain `DISABLED`. |
|
||||
| Geometry Nodes | Self-contained Transform Geometry, Set Position and simulation-zone graphs | Constant Transform and Set Position match desktop positions/topology. Simulation zones preserve input and return `GEOMETRY_NODES_SIMULATION_UNAVAILABLE` without consuming temporal state. |
|
||||
| Grease Pencil | One drawing plus all 26 GP modifier types exposed by Blender 5.2 Python | GP data loads; all modifier codes/modes are preserved and remain `DISABLED`. |
|
||||
| Extended native | Edge Split, Screw and bounded Displace | All match desktop topology/positions; RGB/resource Displace preserves input and returns `MODIFIER_CONFIGURATION_UNSUPPORTED`. |
|
||||
|
||||
Line Art is exposed as `LINEART` rather than with the `GREASE_PENCIL_` prefix;
|
||||
the generator includes it explicitly. The fixtures, desktop goldens and
|
||||
comparison runner are generated by
|
||||
`tools/web/generate-modifier-fixtures.py`,
|
||||
`tools/web/generate-modifier-goldens.py` and checked offline with
|
||||
`npm --prefix web run test:modifier-goldens`.
|
||||
|
||||
## Local native dependencies
|
||||
|
||||
Subdivision uses the local OpenSubdiv 3.7.0 source and archive under
|
||||
`blender-5.2.0/extern/opensubdiv-source`. The Web build enables its CPU-only
|
||||
static evaluator and disables GPU, examples, documentation and tests. The
|
||||
archive MD5 is `470d53c4d4335a601c33a052ce7c33b4`; SHA-256 is
|
||||
`f843eb49daf20264007d807cbc64516a1fed9cdb1149aaf84ff47691d97491f9`.
|
||||
|
||||
Exact Boolean uses the local GMP 6.3.0 DFSG source plus Emscripten static
|
||||
archives under `blender-5.2.0/extern/gmp-source` and
|
||||
`blender-5.2.0/extern/gmp-wasm`. The source archive MD5 is
|
||||
`d4a3890b5e28df535b653b07798b11b2`; SHA-256 is
|
||||
`bd2966e6d277f79328e894a5a9f3ba3fbf2ed2be81def5f48623e30c23fb1572`.
|
||||
`WITH_MANIFOLD` remains off: Blender 5.2's verified Exact solver path uses GMP,
|
||||
so Manifold is not part of the tested runtime closure. wasm32 and desktop may
|
||||
choose different valid diagonals on coplanar faces; the golden therefore
|
||||
compares oriented surface area and geometry instead of requiring identical
|
||||
triangle indices.
|
||||
|
||||
`npm --prefix web run check:local-deps` verifies both source archive hashes,
|
||||
the OpenSubdiv CMake source and the local GMP/GMPXX headers and WASM archives.
|
||||
|
||||
## Future whitelist expansion
|
||||
|
||||
1. Add deterministic physics cache stepping for Cloth/Soft Body/Collision;
|
||||
Build and Wave are complete for the current frame golden.
|
||||
2. Expand Geometry Nodes from the verified Transform Geometry and Set Position closures in small
|
||||
node/dependency batches. Simulation zones, bake data, fields, instances and
|
||||
the full lazy-function graph remain outside the current whitelist.
|
||||
3. Enable Grease Pencil modifiers in small dependency batches; keep target and
|
||||
simulation types disabled until their external resources are validated.
|
||||
4. Add native geometry goldens for the remaining Generate/Deform families,
|
||||
including Cast, Remesh, Multires and volume conversions.
|
||||
78
docs/web/third-party-notices.json
Normal file
78
docs/web/third-party-notices.json
Normal file
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"packages": [
|
||||
{
|
||||
"name": "Blender",
|
||||
"version": "5.2.0",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"source": "blender-5.2.0/",
|
||||
"notice": "Blender source and license files remain in the upstream source tree."
|
||||
},
|
||||
{
|
||||
"name": "React",
|
||||
"version": "19.2.8",
|
||||
"license": "MIT",
|
||||
"source": "web/node_modules/react (installed from locked npm package)"
|
||||
},
|
||||
{
|
||||
"name": "ReactDOM",
|
||||
"version": "19.2.8",
|
||||
"license": "MIT",
|
||||
"source": "web/node_modules/react-dom (installed from locked npm package)"
|
||||
},
|
||||
{
|
||||
"name": "Three.js",
|
||||
"version": "0.185.1",
|
||||
"license": "MIT",
|
||||
"source": "web/app/src/vendor/three/"
|
||||
},
|
||||
{
|
||||
"name": "Emscripten runtime",
|
||||
"version": "3.1.69",
|
||||
"license": "MIT",
|
||||
"source": "local emsdk"
|
||||
},
|
||||
{
|
||||
"name": "Vite",
|
||||
"version": "8.2.0",
|
||||
"license": "MIT",
|
||||
"source": "web/node_modules/vite (build-time only)"
|
||||
},
|
||||
{
|
||||
"name": "TypeScript",
|
||||
"version": "5.9.3",
|
||||
"license": "Apache-2.0",
|
||||
"source": "web/node_modules/typescript (build-time only)"
|
||||
},
|
||||
{
|
||||
"name": "Playwright",
|
||||
"version": "1.62.1",
|
||||
"license": "Apache-2.0",
|
||||
"source": "web/node_modules/@playwright/test (test-time only)"
|
||||
},
|
||||
{
|
||||
"name": "OpenSubdiv",
|
||||
"version": "3.7.0",
|
||||
"license": "Apache-2.0",
|
||||
"source": "blender-5.2.0/extern/opensubdiv-source"
|
||||
},
|
||||
{
|
||||
"name": "GMP",
|
||||
"version": "6.3.0",
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"source": "blender-5.2.0/extern/gmp-source"
|
||||
},
|
||||
{
|
||||
"name": "zlib",
|
||||
"version": "1.3.1",
|
||||
"license": "Zlib",
|
||||
"source": "blender-5.2.0/extern/zlib/ (vendored build dependency)"
|
||||
},
|
||||
{
|
||||
"name": "zstd",
|
||||
"version": "1.5.7",
|
||||
"license": "BSD-3-Clause",
|
||||
"source": "blender-5.2.0/extern/zstd/ (vendored build dependency)"
|
||||
}
|
||||
]
|
||||
}
|
||||
19
docs/web/three-vendor.md
Normal file
19
docs/web/three-vendor.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Three.js 本地资源
|
||||
|
||||
当前使用 Three.js `0.185.1`。运行时模块已从锁定的 npm 包复制到项目源码:
|
||||
|
||||
- `web/app/src/vendor/three/three.module.js`
|
||||
- `web/app/src/vendor/three/three.core.js`
|
||||
- `web/app/src/vendor/three/addons/controls/OrbitControls.js`
|
||||
|
||||
视口适配器只引用上述相对路径,OrbitControls 的裸 `three` 导入也已改为
|
||||
本地相对导入。构建产物把代码打进本地 `index` chunk,不从 CDN 或网页运行时
|
||||
网络加载 Three.js。`@types/three` 仅作为开发期类型依赖。
|
||||
|
||||
## 校验
|
||||
|
||||
```text
|
||||
three.module.js bbf5ed13fe4373f5bd38b14ea8e62e9f157327da5638edc6d3863e08b167c9c7
|
||||
three.core.js 3718df126d69c125362a03340913204470d8c50238605150e57f808840fb7759
|
||||
OrbitControls.js 1e08bf297c9062aa5055a9d649d8a8458c3871aa31c7d600f535a06f567e7cad
|
||||
```
|
||||
Reference in New Issue
Block a user