Files
AnyImage/docs/technical.md
nan 7cd5681a8b Add tests for foreground preservation and refactor geometry node asset
- Implement test to ensure foreground preserves source RGB and Ben2 alpha in WorkerTest.
- Remove outdated tests related to background distance and original background depth.
- Update geometry node asset to reflect new naming conventions and structure.
- Introduce validation for depth plane asset, ensuring correct input/output configurations and attribute handling.
- Adjust confidence and edge parameters in geometry node asset to support a wider range of values.
2026-08-11 23:25:51 +08:00

36 KiB
Raw Blame History

SnapForm 技术文档

本文档面向开发者和需要了解内部实现细节的用户,从原 README 迁移而来。普通用户请阅读项目根目录的 README.md。

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

当前功能

  • 使用 Blender Extension manifest,可通过 Install from Disk 安装
  • 在独立 Python Runtime 的常驻 HTTP AI Host 中运行 Torch、DA3 与 BEN2,避免污染 Blender Python 进程
  • Blender 使用内置 urllib.request 访问仅监听 127.0.0.1 的 Host;请求带随机 Token
  • 常驻 Host 复用 Torch、CUDA、BEN2 与最近使用的 DA3 模型,连续执行时不再重复加载
  • 多个 Blender 实例自动连接同一个共享 Host;Host 面板显示状态、端口、客户端与模型缓存,并提供安装、启动、清理、重启和停止控制
  • Runtime、模型和任务结果默认保存在 ~/.snapform,可由多个 Blender 版本共享
  • 支持 DA3 Small、Base、Large 1.1、Giant 1.1 和 Nested Giant Large 1.1
  • 支持 BEN2 Base 单图背景剔除测试,输出透明 PNG 与推理耗时
  • 支持单张 JPG、JPEG、PNG、WEBP 图片或常见视频文件输入
  • 视频按顺序截取前若干帧,可设置参与重建的最大帧数
  • Host > Models 默认折叠,展开后可逐项查看和下载所有可用模型
  • Runtime 已就绪时不额外占用面板空间;模型列表每个模型只占一行
  • Debug 默认折叠,内部的 DA3 Output Test 与 BEN2 Removal Test 也分别默认折叠
  • 使用一个输出类型下拉菜单和一个 Generate Output 按钮
  • 只显示当前格式的专属参数;GLB 与 PLY 设置不会同时出现
  • Debug 的模型选项按格式过滤;PLY 只提供两个带 Gaussian head 的 Giant 模型
  • Debug 与 Convert to Depth Plane 的模型选项直接显示下载状态;未下载模型带 (Missing),已下载模型保持原名
  • 分别调用 DA3 的 glb、gs_ply、depth_vis 和 mini_npz exporter
  • Textured Surface (GLB) 直接使用 DA3 Prediction 中的深度、置信度和相机参数,把相邻像素 组成三角面并写入 mesh.glb;每个输入帧生成一张独立纹理网格,不做多视图融合
  • Image Empty 右键菜单可直接运行 DA3,根据 mini_npz 深度生成面片
  • Image Empty 右键菜单可直接运行 BEN2,保留原图并换用新建的透明背景图片
  • Image Empty 支持视频与序列帧输入:Convert to Depth Plane 逐帧估计深度, Remove Background 逐帧抠图,入口保持不变
  • 视频生成的序列帧以外部文件引用保留在 job 目录(Blender 无法整体 Pack 序列帧); Geometry Nodes 与材质 Image Texture 均可按场景帧播放序列帧
  • 使用浮点深度贴图、O DA3 Depth Plane Geometry Nodes 和原图 Bump 构建立体面片
  • 转换对话框选择推理模式和处理分辨率;细分、背景与置换方式在 Geometry Nodes 修改器中调整
  • Debug 的 DA3 输出或 BEN2 背景剔除完成后只打开对应 job 文件夹,不修改当前场景
  • 完整保留每次任务生成的所有官方文件
  • 安装和模型下载使用后台子进程;推理提交给常驻 AI Host,状态栏实时显示阶段、百分比进度条与取消按钮
  • 后台任务运行时,Install、Download 和 Export 按钮保持原位置并变灰,任务完成后恢复

使用

  1. 先运行 uv run python prepare_vendor.py,按 vendor.lock.toml 下载并校验固定版本的 第三方构建输入;再运行 uv run python pack.py,分别构建 windows-x64、macos-arm64、 linux-x64 三个平台的 Extension ZIP(如 SnapForm.v0.10.11.macos-arm64.zip)。 每个包只含对应平台的 uv 二进制,并内置 DA3、BEN2 源码包。
  2. 在 Blender 的 Preferences > Extensions 中选择 Install from Disk。
  3. 在 Extension Preferences 中确认 Storage Root 与 Device。Device 是正式功能 (Image Empty 右键菜单)使用的推理设备,默认取本机最快的 CUDA/MPS,否则 CPU,且只列出 本机支持的设备。
  4. 在 Host 点击 Install Runtime。首次安装会下载 Python、PyTorch、FastAPI、Uvicorn; DA3、BEN2 源码包与 uv 已内置在扩展中,安装时从 ~/.snapform/vendor/ 解包使用, 并在 Runtime 就绪后自动下载 DA3 Small 和 BEN2 Base 推荐模型。Runtime 安装 固定显示 Environment、PyTorch、AI components 三个用户阶段;xFormers(macOS 跳过)、 FastAPI 等内部安装步骤合并在 AI components 中。耗时最长的 PyTorch 与 AI 组件占主要进度 区间。安装完成后直接写入 Runtime 就绪信息,不再额外导入全部组件进行验证。推荐模型属于安装 后的自动步骤,不计入阶段编号;DA3 Base 等其他模型可稍后在 Models 面板按需下载。 状态文字使用 阶段/总数 阶段名 | 当前操作 | 预计剩余时间,依赖安装会结合预设耗时与实际 进度修正预期;模型下载根据字节数和速度计算剩余时间,例如 Downloading DA3 Small | 14.2 MB/s | About 2 min left。重试或切换镜像时进度不会倒退。 Runtime 就绪后即使模型下载中断也不影响 Host 使用,可稍后在 Models 面板单独补下。 安装不做启动网络预检:pip 安装失败会自动依次重试清华、阿里镜像,模型下载由 worker 自行探测回退到 HF 镜像;需要手动指定镜像时可通过 PIP_INDEX_URL 环境变量覆盖。
  5. 在 3D View 按 N,打开 SnapForm 页签。
  6. 如需其他模型,展开 Host > Models,找到模型并点击该行的 Download。
  7. 展开默认收起的 Debug,选择 Output Type 和本次执行使用的模型。
  8. 选择一张图片或一个视频文件。视频可设置从头截取的帧数,然后点击 Generate Output。
  9. 测试背景剔除时,确认 Host > Models 中的 BEN2 Base 已就绪,然后在 Debug 的 BEN2 Removal Test 区域选择单张图片并点击 Remove Background。 完成后会打开 job 文件夹,其中的 foreground.png 带透明 Alpha;状态栏显示 BEN2 推理、模型加载与任务总耗时。当前测试固定关闭较慢的 foreground refinement。

Image Empty 去背景

  1. 确认 Host > Models 中的 BEN2 Base 已就绪;首次安装 Runtime 时会默认下载。
  2. 在 3D View 选中 Image Empty,右键打开 SnapForm 子菜单并选择 Remove Background。
  3. 完成后以 Fake User 保留原 Image datablock,新建并 Pack 一张透明 PNG 到当前 .blend,然后只把 当前 Empty 的 data 换成新图;Empty 的 Transform、显示尺寸、Offset 及其他设置保持不变。
  4. 新 Image 使用原图去掉格式后再追加 .foreground 的名称。例如 img.png 生成 img.foreground,img.png.001 生成 img.001.foreground。已有同名 datablock 时由 Blender 自动追加编号。

原图已 Pack 时会先写出临时 PNG 交给 BEN2,任务结束后删除临时输入;原 Image 仍保持 Pack 状态和原始内容。BEN2 的 foreground.png 也会保留在对应 job 目录中。

Image Empty 引用视频或序列帧时,Remove Background 直接执行,默认取 Empty 的 Image Frames 数值(未设置时为完整帧数,显式设为 1 时只处理 1 帧),起始帧跟随 Empty 的 Offset;若 Offset 加 Frames 超出视频长度, 会把窗口整体收进视频内(保证实际处理 Frames 帧数),Offset 过小时从第 1 帧开始。输出 foreground.0001.png 等透明序列帧(帧号从 0001 开始,与 Blender 场景帧一一对应),并把 源帧以 frame.0001.jpg 等命名复制到 job 目录根下供材质颜色导入。替换 Empty 的 Image 为 加载这些帧的 SEQUENCE Image,从原 Empty 的 Start 位置开始播放(Start 原样保留), Cyclic 沿用原 Empty 的设置。序列帧无法被 Blender 整体 Pack,因此保持外部引用 job 目录; 请保留对应 job 目录,否则序列会失效。

Image Empty 转深度面片

  1. 在 3D View 选中 Object Type = Empty、Display As = Image 的对象。
  2. 右键打开 SnapForm 子菜单并选择 Convert to Depth Plane,通过 Depth from 选择深度来源:
    • AI Generated:显示 Model、Use Ray Pose 和 Resolution Scale。实际 Process Res 为图片长边像素数 乘以 Resolution Scale;范围为 0.1–1.0,默认 1.0。计算后的 Process Res 会直接显示在 Resolution Scale (… px) 标签中。 转换导出 mini_npz,使用前需要在 Host > Models 下载所选模型,并固定使用 process_res_method="upper_bound_resize";设备和参考视图策略 继续使用场景设置。Model 下拉菜单只列出已经下载的 DA3 模型;若没有可用模型,对话框会引导到 Host > Models 下载。
    • Original:直接把原图作为深度贴图,不显示估算参数。单张图片运行 BEN2 取得前景 Alpha;视频或 序列帧同时抽取原始帧与前景序列,把原始帧作为 .depth 序列。 Original 是默认深度来源。选择 AI Generated 时,其 Model、Use Ray Pose 与 Resolution Scale 参数会集中显示在独立边框中。两种模式都有默认折叠的 Options,内部只保留 Unshaded; Delete Original 保持在折叠项外。转换固定需要 BEN2 Base,只把 .foreground 的 Alpha 作为独立 Mask,不在 Host 中改写深度值。保存 .foreground 时保留 BEN2 Alpha,但 RGB 使用未经修改的原始输入; 因此材质直接用 .foreground 同时提供颜色和 Mask,不再额外加载原图 Image Texture。 Image Empty 引用视频或序列帧时,AI Generated 会按 Empty 的 Image Frames 数值逐帧估计 深度(未设置时为完整帧数,显式设为 1 时只处理 1 帧),起始帧跟随 Empty 的 Offset,与背景蒙版范围一致; Offset 超出视频长度时同样把窗口收进视频内。材质节点与置换贴图的 Start 保持与原 Empty 一致;Original 模式的视频或序列帧使用 frame.0001.jpg 等原图序列作为颜色与深度, foreground.0001.png 只提供前景 Alpha。 AI Generated 的深度仍以 EXR 序列帧(depth.0001.exr 起)保存在 job 目录根下。 Unshaded 默认关闭,并默认删除原对象。
  3. AI Generated 完成后会自动创建面片。面片几何先由 mini_npz 的相机内参与深度确定,再通过对象 Transform 匹配原 Image Empty 的可见尺寸、位置、旋转和 Offset。Original 模式直接使用源 Empty 的可见尺寸、Offset 与 Transform。AI Generated 会把用于匹配画面尺寸的缩放预乘到 .depth 数值, XY 缩放烘焙到 Mesh,Z 不参与平面匹配;最终对象 Scale 为 (1, 1, 1),视觉深度与旧逻辑一致。 开启 Delete Original 时,成功生成后 删除源 Empty。生成面片 Object 使用源 Empty 的原名;关闭 Delete Original 时不处理 同名冲突,由 Blender 自动为生成面片追加编号。
  4. Blender 只创建保留图像纵横比的最低密度基础网格,再把 O DA3 Depth Plane 作为 Geometry Nodes 修改器添加到对象。节点组与 O Refine DA3 Surface 一同保存在 O_SnapForm.blend,关闭 show_group_selector,不为每个对象复制节点组。修改器公开以下参数:
    • Subdivision:默认 5。节点读取基础平面的 Bounding Box,短边分段数为 2^Subdivision, 长边按宽高比计算并四舍五入;例如 16:9 图片在等级 5 时生成 57×32 个面;
    • Remove Background:默认关闭的 Panel Toggle。关闭时折叠隐藏 Background Depth,开启后才显示; 它不删除几何,而是通过点域的 o_remove_background Attribute 控制材质 Alpha 是否乘以前景 Mask;
    • Background Depth:默认 0,允许正负值。只有开启 Remove Background 时,前景 Mask 外的 结构或材质置换才使用该值;关闭时所有像素继续使用原始深度;
    • Displacement:菜单包含 Geometry(默认)与 Material。Geometry 在节点组内沿法线修改网格, Material 保持网格平面并启用材质置换。
    • Depth Scale:默认 1,允许正负值,Structure Type 为 Single,同时控制 Geometry 与 Material 两条置换路径。 Grid 重建后通过隐藏的 Material 输入重新赋予原图材质,并对所有面执行 Shade Smooth。 材质使用显式指向 UVMap 的 UV Map 节点连接颜色、前景 Mask 与深度 Image Texture,不依赖活动 UV。 开启背景移除时,前景深度先与 Background Depth 取 Maximum,再按前景 Alpha 与背景深度混合, 深度分支在混合前使用 Alpha > 0.5 转为二值 Mask,避免半透明前景被背景深度拉扯; 材质表面 Alpha 仍保留柔和边缘。材质置换使用相同的二值和钳制顺序。 节点组还会把 o_material_displacement 与 o_background_depth 写入点域,材质通过 Geometry 类型的 Attribute 节点读取。点域会为顶点保存重复值,但能在应用修改器后继续保留参数; 相比自适应网格本身,其占用很小。Depth Image 与 Foreground Image 是修改器隐藏数据输入, 由导入流程自动设置。 视频与序列帧还会为 Depth 与 Foreground 共同写入隐藏的 Frame Start、Frames 与 Cyclic。 导入内容已经是截取后的帧,因此 Offset 在节点组内恒定为 0,不再作为输入。节点组使用 Scene Time 计算从 1 开始的 Image Texture Frame:场景帧与 Start 都为 1 时读取图片第 1 帧;非循环输入 钳制到有效范围;循环输入使用 Floored Modulo,让 Frame Start 前后的负、正相对帧都映射到 1…Frames,因此开始帧之前也会循环播放。Geometry 置换会像材质 Image Texture 一样随场景帧刷新。

Image Empty 转透视网格

  1. 在 3D View 选中仅包含一帧的 Image Empty,右键打开 SnapForm 子菜单并选择 Convert to Surface。该入口独立于 Convert to Depth Plane,当前不处理视频或序列帧。
  2. Host 请求 DA3 的 depth、conf 与 intrinsics,同时固定运行 BEN2 取得前景 alpha。Depth 不做 smoothing,也不在 Host 中剔面或减面;Host 只反投影完整有效拓扑,并计算 confidence percentile、 camera-space edge stretch 与 background 标记。
  3. Blender 把勾选 Usage > Modifier 的 O Refine DA3 Surface 节点组直接作为 Geometry Nodes 修改器 添加到 Surface,不另设修改器名称。节点组内没有子节点组,依次完成:
    • 修改器顶层依次显示 Resolution、Relax Iterations、Smooth;默认展开的 Culling Panel 包含 Confidence、Stretch、Background。两个百分比输入都使用 0–100 的节点值,并在组内 转换为 0–1 阈值;Stretch = 100% 明确选择全部面,剔面后同时删除 Face Count 为零的孤立顶点;
    • 每轮 Remesh Iteration 依次执行 Connected Merge、循环拓扑修复与一次 Smooth,使新拓扑在进入下一轮 Merge 前先稳定;拓扑修复删除非流形面、单面拓扑和小面积 mesh islands;
    • 默认 Resolution 为原始有效三角边长中位数乘以 sqrt(10) * 2。sqrt(10) 来自原先 90% 面数缩减 的二维边距估计,再乘以 2 为迭代合并留出更平滑、稳定的默认尺度;节点内部 Connected Merge 的 Distance 为 Resolution * 0.5;
    • Smooth 采用 O Smooth 的边界检测和模糊法线权重,固定开放边界与薄面,只保留一个 Smooth 程度系数;节点组不再额外执行 Flip Faces;
    • 从修改前的原始表面以 nearest-surface 重新采样 UVMap,最终明确写为 Corner 域 2D Vector。
  4. 节点组随插件放在 O_SnapForm.blend。Blender 4.5 首次 Append 后复用同一 datablock; Blender 5.0 以 linked ID 载入后调用 Pack,后续 Surface 继续复用。插件不会为每个 Surface 新建节点组, 也不会在添加后重命名 Geometry Nodes 修改器。节点组只启用 Usage > Modifier,不 Mark as Asset; 修改器关闭 show_group_selector。Fix Topology 位于默认折叠的 Options Panel。 节点图按 Culling、Remesh、Topology Fix、Island Cleanup 与 UV 分区摆放;各区就近使用独立的 Group Input,并隐藏没有连线的接口,避免跨越整个节点图的输入连线。
  5. Host 准备过程固定显示 6 个编号阶段:验证 DA3 数据、反投影、准备 DA3/BEN2 attributes、构建原始 拓扑、投影 UV/attributes、写出网格。状态栏显示 Post-processing n/6: ...。
  6. Host 在 job 根目录写出 mesh.npz 与 texture.png。NPZ 保存 camera-space vertices、 faces、uv、intrinsics、image_size 与有效深度中位数 reference_depth。Blender 读取这些 数据后直接创建 Surface 与原图材质,不需要 Open3D 或 OpenCV 进入 Blender Python 环境。 Surface 保留下列结构化 attributes:
    • 点域:o_depth、o_confidence、o_confidence_percentile、o_background;
    • 面域:o_face_confidence、o_edge_stretch、o_background_face。
  7. 网格以 reference_depth 截面匹配 Image Empty 的显示矩形:该截面的投影四角与 Empty 的可见 边界重合,主点同时匹配 Empty Offset。网格对象直接沿用源 Empty 的 matrix_world,因此位置、旋转、 缩放及父级关系产生的世界变换保持一致。更近的顶点沿 Empty 局部 +Z 方向凸出,三角面正面朝向 观察相机,启用 Backface Culling 时可从正面看到。
  8. 转换对话框不再提供后处理参数,只保留模型设置、Create Matching Camera、Unshaded 与 Delete Original。Unshaded 使用与 Depth Plane 相同的 Emission/Transparent 材质路径;普通材质的 Bump Scale 按 abs(object.scale.z) × camera scale_z 设置,并在材质组内乘以固定基准 0.001, 与透视表面实际深度尺度一致;它允许负数以反转凹凸方向。 相机默认关闭;开启后会在 Empty 局部 +Z 侧创建一台朝向局部 -Z 的透视相机,并成为生成 Surface 的子级,使二者移动时保持投影关系。开启 Delete Original 时,网格成功创建后删除源 Empty。 表面、材质与相机会归入同一个 Convert to Surface Undo 步骤。

Debug 的 Textured Surface GLB 会把 depth、confidence 与 confidence percentile 写入自定义顶点 attributes。其他 DA3 Debug 三维输出会同时写出未压缩的 prediction.attributes.npz,保存完整 depth、confidence、intrinsics、extrinsics 与 confidence percentile。当前 trimesh 的 glTF 点图元 导出器只写 Position/Color,无法可靠把任意 attribute 嵌入点云 GLB,因此点云先以 companion NPZ 保留完整结构;后续若改为 SnapForm 自有 glTF writer,可再把这些字段直接嵌入点图元。

所有任务使用统一的状态栏进度显示。变化中的阶段说明显示在右侧的进度条内部,取消按钮 位于进度条右侧。状态字段支持阶段、当前操作与预计剩余秒数,界面统一组合为紧凑文案并保证 进度单调递增。任务进程与 Host 请求在后台启动,按钮点击后立即进入进度状态。Image Depth 的阶段包括 Runtime 启动、输入准备、模型加载、深度估算、缓存 写出和面片构建。进度更新会强制刷新状态栏与窗口,无需移动鼠标即可实时显示。安装中断后残留的 半成品 Runtime 会在下次安装前自动清理,不会因为中断而无法再次安装。

导入过程精确保留 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,便于检查实际采用的 参考深度和尺寸。

材质始终导入深度 Image Texture,并连接到 Displacement 节点和 Material Output;材质 Surface Displacement 设置为 Displacement Only,AI Generated 与 Original 都使用 Midlevel = 0、Scale = 1。 o_material_displacement 为 False 时,材质把 Height 乘以零,置换只在几何节点中生效;为 True 时, 几何节点关闭结构置换,材质 Height 恢复。开启 Remove Background 时,前景 Alpha 同时用于选择 原始深度或有符号的 Background Depth,使两种置换路径保持一致;关闭时背景深度不参与计算。 视频与序列帧的颜色、深度与前景 Image Texture 通过 image_user 的 Frames / Offset / Start 把第 i 帧映射到场景 Start+i 帧,并启用 Auto Refresh。 颜色贴图到 Principled BSDF 之间使用独立的 Shader Node Group。Surface 使用 O DA3 Surface; Depth Plane 使用显示名为 O DA3 Depth Plane 的材质组,并把背景剔除、背景深度与材质置换 Attribute 读取全部收进组内。两者都依次接收 Color、Alpha、Float 类型的 Depth、Bump Scale,输出 Color、 Roughness、Alpha、Normal、Displacement。Surface 把原图 Color 同时送入 Color 与 Depth, 保持图像 Bump 效果。外层材质只保留贴图、材质组、Principled BSDF 与 Material Output,方便继续调整。 无论选择哪种置换方式,原始彩色贴图都会连接 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。 开启 Unshaded 后,原图 Color 连接 Emission,原图 Alpha 作为 Mix Shader 系数,在 Transparent BSDF 与 Emission 之间混合后连接 Material Output;不创建 Principled BSDF、Bump 或 Float Curve。Remove Background 开启时,原图 Alpha 会再乘以前景 Mask Alpha;关闭时仍完整显示原图。

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

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

Image Empty 使用 Packed Image 时,SnapForm 会通过 Blender 写出临时 PNG 交给 DA3, 不会 Unpack 或修改源 Image;任务结束后自动删除临时文件。普通图片仍直接读取源文件。DA3 的原始 results.npz 保留在对应 job 文件夹根下,生成的浮点深度 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 等编号。 视频输入时 Blender 无法整体 Pack 序列帧,因此 .depth 与颜色序列改为引用 job 目录根下的 depth.0001.exr、frame.0001.jpg(.frame)或 foreground.0001.png,并在每帧保留原始 浮点深度;保存 .blend 后再次打开仍需对应 job 目录存在。

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

每个任务在 ~/.snapform/jobs/ 下用独立文件夹包裹。文件夹统一采用 动作-对象_日期-时间-微秒,每种任务都有唯一名称,例如 generate-depth-plane_20260807-153000-123456。微秒用于避免同一秒启动的任务共用目录。

Blender 为 Packed Image 或序列帧生成的输入副本也归档到对应 job 根目录:单图命名为 input.png,序列帧命名为 frame.0001.*。它们以前暂存在 jobs/inputs/,现在不再创建这个 公共中转文件夹。普通磁盘文件和视频仍直接读取原文件,不额外复制。

日志、运行中的状态文件、归档输入与输出产物均直接放在 job 根目录。各类任务名称为:

  • install-runtime
  • download-model
  • export-reconstruction
  • generate-depth-plane
  • generate-image-mesh
  • remove-background
  • remove-image-background
  • generate-original-depth-plane

DA3 官方 exporter 产生的 gs_ply/、depth_vis/、exports/mini_npz/ 会在完成后自动平铺, 不会保留只含一层产物的子目录:

export-reconstruction_20260807-153000-123456/
├── export-reconstruction_20260807-153000-123456.log
├── export-reconstruction_20260807-153000-123456.json
└── scene.glb

export-reconstruction_20260807-153000-123456/
├── export-reconstruction_20260807-153000-123456.log
├── export-reconstruction_20260807-153000-123456.json
└── *.ply

export-reconstruction_20260807-153000-123456/
├── export-reconstruction_20260807-153000-123456.log
├── export-reconstruction_20260807-153000-123456.json
└── *.jpg

export-reconstruction_20260807-153000-123456/
├── export-reconstruction_20260807-153000-123456.log
├── export-reconstruction_20260807-153000-123456.json
└── results.npz

remove-background_20260807-153000-123456/
├── remove-background_20260807-153000-123456.log
├── remove-background_20260807-153000-123456.json
├── foreground.png            单图结果
├── foreground.0001.png…      视频/序列帧结果
├── frame.0001.jpg…           视频/序列帧的源帧副本
└── depth.0001.exr…           AI 深度序列帧

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

输出格式说明

Output Type 提供以下结果:

  • Point Cloud (GLB):DA3 glb
  • Gaussian Splats (PLY):DA3 gs_ply,同时传入 infer_gs=True
  • Depth Preview (Images):DA3 depth_vis
  • Depth Data (NPZ):DA3 mini_npz
  • Textured Surface (GLB):SnapForm 根据 DA3 Prediction 构建并输出 mesh.glb

Point Cloud 专属设置仅在对应类型下显示,gs_views_interval 仅用于 Gaussian Splats。 Textured Surface 使用 0–100% 的 Confidence Threshold 删除置信度最低的一定比例:

  • process_res=504
  • 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 保存深度、置信度和可用的相机参数。 Point Cloud GLB 任务会关闭其默认附带的深度预览,使五种输出产物保持分离。

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

Runtime

Extension 本身不包含 Torch。Install Runtime 使用 uv 创建独立 Python 3.12 环境,并安装。机器上即使没有安装 uv 或 Python 也没关系:安装程序由 Blender 自带的 Python 启动,缺 uv 时会解包扩展内置的对应平台二进制,再用它下载 Python 3.12 与全部依赖。uv 会缓存在扩展存储目录下,后续安装直接复用。 安装不做网络预检,直接开始;环境变量仍可切换镜像与代理:PIP_INDEX_URL(PyPI 镜像)、 SNAPFORM_TORCH_INDEX(PyTorch 索引)、HF_ENDPOINT(Hugging Face 镜像)、 HTTP(S)_PROXY/ALL_PROXY(代理)。未指定 PyPI 镜像时, pip 安装失败会自动依次重试镜像(清华、阿里云);模型下载不预探测,官方 Hugging Face 失败后自动回退 ModelScope(modelscope.cn,仓库名与 Hugging Face 一致)。 GitHub 不再参与安装:DA3、BEN2、uv 已内置,缺少内置文件会直接报错提示重新安装,不再下载兜底。 单独下载模型时遵循同样的顺序:Hugging Face(可用 HF_ENDPOINT 指定其他镜像)失败后自动切换到 ModelScope。 Windows 上代理若只在系统设置里而未写入环境变量,安装程序会尝试自动从系统代理注入子进程。

  • PyTorch 2.9.1
  • TorchVision 0.24.1
  • xFormers 0.0.33.post2(与 PyTorch 2.9.1 对应,仅 Windows/Linux;macOS 无 wheel 自动跳过)
  • 固定到已验证 commit 的 Depth Anything 3
  • 固定到已验证 commit 的 BEN2
  • FastAPI 0.139.2 与 Uvicorn 0.51.0
  • DA3 与 BEN2 源码包随扩展打包,安装时复制到 ~/.snapform/vendor/ 后由 uv 本地安装 (无需访问 GitHub);SnapForm 直接调用 DA3 底层 export 接口,gs_ply 导出不会触发 gs_video 渲染,因此不需要 gsplat 与 C++ 编译工具链
  • vendor/ 是不进入 Git 的本地缓存;vendor.lock.toml 固定下载 URL、commit/version 与 SHA-256,patches/<包名>/ 进入 Git 并存放 SnapForm 对源码的覆盖文件(移除 xformers 硬依赖、export 入口改懒加载、 射线位姿的 3×3 QR 分解在 MPS 上改走 CPU), pack.py 打包时自动套入官方包,扩展 zip 内才是修补后的版本;更新上游只需替换官方包 并核对覆盖文件是否仍适用
  • addict 2.4.0(补充 DA3 上游包元数据暂未声明的运行依赖)

安装 Runtime 时会自动选择 PyTorch 后端:检测到 NVIDIA 驱动则安装 CUDA 12.8 版本,否则安装 CPU 版;macOS 始终安装 CPU 版 PyTorch(MPS 包含其中)。CPU 可以用于验证,但实际推理通常很慢。 Extension Preferences 的 Device 决定正式功能的推理设备,默认取本机最快的 CUDA/MPS,否则 CPU;Debug 面板的 Debug Device 只影响 Debug 任务。两处设备选项都只列出本机支持的设备: Windows 不显示 MPS,机器上没有可用 NVIDIA 驱动时不显示 CUDA。Runtime 安装完成时会检测真实 可用的设备并写入 snapform_ready.json,设备列表以该检测结果为准。 CUDA 12.8 的 PyTorch wheel 自带 CUDA 运行库,无需安装 CUDA Toolkit;只需要 NVIDIA 驱动 ≥ 570(数据中心显卡可用更老驱动)。驱动不满足或没有 NVIDIA 显卡时, 设备会自动回退到 CPU(macOS 为 MPS),只有显式选择 CUDA 才会报错。

macOS(Apple Silicon)会自动从 PyPI 安装 CPU 版 PyTorch,推理设备默认使用 MPS (Apple Metal)加速,也可以在设备选项里切换 CPU。PyTorch 自 2.3 起不再提供 Intel Mac(x86_64)轮子,Intel Mac 暂不支持。DA3 射线位姿估计中的 3×3 QR 分解在 MPS 上尚未实现,SnapForm 的覆盖文件会单独把该分解放到 CPU 执行,其余推理仍走 MPS。

Extension 启用后只会查找已有的共享 AI Host,不会主动启动新进程。第一次执行 AI 操作或在侧边栏 手动点击 Start 时才会启动 Host。Host 只绑定回环地址,并让操作系统分配动态端口;第一个实例把 端口、进程和随机 Token 写入 host.json,其余 Blender 通过标准库 urllib.request 连接同一个 Host。host.lock 保证同一 Storage Root 同时只有一个 Host,Token 则阻止同机其他进程直接调用接口。Host 全局同时只执行一个 AI 任务。

每个 Blender 会注册独立客户端并每 5 秒发送心跳。正常关闭 Blender 时先注销自身;如果当前 Host 就是由这个 Blender 启动的,会直接终止它,无需等待。异常退出的客户端会在 10 秒后过期;Host 在最后一个客户端离开后仍会保留模型缓存等待 20 秒再退出,作为 Host 由其他进程启动等场景的兜底。 取消任务不会重启 Host,并会保留已经加载的模型; 如果取消发生在一次不可中断的 Torch 调用中,任务会在该调用返回后的最近检查点结束。

侧边栏 Host 面板以 Running (Clients: n) 表示空闲服务,以 Running (Busy) 表示正在执行任务, 并显示缓存模型和活动任务。Blender 完成结果导入时会立即释放当前任务对应的本地 Busy 快照,无需等待 下一次 Host 轮询。空闲且只有当前 Blender 连接时,可以清理模型缓存、重启或停止 Host; 多客户端或任务执行期间不会允许破坏共享服务。

BEN2 在首次使用后保持加载;DA3 保留最近使用的一个模型。切换 DA3 模型时会释放旧模型;加载时如果 显存不足,会先释放另一类缓存模型并重试。

Runtime Schema 已升级,旧 Runtime 需要重新执行 Install Runtime 才能安装 HTTP Host 依赖。 Host 的启动和崩溃日志写入 ~/.snapform/ai-host.log。

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

~/.snapform/
├── runtime/
├── models/
├── jobs/
├── ai-host.log
├── host.json       # Host 运行时存在
└── host.lock       # Host 运行时持有

models/ 下每个模型一个文件夹,命名统一带前缀:DA3 为 da3_*(如 da3_small、da3_base), BEN2 为 ben2_*(如 ben2_base)。旧版无前缀的 DA3 文件夹会在首次使用时自动改名为新名称。

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

开发

uv run python prepare_vendor.py
uv run pytest tests -v
uv run python pack.py

项目结构:

.
├── vendor.lock.toml        第三方构建输入的版本、URL 与 SHA-256
├── prepare_vendor.py       下载并校验第三方构建输入
├── pack.py
├── patches/                进入 Git 的 DA3 源码覆盖文件
├── vendor/                 不进入 Git 的下载缓存;本地调试也直接读取这里
├── src/
│   └── snapform/
│       ├── blender_manifest.toml
│       ├── ai_host.py
│       ├── 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。
  • BEN2 代码与模型权重采用 MIT License。
  • 本 Extension 代码采用 GPL-3.0-or-later。
  • 模型权重许可证由所选 Hugging Face 模型仓库决定,Extension 下载前会在界面显示。