Add comprehensive tests for image processing and mask functionalities
- Introduced tests for color image handling, ensuring source preservation and premultiplied alpha usage. - Implemented tests for brush stroke operations, validating segment boundaries and brush anti-aliasing. - Added tests for frame anti-aliasing, confirming correct rendering behavior with various alpha values and depth settings. - Created tests for frame projection, ensuring accurate overlap calculations and half-plane clipping. - Developed tests for image premultiplied retention, verifying behavior during loading and packing processes. - Added undo functionality tests for mask operations, ensuring single transaction behavior during edits.
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
schema: spec-driven
|
||||
created: 2026-09-03
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
## Context
|
||||
|
||||
Frame 当前把每个 Image Empty 的四个本地角投影到 Region,要求结果是有限凸 Quad,再由 `screen_quad → source pixels` Homography 对输出像素采样。`_frame_source()` 还要求四个角的视图深度全部大于固定阈值,`composite_frame_pixels()` 则把深度不为正的样本设为透明。
|
||||
|
||||
这套表示只适用于完整图片位于透视观察原点前方的情况:
|
||||
|
||||
- 正交投影的屏幕坐标不因观察原点前后而产生透视奇点,但现有统一深度检查仍会拒绝它。
|
||||
- 透视图片穿过观察原点时,完整图片投影会经过无穷远,不能表示成一个有限凸 Quad;然而 Frame 内的许多屏幕射线仍可能与图片前方部分形成稳定交点。
|
||||
- 简单删除报错会把非凸、翻转或经过无穷远的角点继续交给 Quad Homography 与 SAT 重叠判断,无法保证采样正确。
|
||||
|
||||
Frame 仍然只烘焙 Image RGBA 与几何投射,不是 Viewport 截图,因此场景遮挡、Grid、Gizmo、Overlay、显示 tint 与 Color Management 不属于本变更。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- 让正交视图中的 Frame 不受透视观察平面深度符号限制。
|
||||
- 在透视视图中支持 Image Empty 部分跨越观察原点,只采样观察方向前方的有效部分。
|
||||
- 使用同一套输出驱动求交模型计算源像素位置、样本有效性与逐像素深度。
|
||||
- 保留无 active 几何交叠 warning,并使判断覆盖无界或被 Frame 截断的投射。
|
||||
- 在 active 原点无法作为可见结果深度时,为结果 Image Empty 选择稳定、可解释的前方深度。
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- 不捕获 Blender Viewport framebuffer,也不复刻其他对象遮挡或 Overlay。
|
||||
- 不把透视观察方向后方的平面交点镜像到结果中。
|
||||
- 不改变 Viewport `clip_start`、`clip_end` 或 Image Empty 自身显示规则。
|
||||
- 不改变 Frame 的输出 Canvas、分辨率限制、插值、Alpha、选择集合和对象生命周期语义。
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. 以屏幕观察射线到图片平面的映射替代角点 Quad
|
||||
|
||||
对每个源对象,组合冻结的 Viewport 投影矩阵与对象世界矩阵,得到本地图片平面 `z = 0` 到 clip-space 的三阶 Projective Transform。Frame 输出像素中心先映射到 Region screen-space,再通过该变换的逆映射得到图片局部坐标,最后按 Image Empty bounds 换算为源像素坐标。
|
||||
|
||||
这与“从屏幕像素生成观察射线,再与图片平面求交”等价,但可以继续使用 NumPy 分块向量化,不需要为每个像素创建 Blender `Vector` 或调用几何 API。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Frame["Frame 像素中心"] --> Screen["Region 屏幕坐标"]
|
||||
View["冻结的 Viewport 投影"] --> Mapping["Screen → Image Local 平面映射"]
|
||||
Object["Image Empty 世界矩阵"] --> Mapping
|
||||
Screen --> Mapping --> Local{"有限且位于 Image bounds?"}
|
||||
Local -->|是| Sample["源 RGBA + View Depth"]
|
||||
Local -->|否| Clear["透明样本"]
|
||||
Sample --> Composite["逐像素深度与 Alpha 合成"]
|
||||
```
|
||||
|
||||
逆映射的齐次分母接近零表示该屏幕射线与图片平面平行。该像素作为无效透明样本处理;只有整个有效投射无法稳定求解时才取消操作。容差按矩阵和齐次量级计算,不再使用固定世界单位的 `1e-8` 作为整张图片的有效性条件。
|
||||
|
||||
### 2. 投影模式分别定义样本有效性
|
||||
|
||||
正交视图的观察射线互相平行,视图深度的符号不构成投影奇点。局部交点有限、映射稳定且位于 Image Empty bounds 内时,样本有效;其带符号视图深度继续用于多个源之间的前后排序。
|
||||
|
||||
透视视图只接受视图深度严格位于观察方向前方的交点。图片跨越观察原点时,前方交点正常采样,后方交点和射线平行位置透明。深度比较继续在同一个屏幕像素的观察射线上进行,因此可保持多张倾斜图片逐像素变化的遮挡关系。
|
||||
|
||||
### 3. active 交叠使用可求交区域
|
||||
|
||||
Frame 成功条件仍要求 Frame 与 active Image Empty 有正面积几何交叠,但交叠对象改为“在当前投影模式下可稳定求交且位于 active 图片 bounds 内的区域”。它不依赖源图片四角形成有限凸 Quad,也不依赖源图片 Alpha。
|
||||
|
||||
实现使用齐次平面投影裁剪得到 active 的有效前方区域,再与 Frame 矩形裁剪并计算正面积。逐输出像素是否恰好命中 active 不作为唯一成功判断,避免极窄但有效的交叠因输出分辨率取整而被误判。
|
||||
|
||||
### 4. 结果深度优先保持 active 原点语义
|
||||
|
||||
正交视图继续使用穿过 active 对象世界原点的视平面放置结果,因为任意有限深度都能保持相同的正交屏幕覆盖。
|
||||
|
||||
透视视图中,active 原点位于观察方向前方时继续沿用其视图深度,保持既有结果位置。若 active 原点不在前方、但 active 图片与 Frame 存在有效前方交叠,则以该交叠区域的屏幕几何中心生成观察射线,并采用它与 active 图片平面的正深度作为结果平面深度。由此得到的 view-facing 结果仍严格覆盖 Frame,同时位于实际被烘焙内容的代表深度。
|
||||
|
||||
如果代表射线无法稳定求交,系统取消操作并保持输入不变,不使用任意常量或 Viewport clip 距离猜测结果位置。
|
||||
|
||||
### 5. 退化只淘汰受影响区域
|
||||
|
||||
单条射线平行、位于透视观察方向后方或映射到图片 bounds 外时,只让对应源样本透明。以下情况才取消整个操作:
|
||||
|
||||
- 源平面到 screen-space 的 Projective Transform 不可逆或非有限。
|
||||
- Frame 与 active 的有效投射没有正面积交叠。
|
||||
- active 的结果深度无法按既定规则稳定取得。
|
||||
- 既有的 Frame 尺寸、图片数据或对象状态校验失败。
|
||||
|
||||
非 active 图片没有有效样本时可以继续作为透明参与源,并沿用 Frame 成功后消费全部参与 Image Empty 的既有语义。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [跨观察原点的投射包含无穷远分界] → 使用输出驱动逆映射,按像素屏蔽齐次分母退化,不构造完整有限 Quad。
|
||||
- [容差不当造成边界闪烁或误杀] → 使用与矩阵量级相关的齐次容差,并覆盖不同对象尺度与极近正深度测试。
|
||||
- [active 原点在视后方时结果深度发生变化] → 仅在原点无法产生可见结果时使用有效交叠中心深度,正常情况保持既有语义。
|
||||
- [有效交叠很窄而输出像素未命中] → 成功判断使用连续几何裁剪面积,不依赖离散采样结果。
|
||||
- [正交视图中的带符号深度排序与现有正深度假设不同] → 明确拆分投影模式,并用前后对象、共面 active 和负深度样本测试验证排序。
|
||||
|
||||
## Migration Plan
|
||||
|
||||
实施时先建立独立的屏幕到图片平面映射和有效区域裁剪函数,再替换 Frame source descriptor 与合成采样,随后调整结果深度选择。保留现有普通透视、Alpha、多图排序、Frame Canvas 和对象替换测试作为回归基线,并加入新边界测试。
|
||||
|
||||
本变更不修改保存数据或公开 ID,不需要迁移。回滚只需恢复原 Quad 投影描述、四角正深度校验和 active 原点深度放置;已生成的 packed Image Empty 不依赖新运行时代码。
|
||||
|
||||
## Open Questions
|
||||
|
||||
无。产品语义确定为:正交视图按平行射线求交;透视视图烘焙观察方向前方的有效交点;active 原点无法提供可见结果深度时使用 active 有效交叠区域的代表深度。
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
## Why
|
||||
|
||||
Frame 当前先把 Image Empty 的四个角投影为有限凸四边形,并要求四角的视图深度全部为正。这个前置条件把正交视图错误地套入透视观察平面的限制,也会在倾斜图片靠近透视观察原点、仍有有效可见区域时取消操作。用户已经能在 Viewport 中看到的有效图片投射因此无法被重新取景。
|
||||
|
||||
## What Changes
|
||||
|
||||
- Frame 改以 Frame 像素对应的观察射线与各 Image Empty 平面求交,决定源像素坐标、有效性和几何深度,不再要求源图片四角全部位于观察平面前方。
|
||||
- 正交视图接受任意有限深度的平面交点,只在图片平面与观察射线平行或投影退化时取消。
|
||||
- 透视视图只采样观察方向前方的交点;Image Empty 穿过观察原点时,仍烘焙 Frame 内可稳定求交的前方部分,后方与平行射线对应区域保持透明。
|
||||
- Frame 与 active Image Empty 的有效投射交叠改为按可求交区域判断,不再依赖完整凸四边形。
|
||||
- 当 active 对象原点不在透视观察方向前方、但 active 图片仍有有效交叠时,结果平面使用 active 有效交叠区域的代表深度,保证结果仍位于观察方向前方并覆盖 Frame。
|
||||
- 补充正交深度、极近透视、跨观察平面、平行视线、无有效交叠和结果放置测试,并同步 Frame 内部文档。
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `frame-tool`: 放宽 Frame 的投影有效性边界,以逐射线平面求交支持正交视图和部分跨越透视观察平面的 Image Empty,并定义相应的结果深度。
|
||||
|
||||
## Impact
|
||||
|
||||
- 主要影响 `src/anyimage/operators/image_edit_tool/frame.py` 的源投影描述、有效区域判断、像素采样、深度合成和结果平面放置。
|
||||
- 相关测试集中在 `tests/test_blender_addon.py`,内部说明同步到 `docs/internals/common.md` 与 Image Edit Tool 文档。
|
||||
- 不改变 Frame 的工具入口、输出分辨率、Alpha 合成、Selection 输入集合、对象消费或 Undo 语义,不引入依赖,也不修改节点资产。
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Frame samples every valid view-plane intersection
|
||||
Frame SHALL 根据当前投影模式,以 Frame 屏幕位置对应的观察射线与每个参与 Image Empty 平面求交,并 SHALL 以有限且位于图片显示边界内的交点计算源像素坐标和几何深度。系统 SHALL NOT 仅因 Image Empty 的一个或多个角位于观察平面另一侧而取消整个操作。
|
||||
|
||||
#### Scenario: User finishes a frame in orthographic view at a non-positive view depth
|
||||
- **WHEN** active Image Empty 在正交视图中具有有限稳定的屏幕投射,但其视图深度不为正
|
||||
- **AND** Frame 与 active 图片的有效投射存在正面积交叠
|
||||
- **THEN** 系统完成 Frame
|
||||
- **AND** 结果保持操作时的正交屏幕图案
|
||||
|
||||
#### Scenario: Orthographic rays are parallel to the image plane
|
||||
- **WHEN** 正交观察射线与 active Image Empty 平面平行,无法形成稳定的有限交点
|
||||
- **THEN** 系统取消 Frame
|
||||
- **AND** 所有参与对象保持不变
|
||||
|
||||
#### Scenario: A perspective image partially crosses the view plane
|
||||
- **WHEN** Image Empty 的一部分位于透视观察方向前方,另一部分越过观察原点
|
||||
- **AND** Frame 与 active 图片的有效前方投射存在正面积交叠
|
||||
- **THEN** 系统采样 Frame 内观察方向前方的稳定平面交点
|
||||
- **AND** 位于观察方向后方、与射线平行或超出图片边界的源样本为透明
|
||||
- **AND** 系统不因完整图片无法形成有限凸四边形而取消操作
|
||||
|
||||
#### Scenario: A perspective image is extremely close but remains in front
|
||||
- **WHEN** Image Empty 的有效交点位于透视观察方向前方且非常接近观察原点
|
||||
- **AND** 屏幕到图片平面的映射仍可稳定求解
|
||||
- **THEN** 系统允许该投射参与 Frame
|
||||
- **AND** 系统不使用固定世界距离阈值拒绝整张图片
|
||||
|
||||
#### Scenario: A frame contains a ray parallel to one source plane
|
||||
- **WHEN** Frame 中部分屏幕位置的观察射线与某个参与 Image Empty 平面平行
|
||||
- **THEN** 该源在对应位置贡献透明样本
|
||||
- **AND** 其他稳定位置及其他参与源继续正常采样与合成
|
||||
|
||||
### Requirement: Frame validates active overlap from the valid projection region
|
||||
Frame SHALL 使用 active Image Empty 在当前投影模式下可稳定求交的连续几何区域判断 Frame 交叠。交叠 SHALL 具有正面积,且 SHALL 独立于 active 图片的 Alpha 和离散输出像素是否恰好命中该区域。
|
||||
|
||||
#### Scenario: The complete active projection is unbounded but its valid part overlaps the frame
|
||||
- **WHEN** active Image Empty 跨越透视观察原点,其完整角点投影无法表示为有限凸 Quad
|
||||
- **AND** 其观察方向前方的有效投射与 Frame 存在正面积交叠
|
||||
- **THEN** 系统接受该 active 交叠并继续 Frame
|
||||
|
||||
#### Scenario: Only invalid or rear-facing intersections overlap the frame
|
||||
- **WHEN** Frame 内不存在 active Image Empty 的稳定前方透视交点,或不存在稳定的正交交点
|
||||
- **THEN** 系统以 warning 提醒用户 Frame 没有与 active Image Empty 的有效投射交叠
|
||||
- **AND** 系统取消操作并保持所有参与对象不变
|
||||
|
||||
#### Scenario: A narrow valid overlap falls between output pixel centers
|
||||
- **WHEN** Frame 与 active 有正面积有效几何交叠,但当前输出尺寸的像素中心没有命中该区域
|
||||
- **THEN** 系统仍将该 Frame 视为具有 active 交叠
|
||||
- **AND** 离散输出像素可以按实际采样结果保持透明
|
||||
|
||||
### Requirement: Perspective Frame uses a visible result depth
|
||||
Frame SHALL 在透视视图中优先使用 active Image Empty 世界原点的正视图深度放置 view-facing 结果。当 active 原点不在观察方向前方、但 active 图片存在有效前方交叠时,系统 SHALL 使用 active 有效交叠区域屏幕几何中心对应的稳定正交点深度放置结果。系统 SHALL NOT 以任意常量深度替代无法求解的结果位置。
|
||||
|
||||
#### Scenario: Active origin remains in front of the perspective view
|
||||
- **WHEN** active Image Empty 世界原点位于透视观察方向前方
|
||||
- **THEN** 结果平面继续使用 active 原点的视图深度
|
||||
|
||||
#### Scenario: Active origin is behind while part of the image remains visible
|
||||
- **WHEN** active Image Empty 世界原点不在透视观察方向前方
|
||||
- **AND** active 图片的有效前方投射与 Frame 存在正面积交叠
|
||||
- **THEN** 系统使用有效交叠区域屏幕几何中心与 active 图片平面的交点深度
|
||||
- **AND** 结果 Image Empty 位于观察方向前方并覆盖用户所画 Frame
|
||||
|
||||
#### Scenario: No stable representative depth exists
|
||||
- **WHEN** active 原点不能提供正深度,且有效交叠区域的代表射线无法稳定取得正交点深度
|
||||
- **THEN** 系统取消 Frame
|
||||
- **AND** 所有参与对象保持不变
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
## 1. 投影与求交基础
|
||||
|
||||
- [x] 1.1 从冻结的 Viewport 投影矩阵和 Image Empty 世界矩阵构建本地图片平面到 Region screen-space 的 Projective Transform,并实现带量级容差的逆映射与逐点有效性结果
|
||||
- [x] 1.2 实现 active 图片有效投射区域与 Frame 矩形的连续几何裁剪和正面积判断,覆盖正交投影、透视前方、跨观察原点、无穷远分界、平行视线和窄交叠
|
||||
- [x] 1.3 为屏幕到图片局部坐标、源像素坐标和视图深度计算补充不同对象尺度、极近正深度、固定阈值误判与退化矩阵单元测试
|
||||
|
||||
## 2. Frame 采样与合成
|
||||
|
||||
- [x] 2.1 将 Frame source descriptor 从有限角点 Quad 改为屏幕观察射线到图片平面的映射,并按正交与透视模式分别计算样本有效性
|
||||
- [x] 2.2 更新分块像素合成:正交视图保留任意有限深度样本,透视视图只保留观察方向前方样本,单条平行或无效射线只让对应源透明
|
||||
- [x] 2.3 补充正交负深度多图排序、透视跨平面部分采样、后方透明、单源局部退化、共面 active 置顶和既有普通透视结果回归测试
|
||||
|
||||
## 3. 结果放置与事务边界
|
||||
|
||||
- [x] 3.1 保留正常透视和正交视图的 active 原点深度放置;当透视 active 原点不在前方时,从 active 有效交叠区域屏幕几何中心求取代表正深度
|
||||
- [x] 3.2 在代表深度不可稳定求解时于创建或替换结果 Image 前取消操作,并验证所有参与 Object、Image 和变换保持不变
|
||||
- [x] 3.3 补充 active 原点在前方、位于观察原点、处于后方但图片部分可见,以及没有稳定代表深度的结果矩阵与显示范围测试
|
||||
|
||||
## 4. 文档与验证
|
||||
|
||||
- [x] 4.1 更新 Frame 与公共 Viewport/Image 内部文档,用从 Frame 像素到观察射线、图片平面交点、源像素和深度合成的流程正面描述当前实现
|
||||
- [x] 4.2 运行 Frame、Image Edit Tool、注册与 Blender Addon 相关测试,再运行 `uv run pytest`,确认完整测试集通过且不构建文档、节点资产或扩展包
|
||||
Reference in New Issue
Block a user