Remove obsolete implementation and simplify project structure
This commit is contained in:
6
.github/workflows/docs.yml
vendored
6
.github/workflows/docs.yml
vendored
@@ -28,8 +28,8 @@ jobs:
|
||||
|
||||
- name: 整理发布目录
|
||||
run: |
|
||||
mkdir -p public/snapform
|
||||
cp -a site/. public/snapform/
|
||||
mkdir -p public/anyimage
|
||||
cp -a site/. public/anyimage/
|
||||
|
||||
- name: 配置 Node.js
|
||||
uses: actions/setup-node@v6
|
||||
@@ -50,5 +50,5 @@ jobs:
|
||||
--name "$CLOUDFLARE_WORKER_NAME" \
|
||||
--compatibility-date 2026-08-19 \
|
||||
--keep-vars \
|
||||
--message "SnapForm docs $GITHUB_SHA" \
|
||||
--message "AnyImage docs $GITHUB_SHA" \
|
||||
--autoconfig=false
|
||||
|
||||
16
AGENTS.md
16
AGENTS.md
@@ -1,4 +1,4 @@
|
||||
# SnapForm 开发约定
|
||||
# AnyImage 开发约定
|
||||
|
||||
## 总则
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
├── docs/ # 按功能拆分的设计与开发文档
|
||||
├── pack.py # 构建各平台 Blender Extension ZIP
|
||||
├── sync_models.py # 准备并同步 ONNX 模型
|
||||
├── src/snapform/
|
||||
├── src/anyimage/
|
||||
│ ├── __init__.py # Blender 注册入口
|
||||
│ ├── operators.py # Job Operator 与结果导入
|
||||
│ ├── panel.py # 3D View 面板
|
||||
@@ -24,7 +24,7 @@
|
||||
│ ├── job_runtime.py # BlendJob Runtime 配置
|
||||
│ ├── blender/ # Depth Plane、Surface 的 Blender 侧实现
|
||||
│ ├── server/ # Job、模型、ONNX 推理与输出实现
|
||||
│ ├── assets/O_SnapForm.blend # Geometry Nodes 与材质资产
|
||||
│ ├── assets/O_AnyImage.blend # Geometry Nodes 与材质资产
|
||||
│ └── wheels/ # 随扩展分发的 BlendJob wheel
|
||||
├── tools/ # Blender 资产构建与验证脚本
|
||||
└── tests/ # Python 自动化测试
|
||||
@@ -58,19 +58,19 @@ uv lock --refresh
|
||||
## 命名规范
|
||||
|
||||
- 变量、函数、Docstring 使用英文;同一概念在代码和文档中使用统一表达
|
||||
- Python 类使用大驼峰,不添加项目名前缀。Operator 使用动宾结构,如 `ConvertToDepthPlane`、`RemoveImageBackground`;Menu、Panel、AddonPreferences、PropertyGroup 分别使用实际类型后缀,如 `SnapFormImageMenu`、`ServerPanel`、`SnapFormPreferences`、`SnapFormSettings`
|
||||
- `bl_idname` 与挂载到公共 Blender RNA 类型的 Property 使用 `snapform` 项目前缀:Operator 如 `snapform.convert_to_depth_plane`,Menu 如 `SNAPFORM_MT_image_context`,Panel 如 `SNAPFORM_PT_server`,公共 Property 如 `Scene.snapform_settings`
|
||||
- Python 类使用大驼峰,不添加项目名前缀。Operator 使用动宾结构,如 `ConvertToDepthPlane`、`RemoveImageBackground`;Menu、Panel、AddonPreferences、PropertyGroup 分别使用实际类型后缀,如 `AnyImageImageMenu`、`ServerPanel`、`AnyImagePreferences`、`AnyImageSettings`
|
||||
- `bl_idname` 与挂载到公共 Blender RNA 类型的 Property 使用 `anyimage` 项目前缀:Operator 如 `anyimage.convert_to_depth_plane`,Menu 如 `ANYIMAGE_MT_image_context`,Panel 如 `ANYIMAGE_PT_server`,公共 Property 如 `Scene.anyimage_settings`
|
||||
- Operator 自身 Property 不加项目前缀,使用业务名称,如 `input_path`、`process_res`、`resolution_level`
|
||||
- 扩展包名使用 Manifest 中的真实名称、版本和平台,例如 `SnapForm.v0.11.2.windows-x64.zip`;节点组名称沿用资产中的 `O DA3 Depth Plane`、`O MoGe2 Surface` 等既有名称
|
||||
- 扩展包名使用 Manifest 中的真实名称、版本和平台,例如 `AnyImage.v0.11.2.windows-x64.zip`;节点组名称沿用资产中的 `O DA3 Depth Plane`、`O MoGe2 Surface` 等既有名称
|
||||
|
||||
## 代码规范
|
||||
|
||||
- 避免不必要的嵌套,优先使用提前返回和小而明确的函数
|
||||
- 只为特殊、非常规或存在兼容性原因的实现写注释,不复述代码本身
|
||||
- 删除功能时同时删除无效参数、分支、测试和文档,不保留没有实际消费者的兼容层
|
||||
- Blender 侧不载入 AI 依赖:UI、Operator 和结果导入放在 `src/snapform/` 或 `src/snapform/blender/`,模型下载、ONNX 推理和输出放在 `src/snapform/server/`
|
||||
- Blender 侧不载入 AI 依赖:UI、Operator 和结果导入放在 `src/anyimage/` 或 `src/anyimage/blender/`,模型下载、ONNX 推理和输出放在 `src/anyimage/server/`
|
||||
- Job 参数使用可序列化的普通字典;Blender 数据只能在主线程的 Operator 响应阶段读写
|
||||
- 新增或修改 Blender 类型时同步检查 `src/snapform/__init__.py` 的注册与逆序注销,并补充对应测试
|
||||
- 新增或修改 Blender 类型时同步检查 `src/anyimage/__init__.py` 的注册与逆序注销,并补充对应测试
|
||||
- 依赖版本、wheel 或 Manifest 改变时同步检查 `pyproject.toml`、`uv.lock`、`blender_manifest.toml` 和打包测试
|
||||
|
||||
## 文档与 Markdown 规范
|
||||
|
||||
24
README.md
24
README.md
@@ -1,6 +1,6 @@
|
||||
# SnapForm
|
||||
# AnyImage
|
||||
|
||||
SnapForm 是一个 Blender 扩展,可以把一张照片、一段视频或一组序列帧快速变成有真实深度的立体面片。
|
||||
AnyImage 是一个 Blender 扩展,可以把一张照片、一段视频或一组序列帧快速变成有真实深度的立体面片。
|
||||
|
||||
完整使用说明请从[文档首页](docs/index.md)开始;首次使用请依次阅读
|
||||
[安装与首次配置](docs/installation.md)和[五分钟上手](docs/quick-start.md)。
|
||||
@@ -22,14 +22,14 @@ SnapForm 是一个 Blender 扩展,可以把一张照片、一段视频或一
|
||||
3. 点击 `Install from Disk`,选择下载的压缩包
|
||||
4. 在扩展偏好设置中确认 Storage Root 与 Device(保持默认即可);Device 默认取本机
|
||||
最快的 DirectML provider;Apple M4 或更新芯片可选 MPS/CoreML,其他 Mac 只提供 CPU
|
||||
5. 打开 3D 视图右侧的 `SnapForm` 面板:使用官方源点击 `Install Environment`,使用国内镜像点击 `Install Environment (Mirror)`
|
||||
5. 打开 3D 视图右侧的 `AnyImage` 面板:使用官方源点击 `Install Environment`,使用国内镜像点击 `Install Environment (Mirror)`
|
||||
|
||||
扩展不内置 uv 或 AI 运行库。首次使用会先下载并校验固定版本的 uv,随后自动安装轻量的 ONNX Runtime 环境,再下载 `MoGe-2 ViT-S Normal` 和
|
||||
`BEN2 Base`;不安装 PyTorch,也不下载各模型的 Python 源码包。其他 AI 模型可在
|
||||
`Models` panel 中按需下载,请保持网络畅通,首次安装需要一些时间。
|
||||
Environment Bootstrap 使用连续的 0–100%:uv 为 1–20%、Python 为 20–50%、packages 为 50–98%,最终验证为 98–100%。三个阶段显示真实的 `1/3`、`2/3`、`3/3`,下载占各阶段的 84–87%;开始与最终验证不显示编号,单阶段状态不显示 `1/1`。官方按钮固定使用 GitHub、uv 默认 Python 下载源和 PyPI;镜像按钮固定使用 CNB uv Release、CNB Python 解释器镜像和清华 PyPI,两种方式都不竞速或自动切换。MoGe-2 与 BEN2 属于 post-install,各自使用独立进度,不计入 Environment 的这轮 0–100%,其模型下载源逻辑不受按钮选择影响。
|
||||
任一必需模型在两个来源都下载失败时,`Install Environment` 会明确报错;Environment 本身仍会保留。
|
||||
选中 Image Empty 后,右键 `SnapForm` 子菜单会在缺少 `MoGe-2 ViT-S Normal` 或 `BEN2 Base`
|
||||
选中 Image Empty 后,右键 `AnyImage` 子菜单会在缺少 `MoGe-2 ViT-S Normal` 或 `BEN2 Base`
|
||||
时显示 `Download Required Models`,一次补齐缺失项,不会重复下载已经就绪的模型。
|
||||
Environment 未安装时,同一位置显示两个安装按钮。Environment 或必需模型未就绪时,
|
||||
菜单仍显示 `Convert to Depth Plane`、`Convert to Surface` 和 `Remove Background`,但三个入口都会保持禁用。
|
||||
@@ -41,7 +41,7 @@ Environment 未安装时,同一位置显示两个安装按钮。Environment
|
||||
### 转换为立体面片
|
||||
|
||||
1. 在 3D 视图中选中一个 Image Empty(空物体,显示方式为 Image)
|
||||
2. 右键打开 `SnapForm` 子菜单,选择 `Convert to Depth Plane`
|
||||
2. 右键打开 `AnyImage` 子菜单,选择 `Convert to Depth Plane`
|
||||
3. 在对话框中选择:
|
||||
- `Depth from`:`Original` 直接用原图,`DA3` 使用现有 DA3 流程,`MoGe-2` 生成 metric depth、normal 与有效区域 mask
|
||||
- `Resolution Scale` 使用 `1–100%`,按原图长边计算 Process Res;结果会限制在 `252–1008` 并自动对齐到 14 的倍数
|
||||
@@ -52,7 +52,7 @@ Environment 未安装时,同一位置显示两个安装按钮。Environment
|
||||
|
||||
### 套索生成 Balloon
|
||||
|
||||
选中单张图片的 Image Empty,右键打开 `SnapForm` 子菜单并选择 `Balloon Lasso Tool`。Blender 会激活 3D Viewport 左侧工具栏底部、紧邻 Add Cube、且不增加分隔空隙的独立 Balloon Lasso,Poly Build 的绿色图标、Annotate 同款铅笔光标、Tool Header 与状态栏共同提示当前工具状态,不再用黄色外框或强制修改 Shading、Overlay。Blender 的公开 Workspace Tool API 不支持按 Active Object 动态隐藏工具,因此图标在 Object Mode 中保持可见,但只有 Active Object 是 Image Empty 时才能启动 Stroke。
|
||||
选中单张图片的 Image Empty,右键打开 `AnyImage` 子菜单并选择 `Balloon Lasso Tool`。Blender 会激活 3D Viewport 左侧工具栏底部、紧邻 Add Cube、且不增加分隔空隙的独立 Balloon Lasso,Poly Build 的绿色图标、Annotate 同款铅笔光标、Tool Header 与状态栏共同提示当前工具状态,不再用黄色外框或强制修改 Shading、Overlay。Blender 的公开 Workspace Tool API 不支持按 Active Object 动态隐藏工具,因此图标在 Object Mode 中保持可见,但只有 Active Object 是 Image Empty 时才能启动 Stroke。
|
||||
|
||||
按住左键沿目标轮廓绘制,松开后生成一个带原图 UV 的封闭网格。每次拖动都是一个独立完成的顶层 `Extract Balloon` Operator,工具本身继续保持激活,下一次拖动会创建另一个 Balloon;因此 `Ctrl+Z` 只撤销最近一次生成,`Ctrl+Shift+Z` 重做。每次生成后源 Image Empty 都保持选中和 Active。未绘制时没有持续 Modal 拦截事件,视图导航和其他原生快捷键由 Blender 正常处理;绘制中可用右键或 `Esc` 取消当前轨迹。选择左侧工具栏中的其他工具即可离开 Balloon Lasso。
|
||||
|
||||
@@ -68,13 +68,13 @@ MoGe normal 会转换成适配 Balloon UV 的 tangent-space `normal.png`,由
|
||||
|
||||
### 去除背景
|
||||
|
||||
选中 Image Empty 后,右键打开 `SnapForm` 子菜单并选择 `Remove Background`,完成后 Empty 会自动
|
||||
选中 Image Empty 后,右键打开 `AnyImage` 子菜单并选择 `Remove Background`,完成后 Empty 会自动
|
||||
换成透明前景图。该操作在子菜单中使用独立分割区域。
|
||||
|
||||
### 转换为透视网格
|
||||
|
||||
选中单张图片的 Image Empty,右键打开 `SnapForm` 子菜单并选择 `Convert to Surface`。可选择 MoGe-2
|
||||
ViT-S、ViT-B、ViT-L 或 DA3 Small、Base,其中 MoGe-2 ViT-S 为默认模型。SnapForm 会按模型输出的
|
||||
选中单张图片的 Image Empty,右键打开 `AnyImage` 子菜单并选择 `Convert to Surface`。可选择 MoGe-2
|
||||
ViT-S、ViT-B、ViT-L 或 DA3 Small、Base,其中 MoGe-2 ViT-S 为默认模型。AnyImage 会按模型输出的
|
||||
相机内参与三维点建立透视网格,并匹配原 Empty 的可见尺寸、Offset 与 Transform。Server 通过统一的
|
||||
Surface 输出流程构建 DA3 与 MoGe-2 源网格:MoGe-2 使用深度断层 mask,DA3 保留 confidence 与边拉伸
|
||||
数据。两者再由独立的 Geometry Nodes
|
||||
@@ -102,19 +102,19 @@ Layer Color 同时驱动 Principled BSDF 的 Base Color、Subsurface Radius 和
|
||||
|
||||
### 视频与序列帧
|
||||
|
||||
SnapForm 支持视频(mp4、mkv、mov 等)和序列帧,会逐帧处理并生成逐帧对应的立体面片。`.color` 与 `.depth` 按源 Empty Image 的类型载入:普通单图为 `IMAGE`,Movie/Sequence 即使只处理一帧也仍为 `SEQUENCE`。处理范围默认
|
||||
AnyImage 支持视频(mp4、mkv、mov 等)和序列帧,会逐帧处理并生成逐帧对应的立体面片。`.color` 与 `.depth` 按源 Empty Image 的类型载入:普通单图为 `IMAGE`,Movie/Sequence 即使只处理一帧也仍为 `SEQUENCE`。处理范围默认
|
||||
跟随 Empty 上设置的 `Image Frames` 与 `Offset`,不需要额外配置。DA3 的转换任务复用同一个 ONNX
|
||||
Session 逐帧推理,显存峰值不随视频帧数平方增长。Debug 只保存模型 API 的直接返回:DA3 多帧输入
|
||||
保留联合推理,MoGe-2 与 BEN2 按各自的单图 API 逐帧保存。
|
||||
|
||||
## 任务结果保存在哪里
|
||||
|
||||
任务结果保存在 Runtime Storage Root 的 `jobs/` 下,默认是 `~/.snapform/jobs/`。Job Server 接受任务时自动生成 opaque Job ID,并创建同名文件夹;Blender 不预先申请 ID 或目录。Packed Image 和序列帧的临时输入由 Blender 在任务结束后清理,Server 产物直接写入该 Job 目录。视频或序列帧生成的面片会引用其中的序列帧,请保留对应文件夹,不要随意删除。
|
||||
任务结果保存在 Runtime Storage Root 的 `jobs/` 下,默认是 `~/.anyimage/jobs/`。Job Server 接受任务时自动生成 opaque Job ID,并创建同名文件夹;Blender 不预先申请 ID 或目录。Packed Image 和序列帧的临时输入由 Blender 在任务结束后清理,Server 产物直接写入该 Job 目录。视频或序列帧生成的面片会引用其中的序列帧,请保留对应文件夹,不要随意删除。
|
||||
|
||||
## 常见问题
|
||||
|
||||
- 从 0.12.0–0.12.5 升级到 0.12.6 或更高版本后,请重新执行一次 `Install Environment`,重建不再单独安装 BlendJob 的 Server Environment
|
||||
- 首次使用需要下载模型,如果下载慢或失败,可在 Image Empty 的 `SnapForm` 右键菜单点击
|
||||
- 首次使用需要下载模型,如果下载慢或失败,可在 Image Empty 的 `AnyImage` 右键菜单点击
|
||||
`Download Required Models`,也可在 `Models` panel 里逐项重试
|
||||
- 安装 Environment 时下载状态会显示平均速度;网络适合海外源时选择 `Install Environment`,国内网络选择 `Install Environment (Mirror)`。每个按钮固定使用对应来源,失败时不会自动切换
|
||||
- 默认模型下载会在 Hugging Face 与 OmooLab 镜像之间自动回退;某一来源暂时断线不会阻止后续模型尝试另一来源
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 视频与序列帧
|
||||
|
||||
SnapForm 可以逐帧处理视频和序列帧,并生成随场景时间播放的 Depth Plane 或透明 Image Empty。
|
||||
AnyImage 可以逐帧处理视频和序列帧,并生成随场景时间播放的 Depth Plane 或透明 Image Empty。
|
||||
|
||||
## 支持的工作流
|
||||
|
||||
@@ -17,7 +17,7 @@ SnapForm 可以逐帧处理视频和序列帧,并生成随场景时间播放
|
||||
- **Start** 决定结果从场景的哪一帧开始播放。
|
||||
- **Cyclic** 会保留到生成的颜色与深度序列中。
|
||||
|
||||
显式把 Image Frames 设为 `1` 时,SnapForm 只处理一帧。范围超过视频长度时,SnapForm 会把窗口收回有效范围内。
|
||||
显式把 Image Frames 设为 `1` 时,AnyImage 只处理一帧。范围超过视频长度时,AnyImage 会把窗口收回有效范围内。
|
||||
|
||||
## 性能建议
|
||||
|
||||
@@ -28,7 +28,7 @@ SnapForm 可以逐帧处理视频和序列帧,并生成随场景时间播放
|
||||
|
||||
## 保存和移动工程
|
||||
|
||||
Blender 无法把整组动画图片序列完整打包进 `.blend`。SnapForm 因此让动画结果直接引用 Storage Root 的 Job 文件夹。
|
||||
Blender 无法把整组动画图片序列完整打包进 `.blend`。AnyImage 因此让动画结果直接引用 Storage Root 的 Job 文件夹。
|
||||
|
||||
!!! danger
|
||||
删除、移动或清理仍被工程引用的 Job 文件夹,会导致动画颜色或深度序列丢失。
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## 程序设计
|
||||
|
||||
SnapForm 分为 Blender 交互层、BlendJob Runtime 和 Job Server 计算层。
|
||||
AnyImage 分为 Blender 交互层、BlendJob Runtime 和 Job Server 计算层。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
@@ -30,7 +30,7 @@ Blender 交互层管理 UI、RNA 状态、任务参数和结果导入。Runtime
|
||||
| `server/geometry/` | 纯数据几何处理 |
|
||||
| `server/outputs/` | 文件序列化 |
|
||||
| `server/media/` | 媒体输入 |
|
||||
| `assets/O_SnapForm.blend` | Geometry Nodes 与材质资产 |
|
||||
| `assets/O_AnyImage.blend` | Geometry Nodes 与材质资产 |
|
||||
|
||||
Depth Plane、Surface、Background 和 Balloon 按功能组织。一个功能的入口、请求和 Blender 回写放在一起;跨功能的图片、材质和参数处理放在 `operators/common.py`、`operators/image.py` 与 `operators/material.py`。
|
||||
|
||||
@@ -44,7 +44,7 @@ Server 的模型模块返回 Prediction,几何模块处理数组与网格,
|
||||
├── docs/
|
||||
├── pack.py
|
||||
├── sync_models.py
|
||||
├── src/snapform/
|
||||
├── src/anyimage/
|
||||
│ ├── blender_manifest.toml
|
||||
│ ├── runtime.py
|
||||
│ ├── menu.py
|
||||
@@ -94,7 +94,7 @@ uv run --only-group docs mike deploy <version> -p
|
||||
uv run --only-group docs mike set-default <version> -p
|
||||
```
|
||||
|
||||
自动部署将 MkDocs 站点发布到专用 Cloudflare Worker。仓库需要配置 `CLOUDFLARE_ACCOUNT_ID`、`CLOUDFLARE_API_TOKEN` 和 `CLOUDFLARE_WORKER_NAME`。Worker 路由对应 `docs.omoolab.xyz/snapform/*`。
|
||||
自动部署将 MkDocs 站点发布到专用 Cloudflare Worker。仓库需要配置 `CLOUDFLARE_ACCOUNT_ID`、`CLOUDFLARE_API_TOKEN` 和 `CLOUDFLARE_WORKER_NAME`。Worker 路由对应 `docs.omoolab.xyz/anyimage/*`。
|
||||
|
||||
## 资产构建与验证
|
||||
|
||||
@@ -117,5 +117,5 @@ BLENDER_BIN="/c/Program Files/Blender Foundation/Blender 4.5/blender.exe"
|
||||
|
||||
- Depth Anything 3 代码采用 Apache 2.0
|
||||
- BEN2 ONNX 模型采用其仓库声明的 Apache 2.0 License
|
||||
- SnapForm Extension 代码采用 GPL-3.0-or-later
|
||||
- AnyImage Extension 代码采用 GPL-3.0-or-later
|
||||
- 模型权重许可证由所选 Hugging Face 模型仓库决定
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# 常见问题
|
||||
|
||||
## 找不到 SnapForm 右键菜单
|
||||
## 找不到 AnyImage 右键菜单
|
||||
|
||||
SnapForm 菜单只会在选中 Image Empty 时出现。确认对象类型是 Empty,并且显示方式为 Image。普通 Mesh、图片编辑器中的图片或未选中的 Image Empty 都不会显示入口。
|
||||
AnyImage 菜单只会在选中 Image Empty 时出现。确认对象类型是 Empty,并且显示方式为 Image。普通 Mesh、图片编辑器中的图片或未选中的 Image Empty 都不会显示入口。
|
||||
|
||||
## 转换入口是灰色的
|
||||
|
||||
@@ -10,7 +10,7 @@ SnapForm 菜单只会在选中 Image Empty 时出现。确认对象类型是 Emp
|
||||
|
||||
- Environment 尚未安装。
|
||||
- 默认必需模型尚未就绪。
|
||||
- 另一个 SnapForm 任务正在运行。
|
||||
- 另一个 AnyImage 任务正在运行。
|
||||
- Surface 的输入不是单张图片。
|
||||
|
||||
如果子菜单显示 **Install Environment** 或 **Download Required Models**,先完成对应操作。
|
||||
@@ -50,7 +50,7 @@ SnapForm 菜单只会在选中 Image Empty 时出现。确认对象类型是 Emp
|
||||
|
||||
## 如何完全撤销一次转换
|
||||
|
||||
转换完成后直接按 `Ctrl+Z`。SnapForm 会把网格、材质、图片和修改器的创建合并为一次 Blender Undo 操作。
|
||||
转换完成后直接按 `Ctrl+Z`。AnyImage 会把网格、材质、图片和修改器的创建合并为一次 Blender Undo 操作。
|
||||
|
||||
## 从旧版本升级后功能不可用
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 功能参考
|
||||
|
||||
本页概览 SnapForm 的能力。安装步骤见[安装与首次配置](installation.md),实际操作见[工作流选择](workflows.md)与各使用指南。
|
||||
本页概览 AnyImage 的能力。安装步骤见[安装与首次配置](installation.md),实际操作见[工作流选择](workflows.md)与各使用指南。
|
||||
|
||||
## 工作流
|
||||
|
||||
@@ -16,9 +16,9 @@ Depth Plane 与 Surface 可使用 DA3 或 MoGe-2。DA3 提供相对深度和相
|
||||
|
||||
## Blender 交互
|
||||
|
||||
主要功能位于 Image Empty 的 `SnapForm` 右键菜单。菜单会显示 Environment 和必需模型的就绪状态,并在缺少内容时提供安装或下载入口。
|
||||
主要功能位于 Image Empty 的 `AnyImage` 右键菜单。菜单会显示 Environment 和必需模型的就绪状态,并在缺少内容时提供安装或下载入口。
|
||||
|
||||
转换任务完成后,SnapForm 在一个 Undo 步骤中创建网格、图片、材质和修改器。源 Image Empty 是否保留由转换选项决定。
|
||||
转换任务完成后,AnyImage 在一个 Undo 步骤中创建网格、图片、材质和修改器。源 Image Empty 是否保留由转换选项决定。
|
||||
|
||||
Balloon 默认在 Blender 内部生成,无需 Environment 或模型。Tool Settings 提供模式、厚度、采样距离、材质复用、`Contour`、`Depth` 与 MoGe-2 `Depth Model`。Depth 会把物理距离相对化并稳健拟合初始基面,保留未截断的正负起伏。Base Plane 子 Empty 的旋转定义基面朝向,沿自身局部 Z 移动定义 middle level。
|
||||
|
||||
@@ -36,7 +36,7 @@ Blender 无法整体 Pack 图片序列,因此动画结果会继续引用 Job
|
||||
|
||||
AI 任务在独立 Python Environment 中通过 ONNX Runtime 执行。Blender 负责界面、任务提交和结果导入,Job Server 负责模型与文件处理。
|
||||
|
||||
默认 Storage Root 为 `~/.snapform`,其中保存 Environment、模型、日志和 Job 结果。连续任务会复用已加载的模型 Session;DA3 与 MoGe-2 共享一个深度模型缓存位置,BEN2 可同时保留。
|
||||
默认 Storage Root 为 `~/.anyimage`,其中保存 Environment、模型、日志和 Job 结果。连续任务会复用已加载的模型 Session;DA3 与 MoGe-2 共享一个深度模型缓存位置,BEN2 可同时保留。
|
||||
|
||||
安装、下载和推理都在后台运行,并通过状态栏提供进度与取消操作。详细设计见[Job Server](server.md)。
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Depth Plane 将图片转换为带位移的立体面片。它适合快速场景
|
||||
## 创建 Depth Plane
|
||||
|
||||
1. 选中 Image Empty。
|
||||
2. 在 3D View 中右键,选择 **SnapForm > Convert to Depth Plane**。
|
||||
2. 在 3D View 中右键,选择 **AnyImage > Convert to Depth Plane**。
|
||||
3. 选择深度来源和需要的选项。
|
||||
4. 确认后等待任务完成。
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ Surface 从单张图片构建带透视关系的纹理网格。它适合建筑、
|
||||
## 创建 Surface
|
||||
|
||||
1. 选中只包含一帧的 Image Empty。
|
||||
2. 在 3D View 中右键,选择 **SnapForm > Convert to Surface**。
|
||||
2. 在 3D View 中右键,选择 **AnyImage > Convert to Surface**。
|
||||
3. 选择模型和转换选项。
|
||||
4. 确认后等待网格、材质和 Geometry Nodes 修改器创建完成。
|
||||
|
||||
@@ -16,7 +16,7 @@ Surface 从单张图片构建带透视关系的纹理网格。它适合建筑、
|
||||
|
||||
默认的 **MoGe-2 ViT-S Normal** 适合多数图片。MoGe-2 使用 **Resolution Level**,DA3 使用 **Resolution Scale**。提高分辨率会增加耗时和内存占用,建议先用默认值判断整体结构。
|
||||
|
||||
如果某个模型名称后显示 **(Missing)**,请先在 3D View 的 **SnapForm > Models** 面板下载它。
|
||||
如果某个模型名称后显示 **(Missing)**,请先在 3D View 的 **AnyImage > Models** 面板下载它。
|
||||
|
||||
## 转换选项
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# SnapForm
|
||||
# AnyImage
|
||||
|
||||
把图片里的空间感带进 Blender。
|
||||
|
||||
SnapForm 是一款 Blender 扩展,可以把照片、视频或序列帧转换为带真实深度变化的立体面片。你只需导入图片、选中 Image Empty,然后从右键菜单选择需要的结果。
|
||||
AnyImage 是一款 Blender 扩展,可以把照片、视频或序列帧转换为带真实深度变化的立体面片。你只需导入图片、选中 Image Empty,然后从右键菜单选择需要的结果。
|
||||
|
||||
- 用 **Depth Plane** 快速得到可调节的浮雕式面片
|
||||
- 用 **Surface** 从单张图片生成透视纹理网格
|
||||
@@ -11,13 +11,13 @@ SnapForm 是一款 Blender 扩展,可以把照片、视频或序列帧转换
|
||||
- 使用 Geometry Nodes 继续调整深度、细分、重拓扑与平滑效果
|
||||
|
||||
!!! info "运行环境与 Blender 分离"
|
||||
SnapForm 的 AI 计算运行在独立环境中,不会把 ONNX Runtime 等计算依赖装进 Blender Python。首次配置完成后,日常操作都可以从 Image Empty 的右键菜单完成。
|
||||
AnyImage 的 AI 计算运行在独立环境中,不会把 ONNX Runtime 等计算依赖装进 Blender Python。首次配置完成后,日常操作都可以从 Image Empty 的右键菜单完成。
|
||||
|
||||
## 从这里开始
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- **安装 SnapForm**
|
||||
- **安装 AnyImage**
|
||||
|
||||
下载与你的系统匹配的扩展包,完成环境和默认模型配置。
|
||||
|
||||
@@ -51,4 +51,4 @@ SnapForm 是一款 Blender 扩展,可以把照片、视频或序列帧转换
|
||||
- 正式使用前需要安装独立 Environment,以及默认的 MoGe-2 和 BEN2 模型
|
||||
|
||||
!!! tip
|
||||
不确定从哪里开始时,先使用默认设置将一张人物或物体照片转换为 Depth Plane。它速度快、参数直观,也最适合熟悉 SnapForm 的基本工作方式。
|
||||
不确定从哪里开始时,先使用默认设置将一张人物或物体照片转换为 Depth Plane。它速度快、参数直观,也最适合熟悉 AnyImage 的基本工作方式。
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# 安装与首次配置
|
||||
|
||||
SnapForm 的安装分为两步:先安装 Blender Extension,再安装独立运行环境和默认模型。第二步只需在首次使用或环境版本发生变化时执行。
|
||||
AnyImage 的安装分为两步:先安装 Blender Extension,再安装独立运行环境和默认模型。第二步只需在首次使用或环境版本发生变化时执行。
|
||||
|
||||
## 安装 Blender Extension
|
||||
|
||||
1. 下载与你的系统匹配的 ZIP 文件:
|
||||
- `SnapForm.v版本号.windows-x64.zip`
|
||||
- `SnapForm.v版本号.macos-arm64.zip`
|
||||
- `SnapForm.v版本号.linux-x64.zip`
|
||||
- `AnyImage.v版本号.windows-x64.zip`
|
||||
- `AnyImage.v版本号.macos-arm64.zip`
|
||||
- `AnyImage.v版本号.linux-x64.zip`
|
||||
2. 打开 Blender,进入 **Edit > Preferences > Extensions**。
|
||||
3. 点击右上角菜单,选择 **Install from Disk**。
|
||||
4. 选择下载的 ZIP 文件并完成安装。
|
||||
@@ -17,21 +17,21 @@ SnapForm 的安装分为两步:先安装 Blender Extension,再安装独立
|
||||
|
||||
## 检查扩展偏好设置
|
||||
|
||||
在 SnapForm 的扩展偏好设置中可以看到两个选项:
|
||||
在 AnyImage 的扩展偏好设置中可以看到两个选项:
|
||||
|
||||
- **Storage Root**:保存运行环境、模型和任务文件的位置。默认是用户目录下的 `.snapform`,一般无需修改。
|
||||
- **Device**:正式转换任务使用的计算设备。SnapForm 默认选择本机可用的最快设备;如果 GPU Provider 不可用,会使用 CPU。
|
||||
- **Storage Root**:保存运行环境、模型和任务文件的位置。默认是用户目录下的 `.anyimage`,一般无需修改。
|
||||
- **Device**:正式转换任务使用的计算设备。AnyImage 默认选择本机可用的最快设备;如果 GPU Provider 不可用,会使用 CPU。
|
||||
|
||||
如果准备把 Storage Root 放到其他磁盘,建议在首次安装 Environment 之前修改。更换目录后,旧目录中的环境和模型不会自动移动。
|
||||
|
||||
## 安装 Environment
|
||||
|
||||
打开 3D View,按 `N` 显示侧栏并切换到 **SnapForm** 页签。在 **Job Server** 面板中选择一个安装入口:
|
||||
打开 3D View,按 `N` 显示侧栏并切换到 **AnyImage** 页签。在 **Job Server** 面板中选择一个安装入口:
|
||||
|
||||
- **Install Environment**:使用官方源,适合能稳定访问 GitHub、Python 下载源和 PyPI 的网络。
|
||||
- **Install Environment (Mirror)**:使用国内镜像下载 uv、Python 和 Python 包。
|
||||
|
||||
安装程序会依次准备 uv、独立 Python 和运行包。Environment 完成后,SnapForm 还会下载日常功能需要的 **MoGe-2 ViT-S Normal** 与 **BEN2 Base**。
|
||||
安装程序会依次准备 uv、独立 Python 和运行包。Environment 完成后,AnyImage 还会下载日常功能需要的 **MoGe-2 ViT-S Normal** 与 **BEN2 Base**。
|
||||
|
||||
!!! note
|
||||
两个安装按钮只影响 Environment 的下载源。模型会按自己的下载源与备用镜像规则获取。
|
||||
@@ -46,7 +46,7 @@ SnapForm 的安装分为两步:先安装 Blender Extension,再安装独立
|
||||
- 展开 **Models** 面板,MoGe-2 ViT-S Normal 和 BEN2 Base 显示 **Ready**。
|
||||
- 选中 Image Empty 后,右键菜单中的 **Convert to Depth Plane**、**Convert to Surface** 和 **Remove Background** 可以点击。
|
||||
|
||||
如果 Environment 已安装但默认模型缺失,Image Empty 的 **SnapForm** 右键子菜单会显示 **Download Required Models**。点击一次即可补齐缺失项。
|
||||
如果 Environment 已安装但默认模型缺失,Image Empty 的 **AnyImage** 右键子菜单会显示 **Download Required Models**。点击一次即可补齐缺失项。
|
||||
|
||||
## 下一步
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# 模型、设备与存储
|
||||
|
||||
SnapForm 把运行环境、模型和任务结果放在 Blender 之外,多个 Blender 版本可以共享同一套数据。
|
||||
AnyImage 把运行环境、模型和任务结果放在 Blender 之外,多个 Blender 版本可以共享同一套数据。
|
||||
|
||||
## Models 面板
|
||||
|
||||
打开 3D View 侧栏中的 **SnapForm > Models**,可以查看和下载模型。
|
||||
打开 3D View 侧栏中的 **AnyImage > Models**,可以查看和下载模型。
|
||||
|
||||
- **Ready** 表示模型文件已经就绪。
|
||||
- **Download** 用于按需下载模型。
|
||||
@@ -25,10 +25,10 @@ Debug 面板中的 **Debug Device** 只影响 Debug 任务,不会覆盖正式
|
||||
|
||||
## Storage Root
|
||||
|
||||
默认 Storage Root 是 `~/.snapform`,主要包含:
|
||||
默认 Storage Root 是 `~/.anyimage`,主要包含:
|
||||
|
||||
```text
|
||||
~/.snapform/
|
||||
~/.anyimage/
|
||||
├── .venv/ # 独立 Python Environment
|
||||
├── models/ # 模型文件
|
||||
├── jobs/ # 每次任务的结果
|
||||
@@ -36,7 +36,7 @@ Debug 面板中的 **Debug Device** 只影响 Debug 任务,不会覆盖正式
|
||||
└── server.log # Job Server 日志
|
||||
```
|
||||
|
||||
更改 Storage Root 相当于切换到另一套环境、模型和任务数据。SnapForm 不会自动移动旧目录。
|
||||
更改 Storage Root 相当于切换到另一套环境、模型和任务数据。AnyImage 不会自动移动旧目录。
|
||||
|
||||
## Job 文件夹
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
|
||||
建议第一次尝试使用主体清晰、前后景关系明确的图片。人物、产品、建筑立面和插画通常都比较适合。
|
||||
|
||||
## 2. 打开 SnapForm 菜单
|
||||
## 2. 打开 AnyImage 菜单
|
||||
|
||||
保持 Image Empty 处于选中状态,在 3D View 中点击右键,选择 **SnapForm > Convert to Depth Plane**。
|
||||
保持 Image Empty 处于选中状态,在 3D View 中点击右键,选择 **AnyImage > Convert to Depth Plane**。
|
||||
|
||||
如果菜单不存在,请确认当前对象是 Image Empty;如果转换入口是灰色,请先完成[安装与首次配置](installation.md)。
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@ Remove Background 使用 BEN2 为 Image Empty 生成透明前景,不创建网
|
||||
## 使用方法
|
||||
|
||||
1. 选中 Image Empty。
|
||||
2. 在 3D View 中右键,选择 **SnapForm > Remove Background**。
|
||||
2. 在 3D View 中右键,选择 **AnyImage > Remove Background**。
|
||||
3. 等待状态栏提示任务完成。
|
||||
|
||||
SnapForm 会创建新的透明颜色图,并把当前 Empty 切换到新图。对象的 Transform、显示尺寸、Offset 和其他显示设置保持不变。
|
||||
AnyImage 会创建新的透明颜色图,并把当前 Empty 切换到新图。对象的 Transform、显示尺寸、Offset 和其他显示设置保持不变。
|
||||
|
||||
## 在转换时去除背景
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Job Server
|
||||
|
||||
SnapForm 把 AI 与媒体处理放在独立 Job Server 中运行,使 Blender Python 保持轻量。安装和使用问题见[安装与首次配置](installation.md)与[常见问题](faq.md)。
|
||||
AnyImage 把 AI 与媒体处理放在独立 Job Server 中运行,使 Blender Python 保持轻量。安装和使用问题见[安装与首次配置](installation.md)与[常见问题](faq.md)。
|
||||
|
||||
## 架构
|
||||
|
||||
@@ -8,7 +8,7 @@ SnapForm 把 AI 与媒体处理放在独立 Job Server 中运行,使 Blender P
|
||||
flowchart LR
|
||||
Blender["Blender Operator"] --> Runtime["JobRuntime"]
|
||||
Runtime --> Queue["FIFO Queue"]
|
||||
Queue --> Job["SnapForm Job"]
|
||||
Queue --> Job["AnyImage Job"]
|
||||
Job --> Media["Media"]
|
||||
Job --> Models["ModelManager"]
|
||||
Job --> Geometry["Geometry"]
|
||||
@@ -19,14 +19,14 @@ flowchart LR
|
||||
|
||||
每个 Blender 实例拥有自己的 Server 进程,连接绑定到本机随机端口和 Instance ID。多个实例可以共享 Storage Root,但各自维护进程、队列和内存中的模型 Session。
|
||||
|
||||
BlendJob 提供 Runtime、HTTP transport、队列、状态和取消协议。SnapForm 的 Operator 负责业务参数,Server Job 负责工作流编排,结果由 Operator 在 Blender 主线程中导入。
|
||||
BlendJob 提供 Runtime、HTTP transport、队列、状态和取消协议。AnyImage 的 Operator 负责业务参数,Server Job 负责工作流编排,结果由 Operator 在 Blender 主线程中导入。
|
||||
|
||||
## Storage Root
|
||||
|
||||
默认位置为 `~/.snapform`:
|
||||
默认位置为 `~/.anyimage`:
|
||||
|
||||
```text
|
||||
~/.snapform/
|
||||
~/.anyimage/
|
||||
├── .venv/ Python Environment
|
||||
├── models/ ONNX 模型
|
||||
├── jobs/ 任务产物
|
||||
|
||||
@@ -53,7 +53,7 @@ DA3 使用 `O DA3 Surface`,MoGe-2 使用 `O MoGe2 Surface`。两者采用相
|
||||
|
||||
网格在 camera space 中生成,再通过源 Image Empty 的 Transform 放入场景。导入过程会匹配图片可见尺寸、宽高比、Offset 与主点位置。
|
||||
|
||||
启用 Create Matching Camera 时,SnapForm 根据模型 intrinsics 创建相机并使用相同坐标变换,使网格与相机视图保持一致。模型估计的焦距和主点决定透视关系;`reference_depth` 决定整体尺度。
|
||||
启用 Create Matching Camera 时,AnyImage 根据模型 intrinsics 创建相机并使用相同坐标变换,使网格与相机视图保持一致。模型估计的焦距和主点决定透视关系;`reference_depth` 决定整体尺度。
|
||||
|
||||
## 材质与文件
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 选择转换方式
|
||||
|
||||
SnapForm 提供三种日常工作流。选择结果时,先考虑你需要的是可调节的“深度面片”、带透视结构的“空间网格”,还是只需要透明前景。
|
||||
AnyImage 提供三种日常工作流。选择结果时,先考虑你需要的是可调节的“深度面片”、带透视结构的“空间网格”,还是只需要透明前景。
|
||||
|
||||
| 工作流 | 适合场景 | 输入 | 结果 | 主要优点 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
|
||||
12
mkdocs.yml
12
mkdocs.yml
@@ -1,13 +1,13 @@
|
||||
site_name: SnapForm 文档
|
||||
site_url: https://docs.omoolab.xyz/snapform/
|
||||
site_name: AnyImage 文档
|
||||
site_url: https://docs.omoolab.xyz/anyimage/
|
||||
site_author: OmooLab
|
||||
site_description: SnapForm 是一款将图片、视频和序列帧转换为立体面片的 Blender 扩展。
|
||||
site_description: AnyImage 是一款将图片、视频和序列帧转换为立体面片的 Blender 扩展。
|
||||
|
||||
repo_name: OmooLab/SnapForm
|
||||
repo_url: https://git.omoolab.xyz/icrdr/SnapForm
|
||||
repo_name: OmooLab/AnyImage
|
||||
repo_url: https://git.omoolab.xyz/icrdr/AnyImage
|
||||
|
||||
nav:
|
||||
- SnapForm:
|
||||
- AnyImage:
|
||||
- index.md
|
||||
- 开始使用:
|
||||
- 安装与首次配置: installation.md
|
||||
|
||||
2
pack.py
2
pack.py
@@ -8,7 +8,7 @@ from zipfile import ZIP_DEFLATED, ZipFile
|
||||
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parent
|
||||
SOURCE_DIR = PROJECT_ROOT / "src" / "snapform"
|
||||
SOURCE_DIR = PROJECT_ROOT / "src" / "anyimage"
|
||||
DIST_DIR = PROJECT_ROOT / "dist"
|
||||
PYTHON_VERSION = "3.11"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[project]
|
||||
name = "snapform"
|
||||
name = "anyimage"
|
||||
version = "0.12.15"
|
||||
description = "Fast image-guided structure building tools for Blender"
|
||||
readme = "README.md"
|
||||
|
||||
@@ -3,9 +3,9 @@ import bpy
|
||||
from .runtime import runtime
|
||||
from .operators import CLASSES as OPERATOR_CLASSES
|
||||
from .operators.balloon import BalloonTool
|
||||
from .preferences import SnapFormPreferences
|
||||
from .properties import SnapFormSettings
|
||||
from .menu import SnapFormImageMenu, draw_image_context_menu
|
||||
from .preferences import AnyImagePreferences
|
||||
from .properties import AnyImageSettings
|
||||
from .menu import AnyImageImageMenu, draw_image_context_menu
|
||||
from .panel import (
|
||||
Ben2RemovalDebugPanel,
|
||||
Da3OutputDebugPanel,
|
||||
@@ -17,10 +17,10 @@ from .panel import (
|
||||
|
||||
|
||||
CLASSES = (
|
||||
SnapFormPreferences,
|
||||
SnapFormSettings,
|
||||
AnyImagePreferences,
|
||||
AnyImageSettings,
|
||||
*OPERATOR_CLASSES,
|
||||
SnapFormImageMenu,
|
||||
AnyImageImageMenu,
|
||||
ServerPanel,
|
||||
ModelsPanel,
|
||||
DebugPanel,
|
||||
@@ -37,8 +37,8 @@ def register():
|
||||
BalloonTool,
|
||||
separator=False,
|
||||
)
|
||||
bpy.types.Scene.snapform_settings = bpy.props.PointerProperty(
|
||||
type=SnapFormSettings,
|
||||
bpy.types.Scene.anyimage_settings = bpy.props.PointerProperty(
|
||||
type=AnyImageSettings,
|
||||
)
|
||||
bpy.types.VIEW3D_MT_object_context_menu.append(draw_image_context_menu)
|
||||
bpy.types.OUTLINER_MT_object.append(draw_image_context_menu)
|
||||
@@ -50,7 +50,7 @@ def unregister():
|
||||
bpy.utils.unregister_tool(BalloonTool)
|
||||
bpy.types.VIEW3D_MT_object_context_menu.remove(draw_image_context_menu)
|
||||
bpy.types.OUTLINER_MT_object.remove(draw_image_context_menu)
|
||||
if hasattr(bpy.types.Scene, "snapform_settings"):
|
||||
del bpy.types.Scene.snapform_settings
|
||||
if hasattr(bpy.types.Scene, "anyimage_settings"):
|
||||
del bpy.types.Scene.anyimage_settings
|
||||
for class_type in reversed(CLASSES):
|
||||
bpy.utils.unregister_class(class_type)
|
||||
@@ -1,8 +1,8 @@
|
||||
schema_version = "1.0.0"
|
||||
|
||||
id = "snapform"
|
||||
id = "anyimage"
|
||||
version = "0.12.15"
|
||||
name = "SnapForm"
|
||||
name = "AnyImage"
|
||||
tagline = "Build spatial structures from images, fast"
|
||||
maintainer = "OmooLab"
|
||||
type = "add-on"
|
||||
@@ -3,9 +3,9 @@ import bpy
|
||||
from .operators.image import is_image_empty
|
||||
|
||||
|
||||
class SnapFormImageMenu(bpy.types.Menu):
|
||||
bl_idname = "SNAPFORM_MT_image_context"
|
||||
bl_label = "SnapForm"
|
||||
class AnyImageImageMenu(bpy.types.Menu):
|
||||
bl_idname = "ANYIMAGE_MT_image_context"
|
||||
bl_label = "AnyImage"
|
||||
|
||||
def draw(self, _context):
|
||||
from .runtime import runtime
|
||||
@@ -14,7 +14,7 @@ class SnapFormImageMenu(bpy.types.Menu):
|
||||
layout = self.layout
|
||||
layout.operator_context = "INVOKE_DEFAULT"
|
||||
layout.operator(
|
||||
"snapform.activate_balloon_tool",
|
||||
"anyimage.activate_balloon_tool",
|
||||
text="Balloon Lasso Tool",
|
||||
icon="MOD_SKIN",
|
||||
)
|
||||
@@ -22,19 +22,19 @@ class SnapFormImageMenu(bpy.types.Menu):
|
||||
environment_ready = runtime.environment_ready()
|
||||
if not environment_ready:
|
||||
layout.operator(
|
||||
"snapform.install_environment",
|
||||
"anyimage.install_environment",
|
||||
text="Install Environment",
|
||||
icon="IMPORT",
|
||||
)
|
||||
layout.operator(
|
||||
"snapform.install_environment_mirror",
|
||||
"anyimage.install_environment_mirror",
|
||||
text="Install Environment (Mirror)",
|
||||
icon="IMPORT",
|
||||
)
|
||||
models_ready = required_models_ready()
|
||||
if environment_ready and not models_ready:
|
||||
layout.operator(
|
||||
"snapform.download_required_models",
|
||||
"anyimage.download_required_models",
|
||||
text="Download Required Models",
|
||||
icon="IMPORT",
|
||||
)
|
||||
@@ -44,14 +44,14 @@ class SnapFormImageMenu(bpy.types.Menu):
|
||||
depth_plane_row = layout.row()
|
||||
depth_plane_row.enabled = features_ready
|
||||
depth_plane_row.operator(
|
||||
"snapform.convert_to_depth_plane",
|
||||
"anyimage.convert_to_depth_plane",
|
||||
text="Convert to Depth Plane",
|
||||
icon="MOD_DISPLACE",
|
||||
)
|
||||
surface_row = layout.row()
|
||||
surface_row.enabled = features_ready
|
||||
surface_row.operator(
|
||||
"snapform.convert_to_surface",
|
||||
"anyimage.convert_to_surface",
|
||||
text="Convert to Surface",
|
||||
icon="MESH_GRID",
|
||||
)
|
||||
@@ -59,7 +59,7 @@ class SnapFormImageMenu(bpy.types.Menu):
|
||||
background_row = layout.row()
|
||||
background_row.enabled = features_ready
|
||||
background_row.operator(
|
||||
"snapform.remove_image_background",
|
||||
"anyimage.remove_image_background",
|
||||
text="Remove Background",
|
||||
icon="IMAGE_ALPHA",
|
||||
)
|
||||
@@ -70,7 +70,7 @@ def draw_image_context_menu(self, context):
|
||||
return
|
||||
self.layout.separator()
|
||||
self.layout.menu(
|
||||
SnapFormImageMenu.bl_idname,
|
||||
text="SnapForm",
|
||||
AnyImageImageMenu.bl_idname,
|
||||
text="AnyImage",
|
||||
icon="PLUGIN",
|
||||
)
|
||||
@@ -23,7 +23,7 @@ from .image import (
|
||||
|
||||
|
||||
class RemoveImageBackground(bpy.types.Operator):
|
||||
bl_idname = "snapform.remove_image_background"
|
||||
bl_idname = "anyimage.remove_image_background"
|
||||
bl_label = "Remove Background"
|
||||
bl_description = "Remove the background from this Image Empty with BEN2"
|
||||
bl_options = {"REGISTER"}
|
||||
@@ -44,7 +44,7 @@ class RemoveImageBackground(bpy.types.Operator):
|
||||
source_object = context.object
|
||||
total_frames = video_total_frames(source_object.data)
|
||||
if total_frames > 1:
|
||||
context.scene.snapform_settings.video_frames = (
|
||||
context.scene.anyimage_settings.video_frames = (
|
||||
default_extract_frames(source_object)
|
||||
)
|
||||
try:
|
||||
@@ -56,7 +56,7 @@ class RemoveImageBackground(bpy.types.Operator):
|
||||
self.report({"ERROR"}, str(error))
|
||||
return {"CANCELLED"}
|
||||
|
||||
result = bpy.ops.snapform.process_image_background(
|
||||
result = bpy.ops.anyimage.process_image_background(
|
||||
input_path=str(source_path),
|
||||
source_object_name=source_object.name,
|
||||
delete_input=delete_input,
|
||||
@@ -83,7 +83,7 @@ def apply_background_response(result, source_object_name):
|
||||
|
||||
|
||||
class ProcessImageBackground(JobOperatorBase, bpy.types.Operator):
|
||||
bl_idname = "snapform.process_image_background"
|
||||
bl_idname = "anyimage.process_image_background"
|
||||
bl_label = "Process Image Background"
|
||||
job_type = "remove-background"
|
||||
starting_message = "Starting Image Empty background removal"
|
||||
@@ -95,7 +95,7 @@ class ProcessImageBackground(JobOperatorBase, bpy.types.Operator):
|
||||
def request(self, context):
|
||||
require_environment()
|
||||
require_model(BEN2_MODEL_KEY)
|
||||
settings = context.scene.snapform_settings
|
||||
settings = context.scene.anyimage_settings
|
||||
return {
|
||||
"input": str(background_input_path(self.input_path)),
|
||||
"model": BEN2_MODEL_KEY,
|
||||
@@ -8,7 +8,7 @@ import bpy
|
||||
BALLOON_DEPTH_ATTRIBUTE = "o_balloon_depth"
|
||||
BALLOON_SHAPE_NODE_GROUP_NAME = "O Balloon Shape"
|
||||
BALLOON_SHAPE_NODE_GROUP_VERSION = 16
|
||||
BALLOON_SHAPE_VERSION_PROPERTY = "snapform_balloon_shape_version"
|
||||
BALLOON_SHAPE_VERSION_PROPERTY = "anyimage_balloon_shape_version"
|
||||
|
||||
|
||||
def load_balloon_depth_data(path):
|
||||
@@ -216,8 +216,8 @@ def create_balloon_base_plane(context, balloon, vertices, local_plane):
|
||||
controller.empty_display_size = max(float(extent.max()) * 0.15, 0.01)
|
||||
controller.show_in_front = True
|
||||
controller.hide_render = True
|
||||
controller["snapform_source_type"] = "BALLOON_BASE_PLANE"
|
||||
controller["snapform_base_plane"] = (slope_y, slope_z, offset)
|
||||
controller["anyimage_source_type"] = "BALLOON_BASE_PLANE"
|
||||
controller["anyimage_base_plane"] = (slope_y, slope_z, offset)
|
||||
return controller
|
||||
|
||||
|
||||
@@ -49,9 +49,9 @@ from ..surface import assign_vertex_uv
|
||||
|
||||
|
||||
MIN_PATH_DISTANCE = 2.0
|
||||
BALLOON_MATERIAL_PROPERTY = "snapform_balloon_material"
|
||||
BALLOON_SOURCE_IMAGE_PROPERTY = "snapform_source_image"
|
||||
BALLOON_NORMAL_IMAGE_PROPERTY = "snapform_balloon_normal_image"
|
||||
BALLOON_MATERIAL_PROPERTY = "anyimage_balloon_material"
|
||||
BALLOON_SOURCE_IMAGE_PROPERTY = "anyimage_source_image"
|
||||
BALLOON_NORMAL_IMAGE_PROPERTY = "anyimage_balloon_normal_image"
|
||||
|
||||
|
||||
def simplify_screen_path(path):
|
||||
@@ -395,11 +395,11 @@ def extract_balloon_object(
|
||||
balloon = bpy.data.objects.new(balloon_name, mesh)
|
||||
context.collection.objects.link(balloon)
|
||||
balloon.matrix_world = orient_balloon_world_matrix(matrix_world)
|
||||
balloon["snapform_source_type"] = "BALLOON"
|
||||
balloon["snapform_balloon_algorithm"] = algorithm
|
||||
balloon["snapform_source_object"] = source_name
|
||||
balloon["snapform_inflation"] = inflation
|
||||
balloon["snapform_resolution"] = point_spacing
|
||||
balloon["anyimage_source_type"] = "BALLOON"
|
||||
balloon["anyimage_balloon_algorithm"] = algorithm
|
||||
balloon["anyimage_source_object"] = source_name
|
||||
balloon["anyimage_inflation"] = inflation
|
||||
balloon["anyimage_resolution"] = point_spacing
|
||||
balloon.data.materials.append(material)
|
||||
if depth_data is not None:
|
||||
base_plane = create_balloon_base_plane(
|
||||
@@ -410,8 +410,8 @@ def extract_balloon_object(
|
||||
)
|
||||
add_balloon_shape_modifier(balloon, thickness, base_plane)
|
||||
if depth_data is not None:
|
||||
balloon["snapform_balloon_depth_analysis"] = True
|
||||
balloon["snapform_reference_depth"] = depth_data["reference_depth"]
|
||||
balloon["anyimage_balloon_depth_analysis"] = True
|
||||
balloon["anyimage_reference_depth"] = depth_data["reference_depth"]
|
||||
except Exception:
|
||||
if base_plane is not None:
|
||||
bpy.data.objects.remove(base_plane, do_unlink=True)
|
||||
@@ -473,7 +473,7 @@ def drawing_in_region(area_pointer, region_pointer):
|
||||
|
||||
|
||||
class ExtractBalloon(bpy.types.Operator):
|
||||
bl_idname = "snapform.extract_balloon"
|
||||
bl_idname = "anyimage.extract_balloon"
|
||||
bl_label = "Extract Balloon"
|
||||
bl_description = "Build one closed Balloon mesh from a saved lasso region"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
@@ -536,7 +536,7 @@ class ExtractBalloon(bpy.types.Operator):
|
||||
|
||||
def invoke(self, context, event):
|
||||
source_object = context.active_object
|
||||
settings = context.scene.snapform_settings
|
||||
settings = context.scene.anyimage_settings
|
||||
self.mode = settings.balloon_mode
|
||||
self.thickness = settings.balloon_thickness
|
||||
self.resolution = settings.balloon_resolution
|
||||
@@ -622,7 +622,7 @@ class ExtractBalloon(bpy.types.Operator):
|
||||
source_object.data,
|
||||
context.scene,
|
||||
)
|
||||
result = bpy.ops.snapform.analyze_balloon(
|
||||
result = bpy.ops.anyimage.analyze_balloon(
|
||||
input_path=str(source_path),
|
||||
delete_input=delete_input,
|
||||
source_object_name=self.source_object_name,
|
||||
@@ -657,7 +657,7 @@ class ExtractBalloon(bpy.types.Operator):
|
||||
select_result=False,
|
||||
reuse_material=self.reuse_material,
|
||||
)
|
||||
balloon["snapform_resolution_m"] = self.resolution
|
||||
balloon["anyimage_resolution_m"] = self.resolution
|
||||
except (json.JSONDecodeError, RuntimeError, TypeError, ValueError) as error:
|
||||
self.report({"ERROR"}, str(error))
|
||||
return {"CANCELLED"}
|
||||
@@ -665,7 +665,7 @@ class ExtractBalloon(bpy.types.Operator):
|
||||
|
||||
|
||||
class AnalyzeBalloon(JobOperatorBase, bpy.types.Operator):
|
||||
bl_idname = "snapform.analyze_balloon"
|
||||
bl_idname = "anyimage.analyze_balloon"
|
||||
bl_label = "Analyze Balloon"
|
||||
job_type = "analyze-balloon"
|
||||
starting_message = "Starting Balloon AI analysis"
|
||||
@@ -744,11 +744,11 @@ class AnalyzeBalloon(JobOperatorBase, bpy.types.Operator):
|
||||
depth_data=depth_data,
|
||||
normal_path=(result.file("normal") if self.depth_analysis else None),
|
||||
)
|
||||
balloon["snapform_resolution_m"] = self.resolution
|
||||
balloon["anyimage_resolution_m"] = self.resolution
|
||||
if self.contour_analysis:
|
||||
balloon["snapform_balloon_contour_analysis"] = True
|
||||
balloon["anyimage_balloon_contour_analysis"] = True
|
||||
if self.depth_analysis:
|
||||
balloon["snapform_balloon_depth_model"] = self.depth_model
|
||||
balloon["anyimage_balloon_depth_model"] = self.depth_model
|
||||
push_undo("Extract Balloon")
|
||||
return "AI-analyzed Balloon is ready"
|
||||
|
||||
@@ -757,7 +757,7 @@ class AnalyzeBalloon(JobOperatorBase, bpy.types.Operator):
|
||||
|
||||
|
||||
class ActivateBalloonTool(bpy.types.Operator):
|
||||
bl_idname = "snapform.activate_balloon_tool"
|
||||
bl_idname = "anyimage.activate_balloon_tool"
|
||||
bl_label = "Balloon Lasso Tool"
|
||||
bl_description = "Activate the Balloon Lasso tool in the 3D Viewport"
|
||||
bl_options = {"INTERNAL"}
|
||||
@@ -780,7 +780,7 @@ class ActivateBalloonTool(bpy.types.Operator):
|
||||
class BalloonTool(bpy.types.WorkSpaceTool):
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_context_mode = "OBJECT"
|
||||
bl_idname = "snapform.balloon_lasso"
|
||||
bl_idname = "anyimage.balloon_lasso"
|
||||
bl_label = "Balloon Lasso"
|
||||
bl_description = (
|
||||
"Draw an Image Empty region and extract one independently undoable "
|
||||
@@ -802,11 +802,11 @@ class BalloonTool(bpy.types.WorkSpaceTool):
|
||||
"properties": [
|
||||
(
|
||||
"data_path_primary",
|
||||
"scene.snapform_settings.balloon_thickness",
|
||||
"scene.anyimage_settings.balloon_thickness",
|
||||
),
|
||||
(
|
||||
"zoom_path",
|
||||
"scene.snapform_settings.balloon_thickness_radial_zoom",
|
||||
"scene.anyimage_settings.balloon_thickness_radial_zoom",
|
||||
),
|
||||
]
|
||||
},
|
||||
@@ -818,11 +818,11 @@ class BalloonTool(bpy.types.WorkSpaceTool):
|
||||
"properties": [
|
||||
(
|
||||
"data_path_primary",
|
||||
"scene.snapform_settings.balloon_resolution",
|
||||
"scene.anyimage_settings.balloon_resolution",
|
||||
),
|
||||
(
|
||||
"zoom_path",
|
||||
"scene.snapform_settings.balloon_resolution_radial_zoom",
|
||||
"scene.anyimage_settings.balloon_resolution_radial_zoom",
|
||||
),
|
||||
]
|
||||
},
|
||||
@@ -830,7 +830,7 @@ class BalloonTool(bpy.types.WorkSpaceTool):
|
||||
)
|
||||
|
||||
def draw_settings(context, layout, tool):
|
||||
settings = context.scene.snapform_settings
|
||||
settings = context.scene.anyimage_settings
|
||||
layout.prop(settings, "balloon_mode", text="")
|
||||
layout.prop(settings, "balloon_thickness")
|
||||
layout.prop(settings, "balloon_resolution", text="Resolution (m)")
|
||||
@@ -46,7 +46,7 @@ def production_device():
|
||||
|
||||
def require_environment():
|
||||
if not runtime.environment_ready():
|
||||
raise RuntimeError("Install the SnapForm Environment first")
|
||||
raise RuntimeError("Install the AnyImage Environment first")
|
||||
|
||||
|
||||
def require_model(model_key):
|
||||
@@ -14,14 +14,14 @@ from .common import (
|
||||
|
||||
|
||||
class DebugDa3(JobOperatorBase, bpy.types.Operator):
|
||||
bl_idname = "snapform.debug_da3"
|
||||
bl_idname = "anyimage.debug_da3"
|
||||
bl_label = "Debug DA3"
|
||||
job_type = "debug-da3"
|
||||
starting_message = "Starting DA3 API inference"
|
||||
|
||||
def request(self, context):
|
||||
require_environment()
|
||||
settings = context.scene.snapform_settings
|
||||
settings = context.scene.anyimage_settings
|
||||
model = settings.model
|
||||
require_model(model)
|
||||
return {
|
||||
@@ -43,14 +43,14 @@ class DebugDa3(JobOperatorBase, bpy.types.Operator):
|
||||
|
||||
|
||||
class DebugMoge2(JobOperatorBase, bpy.types.Operator):
|
||||
bl_idname = "snapform.debug_moge2"
|
||||
bl_idname = "anyimage.debug_moge2"
|
||||
bl_label = "Debug MoGe-2"
|
||||
job_type = "debug-moge2"
|
||||
starting_message = "Starting MoGe-2 inference"
|
||||
|
||||
def request(self, context):
|
||||
require_environment()
|
||||
settings = context.scene.snapform_settings
|
||||
settings = context.scene.anyimage_settings
|
||||
require_model(settings.moge_model)
|
||||
return {
|
||||
**moge2_parameters(
|
||||
@@ -69,14 +69,14 @@ class DebugMoge2(JobOperatorBase, bpy.types.Operator):
|
||||
|
||||
|
||||
class DebugBen2(JobOperatorBase, bpy.types.Operator):
|
||||
bl_idname = "snapform.debug_ben2"
|
||||
bl_idname = "anyimage.debug_ben2"
|
||||
bl_label = "Debug BEN2"
|
||||
job_type = "debug-ben2"
|
||||
starting_message = "Starting BEN2 background removal"
|
||||
|
||||
def request(self, context):
|
||||
require_environment()
|
||||
settings = context.scene.snapform_settings
|
||||
settings = context.scene.anyimage_settings
|
||||
require_model(BEN2_MODEL_KEY)
|
||||
return {
|
||||
"input": str(background_input_path(settings.background_input_path)),
|
||||
@@ -326,7 +326,7 @@ def build_image_depth_plane(
|
||||
use_cyclic=source_use_cyclic,
|
||||
animate_frame=is_animated_image(source_object.data),
|
||||
)
|
||||
plane_object["snapform_frame_count"] = frame_count
|
||||
plane_object["anyimage_frame_count"] = frame_count
|
||||
return finish_depth_plane(
|
||||
context,
|
||||
source_object,
|
||||
@@ -431,11 +431,11 @@ def build_depth_plane(
|
||||
use_cyclic=source_use_cyclic,
|
||||
animate_frame=is_animated_image(source_object.data),
|
||||
)
|
||||
plane_object["snapform_reference_depth"] = reference_depth
|
||||
plane_object["snapform_camera_plane_width"] = bounds[1] - bounds[0]
|
||||
plane_object["snapform_camera_plane_height"] = bounds[3] - bounds[2]
|
||||
plane_object["snapform_depth_scale"] = depth_scale
|
||||
plane_object["snapform_frame_count"] = frame_count
|
||||
plane_object["anyimage_reference_depth"] = reference_depth
|
||||
plane_object["anyimage_camera_plane_width"] = bounds[1] - bounds[0]
|
||||
plane_object["anyimage_camera_plane_height"] = bounds[3] - bounds[2]
|
||||
plane_object["anyimage_depth_scale"] = depth_scale
|
||||
plane_object["anyimage_frame_count"] = frame_count
|
||||
|
||||
return finish_depth_plane(
|
||||
context,
|
||||
@@ -536,9 +536,9 @@ def build_moge2_depth_plane(
|
||||
use_cyclic=source_use_cyclic,
|
||||
animate_frame=is_animated_image(source_object.data),
|
||||
)
|
||||
plane_object["snapform_reference_depth"] = reference_depth
|
||||
plane_object["snapform_depth_scale"] = depth_scale
|
||||
plane_object["snapform_frame_count"] = len(depth)
|
||||
plane_object["anyimage_reference_depth"] = reference_depth
|
||||
plane_object["anyimage_depth_scale"] = depth_scale
|
||||
plane_object["anyimage_frame_count"] = len(depth)
|
||||
return finish_depth_plane(
|
||||
context,
|
||||
source_object,
|
||||
@@ -36,7 +36,7 @@ def image_depth_model_items(owner, context):
|
||||
|
||||
|
||||
class ConvertToDepthPlane(bpy.types.Operator):
|
||||
bl_idname = "snapform.convert_to_depth_plane"
|
||||
bl_idname = "anyimage.convert_to_depth_plane"
|
||||
bl_label = "Convert to Depth Plane"
|
||||
bl_description = "Convert an image to a displaced depth plane"
|
||||
bl_options = {"REGISTER"}
|
||||
@@ -101,7 +101,7 @@ class ConvertToDepthPlane(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
source_object = context.object
|
||||
if video_total_frames(source_object.data) > 1:
|
||||
context.scene.snapform_settings.video_frames = (
|
||||
context.scene.anyimage_settings.video_frames = (
|
||||
default_extract_frames(source_object)
|
||||
)
|
||||
if self.model == "ORIGINAL":
|
||||
@@ -114,9 +114,9 @@ class ConvertToDepthPlane(bpy.types.Operator):
|
||||
self.report({"ERROR"}, str(error))
|
||||
return {"CANCELLED"}
|
||||
run_original = (
|
||||
bpy.ops.snapform.generate_original_background
|
||||
bpy.ops.anyimage.generate_original_background
|
||||
if self.remove_background
|
||||
else bpy.ops.snapform.extract_original_frames
|
||||
else bpy.ops.anyimage.extract_original_frames
|
||||
)
|
||||
result = run_original(
|
||||
input_path=str(source_path),
|
||||
@@ -140,7 +140,7 @@ class ConvertToDepthPlane(bpy.types.Operator):
|
||||
except RuntimeError as error:
|
||||
self.report({"ERROR"}, str(error))
|
||||
return {"CANCELLED"}
|
||||
result = bpy.ops.snapform.generate_moge2_depth(
|
||||
result = bpy.ops.anyimage.generate_moge2_depth(
|
||||
input_path=str(source_path),
|
||||
source_object_name=source_object.name,
|
||||
resolution_level=self.resolution_level,
|
||||
@@ -174,7 +174,7 @@ class ConvertToDepthPlane(bpy.types.Operator):
|
||||
self.report({"ERROR"}, str(error))
|
||||
return {"CANCELLED"}
|
||||
|
||||
result = bpy.ops.snapform.generate_da3_depth(
|
||||
result = bpy.ops.anyimage.generate_da3_depth(
|
||||
input_path=str(source_path),
|
||||
source_object_name=source_object.name,
|
||||
depth_data_name=depth_data_name(source_object),
|
||||
@@ -306,7 +306,7 @@ def build_original_depth_response(
|
||||
push_undo("Convert to Depth Plane")
|
||||
|
||||
class GenerateDa3Depth(JobOperatorBase, bpy.types.Operator):
|
||||
bl_idname = "snapform.generate_da3_depth"
|
||||
bl_idname = "anyimage.generate_da3_depth"
|
||||
bl_label = "Generate DA3 Depth"
|
||||
job_type = "generate-depth"
|
||||
starting_message = "Starting depth estimation"
|
||||
@@ -326,7 +326,7 @@ class GenerateDa3Depth(JobOperatorBase, bpy.types.Operator):
|
||||
require_model(self.model)
|
||||
if self.remove_background:
|
||||
require_model(BEN2_MODEL_KEY)
|
||||
settings = context.scene.snapform_settings
|
||||
settings = context.scene.anyimage_settings
|
||||
return {
|
||||
**da3_parameters(
|
||||
settings,
|
||||
@@ -358,7 +358,7 @@ class GenerateDa3Depth(JobOperatorBase, bpy.types.Operator):
|
||||
|
||||
|
||||
class GenerateMoge2Depth(JobOperatorBase, bpy.types.Operator):
|
||||
bl_idname = "snapform.generate_moge2_depth"
|
||||
bl_idname = "anyimage.generate_moge2_depth"
|
||||
bl_label = "Generate MoGe-2 Depth"
|
||||
job_type = "generate-depth"
|
||||
starting_message = "Starting MoGe-2 inference"
|
||||
@@ -377,7 +377,7 @@ class GenerateMoge2Depth(JobOperatorBase, bpy.types.Operator):
|
||||
require_model(self.model)
|
||||
if self.remove_background:
|
||||
require_model(BEN2_MODEL_KEY)
|
||||
settings = context.scene.snapform_settings
|
||||
settings = context.scene.anyimage_settings
|
||||
return {
|
||||
**moge2_parameters(
|
||||
settings,
|
||||
@@ -407,7 +407,7 @@ class GenerateMoge2Depth(JobOperatorBase, bpy.types.Operator):
|
||||
|
||||
|
||||
class GenerateOriginalBackground(JobOperatorBase, bpy.types.Operator):
|
||||
bl_idname = "snapform.generate_original_background"
|
||||
bl_idname = "anyimage.generate_original_background"
|
||||
bl_label = "Generate Original Background"
|
||||
job_type = "remove-background"
|
||||
starting_message = "Starting background removal"
|
||||
@@ -421,7 +421,7 @@ class GenerateOriginalBackground(JobOperatorBase, bpy.types.Operator):
|
||||
def request(self, context):
|
||||
require_environment()
|
||||
require_model(BEN2_MODEL_KEY)
|
||||
settings = context.scene.snapform_settings
|
||||
settings = context.scene.anyimage_settings
|
||||
return {
|
||||
"input": str(background_input_path(self.input_path)),
|
||||
"model": BEN2_MODEL_KEY,
|
||||
@@ -446,7 +446,7 @@ class GenerateOriginalBackground(JobOperatorBase, bpy.types.Operator):
|
||||
|
||||
|
||||
class ExtractOriginalFrames(JobOperatorBase, bpy.types.Operator):
|
||||
bl_idname = "snapform.extract_original_frames"
|
||||
bl_idname = "anyimage.extract_original_frames"
|
||||
bl_label = "Extract Original Frames"
|
||||
job_type = "extract-frames"
|
||||
starting_message = "Extracting source frames"
|
||||
@@ -459,7 +459,7 @@ class ExtractOriginalFrames(JobOperatorBase, bpy.types.Operator):
|
||||
|
||||
def request(self, context):
|
||||
require_environment()
|
||||
settings = context.scene.snapform_settings
|
||||
settings = context.scene.anyimage_settings
|
||||
return {
|
||||
"input": str(input_path(self.input_path)),
|
||||
"video_frames": settings.video_frames,
|
||||
@@ -205,7 +205,7 @@ def draw_process_resolution(layout, owner, image):
|
||||
|
||||
|
||||
def save_packed_image(image, scene):
|
||||
output_path = Path(tempfile.mkdtemp(prefix="snapform-input-")) / "input.png"
|
||||
output_path = Path(tempfile.mkdtemp(prefix="anyimage-input-")) / "input.png"
|
||||
image_settings = scene.render.image_settings
|
||||
original_file_format = image_settings.file_format
|
||||
try:
|
||||
@@ -261,7 +261,7 @@ def prepare_image_input(image, scene):
|
||||
return source_path, False
|
||||
sequence_frames = collect_sequence_frames(image)
|
||||
if sequence_frames:
|
||||
temporary_directory = Path(tempfile.mkdtemp(prefix="snapform-input-"))
|
||||
temporary_directory = Path(tempfile.mkdtemp(prefix="anyimage-input-"))
|
||||
try:
|
||||
for index, frame_path in enumerate(sequence_frames):
|
||||
suffix = frame_path.suffix.lower() or ".jpg"
|
||||
@@ -10,7 +10,7 @@ ORIGINAL_DISPLACEMENT_MIDLEVEL = 0.0
|
||||
BUMP_BASE_DISTANCE = 0.001
|
||||
DEPTH_PLANE_NODE_GROUP_NAME = "O DA3 Depth Plane"
|
||||
MOGE_DEPTH_PLANE_NODE_GROUP_NAME = "O MoGe2 Depth Plane"
|
||||
NODE_ASSET_NAME = "O_SnapForm.blend"
|
||||
NODE_ASSET_NAME = "O_AnyImage.blend"
|
||||
MATERIAL_DISPLACEMENT_ATTRIBUTE = "o_material_displacement"
|
||||
BACKGROUND_DEPTH_ATTRIBUTE = "o_background_depth"
|
||||
DEPTH_SCALE_ATTRIBUTE = "o_depth_scale"
|
||||
@@ -6,7 +6,7 @@ from .common import HIDDEN, require_environment
|
||||
|
||||
|
||||
class DownloadModel(JobOperatorBase, bpy.types.Operator):
|
||||
bl_idname = "snapform.download_model"
|
||||
bl_idname = "anyimage.download_model"
|
||||
bl_label = "Download Model"
|
||||
job_type = "download-model"
|
||||
|
||||
@@ -23,7 +23,7 @@ class DownloadModel(JobOperatorBase, bpy.types.Operator):
|
||||
|
||||
|
||||
class DownloadRequiredModels(JobOperatorBase, bpy.types.Operator):
|
||||
bl_idname = "snapform.download_required_models"
|
||||
bl_idname = "anyimage.download_required_models"
|
||||
bl_label = "Download Required Models"
|
||||
job_type = "download-required-models"
|
||||
starting_message = "Starting required model downloads"
|
||||
@@ -36,7 +36,7 @@ class DownloadRequiredModels(JobOperatorBase, bpy.types.Operator):
|
||||
|
||||
|
||||
class ClearModels(bpy.types.Operator):
|
||||
bl_idname = "snapform.clear_models"
|
||||
bl_idname = "anyimage.clear_models"
|
||||
bl_label = "Clear Models"
|
||||
|
||||
def execute(self, _context):
|
||||
@@ -50,7 +50,7 @@ OPTIONAL_FACE_ATTRIBUTES = {
|
||||
}
|
||||
NODE_GROUP_NAME = "O DA3 Surface"
|
||||
MOGE_NODE_GROUP_NAME = "O MoGe2 Surface"
|
||||
NODE_ASSET_NAME = "O_SnapForm.blend"
|
||||
NODE_ASSET_NAME = "O_AnyImage.blend"
|
||||
|
||||
|
||||
def image_surface_model_items(owner, context):
|
||||
@@ -212,7 +212,7 @@ def assign_mesh_attribute(mesh, name, data_type, domain, values):
|
||||
attribute.data.foreach_set("value", array.reshape(-1))
|
||||
|
||||
|
||||
def assign_snapform_attributes(mesh, attributes, moge2=False):
|
||||
def assign_anyimage_attributes(mesh, attributes, moge2=False):
|
||||
for name, (data_type, key) in POINT_ATTRIBUTES.items():
|
||||
assign_mesh_attribute(
|
||||
mesh,
|
||||
@@ -446,7 +446,7 @@ def build_image_mesh(
|
||||
mesh = bpy.data.meshes.new(source_name)
|
||||
mesh.from_pydata(vertices.tolist(), [], faces.tolist())
|
||||
assign_vertex_uv(mesh, uv)
|
||||
assign_snapform_attributes(mesh, attributes, moge2=moge2)
|
||||
assign_anyimage_attributes(mesh, attributes, moge2=moge2)
|
||||
mesh.update()
|
||||
for polygon in mesh.polygons:
|
||||
polygon.use_smooth = True
|
||||
@@ -476,8 +476,8 @@ def build_image_mesh(
|
||||
scene=context.scene,
|
||||
)
|
||||
mesh.materials.append(material)
|
||||
mesh_object["snapform_reference_depth"] = reference_depth
|
||||
mesh_object["snapform_source_type"] = "IMAGE_MESH"
|
||||
mesh_object["anyimage_reference_depth"] = reference_depth
|
||||
mesh_object["anyimage_source_type"] = "IMAGE_MESH"
|
||||
add_geometry_nodes_processing(
|
||||
mesh_object,
|
||||
vertices,
|
||||
@@ -505,7 +505,7 @@ def build_image_mesh(
|
||||
|
||||
|
||||
class ConvertToSurface(bpy.types.Operator):
|
||||
bl_idname = "snapform.convert_to_surface"
|
||||
bl_idname = "anyimage.convert_to_surface"
|
||||
bl_label = "Convert to Surface"
|
||||
bl_description = "Convert an Image Empty into a perspective textured surface"
|
||||
bl_options = {"REGISTER"}
|
||||
@@ -604,12 +604,12 @@ class ConvertToSurface(bpy.types.Operator):
|
||||
"remove_background": self.remove_background,
|
||||
}
|
||||
if self.model.startswith("MOGE2_"):
|
||||
result = bpy.ops.snapform.generate_moge2_surface(
|
||||
result = bpy.ops.anyimage.generate_moge2_surface(
|
||||
**common,
|
||||
resolution_level=self.resolution_level,
|
||||
)
|
||||
else:
|
||||
result = bpy.ops.snapform.generate_da3_surface(
|
||||
result = bpy.ops.anyimage.generate_da3_surface(
|
||||
**common,
|
||||
process_res=process_res,
|
||||
)
|
||||
@@ -662,7 +662,7 @@ def build_surface_response(
|
||||
|
||||
|
||||
class GenerateDa3Surface(JobOperatorBase, bpy.types.Operator):
|
||||
bl_idname = "snapform.generate_da3_surface"
|
||||
bl_idname = "anyimage.generate_da3_surface"
|
||||
bl_label = "Generate DA3 Surface"
|
||||
job_type = "generate-surface"
|
||||
starting_message = "Starting perspective surface generation"
|
||||
@@ -682,7 +682,7 @@ class GenerateDa3Surface(JobOperatorBase, bpy.types.Operator):
|
||||
require_model(self.model)
|
||||
if self.remove_background:
|
||||
require_model(BEN2_MODEL_KEY)
|
||||
settings = context.scene.snapform_settings
|
||||
settings = context.scene.anyimage_settings
|
||||
return {
|
||||
**da3_parameters(
|
||||
settings,
|
||||
@@ -713,7 +713,7 @@ class GenerateDa3Surface(JobOperatorBase, bpy.types.Operator):
|
||||
|
||||
|
||||
class GenerateMoge2Surface(JobOperatorBase, bpy.types.Operator):
|
||||
bl_idname = "snapform.generate_moge2_surface"
|
||||
bl_idname = "anyimage.generate_moge2_surface"
|
||||
bl_label = "Generate MoGe-2 Surface"
|
||||
job_type = "generate-surface"
|
||||
starting_message = "Starting MoGe-2 inference"
|
||||
@@ -733,7 +733,7 @@ class GenerateMoge2Surface(JobOperatorBase, bpy.types.Operator):
|
||||
require_model(self.model)
|
||||
if self.remove_background:
|
||||
require_model(BEN2_MODEL_KEY)
|
||||
settings = context.scene.snapform_settings
|
||||
settings = context.scene.anyimage_settings
|
||||
return {
|
||||
**moge2_parameters(
|
||||
settings,
|
||||
@@ -5,10 +5,10 @@ from .properties import BEN2_MODEL_KEY, model_catalog, model_ready
|
||||
|
||||
class ServerPanel(bpy.types.Panel):
|
||||
bl_label = "Job Server"
|
||||
bl_idname = "SNAPFORM_PT_server"
|
||||
bl_idname = "ANYIMAGE_PT_server"
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
bl_category = "SnapForm"
|
||||
bl_category = "AnyImage"
|
||||
bl_order = 0
|
||||
|
||||
def draw(self, _context):
|
||||
@@ -22,14 +22,14 @@ class ServerPanel(bpy.types.Panel):
|
||||
install_row = layout.row()
|
||||
install_row.enabled = not running
|
||||
install_row.operator(
|
||||
"snapform.install_environment",
|
||||
"anyimage.install_environment",
|
||||
text="Install Environment",
|
||||
icon="IMPORT",
|
||||
)
|
||||
mirror_row = layout.row()
|
||||
mirror_row.enabled = not running
|
||||
mirror_row.operator(
|
||||
"snapform.install_environment_mirror",
|
||||
"anyimage.install_environment_mirror",
|
||||
text="Install Environment (Mirror)",
|
||||
icon="IMPORT",
|
||||
)
|
||||
@@ -58,18 +58,18 @@ class ServerPanel(bpy.types.Panel):
|
||||
if state == "READY":
|
||||
controls = row.row(align=True)
|
||||
controls.operator(
|
||||
"snapform.restart_server",
|
||||
"anyimage.restart_server",
|
||||
text="",
|
||||
icon="FILE_REFRESH",
|
||||
)
|
||||
controls.operator(
|
||||
"snapform.stop_server",
|
||||
"anyimage.stop_server",
|
||||
text="",
|
||||
icon="PAUSE",
|
||||
)
|
||||
elif state == "STOPPED":
|
||||
row.operator(
|
||||
"snapform.start_server",
|
||||
"anyimage.start_server",
|
||||
text="Start",
|
||||
icon="PLAY",
|
||||
)
|
||||
@@ -80,7 +80,7 @@ class ServerPanel(bpy.types.Panel):
|
||||
)
|
||||
if state == "ERROR":
|
||||
row.operator(
|
||||
"snapform.start_server",
|
||||
"anyimage.start_server",
|
||||
text="Start",
|
||||
icon="PLAY",
|
||||
)
|
||||
@@ -103,7 +103,7 @@ class ServerPanel(bpy.types.Panel):
|
||||
clear = cached_row.row(align=True)
|
||||
clear.enabled = state == "READY"
|
||||
clear.operator(
|
||||
"snapform.clear_models",
|
||||
"anyimage.clear_models",
|
||||
text="",
|
||||
icon="TRASH",
|
||||
)
|
||||
@@ -111,10 +111,10 @@ class ServerPanel(bpy.types.Panel):
|
||||
|
||||
class ModelsPanel(bpy.types.Panel):
|
||||
bl_label = "Models"
|
||||
bl_idname = "SNAPFORM_PT_models"
|
||||
bl_idname = "ANYIMAGE_PT_models"
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
bl_category = "SnapForm"
|
||||
bl_category = "AnyImage"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_order = 1
|
||||
|
||||
@@ -150,7 +150,7 @@ class ModelsPanel(bpy.types.Panel):
|
||||
download_row = row.row(align=True)
|
||||
download_row.enabled = runtime.environment_ready() and not running
|
||||
operator = download_row.operator(
|
||||
"snapform.download_model",
|
||||
"anyimage.download_model",
|
||||
text="Download",
|
||||
icon="IMPORT",
|
||||
)
|
||||
@@ -159,16 +159,16 @@ class ModelsPanel(bpy.types.Panel):
|
||||
|
||||
class DebugPanel(bpy.types.Panel):
|
||||
bl_label = "Debug"
|
||||
bl_idname = "SNAPFORM_PT_debug"
|
||||
bl_idname = "ANYIMAGE_PT_debug"
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
bl_category = "SnapForm"
|
||||
bl_category = "AnyImage"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_order = 2
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
settings = context.scene.snapform_settings
|
||||
settings = context.scene.anyimage_settings
|
||||
|
||||
layout.prop(settings, "device")
|
||||
|
||||
@@ -198,17 +198,17 @@ def draw_da3_input_settings(layout, settings, model_property):
|
||||
|
||||
class Da3OutputDebugPanel(bpy.types.Panel):
|
||||
bl_label = "DA3"
|
||||
bl_idname = "SNAPFORM_PT_debug_da3_output"
|
||||
bl_idname = "ANYIMAGE_PT_debug_da3_output"
|
||||
bl_parent_id = DebugPanel.bl_idname
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
bl_category = "SnapForm"
|
||||
bl_category = "AnyImage"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_order = 1
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
settings = context.scene.snapform_settings
|
||||
settings = context.scene.anyimage_settings
|
||||
|
||||
draw_da3_input_settings(layout, settings, "model")
|
||||
export_row = layout.row()
|
||||
@@ -217,7 +217,7 @@ class Da3OutputDebugPanel(bpy.types.Panel):
|
||||
and model_ready(settings.model)
|
||||
)
|
||||
export_row.operator(
|
||||
"snapform.debug_da3",
|
||||
"anyimage.debug_da3",
|
||||
text="Run DA3 API",
|
||||
icon="EXPORT",
|
||||
)
|
||||
@@ -225,17 +225,17 @@ class Da3OutputDebugPanel(bpy.types.Panel):
|
||||
|
||||
class Moge2ApiDebugPanel(bpy.types.Panel):
|
||||
bl_label = "MoGe-2"
|
||||
bl_idname = "SNAPFORM_PT_debug_moge2_api"
|
||||
bl_idname = "ANYIMAGE_PT_debug_moge2_api"
|
||||
bl_parent_id = DebugPanel.bl_idname
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
bl_category = "SnapForm"
|
||||
bl_category = "AnyImage"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_order = 0
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
settings = context.scene.snapform_settings
|
||||
settings = context.scene.anyimage_settings
|
||||
layout.prop(settings, "input_path")
|
||||
layout.prop(settings, "moge_model")
|
||||
layout.prop(settings, "moge_resolution_level")
|
||||
@@ -245,7 +245,7 @@ class Moge2ApiDebugPanel(bpy.types.Panel):
|
||||
and model_ready(settings.moge_model)
|
||||
)
|
||||
run_row.operator(
|
||||
"snapform.debug_moge2",
|
||||
"anyimage.debug_moge2",
|
||||
text="Run MoGe-2 API",
|
||||
icon="EXPORT",
|
||||
)
|
||||
@@ -253,17 +253,17 @@ class Moge2ApiDebugPanel(bpy.types.Panel):
|
||||
|
||||
class Ben2RemovalDebugPanel(bpy.types.Panel):
|
||||
bl_label = "BEN2"
|
||||
bl_idname = "SNAPFORM_PT_debug_ben2_removal"
|
||||
bl_idname = "ANYIMAGE_PT_debug_ben2_removal"
|
||||
bl_parent_id = DebugPanel.bl_idname
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
bl_category = "SnapForm"
|
||||
bl_category = "AnyImage"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_order = 2
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
settings = context.scene.snapform_settings
|
||||
settings = context.scene.anyimage_settings
|
||||
|
||||
layout.prop(settings, "background_input_path")
|
||||
background_row = layout.row()
|
||||
@@ -272,7 +272,7 @@ class Ben2RemovalDebugPanel(bpy.types.Panel):
|
||||
and model_ready(BEN2_MODEL_KEY)
|
||||
)
|
||||
background_row.operator(
|
||||
"snapform.debug_ben2",
|
||||
"anyimage.debug_ben2",
|
||||
text="Remove Background",
|
||||
icon="IMAGE_ALPHA",
|
||||
)
|
||||
@@ -4,7 +4,7 @@ from .runtime import DEFAULT_STORAGE_ROOT, runtime
|
||||
from .properties import device_enum_items
|
||||
|
||||
|
||||
class SnapFormPreferences(bpy.types.AddonPreferences):
|
||||
class AnyImagePreferences(bpy.types.AddonPreferences):
|
||||
bl_idname = __package__
|
||||
|
||||
storage_root: bpy.props.StringProperty(
|
||||
@@ -38,20 +38,20 @@ class SnapFormPreferences(bpy.types.AddonPreferences):
|
||||
install_row = layout.row()
|
||||
install_row.enabled = runtime.active_job is None
|
||||
install_row.operator(
|
||||
"snapform.install_environment",
|
||||
"anyimage.install_environment",
|
||||
text="Install Environment",
|
||||
icon="IMPORT",
|
||||
)
|
||||
mirror_row = layout.row()
|
||||
mirror_row.enabled = runtime.active_job is None
|
||||
mirror_row.operator(
|
||||
"snapform.install_environment_mirror",
|
||||
"anyimage.install_environment_mirror",
|
||||
text="Install Environment (Mirror)",
|
||||
icon="IMPORT",
|
||||
)
|
||||
layout.separator()
|
||||
layout.operator(
|
||||
"snapform.open_server_log",
|
||||
"anyimage.open_server_log",
|
||||
text="Open Server Log",
|
||||
icon="TEXT",
|
||||
)
|
||||
@@ -269,7 +269,7 @@ def balloon_radial_zoom_property(scale):
|
||||
)
|
||||
|
||||
|
||||
class SnapFormSettings(bpy.types.PropertyGroup):
|
||||
class AnyImageSettings(bpy.types.PropertyGroup):
|
||||
balloon_mode: balloon_mode_property()
|
||||
balloon_thickness: balloon_thickness_property()
|
||||
balloon_resolution: balloon_resolution_property()
|
||||
@@ -5,7 +5,7 @@ import bpy
|
||||
from blendjob import JobRuntime
|
||||
|
||||
|
||||
DEFAULT_STORAGE_ROOT = Path.home() / ".snapform"
|
||||
DEFAULT_STORAGE_ROOT = Path.home() / ".anyimage"
|
||||
|
||||
|
||||
def configured_storage_root():
|
||||
@@ -53,7 +53,7 @@ runtime = JobRuntime(
|
||||
storage_root=configured_storage_root,
|
||||
environment=ENVIRONMENT,
|
||||
post_install=post_install,
|
||||
namespace="snapform",
|
||||
namespace="anyimage",
|
||||
)
|
||||
|
||||
JobOperatorBase = runtime.JobOperatorBase
|
||||
@@ -1,4 +1,4 @@
|
||||
"""SnapForm Job Server without Blender dependencies."""
|
||||
"""AnyImage Job Server without Blender dependencies."""
|
||||
|
||||
from blendjob import JobServer
|
||||
|
||||
@@ -13,7 +13,7 @@ from .jobs.frames import run as _extract_frames
|
||||
from .model_manager import ModelManager, ModelSessionCache
|
||||
|
||||
|
||||
server = JobServer("SnapForm Job Server")
|
||||
server = JobServer("AnyImage Job Server")
|
||||
|
||||
|
||||
@server.resource("model_manager")
|
||||
@@ -101,7 +101,7 @@ def prepare_input(
|
||||
import av
|
||||
|
||||
temporary_directory = Path(
|
||||
tempfile.mkdtemp(prefix="snapform-video-", dir=temporary_root)
|
||||
tempfile.mkdtemp(prefix="anyimage-video-", dir=temporary_root)
|
||||
)
|
||||
try:
|
||||
images = extract_video_frames(
|
||||
@@ -116,7 +116,7 @@ def create_download_progress_class(
|
||||
description = str(kwargs.get("desc", ""))
|
||||
# huggingface_hub 1.x 的字节进度条描述是 "Downloading (incomplete total...)",
|
||||
# 用前缀匹配而非精确匹配,否则真实下载进度会被忽略。
|
||||
self.snapform_reports_progress = (
|
||||
self.anyimage_reports_progress = (
|
||||
description.startswith("Downloading")
|
||||
or description.startswith("Fetching ")
|
||||
)
|
||||
@@ -124,13 +124,13 @@ def create_download_progress_class(
|
||||
|
||||
def update(self, amount=1):
|
||||
result = super().update(amount)
|
||||
if self.snapform_reports_progress:
|
||||
if self.anyimage_reports_progress:
|
||||
reporter.report(self.n, self.total, self._download_rate())
|
||||
return result
|
||||
|
||||
def refresh(self, *args, **kwargs):
|
||||
result = super().refresh(*args, **kwargs)
|
||||
if self.snapform_reports_progress:
|
||||
if self.anyimage_reports_progress:
|
||||
reporter.report(self.n, self.total, self._download_rate())
|
||||
return result
|
||||
|
||||
@@ -295,7 +295,7 @@ def _download_file_from_url(
|
||||
cancel_check=None,
|
||||
):
|
||||
"""Download and verify one model file atomically from a direct URL."""
|
||||
request = Request(url, headers={"User-Agent": "SnapForm"})
|
||||
request = Request(url, headers={"User-Agent": "AnyImage"})
|
||||
opener = _download_opener.open if request.type == "https" else urlopen
|
||||
last_error = None
|
||||
for _attempt in range(retries):
|
||||
@@ -53,7 +53,7 @@ def infer(
|
||||
if provider_label(model) == "DirectML":
|
||||
raise RuntimeError(
|
||||
"DA3 inference failed on DirectML. Switch the device to "
|
||||
"CPU in SnapForm Preferences and retry. "
|
||||
"CPU in AnyImage Preferences and retry. "
|
||||
f"Original error: {error}"
|
||||
) from error
|
||||
raise
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Prepare SnapForm ONNX models and sync them to OmooLab R2."""
|
||||
"""Prepare AnyImage ONNX models and sync them to OmooLab R2."""
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
@@ -114,7 +114,7 @@ def download_once(model, url):
|
||||
destination.parent.mkdir(parents=True, exist_ok=True)
|
||||
temporary = destination.with_suffix(".onnx.part")
|
||||
temporary.unlink(missing_ok=True)
|
||||
request = Request(url, headers={"User-Agent": "SnapForm model sync"})
|
||||
request = Request(url, headers={"User-Agent": "AnyImage model sync"})
|
||||
print(f"Download: {url}")
|
||||
downloaded = 0
|
||||
digest = hashlib.sha256()
|
||||
|
||||
@@ -19,7 +19,7 @@ class AddonTest(unittest.TestCase):
|
||||
cls.remove_modules()
|
||||
|
||||
def append_status_bar(draw):
|
||||
draw._owner = "snapform"
|
||||
draw._owner = "anyimage"
|
||||
cls.status_bar_draws.append(draw)
|
||||
|
||||
fake_bpy = ModuleType("bpy")
|
||||
@@ -79,28 +79,28 @@ class AddonTest(unittest.TestCase):
|
||||
sys.modules["bpy"] = fake_bpy
|
||||
sys.path.insert(0, str(SOURCE_ROOT))
|
||||
cls.paths_before_import = tuple(sys.path)
|
||||
cls.addon = importlib.import_module("snapform")
|
||||
cls.job_runtime = importlib.import_module("snapform.runtime")
|
||||
cls.model_operators = importlib.import_module("snapform.operators.models")
|
||||
cls.image_depth = importlib.import_module("snapform.operators.material")
|
||||
cls.image_data = importlib.import_module("snapform.operators.image")
|
||||
cls.addon = importlib.import_module("anyimage")
|
||||
cls.job_runtime = importlib.import_module("anyimage.runtime")
|
||||
cls.model_operators = importlib.import_module("anyimage.operators.models")
|
||||
cls.image_depth = importlib.import_module("anyimage.operators.material")
|
||||
cls.image_data = importlib.import_module("anyimage.operators.image")
|
||||
cls.depth_operator = importlib.import_module(
|
||||
"snapform.operators.depth_plane.operator"
|
||||
"anyimage.operators.depth_plane.operator"
|
||||
)
|
||||
cls.depth_build = importlib.import_module(
|
||||
"snapform.operators.depth_plane.build"
|
||||
"anyimage.operators.depth_plane.build"
|
||||
)
|
||||
cls.image_background = importlib.import_module("snapform.operators.background")
|
||||
cls.image_mesh = importlib.import_module("snapform.operators.surface")
|
||||
cls.balloon = importlib.import_module("snapform.operators.balloon.operator")
|
||||
cls.image_background = importlib.import_module("anyimage.operators.background")
|
||||
cls.image_mesh = importlib.import_module("anyimage.operators.surface")
|
||||
cls.balloon = importlib.import_module("anyimage.operators.balloon.operator")
|
||||
cls.balloon_geometry = importlib.import_module(
|
||||
"snapform.operators.balloon.geometry"
|
||||
"anyimage.operators.balloon.geometry"
|
||||
)
|
||||
cls.balloon_depth = importlib.import_module("snapform.operators.balloon.depth")
|
||||
cls.balloon_depth = importlib.import_module("anyimage.operators.balloon.depth")
|
||||
cls.balloon_poisson = importlib.import_module(
|
||||
"snapform.operators.balloon.poisson"
|
||||
"anyimage.operators.balloon.poisson"
|
||||
)
|
||||
cls.balloon_teddy = importlib.import_module("snapform.operators.balloon.teddy")
|
||||
cls.balloon_teddy = importlib.import_module("anyimage.operators.balloon.teddy")
|
||||
cls.paths_after_import = tuple(sys.path)
|
||||
cls.fake_bpy = fake_bpy
|
||||
|
||||
@@ -113,7 +113,7 @@ class AddonTest(unittest.TestCase):
|
||||
@staticmethod
|
||||
def remove_modules():
|
||||
for module_name in tuple(sys.modules):
|
||||
if module_name == "snapform" or module_name.startswith("snapform."):
|
||||
if module_name == "anyimage" or module_name.startswith("anyimage."):
|
||||
sys.modules.pop(module_name)
|
||||
|
||||
def setUp(self):
|
||||
@@ -122,7 +122,7 @@ class AddonTest(unittest.TestCase):
|
||||
device="CUDA",
|
||||
)
|
||||
self.fake_bpy.context.preferences.addons = {
|
||||
"snapform": SimpleNamespace(preferences=preferences)
|
||||
"anyimage": SimpleNamespace(preferences=preferences)
|
||||
}
|
||||
|
||||
def tearDown(self):
|
||||
@@ -135,8 +135,8 @@ class AddonTest(unittest.TestCase):
|
||||
self.fake_bpy.data = SimpleNamespace(
|
||||
objects=SimpleNamespace(get=lambda _name: None),
|
||||
)
|
||||
if hasattr(self.fake_bpy.types.Scene, "snapform_settings"):
|
||||
del self.fake_bpy.types.Scene.snapform_settings
|
||||
if hasattr(self.fake_bpy.types.Scene, "anyimage_settings"):
|
||||
del self.fake_bpy.types.Scene.anyimage_settings
|
||||
|
||||
def test_runtime_and_operator_support_modules_have_explicit_boundaries(self):
|
||||
for name in (
|
||||
@@ -146,13 +146,13 @@ class AddonTest(unittest.TestCase):
|
||||
"models.py",
|
||||
"status_bar.py",
|
||||
):
|
||||
self.assertFalse((SOURCE_ROOT / "snapform" / name).exists(), name)
|
||||
self.assertTrue((SOURCE_ROOT / "snapform" / "runtime.py").is_file())
|
||||
self.assertFalse((SOURCE_ROOT / "snapform" / "job_runtime.py").exists())
|
||||
self.assertFalse((SOURCE_ROOT / "snapform" / "client").exists())
|
||||
self.assertFalse((SOURCE_ROOT / "snapform" / "ui").exists())
|
||||
self.assertFalse((SOURCE_ROOT / "snapform" / "operators.py").exists())
|
||||
self.assertFalse((SOURCE_ROOT / "snapform" / "blender").exists())
|
||||
self.assertFalse((SOURCE_ROOT / "anyimage" / name).exists(), name)
|
||||
self.assertTrue((SOURCE_ROOT / "anyimage" / "runtime.py").is_file())
|
||||
self.assertFalse((SOURCE_ROOT / "anyimage" / "job_runtime.py").exists())
|
||||
self.assertFalse((SOURCE_ROOT / "anyimage" / "client").exists())
|
||||
self.assertFalse((SOURCE_ROOT / "anyimage" / "ui").exists())
|
||||
self.assertFalse((SOURCE_ROOT / "anyimage" / "operators.py").exists())
|
||||
self.assertFalse((SOURCE_ROOT / "anyimage" / "blender").exists())
|
||||
|
||||
def test_mps_requires_m4_or_newer(self):
|
||||
properties = self.addon.properties
|
||||
@@ -205,7 +205,7 @@ class AddonTest(unittest.TestCase):
|
||||
self.assertEqual(self.paths_after_import, self.paths_before_import)
|
||||
self.assertFalse(
|
||||
any(
|
||||
name == "snapform.server" or name.startswith("snapform.server.")
|
||||
name == "anyimage.server" or name.startswith("anyimage.server.")
|
||||
for name in sys.modules
|
||||
)
|
||||
)
|
||||
@@ -217,7 +217,7 @@ class AddonTest(unittest.TestCase):
|
||||
def test_operator_modules_use_plain_properties(self):
|
||||
operators = self.addon.operators
|
||||
for name in (
|
||||
"SnapFormJobMixin",
|
||||
"AnyImageJobMixin",
|
||||
"ImageInputJobOperator",
|
||||
"GeometryImageJobOperator",
|
||||
"Da3ImageJobOperator",
|
||||
@@ -227,11 +227,11 @@ class AddonTest(unittest.TestCase):
|
||||
self.assertFalse(hasattr(operators, name), name)
|
||||
for operator in operators.CLASSES:
|
||||
for name in getattr(operator, "__annotations__", {}):
|
||||
self.assertFalse(name.startswith("snapform_"), (operator, name))
|
||||
self.assertFalse(name.startswith("anyimage_"), (operator, name))
|
||||
|
||||
def test_concrete_job_operator_is_the_blender_operator(self):
|
||||
operator = self.addon.operators.GenerateMoge2Depth
|
||||
self.assertEqual(operator.bl_idname, "snapform.generate_moge2_depth")
|
||||
self.assertEqual(operator.bl_idname, "anyimage.generate_moge2_depth")
|
||||
self.assertIn(self.job_runtime.JobOperatorBase, operator.__mro__)
|
||||
self.assertIn(self.fake_bpy.types.Operator, operator.__mro__)
|
||||
|
||||
@@ -364,7 +364,7 @@ class AddonTest(unittest.TestCase):
|
||||
)
|
||||
self.assertTrue(callable(runtime.post_install))
|
||||
|
||||
def test_snapform_post_install_is_ordinary_code_using_runtime_request(self):
|
||||
def test_anyimage_post_install_is_ordinary_code_using_runtime_request(self):
|
||||
calls = []
|
||||
fake_runtime = SimpleNamespace(
|
||||
request=lambda job_type, parameters: calls.append((job_type, parameters))
|
||||
@@ -378,7 +378,7 @@ class AddonTest(unittest.TestCase):
|
||||
],
|
||||
)
|
||||
|
||||
def test_snapform_post_install_names_each_failed_model(self):
|
||||
def test_anyimage_post_install_names_each_failed_model(self):
|
||||
calls = []
|
||||
|
||||
def request(_job_type, parameters):
|
||||
@@ -476,7 +476,7 @@ class AddonTest(unittest.TestCase):
|
||||
self.assertNotIn("stages", controller.post_status)
|
||||
|
||||
def test_conversion_model_lists_default_to_moge2_vits(self):
|
||||
properties = importlib.import_module("snapform.properties")
|
||||
properties = importlib.import_module("anyimage.properties")
|
||||
catalog = (
|
||||
{
|
||||
"key": "SMALL",
|
||||
@@ -534,7 +534,7 @@ class AddonTest(unittest.TestCase):
|
||||
def separator(self):
|
||||
calls.append(("separator", self.enabled))
|
||||
|
||||
menu = self.addon.SnapFormImageMenu()
|
||||
menu = self.addon.AnyImageImageMenu()
|
||||
menu.layout = Layout()
|
||||
with (
|
||||
patch.object(
|
||||
@@ -543,7 +543,7 @@ class AddonTest(unittest.TestCase):
|
||||
return_value=True,
|
||||
),
|
||||
patch(
|
||||
"snapform.properties.required_models_ready",
|
||||
"anyimage.properties.required_models_ready",
|
||||
return_value=False,
|
||||
),
|
||||
):
|
||||
@@ -551,15 +551,15 @@ class AddonTest(unittest.TestCase):
|
||||
|
||||
self.assertEqual(
|
||||
calls[0],
|
||||
("snapform.activate_balloon_tool", True),
|
||||
("anyimage.activate_balloon_tool", True),
|
||||
)
|
||||
self.assertIn(
|
||||
("snapform.download_required_models", True),
|
||||
("anyimage.download_required_models", True),
|
||||
calls,
|
||||
)
|
||||
self.assertIn(("snapform.convert_to_depth_plane", False), calls)
|
||||
self.assertIn(("snapform.convert_to_surface", False), calls)
|
||||
self.assertIn(("snapform.remove_image_background", False), calls)
|
||||
self.assertIn(("anyimage.convert_to_depth_plane", False), calls)
|
||||
self.assertIn(("anyimage.convert_to_surface", False), calls)
|
||||
self.assertIn(("anyimage.remove_image_background", False), calls)
|
||||
|
||||
def test_image_menu_keeps_disabled_features_when_environment_is_missing(self):
|
||||
calls = []
|
||||
@@ -581,7 +581,7 @@ class AddonTest(unittest.TestCase):
|
||||
def separator(self):
|
||||
calls.append(("separator", self.enabled))
|
||||
|
||||
menu = self.addon.SnapFormImageMenu()
|
||||
menu = self.addon.AnyImageImageMenu()
|
||||
menu.layout = Layout()
|
||||
with (
|
||||
patch.object(
|
||||
@@ -590,7 +590,7 @@ class AddonTest(unittest.TestCase):
|
||||
return_value=False,
|
||||
),
|
||||
patch(
|
||||
"snapform.properties.required_models_ready",
|
||||
"anyimage.properties.required_models_ready",
|
||||
return_value=False,
|
||||
),
|
||||
):
|
||||
@@ -598,14 +598,14 @@ class AddonTest(unittest.TestCase):
|
||||
|
||||
self.assertEqual(
|
||||
calls[0],
|
||||
("snapform.activate_balloon_tool", True),
|
||||
("anyimage.activate_balloon_tool", True),
|
||||
)
|
||||
self.assertIn(("snapform.install_environment", True), calls)
|
||||
self.assertIn(("snapform.install_environment_mirror", True), calls)
|
||||
self.assertNotIn(("snapform.download_required_models", True), calls)
|
||||
self.assertIn(("snapform.convert_to_depth_plane", False), calls)
|
||||
self.assertIn(("snapform.convert_to_surface", False), calls)
|
||||
self.assertIn(("snapform.remove_image_background", False), calls)
|
||||
self.assertIn(("anyimage.install_environment", True), calls)
|
||||
self.assertIn(("anyimage.install_environment_mirror", True), calls)
|
||||
self.assertNotIn(("anyimage.download_required_models", True), calls)
|
||||
self.assertIn(("anyimage.convert_to_depth_plane", False), calls)
|
||||
self.assertIn(("anyimage.convert_to_surface", False), calls)
|
||||
self.assertIn(("anyimage.remove_image_background", False), calls)
|
||||
|
||||
def test_balloon_contour_is_smooth_and_evenly_resampled(self):
|
||||
import numpy as np
|
||||
@@ -892,7 +892,7 @@ class AddonTest(unittest.TestCase):
|
||||
self.assertIn("contour_analysis", operator.__annotations__)
|
||||
self.assertIn("depth_analysis", operator.__annotations__)
|
||||
self.assertIn("depth_model", operator.__annotations__)
|
||||
settings = self.addon.properties.SnapFormSettings.__annotations__
|
||||
settings = self.addon.properties.AnyImageSettings.__annotations__
|
||||
for name in (
|
||||
"balloon_contour_analysis",
|
||||
"balloon_depth_analysis",
|
||||
@@ -908,7 +908,7 @@ class AddonTest(unittest.TestCase):
|
||||
request_source = inspect.getsource(self.balloon.AnalyzeBalloon.request)
|
||||
response_source = inspect.getsource(self.balloon.AnalyzeBalloon.response)
|
||||
tool_source = inspect.getsource(self.balloon.BalloonTool.draw_settings)
|
||||
self.assertIn("bpy.ops.snapform.analyze_balloon", execute_source)
|
||||
self.assertIn("bpy.ops.anyimage.analyze_balloon", execute_source)
|
||||
self.assertIn("prepare_image_input(", execute_source)
|
||||
self.assertIn(
|
||||
"settings.balloon_contour_analysis",
|
||||
@@ -1103,7 +1103,7 @@ class AddonTest(unittest.TestCase):
|
||||
self.assertIn("resolution", operator.__annotations__)
|
||||
self.assertIn("reuse_material", operator.__annotations__)
|
||||
self.assertIn("source_matrix_data", operator.__annotations__)
|
||||
settings = self.addon.properties.SnapFormSettings.__annotations__
|
||||
settings = self.addon.properties.AnyImageSettings.__annotations__
|
||||
self.assertIn("balloon_mode", settings)
|
||||
self.assertIn("balloon_thickness", settings)
|
||||
self.assertIn("balloon_resolution", settings)
|
||||
@@ -1150,7 +1150,7 @@ class AddonTest(unittest.TestCase):
|
||||
self.assertIn("return self.execute(context)", modal_source)
|
||||
self.assertIn('return {"RUNNING_MODAL"}', modal_source)
|
||||
self.assertIn('return {"PASS_THROUGH"}', modal_source)
|
||||
self.assertNotIn("bpy.ops.snapform.extract_balloon", modal_source)
|
||||
self.assertNotIn("bpy.ops.anyimage.extract_balloon", modal_source)
|
||||
|
||||
tool = self.balloon.BalloonTool
|
||||
self.assertEqual(tool.bl_space_type, "VIEW_3D")
|
||||
@@ -1169,11 +1169,11 @@ class AddonTest(unittest.TestCase):
|
||||
[
|
||||
(
|
||||
"data_path_primary",
|
||||
"scene.snapform_settings.balloon_thickness",
|
||||
"scene.anyimage_settings.balloon_thickness",
|
||||
),
|
||||
(
|
||||
"zoom_path",
|
||||
"scene.snapform_settings.balloon_thickness_radial_zoom",
|
||||
"scene.anyimage_settings.balloon_thickness_radial_zoom",
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1182,11 +1182,11 @@ class AddonTest(unittest.TestCase):
|
||||
[
|
||||
(
|
||||
"data_path_primary",
|
||||
"scene.snapform_settings.balloon_resolution",
|
||||
"scene.anyimage_settings.balloon_resolution",
|
||||
),
|
||||
(
|
||||
"zoom_path",
|
||||
"scene.snapform_settings.balloon_resolution_radial_zoom",
|
||||
"scene.anyimage_settings.balloon_resolution_radial_zoom",
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1281,20 +1281,20 @@ class AddonTest(unittest.TestCase):
|
||||
)
|
||||
marked = MarkedMaterial(
|
||||
"unrelated-name",
|
||||
snapform_balloon_material=True,
|
||||
snapform_source_image=color_image,
|
||||
anyimage_balloon_material=True,
|
||||
anyimage_source_image=color_image,
|
||||
)
|
||||
marked_other = MarkedMaterial(
|
||||
"cow",
|
||||
snapform_balloon_material=True,
|
||||
snapform_source_image=other_image,
|
||||
anyimage_balloon_material=True,
|
||||
anyimage_source_image=other_image,
|
||||
)
|
||||
normal_image = SimpleNamespace(name="cow.normal")
|
||||
marked_normal = MarkedMaterial(
|
||||
"depth-material",
|
||||
snapform_balloon_material=True,
|
||||
snapform_source_image=color_image,
|
||||
snapform_balloon_normal_image=normal_image,
|
||||
anyimage_balloon_material=True,
|
||||
anyimage_source_image=color_image,
|
||||
anyimage_balloon_normal_image=normal_image,
|
||||
)
|
||||
wrong_group = SimpleNamespace(
|
||||
name="cow",
|
||||
@@ -1393,7 +1393,7 @@ class AddonTest(unittest.TestCase):
|
||||
return_value=False,
|
||||
),
|
||||
patch(
|
||||
"snapform.properties.required_models_ready",
|
||||
"anyimage.properties.required_models_ready",
|
||||
return_value=models_ready,
|
||||
),
|
||||
):
|
||||
@@ -1414,7 +1414,7 @@ class AddonTest(unittest.TestCase):
|
||||
self.assertEqual(operator.poll(context), expected)
|
||||
|
||||
def test_ui_reads_required_model_files_without_starting_server(self):
|
||||
properties = importlib.import_module("snapform.properties")
|
||||
properties = importlib.import_module("anyimage.properties")
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
moge = root / "models" / "moge-2-vits-normal-onnx"
|
||||
@@ -1516,7 +1516,7 @@ class AddonTest(unittest.TestCase):
|
||||
],
|
||||
)
|
||||
self.assertEqual(len(self.status_bar_draws), 1)
|
||||
self.assertEqual(self.status_bar_draws[0]._owner, "snapform")
|
||||
self.assertEqual(self.status_bar_draws[0]._owner, "anyimage")
|
||||
|
||||
self.addon.unregister()
|
||||
self.assertEqual(self.registered, [])
|
||||
@@ -1545,7 +1545,7 @@ class AddonTest(unittest.TestCase):
|
||||
|
||||
self.assertEqual(calls[0][1]["factor"], 0.4)
|
||||
self.assertEqual(calls[0][1]["text"], "Working")
|
||||
self.assertEqual(calls[1], ("operator", "snapform.cancel_job"))
|
||||
self.assertEqual(calls[1], ("operator", "anyimage.cancel_job"))
|
||||
|
||||
def test_moge_depth_request_is_written_on_the_operator(self):
|
||||
operator = self.addon.operators.GenerateMoge2Depth()
|
||||
@@ -1555,7 +1555,7 @@ class AddonTest(unittest.TestCase):
|
||||
operator.resolution_level = 6
|
||||
operator.remove_background = False
|
||||
settings = SimpleNamespace(video_frames=12)
|
||||
context = SimpleNamespace(scene=SimpleNamespace(snapform_settings=settings))
|
||||
context = SimpleNamespace(scene=SimpleNamespace(anyimage_settings=settings))
|
||||
|
||||
with (
|
||||
patch.object(self.depth_operator, "require_environment"),
|
||||
@@ -1603,11 +1603,11 @@ class AddonTest(unittest.TestCase):
|
||||
settings = SimpleNamespace(video_frames=1)
|
||||
context = SimpleNamespace(
|
||||
object=source_object,
|
||||
scene=SimpleNamespace(snapform_settings=settings),
|
||||
scene=SimpleNamespace(anyimage_settings=settings),
|
||||
)
|
||||
calls = []
|
||||
self.fake_bpy.ops = SimpleNamespace(
|
||||
snapform=SimpleNamespace(
|
||||
anyimage=SimpleNamespace(
|
||||
generate_moge2_depth=lambda **options: (
|
||||
calls.append(options) or {"RUNNING_MODAL"}
|
||||
)
|
||||
@@ -1623,7 +1623,7 @@ class AddonTest(unittest.TestCase):
|
||||
|
||||
self.assertEqual(calls[0]["resolution_level"], 7)
|
||||
self.assertEqual(calls[0]["source_object_name"], "Reference")
|
||||
self.assertFalse(any(key.startswith("snapform_") for key in calls[0]))
|
||||
self.assertFalse(any(key.startswith("anyimage_") for key in calls[0]))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -10,7 +10,7 @@ from PIL import Image
|
||||
SOURCE_DIR = (
|
||||
Path(__file__).resolve().parents[1]
|
||||
/ "src"
|
||||
/ "snapform"
|
||||
/ "anyimage"
|
||||
/ "server"
|
||||
/ "models"
|
||||
)
|
||||
|
||||
@@ -11,7 +11,7 @@ from PIL import Image
|
||||
SOURCE_DIR = (
|
||||
Path(__file__).resolve().parents[1]
|
||||
/ "src"
|
||||
/ "snapform"
|
||||
/ "anyimage"
|
||||
/ "server"
|
||||
/ "models"
|
||||
)
|
||||
|
||||
@@ -10,7 +10,7 @@ PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def load_download_module():
|
||||
addon_directory = PROJECT_ROOT / "src" / "snapform"
|
||||
addon_directory = PROJECT_ROOT / "src" / "anyimage"
|
||||
sys.path.insert(0, str(addon_directory))
|
||||
try:
|
||||
return __import__(
|
||||
|
||||
@@ -27,28 +27,28 @@ def load_image_depth():
|
||||
|
||||
module_paths = (
|
||||
(
|
||||
"snapform.operators.image",
|
||||
PROJECT_ROOT / "src" / "snapform" / "operators" / "image.py",
|
||||
"anyimage.operators.image",
|
||||
PROJECT_ROOT / "src" / "anyimage" / "operators" / "image.py",
|
||||
),
|
||||
(
|
||||
"snapform.operators.material",
|
||||
PROJECT_ROOT / "src" / "snapform" / "operators" / "material.py",
|
||||
"anyimage.operators.material",
|
||||
PROJECT_ROOT / "src" / "anyimage" / "operators" / "material.py",
|
||||
),
|
||||
(
|
||||
"snapform.operators.depth_plane.data",
|
||||
PROJECT_ROOT / "src" / "snapform" / "operators" / "depth_plane" / "data.py",
|
||||
"anyimage.operators.depth_plane.data",
|
||||
PROJECT_ROOT / "src" / "anyimage" / "operators" / "depth_plane" / "data.py",
|
||||
),
|
||||
(
|
||||
"snapform.operators.depth_plane.build",
|
||||
PROJECT_ROOT / "src" / "snapform" / "operators" / "depth_plane" / "build.py",
|
||||
"anyimage.operators.depth_plane.build",
|
||||
PROJECT_ROOT / "src" / "anyimage" / "operators" / "depth_plane" / "build.py",
|
||||
),
|
||||
)
|
||||
packages = {
|
||||
name: ModuleType(name)
|
||||
for name in (
|
||||
"snapform",
|
||||
"snapform.operators",
|
||||
"snapform.operators.depth_plane",
|
||||
"anyimage",
|
||||
"anyimage.operators",
|
||||
"anyimage.operators.depth_plane",
|
||||
)
|
||||
}
|
||||
for package in packages.values():
|
||||
@@ -81,7 +81,7 @@ class ImageDepthTest(unittest.TestCase):
|
||||
def test_material_asset_path_survives_package_split(self):
|
||||
self.assertEqual(
|
||||
self.image_depth.node_asset_path(),
|
||||
PROJECT_ROOT / "src" / "snapform" / "assets" / "O_SnapForm.blend",
|
||||
PROJECT_ROOT / "src" / "anyimage" / "assets" / "O_AnyImage.blend",
|
||||
)
|
||||
def test_material_color_space_matches_scene_view_transform(self):
|
||||
mappings = {
|
||||
|
||||
@@ -4,7 +4,7 @@ from pathlib import Path
|
||||
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
||||
MANIFEST_PATH = PROJECT_ROOT / "src" / "snapform" / "blender_manifest.toml"
|
||||
MANIFEST_PATH = PROJECT_ROOT / "src" / "anyimage" / "blender_manifest.toml"
|
||||
|
||||
|
||||
class ManifestTest(unittest.TestCase):
|
||||
@@ -14,7 +14,7 @@ class ManifestTest(unittest.TestCase):
|
||||
|
||||
def test_declares_modern_extension_metadata(self):
|
||||
self.assertEqual(self.manifest["schema_version"], "1.0.0")
|
||||
self.assertEqual(self.manifest["id"], "snapform")
|
||||
self.assertEqual(self.manifest["id"], "anyimage")
|
||||
self.assertEqual(self.manifest["type"], "add-on")
|
||||
self.assertNotIn("bl_info", self.manifest)
|
||||
|
||||
|
||||
@@ -20,12 +20,12 @@ class ModelTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.models = load_module(
|
||||
"snapform_models",
|
||||
"src/snapform/model_catalog.py",
|
||||
"anyimage_models",
|
||||
"src/anyimage/model_catalog.py",
|
||||
)
|
||||
cls.server_models = load_module(
|
||||
"snapform_server_models",
|
||||
"src/snapform/server/model_catalog.py",
|
||||
"anyimage_server_models",
|
||||
"src/anyimage/server/model_catalog.py",
|
||||
)
|
||||
|
||||
def test_client_and_server_catalogs_share_storage_contract(self):
|
||||
|
||||
@@ -12,19 +12,19 @@ PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def load_module():
|
||||
snapform = ModuleType("snapform")
|
||||
snapform.__path__ = [str(PROJECT_ROOT / "src" / "snapform")]
|
||||
server = ModuleType("snapform.server")
|
||||
server.__path__ = [str(PROJECT_ROOT / "src" / "snapform" / "server")]
|
||||
models = ModuleType("snapform.server.models")
|
||||
anyimage = ModuleType("anyimage")
|
||||
anyimage.__path__ = [str(PROJECT_ROOT / "src" / "anyimage")]
|
||||
server = ModuleType("anyimage.server")
|
||||
server.__path__ = [str(PROJECT_ROOT / "src" / "anyimage" / "server")]
|
||||
models = ModuleType("anyimage.server.models")
|
||||
models.__path__ = [
|
||||
str(PROJECT_ROOT / "src" / "snapform" / "server" / "models")
|
||||
str(PROJECT_ROOT / "src" / "anyimage" / "server" / "models")
|
||||
]
|
||||
specification = importlib.util.spec_from_file_location(
|
||||
"snapform.server.models.onnx_moge2",
|
||||
"anyimage.server.models.onnx_moge2",
|
||||
PROJECT_ROOT
|
||||
/ "src"
|
||||
/ "snapform"
|
||||
/ "anyimage"
|
||||
/ "server"
|
||||
/ "models"
|
||||
/ "onnx_moge2.py",
|
||||
@@ -33,9 +33,9 @@ def load_module():
|
||||
with patch.dict(
|
||||
sys.modules,
|
||||
{
|
||||
"snapform": snapform,
|
||||
"snapform.server": server,
|
||||
"snapform.server.models": models,
|
||||
"anyimage": anyimage,
|
||||
"anyimage.server": server,
|
||||
"anyimage.server.models": models,
|
||||
},
|
||||
):
|
||||
specification.loader.exec_module(module)
|
||||
|
||||
@@ -12,7 +12,7 @@ PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
def load_pack():
|
||||
specification = importlib.util.spec_from_file_location(
|
||||
"snapform_pack",
|
||||
"anyimage_pack",
|
||||
PROJECT_ROOT / "pack.py",
|
||||
)
|
||||
module = importlib.util.module_from_spec(specification)
|
||||
@@ -47,7 +47,7 @@ class PackTest(unittest.TestCase):
|
||||
self.assertEqual(
|
||||
{path.name for path in output_paths},
|
||||
{
|
||||
f"SnapForm.v{version}.{platform}.zip"
|
||||
f"AnyImage.v{version}.{platform}.zip"
|
||||
for platform in pack.PLATFORMS
|
||||
},
|
||||
)
|
||||
@@ -66,7 +66,7 @@ class PackTest(unittest.TestCase):
|
||||
self.assertIn("operators/balloon/operator.py", names)
|
||||
self.assertIn("operators/surface.py", names)
|
||||
self.assertIn(
|
||||
"assets/O_SnapForm.blend",
|
||||
"assets/O_AnyImage.blend",
|
||||
names,
|
||||
)
|
||||
self.assertIn("server/media/input.py", names)
|
||||
@@ -100,7 +100,7 @@ class PackTest(unittest.TestCase):
|
||||
any(name.startswith("blendjob/") for name in names)
|
||||
)
|
||||
self.assertNotIn("install_env.py", names)
|
||||
self.assertNotIn("snapform/__init__.py", names)
|
||||
self.assertNotIn("anyimage/__init__.py", names)
|
||||
self.assertNotIn("importer.py", names)
|
||||
self.assertFalse(
|
||||
any(name.startswith("sources/") for name in names)
|
||||
|
||||
@@ -13,7 +13,7 @@ PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def load_server_module():
|
||||
server_directory = PROJECT_ROOT / "src" / "snapform" / "server"
|
||||
server_directory = PROJECT_ROOT / "src" / "anyimage" / "server"
|
||||
specification = importlib.util.spec_from_file_location(
|
||||
"server",
|
||||
server_directory / "__init__.py",
|
||||
@@ -73,7 +73,7 @@ class ServerTest(unittest.TestCase):
|
||||
self.assertEqual(result, {"downloaded": ["MOGE2_VITS_NORMAL"]})
|
||||
|
||||
def test_models_are_owned_by_the_server_resource(self):
|
||||
self.assertFalse((PROJECT_ROOT / "src" / "snapform" / "models.py").exists())
|
||||
self.assertFalse((PROJECT_ROOT / "src" / "anyimage" / "models.py").exists())
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
manager = self.server_module.ModelManager(Path(directory))
|
||||
snapshot = manager.snapshot()
|
||||
@@ -99,7 +99,7 @@ class ServerTest(unittest.TestCase):
|
||||
def create_server(self):
|
||||
source = self.server_module.server
|
||||
server = self.server_module.JobServer(
|
||||
"SnapForm Job Server", storage_root=self.storage_root
|
||||
"AnyImage Job Server", storage_root=self.storage_root
|
||||
)
|
||||
server.handlers.update(source.handlers)
|
||||
server.resource_factories.update(source.resource_factories)
|
||||
|
||||
@@ -15,7 +15,7 @@ PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def load_server_module(name):
|
||||
addon_directory = PROJECT_ROOT / "src" / "snapform"
|
||||
addon_directory = PROJECT_ROOT / "src" / "anyimage"
|
||||
sys.path.insert(0, str(addon_directory))
|
||||
try:
|
||||
return __import__(f"server.{name}", fromlist=[name])
|
||||
|
||||
@@ -14,9 +14,9 @@ DEPTH_SCALE_ATTRIBUTE = "o_depth_scale"
|
||||
OUTPUT_PATH = (
|
||||
Path(__file__).parents[1]
|
||||
/ "src"
|
||||
/ "snapform"
|
||||
/ "anyimage"
|
||||
/ "assets"
|
||||
/ "O_SnapForm.blend"
|
||||
/ "O_AnyImage.blend"
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -8,20 +8,20 @@ PROJECT_ROOT = Path(__file__).parents[1]
|
||||
sys.path.insert(0, str(PROJECT_ROOT / "src"))
|
||||
sys.path.insert(
|
||||
0,
|
||||
str(next((PROJECT_ROOT / "src" / "snapform" / "wheels").glob("blendjob-*.whl"))),
|
||||
str(next((PROJECT_ROOT / "src" / "anyimage" / "wheels").glob("blendjob-*.whl"))),
|
||||
)
|
||||
|
||||
from snapform.operators.balloon.depth import (
|
||||
from anyimage.operators.balloon.depth import (
|
||||
BALLOON_DEPTH_ATTRIBUTE,
|
||||
add_balloon_shape_modifier,
|
||||
balloon_shape_node_group,
|
||||
)
|
||||
from snapform.operators.balloon.operator import (
|
||||
from anyimage.operators.balloon.operator import (
|
||||
mark_balloon_material,
|
||||
merge_balloon_normal_image,
|
||||
reusable_balloon_material,
|
||||
)
|
||||
from snapform.operators.material import (
|
||||
from anyimage.operators.material import (
|
||||
BALLOON_MATERIAL_NODE_GROUP_NAME,
|
||||
material_node_group,
|
||||
set_modifier_input,
|
||||
|
||||
@@ -8,10 +8,10 @@ PROJECT_ROOT = Path(__file__).parents[1]
|
||||
sys.path.insert(0, str(PROJECT_ROOT / "src"))
|
||||
sys.path.insert(
|
||||
0,
|
||||
str(next((PROJECT_ROOT / "src" / "snapform" / "wheels").glob("blendjob-*.whl"))),
|
||||
str(next((PROJECT_ROOT / "src" / "anyimage" / "wheels").glob("blendjob-*.whl"))),
|
||||
)
|
||||
|
||||
from snapform.operators.material import (
|
||||
from anyimage.operators.material import (
|
||||
DEPTH_PLANE_MATERIAL_NODE_GROUP_NAME,
|
||||
SHADELESS_NODE_GROUP_NAME,
|
||||
SURFACE_MATERIAL_NODE_GROUP_NAME,
|
||||
@@ -23,8 +23,8 @@ from snapform.operators.material import (
|
||||
modifier_input_identifier,
|
||||
set_modifier_input,
|
||||
)
|
||||
from snapform.operators.depth_plane.build import add_depth_plane_processing
|
||||
from snapform.operators.surface import load_geometry_node_group
|
||||
from anyimage.operators.depth_plane.build import add_depth_plane_processing
|
||||
from anyimage.operators.surface import load_geometry_node_group
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
@@ -9,11 +9,11 @@ PROJECT_ROOT = Path(__file__).parents[1]
|
||||
sys.path.insert(0, str(PROJECT_ROOT / "src"))
|
||||
sys.path.insert(
|
||||
0,
|
||||
str(next((PROJECT_ROOT / "src" / "snapform" / "wheels").glob("blendjob-*.whl"))),
|
||||
str(next((PROJECT_ROOT / "src" / "anyimage" / "wheels").glob("blendjob-*.whl"))),
|
||||
)
|
||||
|
||||
from snapform.operators.material import get_modifier_input, set_modifier_input
|
||||
from snapform.operators.surface import create_matching_camera, load_geometry_node_group
|
||||
from anyimage.operators.material import get_modifier_input, set_modifier_input
|
||||
from anyimage.operators.surface import create_matching_camera, load_geometry_node_group
|
||||
|
||||
|
||||
def set_input(modifier, group, name, value):
|
||||
|
||||
@@ -12,17 +12,17 @@ PROJECT_ROOT = Path(__file__).parents[1]
|
||||
sys.path.insert(0, str(PROJECT_ROOT / "src"))
|
||||
sys.path.insert(
|
||||
0,
|
||||
str(next((PROJECT_ROOT / "src" / "snapform" / "wheels").glob("blendjob-*.whl"))),
|
||||
str(next((PROJECT_ROOT / "src" / "anyimage" / "wheels").glob("blendjob-*.whl"))),
|
||||
)
|
||||
|
||||
from snapform.operators.image import create_color_image
|
||||
from snapform.operators.material import (
|
||||
from anyimage.operators.image import create_color_image
|
||||
from anyimage.operators.material import (
|
||||
MOGE_DEPTH_PLANE_NODE_GROUP_NAME,
|
||||
MOGE_MATERIAL_NODE_GROUP_NAME,
|
||||
get_modifier_input,
|
||||
modifier_input_identifier,
|
||||
)
|
||||
from snapform.operators.depth_plane.build import build_moge2_depth_plane
|
||||
from anyimage.operators.depth_plane.build import build_moge2_depth_plane
|
||||
|
||||
|
||||
def validate_single_frame_source_types():
|
||||
|
||||
@@ -10,16 +10,16 @@ PROJECT_ROOT = Path(__file__).parents[1]
|
||||
sys.path.insert(0, str(PROJECT_ROOT / "src"))
|
||||
sys.path.insert(
|
||||
0,
|
||||
str(next((PROJECT_ROOT / "src" / "snapform" / "wheels").glob("blendjob-*.whl"))),
|
||||
str(next((PROJECT_ROOT / "src" / "anyimage" / "wheels").glob("blendjob-*.whl"))),
|
||||
)
|
||||
|
||||
from snapform.operators.material import (
|
||||
from anyimage.operators.material import (
|
||||
MOGE_SURFACE_MATERIAL_NODE_GROUP_NAME,
|
||||
material_color_space_name,
|
||||
)
|
||||
from snapform.operators.surface import MOGE_NODE_GROUP_NAME, build_image_mesh
|
||||
from snapform.server.geometry import GeometryFrame, build_surface
|
||||
from snapform.server.outputs.surface import write_surface_archive
|
||||
from anyimage.operators.surface import MOGE_NODE_GROUP_NAME, build_image_mesh
|
||||
from anyimage.server.geometry import GeometryFrame, build_surface
|
||||
from anyimage.server.outputs.surface import write_surface_archive
|
||||
|
||||
|
||||
def write_test_normal_texture(normal, output_path):
|
||||
|
||||
Reference in New Issue
Block a user