nan a503786c62 Refactor and enhance SnapForm functionality
- Introduced MODEL_NUMBERS for better model indexing.
- Improved enum_items function to cache results and handle download status.
- Updated ActiveJob class to manage temporary input paths and added displacement_via property.
- Changed IMAGE_DEPTH_PROCESS_RES_METHOD from "lower_bound_resize" to "upper_bound_resize".
- Enhanced RunJob operator to include new properties and improved error messages.
- Modified panel layout for better user experience and added runtime installation checks.
- Updated SnapFormSettings to reflect new model properties and defaults.
- Added temporary input path management in runtime.
- Refined worker functions to improve error handling and messaging.
- Expanded tests to cover new functionality and ensure backward compatibility.
- Fixed packaging script to align with versioning conventions.
2026-08-03 13:47:15 +08:00

SnapForm

SnapForm 是一套从图片快速构建空间结构的 Blender Extension。目前以 Depth Anything 3 作为首个 AI 能力,在独立 Runtime 中运行 DA3,可将官方导出结果保存在独立 job 目录, 也可把 Image Empty 转换成带几何与材质置换的立体面片。

当前功能

  • 使用 Blender Extension manifest,可通过 Install from Disk 安装
  • 在独立 Python Runtime 中运行 Torch 与 DA3,避免污染 Blender Python 进程
  • Runtime、模型和任务结果默认保存在 ~/.snapform,可由多个 Blender 版本共享
  • 支持 DA3 Small、Base、Large 1.1、Giant 1.1 和 Nested Giant Large 1.1
  • 支持单张 JPG、JPEG、PNG、WEBP 图片或常见视频文件输入
  • 视频均匀抽帧,可设置参与重建的最大帧数
  • Setup 集中管理 Runtime,并逐项列出和下载所有可用模型
  • Runtime 已就绪时不额外占用面板空间;模型列表每个模型只占一行
  • Debug 是独立且默认折叠的 DA3 测试面板
  • 使用一个导出类型下拉菜单和一个 Export 按钮
  • 只显示当前格式的专属参数;GLB 与 PLY 设置不会同时出现
  • Debug 的模型选项按格式过滤;PLY 只提供两个带 Gaussian head 的 Giant 模型
  • Debug 与 Convert to Depth Plane 的模型选项直接显示下载状态;未下载模型带 (Missing),已下载模型保持原名
  • 分别调用 DA3 的 glb、gs_ply、depth_vis 和 mini_npz exporter
  • Image Empty 右键菜单可直接运行 DA3,根据 mini_npz 深度生成面片
  • 使用浮点深度贴图、Simple Subdivision、Displace Modifier 和原图 Bump 构建立体面片
  • 转换对话框可选择推理模式、处理分辨率和面片网格细分
  • Debug 导出完成后只打开对应 job 文件夹,不向当前 Blender 文件添加任何数据
  • 完整保留每次任务生成的所有官方文件
  • 安装、模型下载和推理均在后台子进程运行,状态栏实时显示阶段、百分比进度条与取消按钮
  • 后台任务运行时,Install、Download 和 Export 按钮保持原位置并变灰,任务完成后恢复

使用

  1. 使用 uv run python pack.py 构建 Extension ZIP。
  2. 在 Blender 的 Preferences > Extensions 中选择 Install from Disk。
  3. 在 Extension Preferences 中确认 uv 路径和 Torch Backend。
  4. 点击 Install Runtime。首次安装会下载 Python、PyTorch 和 DA3 依赖。
  5. 在 3D View 按 N,打开 SnapForm 页签。
  6. 在 Setup 中找到需要的模型并点击该行的 Download。
  7. 展开默认收起的 Debug,选择 Export Format 和本次执行使用的模型。
  8. 选择一张图片或一个视频文件。视频可设置均匀抽取的帧数,然后点击 Export。

Image Empty 转深度面片

  1. 在 3D View 选中 Object Type = Empty、Display As = Image 的对象。
  2. 右键选择 Convert to Depth Plane,通过 Depth from 选择深度来源:
    • AI Generated:显示 Model、Use Ray Pose 和 Resolution Scale。实际 Process Res 为图片长边像素数 乘以 Resolution Scale;范围为 0.1–1.0,默认 0.5。计算后的 Process Res 会直接显示在 Resolution Scale (… px) 标签中。 转换导出 mini_npz,使用前需要在 Setup 下载所选模型,并固定使用 process_res_method="upper_bound_resize";设备和参考视图策略 继续使用场景设置。
    • Original:直接把原图作为深度贴图,不显示估算参数,也不启动 Runtime 或要求源图片存在于磁盘。 Original 是默认深度来源。选择 AI Generated 时,其 Model、Use Ray Pose 和 Resolution Scale 参数会集中显示在独立边框中。两种模式始终显示 Displace via、Subdivision 与 Delete Original。 Displace via 可选 Modifier(默认)或 Material; Subdivision 默认为 5,并默认删除原对象。
  3. AI Generated 完成后会自动创建面片。面片几何先由 mini_npz 的相机内参与深度确定,再通过对象 Transform 匹配原 Image Empty 的可见尺寸、位置、旋转和 Offset。Original 模式直接使用源 Empty 的可见尺寸、Offset 与 Transform。开启 Delete Original 时,成功生成后 删除源 Empty。生成面片 Object 使用源 Empty 的原名;关闭 Delete Original 时不处理 同名冲突,由 Blender 自动为生成面片追加编号。
  4. 短边分段数为 2^Subdivision,长边分段数根据图像宽高比取最接近的整数。例如高:宽为 2:3、Subdivision 为 1 时,直接生成 2×3 个面;Subdivision 为 3 时生成 8×12 个面。随后的 Simple Subdivision 修改器使用原生名称,Viewport Levels 固定为 1,Render Levels 固定为 2,不再随 Resolution Scale 或 Subdivision 动态变化。

所有任务使用统一的状态栏进度显示。变化中的阶段说明显示在右侧的紧凑进度条内部,取消按钮 位于进度条右侧。Image Depth 的阶段包括 Runtime 启动、输入准备、模型加载、深度估算、缓存 写出和面片构建。状态更新仅标记相关区域重绘,不强制执行窗口 Draw/Swap。

导入过程精确保留 NPZ 内深度值之间的差值。例如深度 2.0 和 5.5 在 Displacement Strength = -1 时,沿局部 Z 轴相差 3.5 Blender Unit。它不会把数值压缩到 0..1,也不再提供视觉归一化模式。

面片尺寸以有效深度的中位数 Zref 作为参考截面。先用 mini_npz 中的相机内参计算原始 投影面积,再恢复源图纵横比:

RawWidth  = depth_width  × Zref × abs(Displacement Strength) / fx
RawHeight = depth_height × Zref × abs(Displacement Strength) / fy
Area      = RawWidth × RawHeight
Aspect    = source_image_width / source_image_height
Width     = sqrt(Area × Aspect)
Height    = sqrt(Area / Aspect)

这样即使 DA3 估计出的 fx/fy 不一致,也不会把正方形原图拉成长方形。主点 cx/cy 仍用于 确定原始相机面片,随后对象 XY Transform 将它匹配到源 Image Empty。生成对象会记录 snapform_reference_depth、snapform_camera_plane_width 和 snapform_camera_plane_height,便于检查实际采用的 参考深度和尺寸。

选择 Modifier 时,AI Generated 的 Displace Modifier 深度贴图使用 Extension = Extend, Strength 固定为 -1、Midlevel 固定为 1。Original 把原图指定给 Displace Texture,并设置 Texture Coordinates = UV、Midlevel = 0;其余修改器设置保留 Blender 默认值。 选择 Material 时,不创建 Displace Modifier;深度 Image Texture 的 Color 连接到 Displacement 节点的 Height,再连接 Material Output 的 Displacement,并把材质 Surface Displacement 设置为 Displacement Only。AI Generated 使用 Midlevel = 1、Scale = -1;Original 使用 Midlevel = 0、Scale = 1,与对应修改器值一致。无论选择哪种呈现方式,原始彩色贴图都会连接 Principled BSDF 的 Base Color,并通过 Bump.Height → Bump.Normal → Principled.Normal 提供表面细节。Bump 的基础 Distance 为 0.001,会乘以面片 Transform 的统一缩放倍率。原图 Color 还会经过 Float Curve 连接到 Principled BSDF 的 Roughness,曲线两端输出分别为 0.5 和 0.1;材质 IOR 保持 Principled BSDF 默认值 1.5。

这里的“原始距离”是 DA3 模型输出的尺度。普通 Small、Base、Large 和 Giant 模型的深度不应 被解释为现实世界的米;需要现实尺度时应选择带 metric depth 的 DA3 Nested Giant Large 1.1。此外,当前结果仍是固定 XY 平面上的深度位移面,不是使用 相机内参逐像素反投影得到的完整 camera-space 网格;中位深度截面为现有 Displace Modifier 工作流提供正确的整体高宽尺度。

生成完成后会直接创建面片,不提供缓存重建入口或单独的导入参数。重新选择 Convert to Depth Plane 会按当前 Depth from 再次转换。 面片、深度 Image、Texture 与 Material 会在同一个 Blender Undo 步骤中创建;转换完成后执行 Ctrl+Z 会完整撤销本次转换,不会越过转换去回退更早的 Image Empty 操作。

Image Empty 使用 Packed Image 时,SnapForm 会通过 Blender 写出临时 PNG 交给 DA3, 不会 Unpack 或修改源 Image;任务结束后自动删除临时文件。普通图片仍直接读取源文件。DA3 的原始 results.npz 保留在对应 job 的 exports/mini_npz/ 中,生成的浮点深度 Image 会 Pack 到 当前 .blend。Depth Image 与 Displace Texture 根据源 Image datablock 命名。例如 Empty Object 名为 obj_img、引用的 Image 名为 img.png 时,Depth Image 与 Texture 都命名为 img.depth; 生成的 Object、Mesh 与 Material 仍命名为 obj_img。Pack 使用 OpenEXR,因而不会把大于 1.0 的原始深度截断。已有同名 datablock 时由 Blender 自动追加 .001 等编号。

选择 PLY 后,模型菜单只会提供 DA3 Giant 1.1 和 DA3 Nested Giant Large 1.1。Small、Base 和 Large 没有 Gaussian head,无法由 DA3 生成 gs_ply。

每次任务会在 ~/.snapform/jobs/<任务目录>/ 中保留 DA3 官方产物:

<GLB 任务目录>/
└── scene.glb

<PLY 任务目录>/
└── gs_ply/*.ply

<Depth 任务目录>/
└── depth_vis/*.jpg

<Mini NPZ 任务目录>/
└── exports/mini_npz/results.npz

建议从 DA3 Base 开始。它使用 Apache 2.0 模型权重;DA3 Large 1.1 权重采用 CC BY-NC 4.0,仅限非商业用途。

输出格式说明

Export Format 下拉菜单分别把以下原始 export_format 传给 DA3:

  • GLB:glb
  • PLY:gs_ply,同时传入 infer_gs=True
  • Depth Images:depth_vis
  • Mini NPZ:mini_npz

界面使用 DA3 API 的参数名、选项和默认值。GLB 专属设置仅在选择 GLB 时显示, gs_views_interval 仅在选择 PLY (3DGS) 时显示:

  • process_res=1024
  • process_res_method="upper_bound_resize"
  • use_ray_pose=False
  • ref_view_strategy="saddle_balanced"
  • conf_thresh_percentile=40.0
  • num_max_points=1_000_000
  • show_cameras=True
  • export_kwargs["gs_ply"]["gs_views_interval"]=1

DA3 官方 glb 是彩色点云与可选相机线框;gs_ply 是带 Gaussian 属性的 PLY; depth_vis 是原图与着色深度图的并排预览;mini_npz 保存深度、置信度和可用的相机参数。 GLB 任务会关闭其默认附带的深度预览,使四种 job 产物保持分离。

官方格式与限制可参阅 DA3 Python API 文档。

Runtime

Extension 本身不包含 Torch。Install Runtime 使用 uv 创建独立 Python 3.12 环境,并安装:

  • PyTorch 2.9.1
  • TorchVision 0.24.1
  • xFormers 0.0.33.post2(与 PyTorch 2.9.1 对应)
  • 固定到已验证 commit 的 Depth Anything 3
  • 固定到 DA3 官方推荐 commit 的 gsplat;仅安装 PLY 导出所需的纯 Python 部分, 不编译本机 CUDA rasterizer
  • addict 2.4.0(补充 DA3 上游包元数据暂未声明的运行依赖)

默认 CUDA Backend 为 CUDA 12.8,也可以选择 CPU。CPU 可以用于验证,但实际推理 通常很慢。

Runtime、模型和任务结果默认保存在用户主目录的 ~/.snapform:

~/.snapform/
├── runtime/
├── models/
└── jobs/

不同 Blender 版本安装相同 Extension 后会共用这个目录。也可以在 Extension Preferences 的 Storage Root 中修改共享位置。不要把模型写入 Extension 安装目录, 因为该目录可能只读,并且升级时会被替换。不要同时从多个 Blender 实例执行 Install Runtime;推理任务和模型读取可以共享。

开发

uv run python -m unittest discover -s tests -v
uv run python pack.py

项目结构:

.
├── pack.py
├── src/
│   └── snapform/
│       ├── blender_manifest.toml
│       ├── bootstrap_runtime.py
│       ├── models.py
│       ├── image_depth.py
│       ├── operators.py
│       ├── panel.py
│       ├── preferences.py
│       ├── properties.py
│       ├── runtime.py
│       └── worker.py
└── tests/

上游与许可证

  • Depth Anything 3 代码采用 Apache 2.0。
  • 本 Extension 代码采用 GPL-3.0-or-later。
  • 模型权重许可证由所选 Hugging Face 模型仓库决定,Extension 下载前会在界面显示。
Description
No description provided
Readme 252 MiB
Languages
Python 98.9%
HTML 1.1%