feat(cutout): implement boundary padding for cutout textures
- Introduced a new `Boundary Padding` preference in the Cutout Tool with a default of 2 px and a configurable range of 1-4 px. - Updated the Cutout client to establish inward mapping from the final Mask, sampling in a fixed direction and processing independent material RGBA and Depth. - Enhanced the handling of RGBA and Depth during cutout operations, ensuring proper mapping and preservation of source data. - Added tests to validate the new boundary padding functionality and its integration with existing cutout processes. feat(geometry): remove overall mesh smoothing from geometry nodes - Removed the `Smooth` input from several geometry node groups to eliminate unnecessary overall mesh smoothing. - Retained `Smooth Weight` for depth nodes while removing it from Cutout and Relief Plane nodes. - Ensured that boundary, normal, and fill smoothing behaviors remain intact and consistent. - Updated tests and documentation to reflect the changes in node interfaces and behaviors. feat(normals): scale tangent normals with depth - Reused the existing `o_normal_reduction` attribute to adjust Tangent Normal strength based on the geometry's `Depth Scale`. - Ensured that Tangent Normal strength is consistent with the geometry depth, preserving full strength for materials that do not provide the attribute. - Updated tests to verify the correct behavior of normal strength adjustments in both Tangent and Object Space.
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-09-14
|
||||
52
openspec/changes/pad-cutout-material-edges/design.md
Normal file
52
openspec/changes/pad-cutout-material-edges/design.md
Normal file
@@ -0,0 +1,52 @@
|
||||
## Context
|
||||
|
||||
Cutout 客户端持有源图裁切结果、Selection Mask、最终 `content_values` 以及对象创建所需的全部图片。服务端目前在 MoGe 推理后按源图 Alpha 做 Cutout 专用深度延伸,但它不知道 Selection Mask,因此无法与最终 Cutout 轮廓一致。材质、Depth 和 Normal 共用 `UVMap`,移动 UV 会让所有采样发生位移。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- 从最终 Cutout Mask 得到唯一、局部、结构向内的采样方向。
|
||||
- 用同一 mapping 处理材质 RGBA 与 Depth,而不改变 MoGe 输入或 UV。
|
||||
- 在客户端完成处理,使 Selection Mask、颜色图和深度结果处于同一数据边界。
|
||||
- 只保留必要的尺寸、有限值和结构边界保护,不建立 donor 可靠性分级。
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- 不使用 Alpha 0.95、最近可靠 donor、core/candidate/fallback 或跨方向候选比较。
|
||||
- 不处理 Normal,也不修改源 Image、网格几何、UV 或节点组。
|
||||
- 不让 padding 重新定义 MoGe 的整体深度标定。
|
||||
|
||||
## Decisions
|
||||
|
||||
### 从最终 Mask 构造结构 inward mapping
|
||||
|
||||
以 `content_values >= alpha_threshold` 得到最终二值 Mask。用有符号距离场的局部梯度取得指向 Mask 内部的单位法线;轮廓外目标通过其边界落点继承该法线,而不是搜索多个内部 donor。对边界位置 `b`,内部采样位置为 `q = b + inward * padding`,边界带像素沿同一法线使用 `q` 的值。
|
||||
|
||||
同一 `Boundary Padding` 同时定义向内采样距离与向外写入宽度。Mask 内超过该距离的像素不变;边界内侧带、边界和外侧带使用结构内向样本,从而把 UV 边界内缩的采样结果烘焙到纹理,而不改变 UV。薄结构中若 `q` 沿射线提前离开当前 Mask,则使用该射线最后一个内部位置。角点使用距离场给出的局部法线;零梯度位置保持原值。
|
||||
|
||||
该规则没有 Alpha 可靠阈值、最近 donor 或回退层。方向完全由 Cutout 结构决定,像素内容不参与方向选择。
|
||||
|
||||
### 客户端统一处理 Color 与 Depth
|
||||
|
||||
同步 Cutout 在独立 Color Image 创建后立即处理;AI Cutout 等服务端返回原始产物后,加载临时 Color 与 Depth 数据,在创建材质和对象之前处理。两条路径共用一个纯数组 mapping 入口。mapping 按各目标图片分辨率从同一 Mask 重建,padding 以材质图像素为基准同比缩放到 Depth。
|
||||
|
||||
材质对边界带搬运完整 RGBA。Depth 从内部采样 camera Z 与 A validity;目标 R/G 不复制 donor 的相机位置,而是按 Metadata 中的像素单位 intrinsics 和目标像素中心从新 Z 重建 camera X/Y。这样只延伸深度表面,不把 donor 的投影视线横向搬到边界。
|
||||
|
||||
处理后的 Blender Image 重新打包。原始 `reference_depth` 和 intrinsics 保持不变:padding 是采样保护,不参与全局尺度校准。Normal 使用服务端原始结果。
|
||||
|
||||
### 服务端恢复为原始产物生成器
|
||||
|
||||
Cutout Job 不再向 `generate_moge_artifacts` 请求 `extend_edge_depth`。若搜索确认没有其他调用方,移除通用生成器的延伸参数、导入、旧服务端算法和仅覆盖旧行为的测试;否则保留其他真实调用方所需的最小能力。MoGe 仍读取未 padding 的原始 RGB,Depth Metadata 由原始 Frame 生成。
|
||||
|
||||
### Preference 只影响新对象
|
||||
|
||||
Preferences 的 Cutout Tool 提供 `Boundary Padding` 浮点像素值,默认 2、范围 1–4。操作开始时捕获当前值,保证异步响应不受中途设置变化影响;已有 Cutout 不追溯更新。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [薄结构不足以容纳完整内部距离] → 沿同一 inward ray 截止在最后一个内部采样点,不转向其他 donor。
|
||||
- [距离场在尖角或对称轴出现零梯度] → 仅对应位置保持原值,避免引入任意方向。
|
||||
- [Color 与 Depth 分辨率不同] → 从同一 Mask 按目标尺寸重建 mapping,并按统一比例缩放 padding。
|
||||
- [Depth XYZ 被错误整体复制] → 只搬运 Z/A,使用目标像素与原 intrinsics 重建 X/Y。
|
||||
- [修改 packed Image 后保存旧内容] → 在对象消费前 update 并重新 pack,覆盖保存重载与失败清理。
|
||||
28
openspec/changes/pad-cutout-material-edges/proposal.md
Normal file
28
openspec/changes/pad-cutout-material-edges/proposal.md
Normal file
@@ -0,0 +1,28 @@
|
||||
## Why
|
||||
|
||||
Cutout 的材质和深度在网格轮廓处会线性混合轮廓外的不稳定像素。移动共享 UV 会同时扭曲多个纹理消费者;按最近 donor 搜索又会在复杂轮廓处产生不确定方向,因此需要在 Cutout 客户端按唯一的结构内向统一延伸边界纹理。
|
||||
|
||||
## What Changes
|
||||
|
||||
- 服务端停止 Cutout 专用深度延伸,只输出未经边缘处理的 MoGe Depth、Metadata 与 Normal;MoGe 输入保持原样。
|
||||
- Cutout 客户端从最终 Mask 建立局部结构 inward mapping,以固定方向从轮廓内采样,并同时处理独立材质 RGBA 与 Depth。
|
||||
- 材质搬运完整 RGBA;Depth 搬运 camera Z 与 validity,并使用目标像素和原始 intrinsics 重建 camera X/Y。
|
||||
- Preferences 的 Cutout Tool 增加 `Boundary Padding`,默认 2 px、范围 1–4 px;同一数值同时表示内部采样距离和外部延伸宽度。
|
||||
- 保持源 Image、网格几何、UV、Normal 与原始 Depth Metadata 标定不变。
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `cutout-boundary-padding`: 规定 Cutout 客户端对材质和深度使用同一结构内向映射的边界延伸、设置与数据隔离。
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
|
||||
## Impact
|
||||
|
||||
- `src/anyimage/operators/cutout_tool` 的最终 Mask、颜色图和深度图处理及对象创建路径。
|
||||
- `src/anyimage/operators/cutout_tool` 中的图片缓冲读写与目标射线 Depth 重建。
|
||||
- `src/anyimage/preferences.py` 的 Cutout Tool 设置。
|
||||
- `src/anyimage/server/jobs/cutout.py` 与 `server/geometry/prediction_artifacts.py` 移除 Cutout 深度延伸启用路径;无节点资产变化。
|
||||
- Cutout padding、深度投影、同步/异步路径、Preferences 和资源生命周期测试。
|
||||
@@ -0,0 +1,60 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Cutout boundary mapping follows the structural interior
|
||||
The system SHALL derive one local inward direction from the final Cutout threshold Mask without selecting among content-based donor candidates. For each boundary location it SHALL sample at Boundary Padding pixels along that inward direction and transport the sample through the inner boundary band, boundary and outer padding band.
|
||||
|
||||
#### Scenario: Outer and hole boundaries
|
||||
- **WHEN** the final Cutout Mask contains an outer outline or a hole
|
||||
- **THEN** its mapping points from that boundary into the adjacent filled Mask region
|
||||
|
||||
#### Scenario: Thin structure
|
||||
- **WHEN** the configured inward distance would leave the current Mask along the same ray
|
||||
- **THEN** the mapping stops at the last position inside that Mask without changing direction or searching another donor
|
||||
|
||||
#### Scenario: Undefined local direction
|
||||
- **WHEN** a boundary-band location has no finite nonzero local inward direction
|
||||
- **THEN** that location remains unchanged
|
||||
|
||||
### Requirement: Material and depth share the Cutout boundary mapping
|
||||
The system SHALL apply the same structural mapping to the independent Cutout material Color Image and optional Depth Image after raw AI artifacts return and before material or geometry consumption. It SHALL scale the mapping to each target image resolution.
|
||||
|
||||
#### Scenario: Material padding
|
||||
- **WHEN** Boundary Padding is positive
|
||||
- **THEN** the material boundary band receives complete RGBA from its mapped internal location
|
||||
|
||||
#### Scenario: Depth padding
|
||||
- **WHEN** a Depth Cutout has positive Boundary Padding
|
||||
- **THEN** its boundary band receives camera Z and validity from the mapped internal location and camera X/Y are reconstructed for each target pixel from the original intrinsics
|
||||
|
||||
#### Scenario: Different resolutions
|
||||
- **WHEN** material and Depth images have different dimensions
|
||||
- **THEN** both mappings represent the same normalized Cutout boundary and proportional padding width
|
||||
|
||||
### Requirement: Boundary processing is isolated from source and AI data
|
||||
The system SHALL preserve the source Image, original Cutout Mask, mesh geometry, UV coordinates, MoGe input, Normal output, intrinsics and reference depth. The server SHALL generate raw Cutout Depth without edge extension.
|
||||
|
||||
#### Scenario: AI Cutout
|
||||
- **WHEN** Cutout requests Depth or Normal generation
|
||||
- **THEN** MoGe processes the unpadded input and only the returned Color and Depth images receive client-side boundary processing
|
||||
|
||||
#### Scenario: Existing depth calibration
|
||||
- **WHEN** client-side Depth padding changes boundary pixels
|
||||
- **THEN** the original Metadata reference depth remains the Cutout calibration reference
|
||||
|
||||
### Requirement: Boundary Padding is configurable
|
||||
The system SHALL expose `Boundary Padding` in Preferences under Cutout Tool as a pixel distance with a default of 2, a minimum of 1 and a maximum of 4. Each Cutout operation SHALL capture the current value and existing objects SHALL remain unchanged.
|
||||
|
||||
#### Scenario: Asynchronous preference change
|
||||
- **WHEN** the preference changes after an AI Cutout starts
|
||||
- **THEN** its response uses the value captured when that operation started
|
||||
|
||||
### Requirement: Processed images preserve their lifecycle
|
||||
The system SHALL preserve existing Color and Depth precision, interpretation, ownership and cleanup behavior after client-side boundary processing.
|
||||
|
||||
#### Scenario: Successful creation
|
||||
- **WHEN** a padded Cutout is created successfully
|
||||
- **THEN** its processed independent Color and optional Depth Images are packed with their updated pixels
|
||||
|
||||
#### Scenario: Failed creation
|
||||
- **WHEN** Cutout creation fails after loading either image
|
||||
- **THEN** unowned Blender Images and temporary files are released by the existing cleanup path
|
||||
26
openspec/changes/pad-cutout-material-edges/tasks.md
Normal file
26
openspec/changes/pad-cutout-material-edges/tasks.md
Normal file
@@ -0,0 +1,26 @@
|
||||
## 1. Boundary Padding setting
|
||||
|
||||
- [x] 1.1 Add the Cutout Tool `Boundary Padding` preference with default 2 px, range 1–4 px and a clamped reader.
|
||||
- [x] 1.2 Capture the configured value when each Cutout operation starts so synchronous and asynchronous responses use the same operation value.
|
||||
|
||||
## 2. Structural inward mapping
|
||||
|
||||
- [x] 2.1 Build a pure array mapping from the final threshold Mask that carries each boundary-band location along one local structural inward direction to the configured internal distance.
|
||||
- [x] 2.2 Bound thin-structure rays to their last same-direction internal position and leave undefined directions unchanged without donor thresholds or fallback searches.
|
||||
- [x] 2.3 Cover outer outlines, holes, concave corners, thin structures, scaled target resolutions and zero bypass.
|
||||
|
||||
## 3. Client-side image processing
|
||||
|
||||
- [x] 3.1 Apply the mapping to independent material Color RGBA for synchronous and AI Cutouts while preserving the source Image and AI input.
|
||||
- [x] 3.2 Apply the mapping to Depth Z and validity, reconstruct target X/Y from Metadata intrinsics, and preserve reference depth.
|
||||
- [x] 3.3 Update and repack processed Color and Depth Images before object consumption while preserving byte, float/HDR and CHANNEL_PACKED interpretation and cleanup.
|
||||
|
||||
## 4. Raw server artifacts
|
||||
|
||||
- [x] 4.1 Stop enabling server-side depth edge extension for Cutout and remove the unused extension path if no real caller remains.
|
||||
- [x] 4.2 Update server tests to require raw MoGe Depth and unchanged Metadata generation.
|
||||
|
||||
## 5. Integration and validation
|
||||
|
||||
- [x] 5.1 Cover preference capture, synchronous/AI parity, unmodified geometry and UV, correct target-ray Depth projection, Normal isolation, packed ownership and failure cleanup.
|
||||
- [x] 5.2 Run related tests, validate OpenSpec strictly, and inspect the final diff and stale references without rebuilding node assets or extension packages.
|
||||
Reference in New Issue
Block a user