Refactor geometry node groups for image depth processing

- Introduced new utility functions in common nodes for evaluating fields and capturing attributes.
- Simplified volume field calculations in image depth cutout and panorama groups by utilizing new utility functions.
- Enhanced readability and maintainability of the image depth cutout and panorama node groups by removing redundant code and improving function usage.
- Adjusted default values for thickness and depth scale in image relief plane group for better user experience.
- Improved handling of geometry attributes and connections in image depth plane group to streamline processing.
This commit is contained in:
2026-09-10 16:46:19 +08:00
parent 489003c2cc
commit 8ae3c1d5b7
20 changed files with 553 additions and 473 deletions

View File

@@ -0,0 +1,3 @@
schema: spec-driven
skip_specs: true
created: 2026-09-10

View File

@@ -0,0 +1,79 @@
## Context
动机见 `proposal.md`。`tools/nodes/build.py` 构建七个几何节点组和三个材质节点组;材质组作为属性消费者纳入检查。现有测试包含真实 Blender 求值,也有通过临时属性或默认节点编号定位中间阶段的用例。
`docs/internals/node-assets.md` 当前按跨区域距离推荐命名属性。Depth Cutout 的 `_depth_volume` 同时依赖 `Store Named Attribute.005`、`Math.018` 等默认编号,并通过几何输入反查阶段。删除存储节点必须同步调整这些连接。
## Goals / Non-Goals
以等价几何、求值域、数据类型、属性版本和求值时机为验收边界,简化字段传递。修改器接口、几何结果及对外属性协议保持一致。
## Decisions
### 按实际消费者判断字段传递
以构建入口为清单,逐项记录 Store 的名称、类型、域、Selection、输入几何、读者及读取位置。重复写入同名属性按不同版本追踪,检查输入网格和材质中的外部读写;消费次数仅作为排查线索。
```mermaid
flowchart TD
A[字段生产与消费] --> B{需要按名称对外访问}
B -->|是| C[命名属性及明确的生命周期]
B -->|否| D{目标上下文重新求值是否等价}
D -->|是| E[直接连接字段]
E --> F[显式表达必要的域与类型转换]
D -->|否| G[在源几何和源域捕获字段]
G --> H[随几何传递匿名属性并验证传播]
```
直连允许多个消费者。跨区域或连线较长交给布局处理。只要几何、域或输入属性版本变化会改变字段结果,即使只有一个消费者,也保留求值快照。Capture 必须接入产生该快照的几何链,并沿分支传播至消费者;确有按名称访问需求时才使用 Store Named Attribute。
### 已定位的调整清单
下表是源码核查结果;涉及上下文传播的候选必须通过 Blender 求值确认后落地。
| 范围 | 当前字段或链路 | 调整判断 |
| --- | --- | --- |
| 共用 Depth Surface;Depth Plane、Depth Cutout、Panorama | `o_depth_face_center`、`o_depth_face_camera` | 相邻面采样和分裂前计算优先直接连接;显式保持 FACE 求值,尤其保证图像在面中心采样后再用于角域,避免变成逐点采样的平均值 |
| 共用 Depth Surface | `o_depth_camera` | 当前结果写入 POINT 后只供紧接的投影字段使用,优先改为返回字段;保持 CORNER 到 POINT 的转换顺序 |
| 共用 Depth Surface | `o_depth_corner_camera`、`o_depth_cut_vertex` | 跨 Split Edges 和删面保存分裂前数据;保留快照,优先用匿名属性传递 |
| 共用厚度构建 | `o_depth_surface_position`、`o_depth_source_vertex`、`o_depth_surface_normal` | 跨展平、挤出、合并、恢复位置使用;保留源位置、身份和法线快照,验证匿名属性在所有分支上的传播 |
| Depth Cutout | 中心 seed 写入 `o_balloon_surface_center`,读取做 Blur,再覆盖同名属性 | seed 直接接 Blur;最终中心值跨壳体变形的快照独立保存,避免改变 Blur 权重和域 |
| Depth Cutout | `rim`、`center`、`thickness`、`edge_weight`、`front_delta`、`normal`、`structure`、`front_normal`、`inflation_normal` | 逐版本核对计算与壳体消费者;局部算术直连,源表面上的 Blur、Normal、边界与统计结果在变形前固定;Uniform 与 Balloon 分支都提供消费者所需数据 |
| Panorama | `o_panorama_direction`、`o_panorama_uv`、`o_panorama_distance`、`o_panorama_invalid` | 同时检查删面、分裂、极点和周期采样;等价上下文的 UV 与采样直连,需保留原球面数据的路径捕获;invalid 的 POINT 到 FACE 聚合需显式保留 |
| Image Plane | Grid、Cube 写入 `UVMap` | 输出 UV 是材质接口,保留命名属性及 CORNER 域 |
| Image Cutout、Depth Balloon、Depth Cutout | `o_balloon`、`o_normal_scale` | 核对 Shape 输入和材质消费者,保留命名协议、正背面掩码和域 |
| Relief Plane 及三个材质组 | UV 与材质属性读取 | 检查实际生产者及外部消费边界,保证现有着色与位移行为 |
不采用按读者数量自动消除 Store 的图优化器:域转换、同名覆盖和隐式字段上下文需要业务判断,直接修改构建函数更容易验证。
### 通过函数返回值连接阶段
共享构建函数按需要返回几何 socket 与字段 socket,调用方显式传递。Depth Cutout 直接获得投影表面、厚度构建和恢复位置等阶段引用,替换本次影响到的默认编号定位和节点输入反查。简单场景用普通返回值或元组;确需多个有名称的输出时用小型字典。
复用 `tools/nodes/common` 的现有辅助函数;仅在多个实际调用方共享同一操作时提取公共函数。完成调用方迁移后删除失去业务用途的存取辅助函数与临时属性清理节点。
### 规范修改内容
在 `AGENTS.md` 的 Blender 节点组规范加入简短原则,在 `docs/internals/node-assets.md` 替换现有三条字段入口和暂存规则:
- 字段默认直接连接,多个消费者可复用同一输出;以实际消费位置的几何、域、类型和输入属性版本验证等价性。
- 域转换使用 Evaluate on Domain 或明确域的采样节点表达;跨几何变化需要固定源值时使用 Capture Attribute,并明确捕获时机和传播路径。
- 命名属性用于需要按名称访问的数据协议;明确名称、数据类型、域、写入选择和消费者。内部临时命名属性使用专用 `o_*` 前缀,在最后消费者之后按该前缀清理,保留 UV 和外部协议属性。
- 布局通过区域内 Group Input、字段分支排列和必要的 Reroute 保持可读;新增存储须有数据生命周期依据。
- 构建阶段通过明确节点或 socket 引用接线。
### 验证与资产交付
先记录当前真实几何行为和各组存取节点数量,作为结果与简化规模的基线。数量只用于报告;测试以等价求值和必要数据边界为主。
复用并补充面域与角域不一致的非均匀深度、Split 开关、零厚度及正厚度、独立重叠表面、Balloon/Uniform 与法线平滑、Panorama 接缝与无效像素场景。对不再存在的临时属性测试,改为通过测试输出捕获待验证字段或检查最终网格,不为测试保留生产命名属性。
运行相关节点与材质测试,执行 `uv run node-group build`,完成保存后独立 Blender 加载验证,再运行 `uv run pytest` 并确认退出成功。检查重建资产的接口、布局、UV、材质属性及临时属性清理;源码、测试、规范和 `.blend` 资产作为一个完整变更交付。
## Risks / Trade-offs
- 字段直连推迟求值或改变域转换顺序 → 使用面内非均匀输入验证;保留明确的域转换和必要快照。
- 匿名属性跨分支、挤出或合并丢失 → 核对每条几何来源,并检查最终网格的顶点身份、封口和法线。
- 同名属性覆盖导致读取错误版本 → 拆出不同阶段的字段引用,明确消费者依赖的版本。
- 删除存储改变默认节点编号 → 同步替换受影响的隐式接线,检查最终真实连接。
- 直连使布局跨度增加或重复计算 → 使用现有排列器验证可读性;只有实际求值证据支持时引入捕获。

View File

@@ -0,0 +1,29 @@
## Why
几何节点中存在仅为传递中间字段而写入、读取命名属性的链路,增加节点数量和隐式依赖。现行节点资产规范以跨区域连线作为命名存储的依据,需要统一改为按字段求值上下文与数据生命周期选择传递方式。
## What Changes
- 全面检查构建入口中的几何节点组及共享构建函数,沿几何链、字段链和外部消费者记录命名属性的存取域、求值时机与用途。
- 同一几何状态与等价求值域中的中间字段优先直连;显式保留必要的域转换,删除冗余存取及失去用途的清理节点和辅助函数。
- 需要固定变形前、拓扑变化前或分支源几何上的值时优先使用 Capture Attribute;需要按名称供材质、输入网格或其他消费者访问的属性继续使用命名属性。
- 调整受节点数量变化影响的构建接线,使用明确返回的节点或 socket 引用表达业务连接。
- 更新 `AGENTS.md` 与 `docs/internals/node-assets.md` 的节点属性规范,按新规范统一整理节点连线。
- 更新相关测试,重建并验证 `.blend` 资产,确认几何、UV、材质与修改器接口行为一致。
## Capabilities
### New Capabilities
无。本变更属于内部节点重构与开发规范调整,使用 `skip_specs: true`。
### Modified Capabilities
无。保持现有公开接口和几何行为。
## Impact
- `tools/nodes/common`、`tools/nodes/groups`,重点是 Depth Surface、Depth Cutout 和 Panorama。
- `tools/nodes/arrangement` 的现有布局能力与相关测试需验证能正确处理直连及匿名属性;仅在发现实际问题时修改。
- `tests/tools/nodes`、相关 Operator 与材质测试、`src/anyimage/assets/O_AnyImage.blend`。
- `AGENTS.md`、`docs/internals/node-assets.md`。

View File

@@ -0,0 +1,25 @@
## 1. 核查与基线
- [x] 1.1 按 `build_node_groups()` 完成七个几何组、共享函数与材质消费者的属性存取清单,记录每次写入的域、类型、Selection、版本、消费位置及保留或替换依据,在本变更中交付核查结果。
- [x] 1.2 运行现有节点测试,记录各组 Store/Named/Capture 节点数量及代表场景的几何、UV 和材质属性基线,确认测试正常退出并区分已有失败。
## 2. 整理节点字段传递
- [x] 2.1 将 Depth Cutout 受影响的阶段连接改为显式函数返回值与 socket 引用,移除自动编号定位和输入反查;用现有 Depth Cutout 求值测试验证连接等价。
- [x] 2.2 简化共用 Depth Surface 的面中心、面相机值和投影相机值传递,显式保持域转换;用非均匀面深度、Split 开关和零厚度测试验证结果。
- [x] 2.3 为分裂、删面与厚度构建中必须保留的源位置、角值、切分标记、顶点身份和法线建立必要捕获,迁移调用方;通过断层封口、独立重叠表面和法线测试验证快照传播。
- [x] 2.4 将 Depth Cutout 的中心 seed 直接接 Blur,并按属性版本简化局部体积计算、保存必要表面快照;通过 Balloon/Uniform、厚度连续性、边缘圆化、前表面膨胀和法线平滑测试验证行为。
- [x] 2.5 逐项简化 Panorama 的方向、UV、距离和无效标记传递,保持 POINT/FACE 聚合和球面采样时机;通过周期接缝、极点、无效深度边缘、Valid Only 与 Split 测试验证行为。
- [x] 2.6 按清单完成 Image Plane、Relief Plane、Image Cutout、Depth Balloon 及材质边界检查,保留必要 UV 与命名协议;通过对应节点和材质测试确认域、属性值及着色输入一致。
- [x] 2.7 删除失去业务用途的存取函数、读节点和清理节点,调整依赖中间属性的测试;检索确认旧调用消失,并验证所有保留的临时命名属性在最后消费者后清理。
## 3. 更新规范与布局验证
- [x] 3.1 按设计更新 `AGENTS.md` 与 `docs/internals/node-assets.md`,明确直连、域转换、捕获、命名协议与显式接线的选择依据;检查两处规范一致且已替换跨区域即存储的旧规则。
- [x] 3.2 验证现有排列器对直连和匿名属性的处理,仅修复实际出现的布局问题;通过 arrangement 与 saved layout 测试,并检查各组字段连线可读、未使用输出隐藏、接口顺序与默认值一致。
## 4. 重建与整体交付
- [x] 4.1 运行 `uv run node-group build`,更新 `src/anyimage/assets/O_AnyImage.blend`,确认构建、保存后独立 Blender 加载和求值验证全部成功。
- [x] 4.2 运行 `uv run pytest` 并确认正常退出,对照基线检查相关几何、UV、材质属性和修改器接口结果,修复本次变更引入的失败。
- [x] 4.3 检查最终差异、旧引用和临时属性清理,交付逐组调整结论、存取节点数量变化及测试结果,确认源码、测试、规范和 `.blend` 资产同步完成。

View File

@@ -0,0 +1,62 @@
# 节点属性核查与验证
## 存取清单
核查入口为 `tools/nodes/build.py` 的全部七个几何组和三个材质组。以下覆盖原有 44 次 Store 写入;其 Selection 均为常量 True。重复名称按几何阶段区分版本,表中标明重复写入次数。
| 属性 | 原域 / 类型 | 生产、消费与处理 |
| --- | --- | --- |
| `o_depth_face_center`(3 组) | FACE / FLOAT_VECTOR | Depth Plane、Depth Cutout、Panorama 分裂前的面中心,供相邻面距离采样;直接由 FACE 域的 Sample Index 求值 |
| `o_depth_face_camera`(3 组) | FACE / FLOAT_VECTOR | 面中心 UV 采样结果供断层判断及角值捕获;改为 FACE Evaluate on Domain 后直连 |
| `o_depth_corner_camera`(3 组) | CORNER / FLOAT_VECTOR | 分裂、删面前的各面相机值,供切分后投影;与切分标记一起捕获 |
| `o_depth_cut_vertex`(3 组) | CORNER / BOOLEAN | 分裂前 EDGE→POINT 标记,供分裂后的射线调整;在 CORNER 域捕获,保持原转换顺序 |
| `o_depth_camera`(3 组) | POINT / FLOAT_VECTOR | 射线调整结果紧接投影使用;改为 POINT Evaluate on Domain 后直连 |
| `o_depth_surface_position`(2 组) | POINT / FLOAT_VECTOR | Depth Plane、Depth Cutout 展平前的位置,供合并后恢复;与顶点身份一起捕获 |
| `o_depth_source_vertex`(2 组) | POINT / INT | 挤出前身份,供前后盖和侧壁合并;与位置在同拓扑下捕获 |
| `o_depth_surface_normal` | POINT / FLOAT_VECTOR | Depth Plane 的源面平滑法线,供恢复壳体厚度;合并到源几何捕获 |
| `o_panorama_direction` | POINT / FLOAT_VECTOR | 球面方向供 UV、面中心和径向投影;消费前位置保持不变,直接用 Position |
| `o_panorama_uv` | POINT / FLOAT_VECTOR | 球面采样坐标供深度与有效性采样;POINT 域直接求值 |
| `o_panorama_distance` | POINT / FLOAT_VECTOR | 采样距离供分裂后投影;删面与 Split Edges 保持球面坐标,POINT 域直接求值 |
| `o_panorama_invalid` | POINT / FLOAT_VECTOR | 有效性分类供面删除及无效距离选择;改为 POINT/FLOAT 字段,面消费者保留聚合语义 |
| `o_balloon_surface_rim` | POINT / FLOAT | 源面边界供中心和结构 Blur 权重;显式 POINT/FLOAT 字段直连 |
| `o_balloon_surface_center`(2 次) | POINT / FLOAT | 第一版 seed 只供 Blur,直接连接;第二版平滑中心跨表面变形,捕获最终值 |
| `o_balloon_surface_front_normal` | POINT / FLOAT_VECTOR | 源表面法线供 Uniform 厚度及前向平滑;POINT 求值后捕获 |
| `o_balloon_surface_structure` | POINT / FLOAT | 原表面结构幅度供壳体膨胀;在壳体构建前捕获 |
| `o_balloon_surface_inflation_normal` | POINT / FLOAT_VECTOR | 原表面平滑方向供最终膨胀;与结构幅度一起捕获 |
| `o_balloon_surface_thickness`(3 次) | POINT / FLOAT | Balloon 基础厚度、Uniform 控件厚度、Balloon 圆化后厚度三个版本;基础计算直接连接,模式选择后的最终厚度在变形前捕获 |
| `o_balloon_surface_edge_weight` | POINT / FLOAT | 圆化权重供壳体前后表面;在圆化前捕获 |
| `o_balloon_surface_front_delta` | POINT / FLOAT | 圆化位移供当前 Set Position 和后续壳体;在圆化前捕获 |
| `o_balloon_surface_normal` | POINT / FLOAT_VECTOR | 在独立中心表面求值并按顶点采样的法线,供最终壳体;保留采样源并捕获 |
| `UVMap`(3 次) | CORNER / FLOAT2 | Image Plane 的 Grid/Cube 两分支及 Panorama,供材质与输出使用;保留命名属性 |
| `o_normal_scale`(5 次) | FLOAT;Cutout/Balloon 为 POINT,Depth Cutout 为 FACE | 两类 Cutout 输出掩码、Depth Cutout 原面值 1 与背面/侧壁值 0;供 `cutout_tool/object.py` 材质读取,保留全部写入 |
`o_balloon` 由 `cutout_tool/object.py` 写入输入网格,作为形状协议继续按名称读取。Relief Plane 使用 UVMap 读取;Image Layer、Shadeless 通过接口消费材质数据;Depth Layer 的位移属性读取保持原协议。以上外部消费者均已检查。
## 数量变化
表中为 Store / Named Attribute 读取 / Capture 节点数量,包含组内共用构建函数展开后的节点。
| 节点组 | 调整前 | 调整后 |
| --- | --- | --- |
| Depth Panorama | 10 / 14 / 1 | 1 / 0 / 2 |
| Image Plane | 2 / 0 / 1 | 2 / 0 / 1 |
| Depth Plane | 8 / 12 / 0 | 0 / 2 / 2 |
| Relief Plane | 0 / 1 / 0 | 0 / 1 / 0 |
| Image Cutout | 1 / 2 / 0 | 1 / 2 / 0 |
| Depth Cutout | 22 / 36 / 0 | 3 / 7 / 4 |
| Depth Balloon | 1 / 3 / 0 | 1 / 3 / 0 |
| 三个材质组 | 0 / 0 / 0 | 0 / 0 / 0 |
| 合计 | 44 / 68 / 2 | 8 / 15 / 9 |
移除的内部命名空间不再参与清理;输入网格中自行携带的同前缀属性得以保留。快照经匿名属性传播,最终输出不新增内部命名属性。
## 求值验证
- 基线节点测试首次受环境同步文件锁影响:248 通过,2 个材质测试因 Cycles 未能注册失败。恢复完整 bpy 安装后,相关 5 个材质测试全部通过。
- 保存并对比 28 个场景、164 组数组:覆盖 Balloon/Uniform、Split 关闭/开启、零/正厚度、Normal Smooth 0/50、Front Inflation、Panorama 非均匀深度与无效像素。
- 28 个场景的实际顶点位置完全一致。按空间位置对应比较,面的方向、角 UV、材质索引和法线掩码完全一致;Merge by Distance 的部分输出编号顺序发生变化。
- 重构后的 Depth Cutout 与分裂测试:56 通过;其余投影与 Panorama 首轮测试通过,旧临时属性测试已迁移为字段输出验证。
- `uv run node-group build` 成功退出:使用 Blender 4.5.10 LTS 重建 `.blend`,在独立进程中重新加载并验证全部 10 个节点组。
- 同一构建入口调用项目环境的 `python -m pytest`:1182 项全部通过,耗时 217.79 秒,正常退出;包含排列前后行为、保存布局稳定性、材质与 Operator 回归验证。
- 七个几何组的节点边界检查均为零重叠,现有排列器无需调整;已导出本地交互预览 `build/node-attributes.html`。
- `git diff --check` 与 OpenSpec 严格校验通过;节点源代码中已无本次移除的临时命名属性与旧存取入口引用。