- Renamed DA3 and BEN2 debug panels for clarity and consistency. - Added a new function to draw DA3 input settings to reduce code duplication. - Implemented mesh export functionality, including confidence thresholding and edge filtering. - Updated export format options to include new mesh type and adjusted related properties. - Enhanced job handling to move generated inputs into job root and manage temporary directories. - Improved error handling and file management during export processes. - Added unit tests for new mesh functionality and ensured existing tests cover changes.
438 lines
29 KiB
Markdown
438 lines
29 KiB
Markdown
# SnapForm 技术文档
|
||
|
||
本文档面向开发者和需要了解内部实现细节的用户,从原 README 迁移而来。普通用户请阅读项目根目录的
|
||
`README.md`。
|
||
|
||
`SnapForm` 是一套从图片快速构建空间结构的 Blender Extension。目前以
|
||
[Depth Anything 3](https://github.com/ByteDance-Seed/Depth-Anything-3)
|
||
作为首个 AI 能力,在独立 Runtime 中运行 DA3,可将官方导出结果保存在独立 job 目录,
|
||
也可把 Image Empty 转换成带几何与材质置换的立体面片。Debug 面板还可运行
|
||
[BEN2](https://github.com/PramaLLC/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 Mesh (GLB)` 直接使用 DA3 Prediction 中的深度、置信度和相机参数,把相邻像素
|
||
组成三角面并写入 `mesh.glb`;每个输入帧生成一张独立纹理网格,不做多视图融合
|
||
- Image Empty 右键菜单可直接运行 DA3,根据 `mini_npz` 深度生成面片
|
||
- Image Empty 右键菜单可直接运行 BEN2,保留原图并换用新建的透明背景图片
|
||
- Image Empty 支持视频与序列帧输入:`Convert to Depth Plane` 逐帧估计深度,
|
||
`Remove Background` 逐帧抠图,入口保持不变
|
||
- 视频生成的序列帧以外部文件引用保留在 job 目录(Blender 无法整体 Pack 序列帧);
|
||
Displace 修改器与材质 Image Texture 均可按场景帧播放序列帧
|
||
- 使用浮点深度贴图、Simple Subdivision、Displace Modifier 和原图 Bump
|
||
构建立体面片
|
||
- 转换对话框可选择推理模式、处理分辨率和面片网格细分
|
||
- 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,右键选择 `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. 右键选择 `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`:直接把原图作为深度贴图,不显示估算参数。单张图片不启动 Runtime;视频或
|
||
序列帧会启动轻量抽帧任务,把帧抽出来作为 `.depth` 序列(比直接引用视频稳定)。
|
||
`Original` 是默认深度来源。选择 `AI Generated` 时,其 Model、Use Ray Pose 与 Resolution Scale
|
||
参数会集中显示在独立边框中。两种模式都有默认折叠的 Options,内部依次为 Displace via、
|
||
Subdivision、Background Depth Distance 和 Unshaded;Delete Original 保持在折叠项外。
|
||
Background Depth Distance 默认 `0`,表示不剔除背景。大于 `0` 时需要 `BEN2 Base`,并使用固定值
|
||
处理 alpha 背景。AI Generated 的 DA3 仍完全使用原图估算深度,推理后先把全部 depth 转换为
|
||
`1 - DA3 depth`,再只把全透明区域设为 `-Background Depth Distance`;平面尺寸仍使用转换前的深度参考值,
|
||
同时把比背景更远的前景值钳制到背景平面,并强制最外侧 1 像素为背景距离,以减少边缘墙面和毛刺;
|
||
因此背景赋值不会缩放前景。Original 则把原图前景转为灰度深度,并把全透明区域设为该距离的负值,
|
||
生成浮点 `.depth` 图片或 EXR 序列。两种模式都会使用 `.foreground` 作为材质颜色,不修改源
|
||
Image Empty 的 Image datablock,也不根据每帧前景深度动态调整背景值。
|
||
Image Empty 引用视频或序列帧时,AI Generated 会按 Empty 的 Image Frames 数值逐帧估计
|
||
深度(未设置时为完整帧数,显式设为 1 时只处理 1 帧),起始帧跟随 Empty 的 Offset,与背景蒙版范围一致;
|
||
Offset 超出视频长度时同样把窗口收进视频内。材质节点与置换贴图的 Start 保持与原 Empty
|
||
一致;Original 模式在 Distance 为 `0` 时,单帧复制原图作为 `.depth`,视频或序列帧则使用
|
||
`frame.0001.jpg` 等原图序列。Distance 大于 `0` 时改为生成包含固定负背景值的浮点 `.depth` 或
|
||
`depth.0001.exr` 序列。材质颜色在启用固定背景距离时使用 `foreground.0001.png` 序列。
|
||
AI Generated 的深度仍以 EXR 序列帧(`depth.0001.exr` 起)保存在 job 目录根下。
|
||
Displace via 可选 `Modifier`(默认)或 `Material`;
|
||
Unshaded 默认关闭;Subdivision 默认为 `5`,并默认删除原对象。
|
||
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. 短边分段数为 `2^Subdivision`,长边分段数根据图像宽高比取最接近的整数。例如高:宽为
|
||
`2:3`、Subdivision 为 `1` 时,直接生成 `2×3` 个面;Subdivision 为 `3` 时生成
|
||
`8×12` 个面。随后的 Simple Subdivision 修改器使用原生名称,Viewport Levels 固定为
|
||
`1`,Render Levels 固定为 `2`,不再随 Resolution Scale 或 Subdivision 动态变化。
|
||
|
||
所有任务使用统一的状态栏进度显示。变化中的阶段说明显示在右侧的进度条内部,取消按钮
|
||
位于进度条右侧。状态字段支持阶段、当前操作与预计剩余秒数,界面统一组合为紧凑文案并保证
|
||
进度单调递增。任务进程与 Host 请求在后台启动,按钮点击后立即进入进度状态。Image Depth 的阶段包括 Runtime 启动、输入准备、模型加载、深度估算、缓存
|
||
写出和面片构建。进度更新会强制刷新状态栏与窗口,无需移动鼠标即可实时显示。安装中断后残留的
|
||
半成品 Runtime 会在下次安装前自动清理,不会因为中断而无法再次安装。
|
||
|
||
导入过程精确保留 NPZ 内深度值之间的差值。例如深度 `2.0` 和 `5.5` 在
|
||
`Displacement Strength = -1` 时,沿局部 Z 轴相差 `3.5 Blender Unit`。它不会把数值压缩到
|
||
`0..1`,也不再提供视觉归一化模式。
|
||
|
||
面片尺寸以有效深度的中位数 `Zref` 作为参考截面。先用 `mini_npz` 中的相机内参计算原始
|
||
投影面积,再恢复源图纵横比:
|
||
|
||
```text
|
||
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` 固定为 `0`。Original 把原图指定给 Displace Texture,并设置
|
||
`Texture Coordinates = UV`、`Midlevel = 0`;其余修改器设置保留 Blender 默认值。
|
||
视频与序列帧生成的深度贴图是 SEQUENCE Image;Displace 修改器的 Texture 与材质的 Image Texture
|
||
节点都支持序列帧,通过 image_user 的 Frames / Offset / Start 设置把第 i 帧映射到场景
|
||
`Start+i` 帧(Start 沿用 Empty 的 Start),并启用 Auto Refresh,播放时随场景帧逐帧更新。
|
||
选择 `Material` 时,不创建 Displace Modifier;深度 Image Texture 的 Color 连接到 Displacement
|
||
节点的 Height,再连接 Material Output 的 Displacement,并把材质 Surface Displacement 设置为
|
||
`Displacement Only`。AI Generated 与 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`。
|
||
开启 `Unshaded` 后,原图 Color 连接 Emission,原图 Alpha 作为 Mix Shader 系数,在
|
||
Transparent BSDF 与 Emission 之间混合后连接 Material Output;不创建 Principled BSDF、Bump 或
|
||
Float Curve。若 Displace via 选择 `Material`,深度贴图与 Displacement
|
||
节点仍会保留并连接 Material Output 的 Displacement。
|
||
|
||
这里的“原始距离”是 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 操作。
|
||
Background Depth Distance 大于 `0` 时,`.foreground` Image、Original 浮点深度、Pack 和深度面片生成也属于
|
||
同一个 Undo 步骤。
|
||
|
||
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`
|
||
- `remove-background`
|
||
- `remove-image-background`
|
||
- `generate-original-depth-plane`
|
||
- `extract-original-frames`
|
||
|
||
DA3 官方 exporter 产生的 `gs_ply/`、`depth_vis/`、`exports/mini_npz/` 会在完成后自动平铺,
|
||
不会保留只含一层产物的子目录:
|
||
|
||
```text
|
||
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 Mesh (GLB):SnapForm 根据 DA3 Prediction 构建并输出 `mesh.glb`
|
||
|
||
Point Cloud 专属设置仅在对应类型下显示,`gs_views_interval` 仅用于 Gaussian Splats。
|
||
Textured Mesh 使用 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 文档](https://github.com/ByteDance-Seed/Depth-Anything-3/blob/main/docs/API.md)。
|
||
|
||
## 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`:
|
||
|
||
```text
|
||
~/.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、任务队列和模型读取可以共享。
|
||
|
||
## 开发
|
||
|
||
```bash
|
||
uv run python prepare_vendor.py
|
||
uv run pytest tests -v
|
||
uv run python pack.py
|
||
```
|
||
|
||
项目结构:
|
||
|
||
```text
|
||
.
|
||
├── 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 下载前会在界面显示。
|