image-to-figure(图像转3D手办) 是做什么的?
目标
从一张角色图像(插画、概念图或手办照片)生成一个纹理化的3D手办,从每个侧面都与角色匹配:一个 Blender 主文件、一个干净的 GLB 模型、与四视图对比的渲染图,以及一个旋转视频。所有者审批花费并对效果做出判断;你驱动各个阶段并在问题产生成本之前捕获它们。
不在范围内:骨骼绑定和动画、所有者无权使用的角色、在 Blender 中手动建模角色。
完成条件
views/view_front.png、view_left.png、view_back.png、view_right.png文件存在,大小一致,由img2fig crop生成且退出码为0。- 你将四个视图与参考图像及彼此之间进行了比较,并书面报告:每个视图中的每个配件都在身体的正确侧面,没有出现参考中不存在的任何内容(特别注意背面视图、口袋、腰带和发饰),并且姿势和地面线在各视图间匹配。任何差异都用
img2fig edit修复,并在模型阶段之前重新裁剪。 models/<provider>/model.glb由img2fig model --execute生成。img2fig prep退出码为0,其orientation不是ambiguous(或者你确认正面渲染朝向相机),prep.dimensions_units[2]在2.9的0.01范围内,且prep.faces_out等于或低于--faces(对于三角化输入,如提供商GLB)。- 你查看了
renders/compare.jpg(上方为输入视图,下方为渲染图)和renders/face.png,并针对每个视图报告了哪些匹配、哪些不匹配。 - 如果所有者需要视频,
turntable/turntable.mp4文件存在(img2fig turntable,退出码0)。 img2fig spend显示的总花费在所有者批准的范围内。
花费规则
- 调用付费API的命令(
lookdev、turnaround、edit、model)除非给出--execute,否则仅打印计划与估算。向所有者展示计划的估算并获得许可,可以是每次调用许可或他们设定的预算;然后将该预算作为--budget传递(或设置IMG2FIG_BUDGET_USD;否则上限是5美元)。该预算在工作目录的分类账(spend.json,由img2fig spend总结)中被检查,在每次付费调用前都进行,如果超出则调用被拒绝(退出码3)。失败的调用按估算值记录,因为某些调用在提供商已收费后才失败。 img2fig estimate --stages lookdev,turnaround,edit,model为整个运行定价。典型量级:每次图像调用低于0.30美元,每个 Tripo 模型约0.60美元,四个提供商的焙烧约4美元。估算偏高;图像调用的cost_from_usage_usd是基于 token 的数字。- 焙烧(
--provider all)大约需要七次 Tripo 运行。仅当所有者要求或 Tripo 在这个角色上明显失败时才进行。
工作流程
img2fig doctor # 检查密钥是否存在?Blender、ffmpeg是否找到?
img2fig lookdev --ref character.png --description "..." # 计划;批准后添加 --execute
img2fig turnaround --ref character.png --description "..." # 使用最新的外观开发图像
img2fig crop # views/view_{front,left,back,right}.png
img2fig edit --fix "背面视图:移除弓下面的圆形尾巴;那里是素色裙子。" # 仅当需要时
img2fig crop # 重新裁剪:获取最新的图板或编辑
img2fig model # Tripo,计划;批准后 --execute
img2fig prep # 方向、标准化、减面、分级、渲染、compare.jpg
img2fig turntable # turntable/turntable.mp4
所有命令共享 --workdir DIR(默认 $IMG2FIG_WORKDIR 或 ./figure_work);输入默认为该目录中上一阶段的最新文件。每个命令在 stdout 上打印一个 JSON 对象;读取 ok、路径、warning/warnings、next,以及失败时的 error.type、error.message 和 error.detail(提供商的HTTP状态和响应体、Blender 或 ffmpeg 的退出码和 stderr 尾部、日志路径)。
退出码:0 成功(包括干运行),1 提供商错误,2 使用错误,3 预算超限,4 缺少密钥/二进制/包,5 Blender 或 ffmpeg 失败,6 结果检查失败(图板未分割成预期视图),7 内部错误。
编写 --description
列出角色必须保留的内容,从角色自身的视角和观看者的视角(放在方括号中)陈述侧面:“在她左侧的绿色三叶草发夹(前视图中观看者的右侧)”。描述参考图像实际显示的内容,而不是你意图生成的内容:图像模型有时会将配件移动到另一侧,以参考为准。
重要的 Prep 选项
--rot auto(默认)以平直着色渲染模型,角度为0/90/180/270度,并将每个与view_front.png比较。如果结果不明确,则回退到提供商的已知方向(仅对 Tripo 已知;否则输出提示检查正面渲染)。传递--rot DEG来覆盖。--grade matte(默认)、light(浅色服装:保持白色干净)、dark(加深深色布料)、none。--keep-gloss 0.3保留源材质中有光泽部分的原始粗糙度和金属感。--blush=X,Z(可重复)在角色分数坐标位置绘制柔和的腮红;通过测量renders/front.png中的脸颊并运行img2fig point --x PX --y PY获取 X,Z。用=写负值(--blush=-0.08,0.6),否则 argparse 会将其解读为选项。--faces(默认350000)限定面数;法线和颜色纹理保留精细细节。
已知陷阱(均已观察)
- 图像模型会虚构细节,而3D模型会构建它们。 一次四视图生成中,背面出现了一个原本没有的绒球尾巴,夹克口袋里出现了一个徽章;3D模型忠实地重现了这两者。在图像阶段修复此问题(每个问题用一个
--fix的edit,然后重新crop和model)。不要修补网格。第一次编辑可能留下另一个虚构(徽章变成了一个蛋糕形状的装饰),所以每次编辑后都要再次比较。 - 小特征模糊。 3840x2160图板的每个视图只有约1000像素宽,所以毛绒玩具的脸或手指在模型中会变得柔和。没有更大的图板可用;判断面部渲染并告知所有者,而不是承诺清晰的微小细节。
- 提供商在方向上不一致。 Tripo 的 GLB 在导入后朝向 +X(需要旋转90度)。自动检查会处理它;但仍需查看正面渲染。
- 全哑光分级会杀死水晶和光泽部分。 当角色有水晶、金属或漆面部分时,使用
--keep-gloss或--grade none。 - 手工构建的程序化角色无法达到手办质量。 一个在 Blender 中用基元建模的角色无法正确制作有机头发;图像转3D模型做到了。不要回退到程序化建模来处理有机形状。
- AgX vs Standard。 渲染默认使用 AgX:高光不剪切,但淡色和白色材质会变灰且饱和度降低,这就是分级提高饱和度的原因。
--view-transform standard更接近参考颜色,但会剪切明亮区域。方向检查使用 Standard 渲染,以便颜色公平比较。 - Blender 中的 sRGB 与线性。 在 Blender 中读取 PNG 的像素颜色(
Image.pixels)返回的是编码后的 sRGB 值,而非线性值。如果你扩展 Blender 脚本,在使用前将其解码为线性颜色。
资源与边界
- 密钥仅来自环境变量:
OPENAI_API_KEY(图像阶段)和FAL_KEY(模型阶段)。从不打印它们或将它们写入文件。 - Blender 作为外部二进制文件(在5.2上测试;4.2或更新版本应能工作)(在 PATH 上为
blender或IMG2FIG_BLENDER);ffmpeg 用于旋转视频。 - 工作目录保存生成的文件、模型和所有者的角色渲染。除非所有者要求,否则不要发布、上传或提交它们;将所有者从他人处许可的角色视为私有。
- 提示词在
src/image_to_figure/prompts.py中;--prompt-file为单次调用替换模板。
3D 打印
img2fig print 将一个模型(默认为 figure/figure_clean.glb;任何 GLB、STL、OBJ 或 PLY 用 --model;使用 --up auto 时,GLB/glTF/OBJ 作为 Y-up 读取,STL/PLY 作为 Z-up 读取)转换为可打印的实体。需要 print 扩展(uv pip install -e '.[print]');同时安装 pymeshlab(GPL,不是依赖)会在报告中添加显式自交面计数。
img2fig print --height 100 --base pedestal # 实体,FDM 或树脂
img2fig print --height 130 --base pedestal # 带薄部件的 FDM:打印更大而非加厚
img2fig print --height 100 --base pedestal --hollow 2.0 # 树脂:2毫米壁厚,带排水孔
img2fig print --model raw_tripo.glb --rot -90 --height 80 # 原始 Tripo GLB 朝向 +X
完成条件:命令退出码0且 checks.printable 为 true(防水,由 manifold3d 判断为有效2-流形,体积为正);checks.parts 为1,除非松散部件被故意保留;checks.self_intersecting_faces 在测量时为0;output.height_mm 等于 --height 加上底座高度(在一个体素误差内);你查看了 print/figure_section.png(壁厚、空腔和排水孔)和 figure_preview_*.png 渲染图,并报告了 warnings 中的每个条目,特别是薄部件(checks.wall_thickness:thin_part_volume_fraction、largest_thin_parts 及其以毫米为单位的位置;relief_volume_fraction 是精细表面细节,已报告但未加厚)以及如何处理它们。如果使用了 --thicken,你将预览渲染与未加厚的运行进行了比较,看到脸部、头发或配件上没有新的凸起;没有 Blender(无预览)时,检查 thicken.added_mm3 与 wall_thickness_before.thin_part_volume_mm3 处于同一量级(凸起表现为远远超出该量的附加体积)并查看截面图像。
工作原理:表面被体素化(默认体素尺寸 = 高度 / 500),间隙通过能封闭内部的最小形态学闭合(最多8个体素;voxelize 步骤报告 gap_closing_voxels)密封并填充内部,因此开口边缘、重叠壳体和自交消失;然后一个有符号距离场执行底座切割、基座、挖空和排水孔;行进立方体、Taubin 平滑和 manifold3d 生成最终网格。小于约一个体素的细节会丢失,比闭合间隙更近的部件会融合。
选项:--min-wall(默认1.0毫米;树脂可以更低,FDM 通常需要1.2或更多)设定薄壁的判定标准;--thicken(默认关闭)将薄部件增长到该厚度,见下文;--fragments merge|remove|keep 结合 --merge-gap(默认2毫米)决定浮动部件:在合并模式下,间隙内的部件通过桥接连接,更远的部件被保留并报告,绝不会静默丢弃;小于1立方毫米的碎屑始终移除;--base flat|pedestal|none;--hollow WALL 结合 --drain-hole 从下方为每个空腔钻一个孔(小于20立方毫米的凹陷保持实体);--color 从模型纹理写入顶点彩色 PLY 用于全彩服务。STL 和 3MF 是单色的。
薄部件。报告将薄部件(从较厚主体伸出超过 --min-wall 的薄片、鳍、股线、带子和绳索,两个表面紧贴在一起)与表面浮雕(厚主体上的浮雕线、边缘、小点和凸边)区分开。对于 FDM,优选打印更大:每个薄部件随角色缩放(100毫米时0.9毫米的带子在130毫米时变成1.17毫米),没有任何形状被重塑,切片器的薄壁处理(Arachne 壁面、“检测薄壁”)能打印出大部分剩余部分;体积中极小百分比低于壁面是正常的且没问题。当尺寸固定且少数薄部件必须打印成实体(一条丝带环、一根呆毛、一根挂绳、一条裙边)时使用 --thicken:它只增长薄部件,每个增长到约 --min-wall,并钝化其尖端;浮雕从不增长。当 --thicken 后薄部件仍然存在时,警告会说明并建议打印更大或调整切片器设置,而不是再次运行。定义的边界:从主体突出超过 --min-wall 的浮雕(高的窄脊、深的浮雕股线)被视为薄部件并被钝化;跨越两个厚部件之间间隙的短薄网(最多约两倍 --min-wall)被报告为浮雕,切片器可能丢弃它并留下一个孔,因此请在切片器预览中检查网。增长发生在每个方向,因此 --thicken 也会略微延长尖端,并且如果薄部件之间的距离小于 --min-wall,则可能将它们融合。
构建过程中的观察:二进制距离场留下可见的阶梯除非结果被平滑(Taubin、--smooth,默认10次迭代,保持体积);将顶点投影回源表面会导致薄片折叠被丢弃。平滑和网格简化都可能引入薄区域的自交;命令尝试更少的平滑和更紧的容差直到检查干净,并报告其最终采用的参数(smooth_and_simplify 步骤)。挖空必须保持无法排水的空腔为实体,否则它们会成为密封的空隙。在一个真实的图像转3D手办上,两个对称的120立方毫米的部件被建模为距离主体1.3毫米的单独壳;早期版本因为它们在1毫米合并间隙之外而将它们移除,这就是为什么远处部件现在被保留并报告的原因。在一个真实的100毫米手办上,使用 --min-wall 1.2,早期版本的 --thicken 在脸部、头发、蝴蝶结和毛绒配件上覆盖了小的圆形凸起:它将1.2毫米球无法触及的一切都视为薄,包括浅浮雕如丝线边缘、浮雕睫毛和点,并将每一个从每一侧增长0.6毫米(增加5.5%的体积)。不加厚度时,同一个手办保留了发际线上的一条薄丝带和一根极尖的呆毛,它们超出了切片器的薄壁检测;这对许多逐层打印来说是耗材中的额外线头。一个真实的鳍状胸鳍在尖部有一个实体节点,在增加厚度时膨胀成薄膜;在经过减面、渲染、检查自交和壳体并保存后,三角面包含了折痕,平滑步骤成功处理了它们。在最终版本中,浮雕永远不会被加厚。如果模型有开口边(不是流形),填充过程会创建一只涂有纹理的“手套”,并且由于挖空体积包括它,排水孔可能会创建一条穿出身体到达排入口的隧道;图像转3D模型不应有开口边。
清理脚本在打印前重新定位打印件,使得 Z-up 外框边界在底部对齐到 Z=0。
img2fig print-design 将设计文件(3MF、STL、OBJ 或 PLY)分割成适合打印的部件(单个模型或带 --count 值的多个副本),放置它们,添加 --margin,以及可选的在每层方向上的支撑块。如果不支持 trimesh 的段/合并,则回退到 MagicaVoxel(.vox)平铺,使用 blender 进行网格对齐和导出。对于带底座的打印件,底座材质的彩色3MF:用消减颜色给底座上色,标准颜色用于模型,为每个添加 --color-material 值和 Siggraph 样式。