Add new tests and functionality for image processing and geometry handling
- Introduced color_image.py for preparing standalone color images for tests. - Added hdr_image.py to create HDR textures for testing. - Implemented test_image_depth_panorama.py to evaluate panorama topology, UVs, and depth discontinuities. - Created test_shadeless.py to validate the opacity and HDR color endpoints of the Shadeless group. - Developed moge3_export.py for exporting dynamic MoGe-3 backbone and ONNX graphs. - Added material.py to inherit material slots onto generated geometry. - Built image_depth_panorama.py to construct a quad panorama with depth separation and sampling.
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-09-10
|
||||
71
openspec/changes/unify-material-color-images/design.md
Normal file
71
openspec/changes/unify-material-color-images/design.md
Normal file
@@ -0,0 +1,71 @@
|
||||
## Context
|
||||
|
||||
动机与范围见 proposal.md。普通 Cutout 在内存中新建颜色图,AI Cutout 从裁切临时文件加载;Convert To 使用按 Empty 引用决定复用的分支。剪贴板通过输入字节哈希查找 packed Image,编辑覆盖原 Image 后该标记仍然存在。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
设计目标是让所有材质入口共享范围采样和颜色图交付逻辑,并让剪贴板按当前图像状态验证缓存。输入范围统一使用现有像素坐标约定,静态颜色图以独立 packed Image 交付。
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. 统一范围与颜色文件准备
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[读取当前源图像素和解释设置] --> B[确定像素范围]
|
||||
B --> C[Cutout 使用裁切范围]
|
||||
B --> D[Convert To 和剪贴板 Plane 使用整图范围]
|
||||
C --> E[导出唯一临时颜色文件]
|
||||
D --> E
|
||||
E --> F[独立加载并命名为原名_color]
|
||||
F --> G[配置材质颜色空间和 Alpha]
|
||||
G --> H[打包并绑定材质]
|
||||
E --> I[需要 AI 时准备模型输入并生成几何数据]
|
||||
H --> J[完成对象交付并清理临时资源]
|
||||
I --> J
|
||||
```
|
||||
|
||||
公共准备逻辑放在 common,输入源 Image、当前像素及范围。复用现有像素读取、路径清理和 packed 加载能力;由临时产物携带采样时的尺寸与解释设置,异步响应使用同一次准备的内容。AI 和普通 Cutout 采用相同裁切颜色来源,模型推理的缩放或预览处理只作用于分析输入。
|
||||
|
||||
### 2. 独立加载是材质所有权边界
|
||||
|
||||
每次材质创建都从本次临时颜色文件使用 `check_existing=False` 加载新的 Color Image。名称使用源图基名、`_color` 和实际编码后缀,由 Blender 处理重名。文件位于本次操作的唯一临时目录,与原图路径分离。
|
||||
|
||||
材质构建函数接收已准备好的独立 Color Image,负责配置和节点绑定。所有入口在进入该函数前完成相同准备;Cutout 已准备的产物直接交付。原 Image 的像素、名称、路径、颜色空间和 Alpha 保持原值。材质 Image 由文件独立加载,因此不继承源 Image 的剪贴板缓存属性。
|
||||
|
||||
### 3. 编码精度与颜色解释共同验证
|
||||
|
||||
普通 byte 图片使用无损 PNG;float / HDR 使用保留浮点范围和精度的 EXR。复用 common 中适合的 HDR 编码能力,按源 Alpha 解释正确处理关联 RGB 和透明区域颜色。
|
||||
|
||||
普通 byte 材质沿用适配偏好、inverse 空间映射与 sRGB 回退。所有 float / HDR 材质保留源颜色空间与 Alpha 模式;Panorama 保留现有非 sRGB 规则。导出、独立加载、配置、打包和保存重载作为完整往返验证。普通 float 不再强制套用显示颜色空间,原有重载 xfail 改为源解释保留的正常回归测试。
|
||||
|
||||
float / HDR 在导出后按源解释独立加载并比较像素。STRAIGHT 按 Alpha 解关联后编码;源解释与 EXR 无法同时保留像素时明确拒绝转换并清理临时目录,例如 STRAIGHT 下完全透明像素仍含非零 RGB。float 材质不启用场景视图适配的 Alpha Fix。
|
||||
|
||||
### 4. 临时产物由操作持有
|
||||
|
||||
同步操作持有临时目录直至 Color 完成打包和对象交付;异步操作持有颜色产物及分析输入直至响应、取消或失败处理完成。静态普通颜色文件适合作为模型输入时复用同一临时文件;HDR 分析预览保留独立路径。所有清理入口按真实持有关系释放资源,packed Color 在临时文件删除后仍可保存和重载。
|
||||
|
||||
转换源对象与 Image 身份校验继续使用;材质隔离后清理原图复用及相应的原图配置恢复、打包撤销基线分支。保留对象、材质、网格和临时 Image 的异常清理及转换 Undo / Redo。
|
||||
|
||||
### 5. 剪贴板缓存验证实际内容
|
||||
|
||||
输入字节的 SHA256 继续作为候选索引。首次加载 packed Image 后保存其内容指纹:尺寸、统一读取的 RGBA 像素、颜色空间及 Alpha 模式。命中输入哈希时重新计算当前指纹,匹配才复用;不匹配、缺少指纹或无法读取时跳过该候选,从剪贴板原始字节重新创建。
|
||||
|
||||
指纹在稳定的像素读取约定下计算,包含完全透明像素的 RGB。使用前验证能同时覆盖 Mask、Frame、Rectify、AI 编辑与原生绘制,避免依赖每个编辑入口主动通知。`is_dirty` 不能代表内容是否仍相同,packed 的编辑结果也必须验证。
|
||||
|
||||
剪贴板粘贴为参考图、节点或笔刷时沿用有效原图缓存;粘贴为 Plane 材质时基于该原图按整图范围创建独立颜色产物。旧缓存缺少指纹时按未命中处理,无需迁移用户图像。
|
||||
|
||||
### 6. Plane 收紧为静态图片
|
||||
|
||||
在创建材质或临时文件前拒绝 Movie、Sequence 及其他动画输入,明确报告仅支持静态图。移除 Plane 的帧起点、偏移、时长及循环传递,并沿调用链清理仅供材质动画使用的参数。其他图片编辑功能仍按各自输入约定运行。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [PNG / EXR 往返改变 RGB 或 Alpha 解释] → 覆盖 byte、float、HDR、透明 RGB、dirty、generated 和 packed 来源,检查配置前后与保存重载结果。
|
||||
- [全图内容指纹存在读取成本] → 先以剪贴板输入哈希筛选,仅验证匹配候选,复用 common 的无副作用像素读取。
|
||||
- [临时文件被提前删除] → 操作持有文件直至模型输入使用结束与材质打包完成,测试取消和失败路径。
|
||||
- [旧复用测试与当前要求冲突] → 以本提案的独立 Color 规格更新行为断言,保留有效错误恢复覆盖。
|
||||
|
||||
## Migration Plan
|
||||
|
||||
先实现并验证公共颜色产物,再接入 Cutout、Convert To 与剪贴板 Plane;补充缓存指纹校验,移除被替换的原图复用分支和重复实现。仅对后续操作采用新规则,已有场景数据保留。更新相关测试并运行全量测试,确认旧引用清理和正常退出。
|
||||
28
openspec/changes/unify-material-color-images/proposal.md
Normal file
28
openspec/changes/unify-material-color-images/proposal.md
Normal file
@@ -0,0 +1,28 @@
|
||||
## Why
|
||||
|
||||
材质直接复用原 Image 会让再次导入原文件或再次粘贴剪贴板内容带入材质配置及绘制结果。Cutout 与 Convert To 需要统一的独立颜色图流程,剪贴板缓存则需要确认当前图像仍代表最初粘贴的内容。
|
||||
|
||||
## What Changes
|
||||
|
||||
- Cutout、Plane、Depth Plane、Relief Plane、Panorama 和剪贴板 Plane 统一按图片范围生成材质颜色图:导出独立临时文件、独立加载、以 `_color` 命名、配置并打包。
|
||||
- Cutout 始终使用裁切范围;Convert To 和剪贴板 Plane 使用整图范围。是否使用 AI 只影响深度、法线等推理产物。
|
||||
- 材质颜色图与原 Image、原文件加载路径及剪贴板缓存标记隔离,保留源像素精度和各入口的颜色空间、Alpha 规则。
|
||||
- 普通 byte 图继续场景视图适配;所有 float / HDR 保留源解释,无法无损往返的输入明确拒绝转换。
|
||||
- 保留相同剪贴板内容的复用;缓存命中时核对当前像素、尺寸、颜色空间和 Alpha 模式,修改后的图片不再代表原缓存内容。
|
||||
- **BREAKING**:Convert to Plane 仅接受静态图片,拒绝 Movie 和 Sequence,移除该入口的动画帧参数传递。
|
||||
- 保留失败清理、异步源图校验与撤销能力,清理转换原图复用分支和重复颜色图实现。
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `material-color-images`: 所有材质创建入口的范围采样、独立颜色图、精度、配置、静态输入和资源生命周期。
|
||||
- `clipboard-image-cache`: 相同剪贴板内容的有效复用、编辑后的缓存失效以及材质派生图隔离。
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
## Impact
|
||||
|
||||
涉及 `common/image.py`、`common/material.py`、Cutout、两个 Convert To 包、剪贴板图像获取及 Plane 创建入口和相关测试。沿用现有依赖与节点资产。
|
||||
|
||||
本提案取代 `reuse-conversion-source-images` 的材质原图复用策略及 Plane 动画约定;采用当前代码中的失败清理和源对象校验能力继续实施。当前主规格目录为空,新规格集中表达最终行为,后续归档时以本提案的重叠约定为准。
|
||||
@@ -0,0 +1,43 @@
|
||||
## Purpose
|
||||
|
||||
保留相同剪贴板图片的复用能力,同时核对候选 Image 当前内容与解释设置是否仍匹配首次加载状态,确保编辑后的图像和材质派生图不会被误认为原始剪贴板内容再次粘贴。
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Clipboard reuse requires an unchanged image
|
||||
|
||||
相同剪贴板输入 SHALL 仅复用当前像素、尺寸、颜色空间和 Alpha 模式均匹配缓存基线的有效 Image。缓存验证 SHALL 包括透明区域 RGB,并保持候选图像原有内容与状态。
|
||||
|
||||
#### Scenario: Repeated content remains unchanged
|
||||
|
||||
- **WHEN** 相同剪贴板内容再次粘贴,缓存图像内容和设置未改变
|
||||
- **THEN** 系统 SHALL 复用该 Image
|
||||
|
||||
#### Scenario: Mask overwrites the cached image
|
||||
|
||||
- **WHEN** Mask 修改了独占的剪贴板 Image,修改结果已打包,再次粘贴原始剪贴板内容
|
||||
- **THEN** 系统 SHALL 加载原始剪贴板内容到另一 Image,保留已编辑图像
|
||||
|
||||
#### Scenario: Shared edit leaves an intact candidate
|
||||
|
||||
- **WHEN** 编辑产生独立结果,另一个用户仍引用未修改的剪贴板原图
|
||||
- **THEN** 再次粘贴 SHALL 复用该未修改原图
|
||||
|
||||
#### Scenario: Other editing or interpretation changes invalidate a candidate
|
||||
|
||||
- **WHEN** 候选图像经过尺寸修改、原生绘制、透明 RGB 修改、颜色空间或 Alpha 模式变更
|
||||
- **THEN** 再次粘贴 SHALL 跳过已变更候选,使用原始剪贴板内容及其初始解释设置
|
||||
|
||||
#### Scenario: Legacy or unreadable cache entry is found
|
||||
|
||||
- **WHEN** 候选缺少内容校验基线或无法读取
|
||||
- **THEN** 系统 SHALL 按未命中处理,并保留已有图像
|
||||
|
||||
### Requirement: Clipboard material results stay outside the source cache
|
||||
|
||||
剪贴板 Plane SHALL 从有效剪贴板原图按整图范围生成独立材质颜色图。参考图、节点和笔刷的后续粘贴 SHALL 按原图缓存有效性选择 Image。
|
||||
|
||||
#### Scenario: Painted material is followed by another paste
|
||||
|
||||
- **WHEN** 用户粘贴为 Plane 并绘制其材质,随后把相同内容粘贴为参考图、节点或笔刷
|
||||
- **THEN** 系统 SHALL 使用原始剪贴板内容,且不复用材质颜色图
|
||||
@@ -0,0 +1,82 @@
|
||||
## Purpose
|
||||
|
||||
统一 Cutout、Convert To 与剪贴板 Plane 的材质颜色图来源和交付约定,使裁切与整图转换使用同一范围采样流程,并保障材质编辑、再次导入原文件及保存重载时图像内容与设置保持隔离。
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Material color uses the requested source bounds
|
||||
|
||||
所有材质生成入口 SHALL 按本次准备时的源图像素和范围生成颜色图。Cutout SHALL 使用裁切范围,四种 Convert To 与剪贴板 Plane SHALL 使用整图范围。AI 的参与 SHALL 保持相同颜色来源及颜色分辨率。
|
||||
|
||||
#### Scenario: Cutout uses or omits AI
|
||||
|
||||
- **WHEN** 同一源图和裁切范围分别执行普通 Cutout 和需要 AI 的 Cutout
|
||||
- **THEN** 两者的颜色图 SHALL 对应同一裁切内容、尺寸和原有 Alpha,包含透明区域 RGB
|
||||
|
||||
#### Scenario: A full image is converted
|
||||
|
||||
- **WHEN** 执行 Plane、Depth Plane、Relief Plane、Panorama 或剪贴板 Plane
|
||||
- **THEN** 颜色图 SHALL 对应完整源图片,保持原始尺寸和当前像素
|
||||
|
||||
### Requirement: Every material owns an isolated color image
|
||||
|
||||
每次生成材质 SHALL 使用独立 Color Image 和独立临时颜色文件路径,以源图基名、`_color` 及实际文件后缀命名并打包。原 Image 的内容和解释设置 SHALL 保持不变,材质 Color SHALL 不携带剪贴板原图缓存身份。
|
||||
|
||||
#### Scenario: Source users vary
|
||||
|
||||
- **WHEN** 原图没有其他用户,或被其他 Empty、材质或笔刷引用
|
||||
- **THEN** 新材质 SHALL 使用独立颜色图,原图的引用、像素、名称、路径、颜色空间及 Alpha 模式 SHALL 保持原值
|
||||
|
||||
#### Scenario: Original file is imported after material painting
|
||||
|
||||
- **WHEN** 转换后修改材质颜色图,再次按原文件路径导入图片,包括原 Image 已移除的情况
|
||||
- **THEN** 导入 SHALL 不命中材质颜色图,不带入该颜色图的材质设置和绘制像素
|
||||
|
||||
### Requirement: Encoding preserves color precision and presentation
|
||||
|
||||
颜色图 SHALL 保留对应范围的 RGB、Alpha、透明区域 RGB 及源编码精度,float / HDR SHALL 保留浮点范围。普通 byte 材质 SHALL 沿用颜色空间适配与 Alpha 配对规则,所有 float / HDR 材质 SHALL 保留源颜色空间与 Alpha 模式。
|
||||
|
||||
#### Scenario: Ordinary material is configured
|
||||
|
||||
- **WHEN** 普通 byte 材质适配关闭或回退到 sRGB,或者启用可用的 inverse 空间
|
||||
- **THEN** 颜色图 SHALL 分别采用 sRGB + PREMUL 或对应 inverse 空间 + STRAIGHT,原图设置保持不变
|
||||
|
||||
#### Scenario: HDR and unsaved pixels are serialized
|
||||
|
||||
- **WHEN** float / HDR、generated、dirty 或 packed 源图完成颜色图生成、打包和保存重载
|
||||
- **THEN** 结果 SHALL 在对应编码精度内保留业务像素、动态范围与选定的颜色解释
|
||||
- **AND** 所有 float / HDR 材质 SHALL 保留源图颜色空间与 Alpha 模式;Panorama 非 sRGB 分支沿用源解释
|
||||
|
||||
#### Scenario: Float source interpretation prevents lossless serialization
|
||||
|
||||
- **WHEN** 按源颜色空间和 Alpha 模式解码 EXR 后无法保留源浮点像素
|
||||
- **THEN** 操作 SHALL 明确拒绝转换,清理临时资源并保持源图不变
|
||||
- **AND** float / HDR 材质 SHALL 不启用场景视图适配的 Alpha Fix
|
||||
|
||||
### Requirement: Material operations release temporary resources safely
|
||||
|
||||
临时颜色文件 SHALL 在打包和相关 Job 使用结束后释放。取消或失败 SHALL 清理本次临时文件与未交付数据,保留源对象及原图。成功转换 SHALL 支持 Undo / Redo;异步源对象失效或 Image 被替换时 SHALL 取消应用。
|
||||
|
||||
#### Scenario: Packed result survives file cleanup
|
||||
|
||||
- **WHEN** 操作成功且临时目录已删除
|
||||
- **THEN** 材质颜色图 SHALL 仍能正确读取并保存重载
|
||||
|
||||
#### Scenario: An operation fails or is cancelled
|
||||
|
||||
- **WHEN** 导出、模型处理、图像加载、材质或对象创建失败,或用户取消 Job
|
||||
- **THEN** 本次临时资源 SHALL 释放,源对象、源像素和源图设置保持原值
|
||||
|
||||
#### Scenario: Conversion is undone and redone
|
||||
|
||||
- **WHEN** 用户撤销并重做转换
|
||||
- **THEN** 撤销 SHALL 恢复源对象和源图,重做 SHALL 恢复带独立颜色图的转换结果
|
||||
|
||||
### Requirement: Plane accepts static images only
|
||||
|
||||
Convert to Plane SHALL 仅接受静态图片;Movie、Sequence 和动画图像 SHALL 在创建颜色图或对象前被拒绝,并给出明确错误。
|
||||
|
||||
#### Scenario: Animated source is selected
|
||||
|
||||
- **WHEN** 源 Image 为 Movie 或 Sequence,即使其声明时长为一帧,或源图片含多帧
|
||||
- **THEN** Plane SHALL 报告仅支持静态图片,并保持源对象及图像不变
|
||||
25
openspec/changes/unify-material-color-images/tasks.md
Normal file
25
openspec/changes/unify-material-color-images/tasks.md
Normal file
@@ -0,0 +1,25 @@
|
||||
## 1. 公共颜色图流程
|
||||
|
||||
- [x] 1.1 在 common 中统一按范围导出、独立加载、命名与打包的颜色产物流程,明确临时目录所有权;测试整图和局部裁切的尺寸、RGB、Alpha、独立 Image 身份及原路径隔离。
|
||||
- [x] 1.2 实现 byte PNG 和 float / HDR EXR 的精度与解释配对,复用适合的公共像素和编码能力;验证 generated、dirty、packed、透明 RGB、HDR 动态范围及材质配置后的保存重载,保留 float / HDR 源解释,无法无损往返时明确拒绝,替换原普通 float 重载 xfail。
|
||||
- [x] 1.3 保留公共材质函数对已准备 Color 的配置及节点绑定职责,验证 inverse / sRGB 回退、Alpha 配对、Panorama HDR 保留和源 Image 设置不变。
|
||||
|
||||
## 2. 接入材质入口
|
||||
|
||||
- [x] 2.1 将普通与 AI Cutout 接入同一裁切颜色产物,协调分析输入与异步文件生命周期;同源同范围测试确认两条路径颜色一致、透明 RGB 保留,推理分辨率不改变颜色分辨率。
|
||||
- [x] 2.2 将 Plane、Depth Plane、Relief Plane 和 Panorama 接入整图范围流程,移除转换原图复用及相应恢复分支,保留异步源身份校验;验证不同共享用户下原图不变、四个入口使用独立 `_color` Image。
|
||||
- [x] 2.3 将 Plane 限定为静态图片并清理该入口帧参数及仅供材质动画使用的路径;测试 Movie、Sequence 单帧与多帧输入在创建临时资源前被拒绝,静态转换与 Operator 注册正常。
|
||||
- [x] 2.4 将剪贴板 Plane 接入整图颜色产物,确保结果不携带缓存身份;测试创建材质后绘制再粘贴为参考图、节点或笔刷,得到原始剪贴板内容。
|
||||
|
||||
## 3. 剪贴板缓存有效性
|
||||
|
||||
- [x] 3.1 为新缓存建立内容指纹,按输入哈希筛选后核对当前像素、尺寸、颜色空间与 Alpha;测试未变内容复用、变化内容跳过、透明 RGB 变化、旧缓存缺少指纹和候选读取失败,验证读取不改变候选状态。
|
||||
- [x] 3.2 补充实际编辑后的重复粘贴测试,覆盖 Mask 覆盖原 Image、已打包编辑结果、共享 Empty 保留原图、尺寸修改及原生绘制;确认原始粘贴内容正确且编辑结果保留。
|
||||
|
||||
## 4. 生命周期与最终验证
|
||||
|
||||
- [x] 4.1 验证导出、加载、模型、材质和对象创建失败以及 Job 取消的资源清理,确认原图与源对象保持有效;通过临时目录删除后的保存重载及转换 Undo / Redo 测试。
|
||||
- [x] 4.2 添加“生成材质 → 绘制 → 再按原文件路径导入”的回归,包含原 Image 已删除场景,验证不会命中材质 Color;检查所有材质入口及重复实现的最终引用。
|
||||
- [x] 4.3 更新受影响测试并运行全量 `uv run pytest`,确认正常退出;检查最终差异、旧引用和 OpenSpec 严格校验,保留工作区已有修改。
|
||||
|
||||
验证结果:`uv run pytest` 共 1162 项通过,退出码 0;OpenSpec 严格校验通过。
|
||||
Reference in New Issue
Block a user