Add image selection refinement functionality with BEN2 integration
- Implemented viewport.py for handling 3D view projections, gestures, and overlay drawing. - Created refine_image_selection.py to manage the refinement of gesture masks and output image bounds. - Added selection module with refine_selection.py to process and crop images based on alpha channel visibility. - Introduced __init__.py for selection module to expose refine_selection function.
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-08-31
|
||||
93
openspec/changes/normalize-moge-alpha-depth/design.md
Normal file
93
openspec/changes/normalize-moge-alpha-depth/design.md
Normal file
@@ -0,0 +1,93 @@
|
||||
## Context
|
||||
|
||||
Cutout Job 会把最终 Region 图像交给 MoGe-2。Remove Background 路径会清除全透明像素下的 RGB,Fit to Foreground 路径则可能保留隐藏 RGB;MoGe-2 只读取 RGB,因此两条业务路径当前并不等价。
|
||||
|
||||
几何预测的另一处边界也不统一:MoGe-2 先返回专用 `Prediction`,Normal Writer 直接读取它,Depth Writer 才临时转换为 `GeometryFrame`;DA3 则有另一套转换入口。这样 `GeometryFrame` 没有真正成为模型预测与几何产物之间的稳定协议。
|
||||
|
||||
MoGe-2 返回连续的 Depth/Points Field 和原始 Mask。当前 Depth Writer 会按有效性 Mask 清零 RGB,而 Depth Surface 线性采样 RGB、不读取 Alpha,因此 Mask 边界的零坐标会把网格拉向相机原点。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- 以 MoGe-2 单帧预测的数据类型重建 `GeometryFrame`,并让 MoGe-2 与 DA3 都通过模型适配器产出该类型。
|
||||
- 让 Depth EXR、Normal Texture 和 `depth.json` 只消费 `GeometryFrame`,不直接依赖模型专用预测结构。
|
||||
- 让所有 MoGe-2 调用在同一个 Server 边界获得确定的黑底 RGB 输入。
|
||||
- 让 Depth EXR 分别表达连续数值场与原始模型 Mask,两者互不改写。
|
||||
- 保留严格的 Metadata 校准筛选,并阻止非有限数值进入 Blender。
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- 不修改 BEN2、MoGe-2 或 DA3 模型实现及其推理分辨率。
|
||||
- 不改变 Depth EXR 文件名、尺寸、RGBA 通道布局或节点组接口。
|
||||
- 不用输入 Alpha 覆盖模型 Mask,也不在本次变更中让 Geometry Nodes 按 Alpha 丢弃点。
|
||||
- 不把 DA3 恢复为当前生产路径;仅保持其适配器与统一协议可用、可测试。
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. `GeometryFrame` 是单帧几何预测协议
|
||||
|
||||
`GeometryFrame` 按 MoGe-2 单帧结果定义:
|
||||
|
||||
- `depth: ndarray[H, W]`,必需的 `float32` 深度场;
|
||||
- `normal: ndarray[H, W, 3] | None`,MoGe-2 提供,DA3 可为空;
|
||||
- `validity: ndarray[H, W]`,必需的 `float32` 模型有效性信号;MoGe-2 的原始 Mask 转换为 `0/1`,DA3 保存原始连续 Confidence;
|
||||
- `intrinsics: ndarray[3, 3]`,必需的 `float32` 像素坐标内参;
|
||||
- `points: ndarray[H, W, 3] | None`,可选的 `float32` 相机空间点场;
|
||||
|
||||
构造时校验 dtype、维度和同帧空间尺寸,但不在容器内改写预测值。`validity` 是唯一存储的模型有效性信号;不再同时保存 `mask`、`confidence` 和派生的 `valid_mask`,避免相同职责出现多个可漂移来源。
|
||||
|
||||
MoGe-2 的生产推理入口直接返回一组 `GeometryFrame`,在适配器内完成 batch 拆分、Mask 到 Validity 的转换和内参像素化。用于调试 NPZ 的原始单次推理入口继续返回模型原始字典,因为它不是 Artifact 生产边界。DA3 保留原始调试推理,并提供同样的逐帧适配器:`normal=None`,从深度和内参生成 Points,并把 Confidence 作为连续 Validity。
|
||||
|
||||
不选择在通用层保留 MoGe-2 `Prediction` 再二次转换,因为这会继续允许 Writer 绕过统一协议。也不把 `GeometryFrame` 限定为 MoGe-2 类型,避免 DA3 和后续模型各自复制 Artifact 逻辑。
|
||||
|
||||
### 2. 所有几何 Artifact Writer 只消费 `GeometryFrame`
|
||||
|
||||
Vector Depth Writer 从 `frame.points` 和 `frame.validity` 写 EXR;Z Depth Writer 从 `frame.depth` 和 `frame.validity` 写 EXR;Normal Writer 从 `frame.normal` 生成贴图;Metadata Writer 从 `frame.depth`、`frame.intrinsics` 和调用方提供的业务 Region Mask 计算 `depth.json`。
|
||||
|
||||
Writer 只依赖通用 `GeometryFrame`,不导入 `moge2` 或 `da3`。缺少所需可选字段时明确失败,例如没有 `points` 不能写 Vector Depth,没有 `normal` 不能写 Normal Texture。Artifact 编排层从 MoGe-2 取得一帧 `GeometryFrame` 后,把同一对象传给各 Writer,不再读取模型专用属性。
|
||||
|
||||
Metadata 所需的校准有效性按使用点计算:正的 `frame.validity`、有限且为正的 Depth,以及业务 Region Mask 的交集。它不是 `GeometryFrame` 的第二个持久字段,也不反向影响 EXR Alpha 或 RGB。
|
||||
|
||||
### 3. 在最终 MoGe-2 输入边界统一黑底合成
|
||||
|
||||
读取最终 `region_image_path` 为 RGBA,按输入上限缩放,然后使用 `output_rgb = source_rgb * alpha` 合成到黑底,并始终写为 Job 内的 RGB PNG。即使无需缩放,也经过相同规范化步骤。
|
||||
|
||||
这会让半透明像素保留按 Alpha 衰减后的颜色,并彻底消除 Alpha 为零时隐藏 RGB 的差异。Metadata 和 Normal 输出所需的业务 Alpha 仍从原始 Region 图读取,不从已移除 Alpha 的模型输入读取。
|
||||
|
||||
不在 Blender 的 `prepare_region_input()` 提前处理,因为该入口还服务其他 Job,而且 Fit to Foreground 会在 Server 端重新生成 RGBA,无法形成唯一收口点。
|
||||
|
||||
### 4. Depth RGB 保留连续 Field,Alpha 只记录 `frame.validity`
|
||||
|
||||
Vector/Z Depth Writer 无条件把完整 Points/Depth Field 写入 RGB,并仅把 `frame.validity` 写入 Alpha。零 Validity 不再导致 RGB 清零,使 Depth Surface 在边缘线性采样时仍能得到连续坐标。
|
||||
|
||||
Writer 在创建文件前要求所需 Field 全部有限。Mask 为假不豁免该检查,因为 Geometry Nodes 仍会读取 Mask 外 RGB;NaN/Inf 会传播到网格。有限但非正的 Depth 仍忠实写入,正值条件只属于 Metadata 校准。
|
||||
|
||||
不把非有限值替换为零或最近有效值:前者会重新引入相机原点尖刺,后者不再忠实于模型结果。
|
||||
|
||||
### 5. 测试固定协议、工作流等价与连续性
|
||||
|
||||
测试分为四层:
|
||||
|
||||
1. `GeometryFrame` 校验,以及 MoGe-2/DA3 适配器的字段、形状、dtype、Validity 映射和批次拆分。
|
||||
2. 模型输入验证 Alpha 为 `0`、`0.5`、`1` 的黑底合成,并验证不同隐藏 RGB 得到相同透明区输入。
|
||||
3. Writer 验证只接收 `GeometryFrame`、Validity 为零时 RGB 保留原值、Alpha 等于 `frame.validity`、缺字段与 NaN/Inf 明确失败;Normal 和 Metadata 不再读取 MoGe-2 专用结果。
|
||||
4. Depth Surface 使用边缘 Mask 为假但 XYZ 连续的 Vector Depth,验证求值网格不会聚集到相机原点。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [MoGe-2 返回类型变化会影响调用方] → 生产调用集中在 Artifact 编排层;一次性迁移并删除旧 `Prediction`/转换入口,不保留兼容层。
|
||||
- [GeometryFrame 严格 dtype 会暴露模型适配错误] → 在适配器边界显式转换并用模型级测试固定协议。
|
||||
- [黑底输入会改变当前 Fit to Foreground 的预测] → 这是统一语义的预期行为,用像素级测试固定合成规则。
|
||||
- [零 Validity 区域的有限 Field 可能精度较低] → Alpha 完整保留模型判断供消费者解释;连续 Field 用于避免几何塌缩。
|
||||
- [完整 Field 中一个非有限值会使 Job 失败] → 失败优于生成被 NaN/Inf 污染的网格,错误信息区分 Depth、Point 和 Normal Field。
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. 重建 `GeometryFrame` 与两种模型适配器,迁移 MoGe-2 生产推理返回值并删除旧专用中间结构。
|
||||
2. 将 Depth、Normal 和 Metadata Writer 改为只消费 `GeometryFrame`,再迁移 Artifact 编排层。
|
||||
3. 建立统一的 MoGe-2 黑底输入准备,并补充像素与工作流等价测试。
|
||||
4. 调整 EXR 通道写入与数值检查,增加 Depth Surface 回归测试。
|
||||
5. 更新 GeometryFrame、Artifact 和 Cutout 内部文档并运行全量测试。
|
||||
|
||||
现有 Job 目录中的旧 EXR 不迁移;重新运行对应功能即可生成新语义 Artifact。回退时必须同时回退协议、适配器、Writer 与测试。
|
||||
32
openspec/changes/normalize-moge-alpha-depth/proposal.md
Normal file
32
openspec/changes/normalize-moge-alpha-depth/proposal.md
Normal file
@@ -0,0 +1,32 @@
|
||||
## Why
|
||||
|
||||
同一前景图片通过“Remove Background 后生成 Depth Surface”和“原图启用 Fit to Foreground 后生成 Depth Surface”时,当前会向 MoGe-2 提交不同的隐藏 RGB,导致不同的 Mask 与 Depth 结果;Vector/Z Depth 又按有效 Mask 将 RGB 清零,使连续深度场在 Mask 边界退化到相机原点。与此同时,Depth 与 Normal 产物仍直接读取 MoGe-2 专用 Prediction,绕过了原本用于统一 MoGe-2 与 DA3 几何预测的 `GeometryFrame` 边界。
|
||||
|
||||
## What Changes
|
||||
|
||||
- 在最终 MoGe-2 推理入口统一将 RGBA 按 Alpha 合成到黑底;Alpha 为 `0.5` 的像素以一半原色、一半黑色进入模型,使 Remove Background 与 Fit to Foreground 工作流具有相同的输入语义。
|
||||
- 以 MoGe-2 的单帧预测数据设计统一 `GeometryFrame`:包含 Depth、Normal、Validity、相机内参与可选 Points。Validity 统一承载 MoGe-2 的 `0/1` Mask 或 DA3 的连续 Confidence。
|
||||
- MoGe-2 的生产推理直接返回 `GeometryFrame` 序列;DA3 保留原始 Debug Prediction,并提供到相同 `GeometryFrame` 的适配作为参考路径。
|
||||
- Depth EXR、Normal Map 与 `depth.json` Writer 只消费 `GeometryFrame`,不直接读取 MoGe-2 Prediction 或模型专用字段。
|
||||
- `vector-depth.exr` 的 RGB 对所有像素保存 MoGe-2 原始相机空间 XYZ,不再因 Validity 为零而写成零。
|
||||
- `z-depth.exr` 的 RGB 对所有像素保存 MoGe-2 原始 Depth,不再因 Validity 为零而写成零。
|
||||
- 两种 Depth EXR 的 Alpha 只保存模型原始 Validity,不与输入 Alpha、正深度检查或有限性检查合并。
|
||||
- 非有限 Depth 或 XYZ 不进行静默替换;Artifact 生成明确失败,避免 NaN/Inf 进入 Blender Geometry Nodes。
|
||||
- `GeometryFrame.validity` 是模型有效性信号的唯一事实;Depth Metadata 的参考深度按需组合输入 Alpha、Validity 与数值有效性,但不在 Frame 中保存第二套有效性字段。
|
||||
- **BREAKING(内部产物语义)**:Depth EXR 中 Alpha 为零像素的 RGB 将从固定零值改为模型原始结果;依赖旧清零行为的内部消费者必须同步更新。
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `moge-depth-artifacts`: 规定统一 `GeometryFrame`、MoGe-2 黑底输入以及 GeometryFrame 驱动的 Depth/Normal/Metadata 产物语义。
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
无。
|
||||
|
||||
## Impact
|
||||
|
||||
- 影响 `server/models/geometry.py`、`server/models/moge2.py`、`server/models/da3.py`、Geometry Writer 与其测试。
|
||||
- Cutout Depth Surface 与 Convert to Depth Plane 将消费连续的 Depth RGB;现有 EXR 文件名、尺寸、通道布局和 Job 返回协议保持不变。
|
||||
- 不改变 BEN2 模型、MoGe-2 模型、Blender Operator 标识符、节点组接口或外部依赖。
|
||||
@@ -0,0 +1,113 @@
|
||||
## Purpose
|
||||
|
||||
统一透明 Region 的 MoGe-2 输入像素语义,并规定 Depth EXR 独立保存连续模型结果与模型 Validity,使不同前景工作流生成一致、可解释且不会在有效性边界坍缩的几何产物。
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: GeometryFrame 是统一几何预测边界
|
||||
|
||||
系统 SHALL 以单帧 `GeometryFrame` 表示供产物生成使用的几何预测。Frame SHALL 包含二维 float32 Depth、同尺寸 float32 Validity、3×3 float32 像素空间相机内参,以及可选的同尺寸三通道 float32 Normal 与 Points。Validity SHALL 统一保存模型提供的逐像素有效性信号。
|
||||
|
||||
#### Scenario: MoGe-2 预测适配
|
||||
- **WHEN** MoGe-2 完成一帧预测
|
||||
- **THEN** 系统生成包含 Depth、Normal、由原始 Mask 转换而来的 `0/1` Validity、像素空间相机内参与按需 Points 的 `GeometryFrame`
|
||||
|
||||
#### Scenario: DA3 预测适配
|
||||
- **WHEN** DA3 预测被转换为统一几何结果
|
||||
- **THEN** 系统生成包含 Depth、派生 Points、由原始 Confidence 提供的连续 Validity 与相机内参的 `GeometryFrame`,且 Normal 为空
|
||||
|
||||
#### Scenario: Frame 字段维度不一致
|
||||
- **WHEN** 任一像素 Field 的高宽与 Depth 不一致,或相机内参不是 3×3
|
||||
- **THEN** `GeometryFrame` 构建失败并报告字段维度错误
|
||||
|
||||
### Requirement: Geometry Artifact 只消费 GeometryFrame
|
||||
|
||||
系统 SHALL 从 `GeometryFrame` 生成 Vector Depth、Z Depth、Normal Map 与 Depth Metadata,Artifact Writer SHALL NOT 直接依赖 MoGe-2 或 DA3 专用 Prediction 类型。
|
||||
|
||||
#### Scenario: 生成 Vector Depth
|
||||
- **WHEN** 一个 `GeometryFrame` 包含 Points
|
||||
- **THEN** Vector Depth Writer 从 Frame 的 Points 与 Validity 生成 `vector-depth.exr`
|
||||
|
||||
#### Scenario: 生成 Z Depth 与 Metadata
|
||||
- **WHEN** 一个 `GeometryFrame` 包含 Depth、Validity 与 Intrinsics
|
||||
- **THEN** Z Depth 与 Metadata Writer 从该 Frame 生成 `z-depth.exr` 与 `depth.json`
|
||||
|
||||
#### Scenario: 生成 Normal Map
|
||||
- **WHEN** 一个 `GeometryFrame` 包含 Normal
|
||||
- **THEN** Normal Writer 从 Frame 的 Normal 及调用方提供的 Region 可见 Mask 生成 Normal Map
|
||||
|
||||
#### Scenario: 缺少所需 Field
|
||||
- **WHEN** Writer 请求的 Points 或 Normal 在 `GeometryFrame` 中为空
|
||||
- **THEN** 产物生成失败并报告缺少对应 Geometry Field
|
||||
|
||||
### Requirement: MoGe-2 使用统一黑底输入
|
||||
|
||||
系统 SHALL 在 MoGe-2 推理前将最终 Region RGBA 合成到黑底,模型 RGB SHALL 等于源 RGB 乘以归一化 Alpha。
|
||||
|
||||
#### Scenario: 完全透明像素
|
||||
- **WHEN** 最终 Region 像素的 Alpha 为 `0`
|
||||
- **THEN** MoGe-2 接收到的对应 RGB 为 `(0, 0, 0)`
|
||||
|
||||
#### Scenario: 半透明像素
|
||||
- **WHEN** 最终 Region 像素的 Alpha 为 `0.5`
|
||||
- **THEN** MoGe-2 接收到的对应 RGB 为源 RGB 的一半
|
||||
|
||||
#### Scenario: 完全不透明像素
|
||||
- **WHEN** 最终 Region 像素的 Alpha 为 `1`
|
||||
- **THEN** MoGe-2 接收到的对应 RGB 与源 RGB 相同
|
||||
|
||||
#### Scenario: 前景工作流输入一致
|
||||
- **WHEN** Remove Background 与 Fit to Foreground 产生相同的可见 RGB 和 Alpha,仅完全透明像素下的隐藏 RGB 不同
|
||||
- **THEN** 两条工作流提交给 MoGe-2 的模型 RGB 完全相同
|
||||
|
||||
### Requirement: Vector Depth 独立保存 Points 与 Validity
|
||||
|
||||
系统 SHALL 在 `vector-depth.exr` 的 RGB 中保存 `GeometryFrame.points` 的每个原始有限相机空间 XYZ,且 SHALL 不因 `GeometryFrame.validity` 为零而修改 XYZ;Alpha SHALL 只保存 `GeometryFrame.validity`。
|
||||
|
||||
#### Scenario: Validity 为零的有限 Point
|
||||
- **WHEN** MoGe-2 为一个像素返回有限 XYZ 且原始 Mask 转换得到的 Validity 为 `0`
|
||||
- **THEN** EXR RGB 等于该 XYZ,Alpha 等于 `0`
|
||||
|
||||
#### Scenario: Validity 为一的有限 Point
|
||||
- **WHEN** MoGe-2 为一个像素返回有限 XYZ 且原始 Mask 转换得到的 Validity 为 `1`
|
||||
- **THEN** EXR RGB 等于该 XYZ,Alpha 等于 `1`
|
||||
|
||||
#### Scenario: 输入 Alpha 不改变 Vector Depth Alpha
|
||||
- **WHEN** Region 输入 Alpha 与 MoGe-2 原始 Mask 不同
|
||||
- **THEN** `vector-depth.exr` Alpha 等于由 MoGe-2 原始 Mask 转换得到的 Validity
|
||||
|
||||
### Requirement: Z Depth 独立保存 Depth 与 Validity
|
||||
|
||||
系统 SHALL 在 `z-depth.exr` 的 RGB 三个通道中保存 `GeometryFrame.depth` 的每个原始有限 Depth,且 SHALL 不因 `GeometryFrame.validity` 为零而修改 Depth;Alpha SHALL 只保存 `GeometryFrame.validity`。
|
||||
|
||||
#### Scenario: Validity 为零的有限 Depth
|
||||
- **WHEN** MoGe-2 为一个像素返回有限 Depth 且原始 Mask 转换得到的 Validity 为 `0`
|
||||
- **THEN** EXR RGB 三个通道均等于该 Depth,Alpha 等于 `0`
|
||||
|
||||
#### Scenario: Validity 为一的有限 Depth
|
||||
- **WHEN** MoGe-2 为一个像素返回有限 Depth 且原始 Mask 转换得到的 Validity 为 `1`
|
||||
- **THEN** EXR RGB 三个通道均等于该 Depth,Alpha 等于 `1`
|
||||
|
||||
#### Scenario: 输入 Alpha 不改变 Z Depth Alpha
|
||||
- **WHEN** Region 输入 Alpha 与 MoGe-2 原始 Mask 不同
|
||||
- **THEN** `z-depth.exr` Alpha 等于由 MoGe-2 原始 Mask 转换得到的 Validity
|
||||
|
||||
### Requirement: Depth Artifact 拒绝非有限结果
|
||||
|
||||
系统 MUST 在写入 Depth EXR 前校验所有待写入 Depth 或 XYZ;任何通道包含 NaN 或 Inf 时 MUST 终止 Artifact 生成并报告错误,且 MUST NOT 以零值替换。
|
||||
|
||||
#### Scenario: Vector Depth 包含非有限值
|
||||
- **WHEN** 任意原始 XYZ 分量为 NaN 或 Inf
|
||||
- **THEN** `vector-depth.exr` 生成失败并报告无效 Point Field
|
||||
|
||||
#### Scenario: Z Depth 包含非有限值
|
||||
- **WHEN** 任意原始 Depth 为 NaN 或 Inf
|
||||
- **THEN** `z-depth.exr` 生成失败并报告无效 Depth Field
|
||||
|
||||
### Requirement: 校准筛选不改写 Depth Artifact
|
||||
|
||||
系统 SHALL 按需使用输入 Alpha、正的 `GeometryFrame.validity`、正 Depth 与有限性共同筛选 Depth Metadata 的参考样本,但 SHALL NOT 把该派生筛选结果存为 Frame 的第二套有效性字段,且 SHALL NOT 改写 Depth EXR 的 RGB 或 Alpha。
|
||||
|
||||
#### Scenario: 零 Validity 区域存在连续 Depth
|
||||
- **WHEN** Validity 为零的区域存在有限 Depth 或 XYZ
|
||||
- **THEN** 这些值保留在 EXR RGB 中,同时不进入参考深度计算
|
||||
23
openspec/changes/normalize-moge-alpha-depth/tasks.md
Normal file
23
openspec/changes/normalize-moge-alpha-depth/tasks.md
Normal file
@@ -0,0 +1,23 @@
|
||||
## 1. 统一 GeometryFrame 边界
|
||||
|
||||
- [x] 1.1 按单帧 MoGe-2 数据重建 `GeometryFrame`:定义 Depth、Normal、Validity、Intrinsics、Points 字段及 dtype/shape 校验,删除 `mask`、`confidence`、`valid_mask`、`model_mask` 多重状态并补充单元测试。
|
||||
- [x] 1.2 让 MoGe-2 生产推理直接返回 `GeometryFrame` 序列,在适配器中完成 batch 拆分、Mask 到 `0/1` Validity 的转换和内参像素化;删除旧 `Prediction` 与二次转换入口,并验证每个字段忠实来自原始预测。
|
||||
- [x] 1.3 为 DA3 保留原始调试推理并实现 `GeometryFrame` 适配器,验证 `normal=None`、派生 Points、Intrinsics 和由 Confidence 提供的连续 Validity,保持该参考路径可用。
|
||||
|
||||
## 2. 统一 MoGe-2 输入
|
||||
|
||||
- [x] 2.1 将模型输入准备改为始终读取最终 Region RGBA、按输入上限缩放并以 `RGB × Alpha` 合成到黑底;用像素测试验证 Alpha 为 `0`、`0.5`、`1` 的输出。
|
||||
- [x] 2.2 增加不同隐藏 RGB 的工作流等价测试,验证可见 RGB 与 Alpha 相同时生成完全一致的 MoGe-2 RGB 输入;运行相关 Server Job 测试。
|
||||
|
||||
## 3. 让几何产物只消费 GeometryFrame
|
||||
|
||||
- [x] 3.1 修改 Vector/Z Depth Writer,使其只接收 `GeometryFrame`,完整写入有限的 Points/Depth RGB,并把 `frame.validity` 单独写入 Alpha;用 EXR 回读测试验证 Validity 为零时 Field 仍保留。
|
||||
- [x] 3.2 为 Depth Writer 增加缺少 Points、NaN/Inf 失败测试,验证错误明确区分 Point Field 与 Depth Field,且失败时不生成 EXR。
|
||||
- [x] 3.3 修改 Normal Writer 只从 `GeometryFrame.normal` 读取预测,保留业务 Region Mask 的可见性处理,并增加缺少 Normal 与非有限值测试。
|
||||
- [x] 3.4 修改 Metadata Writer 从 `GeometryFrame` 按需计算正 Validity、正且有限 Depth、业务 Region Mask 的校准交集;迁移 Artifact 编排层,使其不再读取 MoGe-2 专用预测字段,并运行 Server Job/Runtime 测试。
|
||||
|
||||
## 4. Depth Surface 回归与文档
|
||||
|
||||
- [x] 4.1 增加边缘 Mask 为假但 XYZ 连续的 Depth Surface 测试,验证求值网格不会聚集到相机原点;运行 `uv run pytest tests/test_cutout_objects.py tests/test_node_assets.py`。
|
||||
- [x] 4.2 更新 GeometryFrame、模型适配、MoGe 输入、Depth/Normal/Metadata Artifact 语义及 Cutout Runtime 文档;运行 `uv run pytest tests/test_docs.py`,不构建文档产物。
|
||||
- [x] 4.3 运行 `uv run pytest` 完成全量回归,确认两条前景工作流、Depth Plane、Depth Surface、打包和文档检查全部通过。
|
||||
@@ -0,0 +1,3 @@
|
||||
schema: spec-driven
|
||||
created: 2026-08-31
|
||||
skip_specs: true
|
||||
97
openspec/changes/reorganize-common-modules/design.md
Normal file
97
openspec/changes/reorganize-common-modules/design.md
Normal file
@@ -0,0 +1,97 @@
|
||||
## Context
|
||||
|
||||
`src/anyimage/common/` 当前有七个模块,其中主要问题不是文件数量,而是少数函数位于不符合业务认知的位置:通用 AI UI 位于 `image_interaction.py`,`object.py` 中的大部分代码实际负责材质,多个文件名又使用宽泛的 `*_data` 或 `*_interaction` 后缀。
|
||||
|
||||
调用方直接从具体模块导入函数,`common/__init__.py` 不承担公共导出。迁移必须一次性更新所有调用方并删除旧路径,不增加转发模块或重导出。`server/` 仍保持独立,不能引用上级模块。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- 使用少量、稳定的业务名词,使函数位置容易预测。
|
||||
- 修正明显错位的 AI UI 与材质函数,同时避免为了追求形式纯粹而拆出大量小文件。
|
||||
- 保持函数行为、Job 字典、Operator 行为与 Blender 数据结果不变。
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- 不要求每个模块只有一种技术副作用;同一业务对象的读取、输入准备与结果应用可以集中存在。
|
||||
- 不重写算法、调整 UI、改变公开 Blender 标识符或 Job 协议。
|
||||
- 不增加 Facade、抽象基类、动态导入或 `common/__init__.py` 重导出。
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. 采用八个业务模块
|
||||
|
||||
目标目录如下:
|
||||
|
||||
| 模块 | 职责 | 来源与主要内容 |
|
||||
| --- | --- | --- |
|
||||
| `ai.py` | Blender 侧所有共享 AI 准备能力 | 合并 `ai_job.py` 全部函数,以及 `draw_ai_setup()`、`draw_ai_property()` |
|
||||
| `image.py` | Blender Image 与 Image Empty 的完整生命周期 | 原 `image_data.py` 全部函数 |
|
||||
| `region.py` | Region 值、序列化、栅格化与 Alpha 裁切 | 原 `image_region.py` 全部内容 |
|
||||
| `viewport.py` | View3D 坐标投影、点击解析、工具设置、手势状态与 Overlay 绘制 | 原 `image_interaction.py` 除 AI UI 外的全部内容 |
|
||||
| `depth.py` | Depth 产物导入、校验与尺度换算 | 原 `depth_data.py` 全部内容 |
|
||||
| `material.py` | Image 材质节点树构建与配置 | 从 `object.py` 迁移 `material_color_space_name()`、`set_material_color_space()`、`material_node_group()`、`create_image_material()`、`set_displacement_only()` |
|
||||
| `object.py` | Object 与 Modifier 的共享构建收尾 | 保留 `modifier_input_identifier()`、`set_modifier_input()`、`finalize_object_result()` 及其私有辅助函数 |
|
||||
| `node.py` | 随扩展分发的 Node Group 资产加载 | 原 `node.py` 保持不变 |
|
||||
|
||||
这套分类以开发者查找路径为优先:想处理 AI、Image、Region、Viewport、Depth、Material、Object 或 Node 时,只需选择对应名词;所有不修改 Image 数据、只负责 View3D 输入与显示反馈的函数统一位于 `viewport.py`。
|
||||
|
||||
`image.py` 虽然体量较大,但其中函数共同覆盖 Blender Image 从读取、输入准备、结果导入到 Empty 替换的完整生命周期。拆成 `image_input`、`image_result`、`image_empty` 会迫使多数 Image Operator 同时依赖三至四个文件,增加导航成本,因此不采用。
|
||||
|
||||
`viewport.py` 保留交互上下文、二维预览几何和 Modal 手势。它们共同描述 View3D 中“如何点击、投影、绘制和完成手势”,且共享大量私有辅助函数;拆成 `viewport_draw`、`viewport_gesture` 和 `viewport_context` 对当前规模收益有限。
|
||||
|
||||
### 2. AI 能力使用单一入口
|
||||
|
||||
`ai.py` 同时容纳环境/模型检查、输入校验、参数组装和两项通用 UI 绘制函数。它们都是 Operator 在启动或呈现 AI 功能时使用的共享能力,调用方无需判断某项能力属于 Job、状态还是 UI 子分类。
|
||||
|
||||
备选方案是保留 `ai_job.py` 并新增 `ai_ui.py`。该方案能按技术层分离 UI,却会为两个很短的函数增加模块,并且不能满足“所有 AI 使用方容易找到”的首要目标,因此不采用。
|
||||
|
||||
### 3. 只对 Object 做一次有价值的拆分
|
||||
|
||||
`create_image_material()` 及其辅助函数构成独立、体量较大的材质构建单元,迁移到 `material.py` 后,`object.py` 自然剩下 Object 与其 Modifier 的构建收尾。Modifier 不再单独拆文件,因为只有两个公共入口,且全部由 Object 构建流程消费。
|
||||
|
||||
`node.py` 不改名为 `node_asset.py`:当前文件只负责 Node Group 资产加载,名称已经足够明确,改名不会改善边界。
|
||||
|
||||
### 4. 文件名简化,但函数名和行为保持不变
|
||||
|
||||
`image_data.py`、`image_region.py`、`image_interaction.py`、`depth_data.py` 分别迁移为 `image.py`、`region.py`、`viewport.py`、`depth.py`。迁移只修正模块名和导入,不顺带重命名函数或修改算法。
|
||||
|
||||
完成后直接删除被替代文件,不保留兼容转发;所有生产代码、测试和文档在同一变更中更新。
|
||||
|
||||
### 5. 依赖关系保持简单
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Operator["operators/"] --> AI["ai"]
|
||||
Operator --> Viewport["viewport"]
|
||||
Operator --> Image["image"]
|
||||
Operator --> Depth["depth"]
|
||||
Operator --> Material["material"]
|
||||
Operator --> Object["object"]
|
||||
Viewport --> AI
|
||||
Viewport --> Image
|
||||
Viewport --> Region["region"]
|
||||
Depth --> Image
|
||||
Material --> Image
|
||||
Material --> Node["node"]
|
||||
```
|
||||
|
||||
`region.py` 保持与 Blender UI 无关;`image.py` 不反向依赖编辑、材质或 Object 构建;`common/__init__.py` 不隐藏函数来源。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [直接删除旧路径会使遗漏导入立即失败] → 全仓库检查旧模块名并运行完整测试。
|
||||
- [较大的 `image.py` 与 `viewport.py` 不是技术上最纯的分层] → 优先保证业务内聚与导航效率;只有出现第二个独立消费者群或显著循环依赖时再拆分。
|
||||
- [机械移动可能夹带行为变化] → 保持函数体、签名和私有辅助函数,只修改导入与模块说明。
|
||||
- [Material 移出后可能遗漏 Object 调用方] → 对 `create_image_material()` 和相关辅助函数执行全仓库引用检查并运行 Object 测试。
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. 将 `ai_job.py` 迁移为 `ai.py`,并从 `image_interaction.py` 接收通用 AI UI 函数。
|
||||
2. 将四个宽泛文件名迁移为业务名称:`image.py`、`region.py`、`viewport.py`、`depth.py`。
|
||||
3. 从 `object.py` 提取 `material.py`,保留 Object 与 Modifier 函数;`node.py` 保持原状。
|
||||
4. 更新生产代码、测试和文档的直接导入,确认无旧路径引用后删除旧文件。
|
||||
5. 运行完整测试验证行为不变。
|
||||
|
||||
本变更不涉及持久化数据迁移。若实现阶段需要回退,应整体回退该变更,而不是恢复兼容转发模块。
|
||||
28
openspec/changes/reorganize-common-modules/proposal.md
Normal file
28
openspec/changes/reorganize-common-modules/proposal.md
Normal file
@@ -0,0 +1,28 @@
|
||||
## Why
|
||||
|
||||
`common/` 当前以功能演进过程形成分类,部分模块同时容纳数据、I/O、UI、交互与绘制职责,导致公共函数的位置不能由名称直接判断;例如通用 AI UI 函数 `draw_ai_setup()` 位于 `image_interaction.py`。重新建立稳定、可预测的模块边界,可以降低新增功能复用公共能力时的查找与依赖成本。
|
||||
|
||||
## What Changes
|
||||
|
||||
- 将 `common/` 收敛为八个稳定业务模块:`ai`、`image`、`region`、`viewport`、`depth`、`material`、`object` 和 `node`。
|
||||
- 将 `draw_ai_setup()`、`draw_ai_property()` 从 Image 交互分类移至 `ai.py`,与 AI 环境、模型检查和 Job 参数准备形成统一入口。
|
||||
- 保留完整的 Image 生命周期于 `image.py`,将 View3D 坐标、手势和 Overlay 绘制统一归入 `viewport.py`,避免把视口交互误称为图片编辑。
|
||||
- 仅从 `object.py` 独立出体量较大、职责明确的材质构建函数;Modifier 和结果 Object 处理继续归入 Object 分类。
|
||||
- 更新所有 Operator 与测试的直接导入,同时同步 `docs/internals/common.md` 和架构索引。
|
||||
- **BREAKING**:删除被替代的旧模块路径,不提供重导出、转发函数或兼容层;这是仅面向项目内部源码的导入变更,不改变扩展的用户功能与公开 Blender 标识符。
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
无。本变更只重构 Blender 侧内部公共函数的模块边界,不新增用户可观察行为。
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
无。现有功能、Operator 协议、Job 参数和结果保持不变。
|
||||
|
||||
## Impact
|
||||
|
||||
- 主要影响 `src/anyimage/common/` 及所有直接导入这些模块的 `operators/`、`menu.py` 和测试。
|
||||
- `src/anyimage/server/` 的进程边界、Job 协议、模型实现和依赖均不改变。
|
||||
- 不新增依赖,不改变 Blender 类型注册、`bl_idname`、节点组名称或扩展打包内容。
|
||||
17
openspec/changes/reorganize-common-modules/tasks.md
Normal file
17
openspec/changes/reorganize-common-modules/tasks.md
Normal file
@@ -0,0 +1,17 @@
|
||||
## 1. AI 与业务模块命名
|
||||
|
||||
- [x] 1.1 将 `ai_job.py` 迁移为 `ai.py`,并从 `image_interaction.py` 迁入 `draw_ai_setup()` 与 `draw_ai_property()`;运行相关 Operator 导入测试并用 `rg` 确认 AI 公共函数只定义于 `ai.py`。
|
||||
- [x] 1.2 将 `image_data.py`、`image_region.py`、`depth_data.py` 分别迁移为 `image.py`、`region.py`、`depth.py`,保持函数体和签名不变;运行 `uv run pytest tests/test_image_data.py tests/test_cutout_geometry.py tests/test_cutout_objects.py` 验证行为。
|
||||
- [x] 1.3 将移除 AI UI 后的 `image_interaction.py` 迁移为 `viewport.py`,集中 View3D 坐标投影、点击解析、工具设置、手势与 Overlay 绘制;运行 `uv run pytest tests/test_cutout_interaction.py tests/test_blender_addon.py` 验证视口交互函数和模块导入。
|
||||
|
||||
## 2. Material 与 Object 边界
|
||||
|
||||
- [x] 2.1 建立 `material.py`,从 `object.py` 迁移材质颜色空间、Node Group、材质构建和 Displacement 配置函数;运行 `uv run pytest tests/test_image_data.py tests/test_cutout_objects.py` 验证材质结果。
|
||||
- [x] 2.2 收窄 `object.py` 为 Object 与 Modifier 构建收尾,并保持 `node.py` 不变;运行 Object、Convert to Plane 与 Cutout 相关测试验证 Modifier 输入和结果 Object。
|
||||
|
||||
## 3. 调用方、文档与验证
|
||||
|
||||
- [x] 3.1 更新 `operators/`、`menu.py` 和测试的全部直接导入,删除 `ai_job.py`、`image_data.py`、`image_region.py`、`image_interaction.py` 与 `depth_data.py`;使用 `rg` 确认不存在旧模块导入、重导出或兼容转发。
|
||||
- [x] 3.2 更新 Common 模块结构测试,验证八个目标模块可导入、AI UI 定义位置唯一且 `common/__init__.py` 不重导出;运行该测试确认边界规则生效。
|
||||
- [x] 3.3 按八个业务模块更新 `docs/internals/common.md` 和 `docs/internals/architecture.md`;人工核对文档索引与生产源码一致,不构建文档产物。
|
||||
- [x] 3.4 运行 `uv run pytest` 完成全量回归,确认所有 Operator、Job、节点资产、打包和文档检查通过。
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-08-31
|
||||
91
openspec/changes/unify-selection-terminology/design.md
Normal file
91
openspec/changes/unify-selection-terminology/design.md
Normal file
@@ -0,0 +1,91 @@
|
||||
## Context
|
||||
|
||||
当前图片选区业务横跨 Blender 侧数据结构、Viewport 手势、Image Tool、Cutout Tool 和 Server Job,但统一使用 `region`;与此同时 Blender API 也用 Region 表示编辑器窗口区域。两种含义出现在同一调用链中,增加了阅读和查找成本。
|
||||
|
||||
当前工作树已将 Blender 侧共享模块整理为 `common/region.py` 与 `common/viewport.py`。本次变更以该结构为迁移起点,并遵守项目不保留旧入口或兼容层的约束。Server 仍保持独立包边界,不能引用上级共享模块。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- 让图片选区从数据类型到 Job 产物全程只使用 `selection`。
|
||||
- 明确区分图片 Selection 与 Blender Viewport Region。
|
||||
- 用面向用户的 Mesh Detail 代替实现导向的像素采样间距。
|
||||
- 一次性迁移所有内部调用方、测试和文档,不留下混合术语。
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- 不修改路径栅格化、Mask 运算、BEN2 细化或 Normal Map 生成算法。
|
||||
- 不增加新的网格采样密度,也不改变四个既有间距的几何结果。
|
||||
- 不重命名 Blender API 规定的 Region 概念,也不替换与图片选区无关的普通区域表达。
|
||||
- 不改变 AI 可用性门控、Shape 候选项或 Normal Space 规则。
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. 按业务含义迁移,不做全局文本替换
|
||||
|
||||
业务选区主链统一采用以下名词:
|
||||
|
||||
| 当前表达 | 目标表达 |
|
||||
| --- | --- |
|
||||
| `common/region.py` | `common/selection.py` |
|
||||
| `RegionPath` / `RegionMask` / `RegionContours` | `SelectionPath` / `SelectionMask` / `SelectionContours` |
|
||||
| `region_path` / `region_mask` / `region_contours` | `selection_path` / `selection_mask` / `selection_contours` |
|
||||
| `ImageRegionGesture` | `ImageSelectionGesture` |
|
||||
| `SelectCutoutRegion` / `CutoutRegionToShape` | `SelectCutoutSelection` / `CutoutSelectionToShape` |
|
||||
| `RefineImageRegion` / `refine-image-region` | `RefineImageSelection` / `refine-image-selection` |
|
||||
| `refine_region` | `refine_selection` |
|
||||
| `region_image` / `region_bounds` | `selection_image` / `selection_bounds` |
|
||||
| `server/region/refine_region.py` | `server/selection/refine_selection.py` |
|
||||
|
||||
同一规则应用于相关函数、属性、序列化字段、进度消息、临时文件和测试名称。由于项目不保留兼容层,旧模块、Operator ID、Job 类型和字段在迁移完成后直接删除。
|
||||
|
||||
不纳入迁移的名称包括 `context.region`、`context.region_data`、`event.mouse_region_x/y`、Viewport Region 指针与尺寸,以及算法中确实表示一般连通区域而非用户 Selection 的术语。相比机械替换,按语义清单迁移可以避免破坏 Blender API,并使残留检查具有明确判断标准。
|
||||
|
||||
### 2. Selection 是业务名词,Refine 是动作
|
||||
|
||||
属性工厂和三个工具设置分别改为 `refine_selection_property`、`cutout_refine_selection`、`image_box_refine_selection` 与 `image_lasso_refine_selection`,Operator 参数使用 `refine_selection`。界面统一显示 **Refine Selection**,描述说明使用 BEN2 将手势产生的 Selection 收紧到前景。
|
||||
|
||||
相较只改界面文案,此方案让代码与界面保持同一概念;相较继续使用 `fit`,`refine` 更准确地表达已有 AI 操作,并与原名称一致。
|
||||
|
||||
### 3. Normal Map 只缩短用户界面名称
|
||||
|
||||
Cutout 布尔选项显示名从 **Generate Normal Map** 改为 **Normal Map**。`generate_normal` 等执行层标识继续表达“是否生成”这一布尔动作,不为追求表面一致而改成含义更弱的 `normal_map`。
|
||||
|
||||
### 4. Mesh Detail 映射到既有采样间距
|
||||
|
||||
Cutout 设置从 `cutout_point_spacing` 整数属性迁移为 `cutout_mesh_detail` 枚举属性,显示名为 **Mesh Detail**。枚举标识使用稳定字符串 `"LOW"`、`"MEDIUM"`、`"HIGH"`、`"ULTRA"`,使代码标识与界面档位直接对应;创建 Shape 前通过单一映射转换为实际采样间距:
|
||||
|
||||
| Mesh Detail | Sampling Spacing |
|
||||
| --- | --- |
|
||||
| Low | 32 px |
|
||||
| Medium | 16 px |
|
||||
| High | 8 px |
|
||||
| Ultra | 4 px |
|
||||
|
||||
默认值为 Low,与当前默认 32 px 保持一致。转换函数放在使用网格间距的 Cutout 业务边界,后续几何代码仍接收明确的像素间距,不让 UI 档位渗入采样算法。
|
||||
|
||||
相比保留 4–32 的任意整数输入,四档枚举只暴露实际支持和测试的密度;相比直接把 Level 数值传入几何代码,显式映射保留了算法参数的物理含义。
|
||||
|
||||
### 5. Server 协议与文件产物同步切换
|
||||
|
||||
Blender 和 Server 在同一次变更中切换 Job 类型、参数、结果字段及产物文件名。建议的细化产物为 `selection.png` 与 `selection_bounds.json`;独立 Image Selection Job 的通用输出仍可沿用 `image.png` 与 `bounds.json`,但结果字典键使用 `selection_image` 与 `selection_bounds`。
|
||||
|
||||
协议不做双读或双写。这样符合项目移除旧路径的规则,也避免长期维护两套字段;代价是旧会话中尚未完成的 Job 结果不能由新代码恢复。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [遗漏某个业务 `region` 导致混合术语或运行时字段不匹配] → 按模块清单迁移,并用定向 `rg` 结合人工语义复核;测试覆盖 Blender 调用与 Server 返回值两端。
|
||||
- [机械重命名误伤 Blender Viewport Region] → 将 Blender API 名称列入明确保留清单,重点运行手势绘制、投影和 Perspective 相关测试。
|
||||
- [与当前 `reorganize-common-modules` 工作树重叠] → 以其整理后的 `common/selection.py` 目标结构为准,不恢复已删除的旧模块。
|
||||
- [旧 `.blend` 中保存的工具设置名失效] → 接受该迁移成本,不增加兼容属性;工具设置回到新属性的默认值。
|
||||
- [Mesh Detail 顺序与采样间距方向写反] → 使用单一常量映射,并对 Low、Medium、High、Ultra 四档添加参数化测试。
|
||||
- [旧 Job 或临时结果不可恢复] → 同版本同步发布 Blender 与 Server 代码,并接受更新时终止中的旧 Job。
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. 先迁移 Selection 数据模块、类型和纯函数,再更新 Blender 侧所有导入与调用。
|
||||
2. 迁移 Viewport 手势、工具属性和 Operator,同时切换 Mesh Detail 枚举与间距映射,更新注册与逆序注销。
|
||||
3. 同步迁移 Server 包、Job 类型、参数、结果字段和产物文件名。
|
||||
4. 更新测试与内部文档,使用搜索确认剩余 `region` 均属于保留语义。
|
||||
5. 运行相关测试后运行全部测试;若失败,整体回退本次重命名,不引入临时兼容层。
|
||||
28
openspec/changes/unify-selection-terminology/proposal.md
Normal file
28
openspec/changes/unify-selection-terminology/proposal.md
Normal file
@@ -0,0 +1,28 @@
|
||||
## Why
|
||||
|
||||
当前代码把用户圈定的图像选区称为 `region`,容易与 Blender 的 Viewport Region 混淆,也与界面中的选择概念不完全对应;Cutout 还直接暴露像素采样间距,用户难以判断数值与细节的关系。统一业务术语并改用 Mesh Detail 后,代码、公开协议和界面可以使用更直观且彼此对应的表达。
|
||||
|
||||
## What Changes
|
||||
|
||||
- **BREAKING**:将表示图像选区的模块、类型、函数、属性、Operator、Job 参数、返回字段和文件名从 `region` 重命名为 `selection`,不保留兼容别名或转发入口。
|
||||
- 保留 Blender API 固有的 `context.region`、`region_data`、`mouse_region_x` 等名称,以及与选区业务无关的普通空间区域表达。
|
||||
- 将界面选项 **Fit to Foreground** 恢复为 **Refine Selection**,并同步对应的代码标识。
|
||||
- 将界面选项 **Generate Normal Map** 缩写为 **Normal Map**;其布尔语义和生成行为不变。
|
||||
- **BREAKING**:将 Cutout 的连续整数选项 **Mesh Sampling Spacing** 改为四档 **Mesh Detail**;Low、Medium、High、Ultra 分别使用 32、16、8、4 px 的采样间距。
|
||||
- 同步测试和内部文档,使术语、界面名称与当前实现一致。
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `image-selection`: 规定图像工具和 Cutout 工具对选区的统一表达,以及选区细化、Normal Map 与 Cutout Mesh Detail 选项。
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
无。
|
||||
|
||||
## Impact
|
||||
|
||||
- 影响 `common` 的选区数据与 Viewport 交互、Image Tool、Cutout Tool、Server Job、属性定义、注册入口和相关文件布局。
|
||||
- 影响 Blender 内部 Operator ID、Job 类型、序列化参数与结果字段;旧名称不再可用。
|
||||
- 需要同步相关测试与 `docs/internals` 文档;不新增依赖,不改变选区栅格化、AI 细化、Normal Map 生成或既有四种网格采样密度。
|
||||
@@ -0,0 +1,37 @@
|
||||
## Purpose
|
||||
|
||||
统一 Image Tool 与 Cutout Tool 对图片选区的用户表达和外部协议,并以简洁一致的名称呈现选区细化、Normal Map 与 Cutout 网格细节选项。
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Image selection uses one business term
|
||||
系统 SHALL 在 Image Tool、Cutout Tool 及其对外 Job 协议中使用 Selection 表示用户在图片上圈定并栅格化的范围。
|
||||
|
||||
#### Scenario: Selection passes through a tool workflow
|
||||
- **WHEN** 用户使用图片手势圈定范围并提交工具操作
|
||||
- **THEN** 工具状态、Job 参数和 Job 结果中表示该范围的字段使用 Selection 术语
|
||||
|
||||
### Requirement: Selection refinement option is named Refine Selection
|
||||
支持 AI 选区细化的工具 SHALL 将对应布尔选项显示为 **Refine Selection**,且开启后只细化当前 Selection 中的前景内容。
|
||||
|
||||
#### Scenario: User enables selection refinement
|
||||
- **WHEN** 用户在 Image Box、Image Lasso 或 Cutout 中开启 **Refine Selection**
|
||||
- **THEN** 系统使用 AI 将当前 Selection 收紧到其中的前景内容
|
||||
|
||||
### Requirement: Cutout normal option is named Normal Map
|
||||
Cutout Tool SHALL 将控制法线贴图生成的布尔选项显示为 **Normal Map**,并保持现有 Normal Map 生成行为。
|
||||
|
||||
#### Scenario: User enables Normal Map
|
||||
- **WHEN** 用户在 Cutout 中开启 **Normal Map** 并选择可执行该功能的 Shape
|
||||
- **THEN** 系统按该 Shape 的既定 Normal Space 生成并应用 Normal Map
|
||||
|
||||
### Requirement: Cutout mesh detail uses named presets
|
||||
Cutout Tool SHALL 使用 **Mesh Detail** 档位选择控制网格采样密度,并将 Low、Medium、High、Ultra 分别映射为 32、16、8、4 px 的采样间距。
|
||||
|
||||
#### Scenario: User chooses mesh detail
|
||||
- **WHEN** 用户选择任一 **Mesh Detail** 档位并创建 Cutout Shape
|
||||
- **THEN** 系统使用该档位对应的采样间距构建网格,且从 Low 到 Ultra 逐档增加采样密度
|
||||
|
||||
#### Scenario: User keeps the default mesh detail
|
||||
- **WHEN** 用户未修改 **Mesh Detail**
|
||||
- **THEN** 系统使用 Low 对应的 32 px 采样间距
|
||||
22
openspec/changes/unify-selection-terminology/tasks.md
Normal file
22
openspec/changes/unify-selection-terminology/tasks.md
Normal file
@@ -0,0 +1,22 @@
|
||||
## 1. 迁移 Selection 基础类型
|
||||
|
||||
- [x] 1.1 将 `common/region.py` 迁移为 `common/selection.py`,把图片选区类型、函数、参数与返回值统一重命名为 Selection,并运行 `uv run pytest tests/test_cutout_geometry.py tests/test_cutout_objects.py` 验证栅格化和几何行为不变
|
||||
- [x] 1.2 更新 `common/image.py` 与 `common/viewport.py` 的选区输入、手势基类、设置辅助函数和所有调用方,同时保留 Blender Viewport Region API 名称,并运行相关 image data、clipboard 和手势测试验证交互与投影行为
|
||||
|
||||
## 2. 迁移 Blender 工具
|
||||
|
||||
- [x] 2.1 将属性工厂、三个工具设置和 Operator 参数统一为 `refine_selection`,把显示名改为 **Refine Selection**,把 Cutout 法线选项显示名改为 **Normal Map**,并运行属性与工具设置测试验证名称、独立设置和 AI 门控
|
||||
- [x] 2.2 将 `cutout_point_spacing` 迁移为默认 Low 的 `cutout_mesh_detail` 四档枚举,在 Cutout 业务边界将 Low、Medium、High、Ultra 映射为 32、16、8、4 px,并用参数化测试验证全部映射及采样密度顺序
|
||||
- [x] 2.3 将 Image Tool 的 Selection 数据流、细化 Operator、Operator ID、Job 类型和注册入口迁移到新名称,并运行 Image Tool 与注册测试验证本地和 AI 两条路径
|
||||
- [x] 2.4 将 Cutout Tool 的 Selection Operator、交互传参、Mask/Contour 使用和结果读取迁移到新名称,并运行 `uv run pytest tests/test_cutout_interaction.py tests/test_cutout_geometry.py tests/test_cutout_objects.py` 验证 Shape 菜单、Mesh Detail 与对象构建行为
|
||||
|
||||
## 3. 迁移 Server 协议
|
||||
|
||||
- [x] 3.1 将 `server/region/` 与 Image Selection Job 文件迁移到 Selection 命名,更新 `refine-image-selection` 注册、参数、进度消息、结果字段和细化产物文件名,并运行 Server runtime 测试验证 Job 输出
|
||||
- [x] 3.2 同步 Blender 与 Server 两端的 `selection_image`、`selection_bounds` 和 `refine_selection` 协议,更新打包断言,并运行 `uv run pytest tests/test_server_runtime.py tests/test_extension_packaging.py tests/test_blender_addon.py` 验证跨进程契约和扩展内容
|
||||
|
||||
## 4. 同步文档与完整验证
|
||||
|
||||
- [x] 4.1 更新 `docs/internals`、getting started 与相关索引,将图片业务范围正面描述为 Selection,并确认 **Refine Selection**、**Normal Map**、**Mesh Detail** 档位映射和新 Job/产物协议一致
|
||||
- [x] 4.2 使用 `rg` 检查源码、测试和文档中的 `region`,逐项确认剩余结果仅为 Blender Viewport Region 或与图片选区无关的一般区域表达,且不存在旧模块、旧类型、旧 Operator、旧 Job、旧字段或兼容转发
|
||||
- [x] 4.3 运行 `uv run pytest`,确认全部测试通过且 Selection 重命名未改变现有功能
|
||||
Reference in New Issue
Block a user