Files
AIGame/DGX3D_AI调用指南.md
T

41 KiB
Raw Blame History

LLM3DGraphics · 3D / DGX 3D 跨项目 AI 调用指南

更新:2026-11-03。按当前后端代码、运行服务 OpenAPI 与能力接口核对,供其他项目、开发者和 Agent 通过 HTTP 使用。本文替换旧版“两步生成”和“混元模型不能接绑骨”的说明。

  • 本机服务:http://127.0.0.1:8008;当前局域网部署:http://192.168.130.16:8008。调用方将地址配置为 BASE。
  • 接口文档:{BASE}/docs;机器可读契约:{BASE}/openapi.json。
  • 页面:普通 3D /#workspace、DGX 3D /#dgx、图片 /#local-images、导入人形绑骨 /#skinning。
  • 外部项目统一访问 Windows LLM3DGraphics 服务。DGXA 推理服务、SSH、模型文件和密钥由本项目管理,调用方不需要直接连接。

1. 流程总览

1.1 两种建模引擎

页面 / engine 网格生成 低模、UV、贴图 后续绑骨与动作
3D 模型生成 / hunyuan 混元 3D 官方网页,当前客户端微信登录 官网 Studio 低模、UV,本机 Blender 烘焙;超出目标 30% 时保留 UV 减面 当前已支持:先获得 model_ex.glb,再调用 /rig、/animate,使用与 DGX 相同的角色分支
DGX 3D 生成 / dgx DGXA Hunyuan3D 2.1,生成带贴图高模 本机 Blender 减面、UV、烘焙;低模为 model_ex.glb 网格完成后不自动绑骨;依次调用 /rig、/animate

两种引擎当前都只接收图片建模:mode=image。只有文字时,先生成参考图再上传实际图片;mode=text 不是可用的文生 3D 捷径。

flowchart TD
    A[文字或参考图] --> B{已有可用图片?}
    B -->|否| C[本地图像 API 生成并选择参考图]
    B -->|是| D[上传图片 POST /api/jobs]
    C --> D
    D --> E{engine}
    E -->|hunyuan| F[微信会话 / 官网高模 / Studio 低模 / Blender 烘焙]
    E -->|dgx| G[DGXA Hunyuan3D / Blender 可选低模烘焙]
    F --> H{需要可驱动角色?}
    G --> H
    H -->|否| I[下载静态网格与贴图]
    H -->|是| J[POST /api/jobs/id/rig]
    J --> K[检查本阶段成功与 ready_for_motion]
    K --> L[POST /api/jobs/id/animate]
    L --> M[下载角色和动作 / 检查蒙皮预览]

角色正式调用顺序是 生成网格 → 单独绑骨 → 单独生成动作。三步使用同一个 3D job ID,每步均需等待该阶段完成。静物在第一步结束。

1.2 模型类型、骨架与动作引擎

类型 character_type /rig 实际流程 /animate 实际流程
人形、NPC、士兵 humanoid DGXA Make-It-Animatable 预测关节和权重 → 适配 Mixamo 65 骨 → 本机映射权重、导出 DGXA Kimodo 生成 SOMA 动作 → 本机重定向到 mixamorig:*
猫、狗、鹿、马等四足 quadruped SMAL 表面拟合取得 AniMer 解剖标记 → 适配 Truebones 物种模板 → TokenRig 按指定骨架蒙皮 DGXA UniMate v3,输入适配骨架、官方语义、层级和朝向 → 重定向回原始绑定姿态
鹰隼、鸟类等 non_humanoid 模板匹配;Eagle 用双翼、头颈、尾羽、腿部锚点及翼面约束适配 → TokenRig 固定骨架蒙皮 UniMate v3
鲨鱼、鱼类 non_humanoid 模板匹配;Jaws 用头尾方向、TokenRig 中心线及鳍部表面标记适配 → TokenRig 固定骨架蒙皮 UniMate v3
昆虫、爬虫、恐龙、其他生物 non_humanoid 已匹配模板时适配并蒙皮,多数其他模板仍用几何配准;未识别时回退原生 TokenRig UniMate v3,陌生拓扑需检查骨数、语义和效果
道具、建筑、静物 static 不绑骨 不生成动作
  • 人形当前是 Make-It-Animatable(mia),不是 TokenRig,也不是独立的 HumanRig 推理分支。Kimodo 是人形文生动作默认引擎,Mixamo 骨名不表示自动检索 Mixamo 动作库。
  • 四足最终骨数随物种模板变化,如 Cat=43、Raindeer=35、Deer=41。AniMer 35 关节是拟合中间参考,不是所有动物的最终骨架。
  • 当前 Cat 43 骨、Eagle 51 骨、Jaws 16 骨已完成端到端模型、蒙皮、动作与导出检查。70 套模板均校验结构和导出兼容性,尚未逐套验收生成效果;Eagle/Jaws 专门适配也不能推广为所有鸟、鱼均已验收。
  • static 默认拒绝后续阶段。若确实要改成角色,应在 /rig 显式传入三种角色类型之一。

2. 能力探测与资源调度

GET /api/capabilities
GET /api/local-images/status
GET /api/skeleton-templates
GET /api/skinning/catalog
能力字段 对应阶段
capabilities.hunyuan_logged_in / hunyuan_status 网页混元,按当前 Cookie 会话判断
capabilities.dgx.hy3d_ready / 顶层 dgx_ready DGX 网格生成
capabilities.dgx.mia_ready 人形绑骨
capabilities.dgx.kimodo_ready 人形文生动作
capabilities.dgx.tokenrig_ready 非人形绑骨
capabilities.dgx.animal_templates_ready / animal_template_count 动物模板库,当前 70 套
capabilities.dgx.animer35_ready 四足适配依赖;历史字段名,不表示最终固定 35 骨
capabilities.dgx.unimate_ready / unimate_version 非人形动作,当前 v3
capabilities.formats / target_faces / texture_sizes 可用格式、面数范围和贴图档位
local-images/status.connected / ready / models.turbo.installed 本地图像;不要用云端 image_generate_ready 替代
skinning/catalog.mia_ready / blender_ready 导入人形蒙皮;还提供男女骨架和动作目录

topocap_ready、hymotion_ready 是旧前端兼容别名,目前跟随 UniMate。topocap_legacy_ready 是旧诊断项,不能据此判断正在使用该引擎。Puppeteer、TopoCap、GIF/视频参考动作不属于当前默认调用链。

探测主要检查连接、入口和文件,不代表模型已加载或本次推理一定成功。能力缓存约 20 秒;首次 SSH 探测可能较慢,客户端超时建议至少 90 秒。2026-11-03 核对时主要 DGX 分支均就绪;调用方每次仍应探测。

  • 3D 主队列最多 5 个 queued+running,串行执行;导入人形蒙皮共享执行器。
  • 本地图像最多排队 4 批,每批 1–16 张、逐张生成。图片与 DGX 建模/绑骨/动作遵守本机资源调度,不直接调用 DGXA 的 8090 worker 绕过保护。
  • 图像批次结束后调用 POST /api/local-images/prepare-3d 准备 3D;它只恢复资源,不创建模型。DGX /api/jobs 也会执行准备,显式调用便于阶段诊断。
  • 当前 auto_switch、co_resident 已启用;共同驻留不等于并行推理。是否保留 Turbo 由服务端按内存决定,不要暂停其他项目任务或强制修改精度。
  • 409 等已有阶段结束,429 退避;轮询至少 2 秒、建议 3 秒。创建请求超时后先查询任务记录,避免重复提交;当前没有公开幂等键或任务克隆 API。

3. 第 0 步:文字或参考编辑生成图片

有可用用户图片时可跳过本节。3D 输入应为单个完整主体、简单背景、肢体/鳍/翼轮廓分离,避免极端透视和遮挡。人形用完整 T/A 姿势,四足站姿、四腿分开,鸟类展开双翼,鱼类身体水平。不要把拼贴三视图作为单张多个主体的建模输入。

3.1 本地图像 API

当前安装 Qwen/Qwen-Image-2.1-Turbo BF16,表单请求:

POST /api/local-images/jobs
Content-Type: multipart/form-data

model=turbo
profile=concept
prompt=完整大白鲨,身体水平,尾鳍竖直,各鳍清晰分离,灰蓝色背部、白色腹部,纯白背景,无文字
width=1536
height=1024
count=1
seed=20261103
transparent=false
字段 默认与范围
model turbo,当前唯一支持值;采样步数和 CFG 由 worker 固定
prompt 必填,去空格后 1–4000 字;限制和编辑要求也写在这里
profile 默认 concept;另有 sprite、albedo、background,服务端追加用途提示
width / height 默认 1024;256–2048,必须为 32 的倍数
count 默认 4;1–16
seed 默认 -1 随机;或 0–4294967280;第 i 张使用 seed+i
transparent 默认 false;实际 Alpha 仍需检查
negative_prompt 留空,Turbo CFG=1 不使用独立负面提示词
images 可省略;多参考编辑时重复同名文件字段,最多 10 张 PNG/JPEG/WebP,每张 ≤12 MB、≤1600 万像素

返回 202 和图片批次 ID。轮询 GET /api/local-images/jobs/{id} 至 completed/failed,读取 images[].url、index、seed、has_alpha,下载选中 PNG。图片批次 ID 不能代替之后的 3D job ID。失败批次可能已有图片,应保留结果与错误。

BASE=http://192.168.130.16:8008
curl -fS "$BASE/api/local-images/status"
curl -fS -X POST "$BASE/api/local-images/jobs" \
  -F model=turbo -F profile=concept -F count=1 -F width=1536 -F height=1024 \
  -F 'prompt=完整大白鲨,水平体态,尾鳍竖直,各鳍分离,纯白背景,无文字'
# 取图片批次 ID,轮询至 completed,再下载:
curl -fS "$BASE/api/local-images/jobs/<IMAGE_JOB_ID>"
curl -fL -o shark.png "$BASE/api/local-images/jobs/<IMAGE_JOB_ID>/images/0"
curl -fS -X POST "$BASE/api/local-images/prepare-3d"

以上为 Bash 语法;PowerShell 使用 curl.exe 并按其换行规则书写,或用 §9 Python 客户端。多参考增加 -F 'images=@shape.png' -F 'images=@style.png',提示词按顺序说明各图作用;本接口不接收 URL/base64 作为 images 文件。

只要 2D 素材时可直接导出:GET /api/local-images/jobs/{id}/unity?selected=0,2。省略 selected 导出全部已生成图片;ZIP 含 PNG、参考图、manifest 和 Unity 导入脚本。sprite 按 Sprite,albedo 按 Repeat base color,其他按普通图片;不是 unitypackage 或完整 PBR 材质。转入 3D 则下载 PNG 后上传 /api/jobs。

3.2 可选云端转接

用户选择云端生图时,检查 capabilities.image_generate_ready,再调用:

POST /api/image/generate
Content-Type: application/json

{"prompt":"完整角色,站姿,纯白背景,无文字","aspect_ratio":"1:1","quality":"auto","images":[]}

prompt 必填、≤4000 字;images 最多 4 个 URL/data URL/base64 参考,区别于本地图像文件接口。成功后从返回 url 下载缓存图片再建模。模型与上游 Key 由服务端配置,外部项目不要直连上游或索取 Key。

4. 第 1 步:生成网格

4.1 公共创建接口

POST /api/jobs,multipart/form-data,返回 202 和 job ID。

字段 默认 / 范围 说明
engine 默认 hunyuan;hunyuan / dgx 外部调用务必显式指定,避免误进微信分支
mode image 两种引擎当前都只支持 image
image 必填文件 PNG/JPEG/WebP,≤12 MB、≤1600 万像素;服务端归一化最长边到 1536
prompt 可选,≤2000 字 图片模式作为描述保存并用于物种匹配,不是直接文生 3D
character_type 默认 non_humanoid humanoid / quadruped / non_humanoid / static;两种引擎后续均使用此分类
resolution 默认 256 DGX 为抽取分辨率 16–512;网页仅允许 128/256,不是贴图尺寸
source_faces 默认 50000 网页高模档:5000/20000/50000/500000/1000000;DGX 会改写保存为 50000,不据此承诺精确输出面数
target_faces 默认 5000 低模目标 500–20000 任意整数;500000 或 1000000 表示跳过低模,建议统一用 500000
texture_size 默认 1024 低模烘焙贴图 512/1024/2048,不控制 DGX 原始生成贴图
output_format 默认 glb;glb / fbx 始终保留 GLB;fbx 额外导出资产包,需 Blender

保留字段 mixamo_motion 不是当前动作开关。骨架 skeleton_template 应在 rig 请求中指定,创建网格时传它不会选择骨架。

仅当原模型面数大于目标且未选跳过低模时生成低模。读取 lowpoly_ready、downloads 判断实际产物;原模型低于目标时不会凭空产生 model_ex。DGX 绑骨优先低模、否则高模;网页混元后续绑骨要求低模。

4.2 DGX 示例

curl -fS -X POST "$BASE/api/jobs" \
  -F engine=dgx -F mode=image -F character_type=non_humanoid \
  -F 'prompt=great white shark' -F 'image=@shark.png' \
  -F resolution=256 -F target_faces=20000 -F texture_size=1024 -F output_format=fbx

轮询 GET /api/jobs/{id}。网格完成后 ready_for_motion=false 是正常状态,下一步调用 rig。

4.3 网页混元:微信会话和建模

GET  /api/hunyuan/status
POST /api/hunyuan/login
GET  /api/hunyuan/login/qr
POST /api/hunyuan/login/cancel
POST /api/hunyuan/logout

在发起请求的客户端工作台点击“微信登录”,真人扫描客户端页面展示的二维码;后端用 Playwright/Edge 操作官网,不要求用户去服务机窗口扫码。

HTTP 接入必须在登录、二维码、状态与任务请求间保留同一服务端 Cookie,例如 requests.Session() 或 curl 的 -c cookies.txt -b cookies.txt。浏览器已登录不代表另一个无状态 Python/curl 会话也登录;每台设备、浏览器和无痕会话分别登录。

# COOKIE_FILE 对应已完成扫码的同一 HTTP 会话。
curl -fS -b "$COOKIE_FILE" "$BASE/api/hunyuan/status"
curl -fS -b "$COOKIE_FILE" -X POST "$BASE/api/jobs" \
  -F engine=hunyuan -F mode=image -F character_type=humanoid \
  -F 'image=@person.png' -F source_faces=50000 \
  -F target_faces=5000 -F texture_size=1024 -F output_format=fbx

网格完成后可只下载高/低模;需要角色时确认 lowpoly_ready=true、rig_followup_ready=true,然后对同一 job 调 §5–6。后续依赖 DGXA,因此网页建模不免除绑骨和动作阶段的 DGX 能力要求。

4.4 状态、错误与低模重做

  • GET /api/jobs 返回最近最多 30 个任务的数组,不是 {jobs:[...]};指定 ID 查询不受列表条数限制。
  • 状态 queued → running → completed/failed;后续阶段复用同一 ID 并重走状态。stage、progress、elapsed 是当前阶段信息,不是全流程累计。
  • completed 也必须检查 error。绑骨或动作失败可能保留旧资产并软失败为 completed,同时设置顶层 error;绑骨还会记录 result.dgx.rig_error,部分动作失败会标记 partial_motion。旧文件存在不表示本次阶段成功。
  • 绑骨成功:本阶段无 error、ready_for_motion=true、result.dgx.rigged=true,且 rigged_* 可用。
  • 动作成功:本阶段无 error、result.dgx.animated=true,且 animated_* 可用。
  • POST /api/jobs/{id}/resume-studio 仅用于已有高模/Studio 记录且 can_resume_studio=true 的混元中断任务,不是通用重试 API。
  • POST /api/jobs/{id}/rebake 表单 target_faces、texture_size:重出低模。已有蒙皮角色可能自动重绑骨并按原 motion_prompt 重做动作;先下载要保留的资产。网页混元仍检查当前会话登录。
  • GET /api/jobs/{id}/log 返回 JSON {text:"..."};必要时维护方另查人形任务目录 mia.log。

5. 第 2 步:按类型绑骨

POST /api/jobs/{id}/rig
Content-Type: multipart/form-data

character_type=quadruped
skeleton_template=Cat

返回 202。character_type 可省略以沿用任务,显式值仅 humanoid/quadruped/non_humanoid;skeleton_template 默认 auto,非人形可指定物种 ID。人形由此分支固定使用 Mixamo 65 骨,不通过该参数选择男女或骨数。

5.1 人形

Make-It-Animatable 在 DGXA 预测关节与蒙皮权重,本机适配参考骨架到模型并映射权重。标准 jobs/rig 固定使用 YBot65 资源,生成 mixamorig:* 骨名和 Mixamo profile;YBot 名称不改变输入网格的性别外貌。

选择男女、65/49/41/25 骨或直接导入已有 GLB/FBX/OBJ,使用 §8 独立 skinning 接口;不要给 jobs/rig 传不存在的 gender、bone_count 参数。

5.2 四足:解剖拟合 → 物种模板 → 固定骨架蒙皮

  1. 提取三维表面,在 DGXA 拟合 SMAL/AniMer 参考,得到头颈、躯干、四肢和尾部解剖标记。
  2. 将官方物种模板关节适配到标记和网格表面,保留骨名、父子关系与语义;长尾还参考真实模型尾部中心线。
  3. 指定适配后的骨架输入 TokenRig 计算蒙皮;内部处理共点分支与量化,导出恢复模板定义并校验绑定姿态。
  4. result.dgx.animal_profile 包含 template_id、bones、names、parents、joint_labels、selection、fit、validation,供下游记录与生成动作。

auto 先匹配任务名称(上传文件名)和 prompt 等描述;没有明确描述的四足按拟合后的体型比例选择。它不是基于纹理的通用视觉分类器;已知物种建议显式指定模板。

5.3 鸟类、鱼类和其他非人形

示例 参数 检查重点
鹰隼 non_humanoid + Eagle(51 骨) 双翼、头颈、尾羽和腿部解剖锚点;保持翼展,避免翼尖收缩到躯干
鲨鱼 non_humanoid + Jaws(16 骨) 完整头尾中心线、头尾方向、背鳍朝上、左右鳍分离
其他鱼 non_humanoid + 对应目录 ID,如 Pirrana 当前一般配准分支,检查形态匹配和关节分布
其他已收录生物 non_humanoid + 物种 ID 多数非四足模板仍使用 TokenRig 几何支撑配准,逐模型检查
未收录生物 non_humanoid + auto 未识别时回退原生 TokenRig;骨数、语义和 UniMate 效果不保证

5.4 70 套兼容模板

GET /api/skeleton-templates
GET /api/skeleton-templates/library.zip
GET /api/skeleton-templates/{template_id}/{kind}

kind 为 json/glb/fbx/preview。以目录 ID 为准,保留现有拼写:Raindeer(35 骨)与 Deer(41 骨)不同;Leapord、Comodoa、Pirrana 也不要自行改写。

模板族 数量 ID(骨数)
quadruped 30 BrownBear(38), Buffalo(42), Camel(46), Cat(43), Coyote(40), Deer(41), Dog(51), Dog2(50), Elephant(39), Fox(39), Gazelle(41), Goat(31), Hamster(41), Hippopotamus(40), Horse(63), Hound(44), Jaguar(45), Leapord(47), Lion(31), Lynx(38), Mammoth(41), PolarBear(40), PolarBearB(38), Puppy(39), Raindeer(35), Rat(18), Rhino(43), SabreToothTiger(64), SandMouse(37), Skunk(35)
avian 13 Bat(47), Bird(61), Buzzard(61), Chicken(40), Crow(24), Eagle(51), Flamingo(40), Ostrich(53), Parrot(70), Parrot2(62), Pigeon(9), Pteranodon(43), Tukan(13)
marine 2 Jaws(16), Pirrana(20)
dinosaur 7 Raptor(35), Raptor2(61), Raptor3(60), Stego(40), Trex(60), Tricera(31), Tyranno(68)
arthropod 6 Crab(53), HermitCrab(67), Scorpion(62), Scorpion2(56), Spider(69), SpiderG(61)
insectoid 6 Ant(40), Cricket(53), FireAnt(42), Giantbee(51), Isopetra(60), Roach(43)
reptile 4 Alligator(25), Comodoa(64), Crocodile(38), Turtle(47)
serpentine 2 Anaconda(27), KingCobra(19)

当前选定库最多 70 关节,不是完整 Truebones 动物库;模板数量 70 也不是每套骨数。Truebones 专用模型的 85 骨能力不适用于当前通用 v3 接口。

6. 第 3 步:生成动作

POST /api/jobs/{id}/animate
Content-Type: multipart/form-data

motion_prompt=An object walks forward.
seed=42
cfg_scale=5
in_place=true
字段 默认 / 范围 生效范围
motion_prompt 必填,非空,≤500 字 两类动作引擎
seed 42;0–4294967295 UniMate,当前不传给 Kimodo
cfg_scale 3;0–20 UniMate;可从 5 附近对比,不保证越大越好
in_place true UniMate;只清除根节点水平速度,保留高度变化与旋转

HTTP animate 不公开 duration_sec/fps/model/speed/loop、视频或骨架上传字段。FastAPI 可能忽略多余表单项,返回成功不意味着它们生效。

6.1 人形:Kimodo

runner 默认模型 Kimodo-SOMA-RP-v1.1,默认时长 1.5 秒;可由服务端 kimodo_model、kimodo_duration 配置,非 HTTP 单次参数。动作写明确单一行为,如 A person walks forward at a steady pace.。

Kimodo 输出 SOMA BVH,本机重定向到 Mixamo;当前脚本将 Hips 位置轨道归零,输出偏原地动作。in_place=false 不会改变该人形实现。人形 animated.glb/fbx 是重定向场景导出,可能含角色网格,不应套用非人形“纯动作”假设。

6.2 非人形:UniMate v3

  • 当前实际调用 unimate_uniml3d_f60_v3 和其全局归一化统计;不是 v2,不自动选择 unimate_truebones_f60,也不通过 API 切换 cross-attention 版本。
  • 常规 HTTP 生成 60 帧、30 FPS,名义 2 秒;关键帧首末时间差可能为 59/30 秒。不要用重复帧冒充新生成长动作。
  • 条件包含骨架位置/比例、层级、语义和朝向,不只凭 _00 这样的原始骨名理解物种。不同骨架即使提示词、seed 相同,也不保证逐帧相同或视觉步速相同。
  • 服务端传递模板语义和朝向,不要擅自改骨名/层级,或只换语义标签而不检查绑定姿态。
  • 提示词优先英文 An object ...,只描述动作。走/跑用 forward,原地需求由 in_place=true 处理。中文归一化只覆盖部分常见动作,飞行、游泳中文可能变成泛化 moves forward,建议直接用英文。
目标 提示词起点 需检查
四足走路 An object walks forward at a steady pace. 肢体相位、滑步、躯干起伏
小跑 An object trots forward at a steady pace. 是否对角肢配对,文本不保证正确步态
奔跑 An object runs forward at a steady gallop. 后腿幅度、脊柱、身体倾角
扇翅 An object flies forward while repeatedly flapping its wings. 躯干俯仰、高度漂移、翼面形变
快速游动 An object swims fast. 身体水平、尾鳍左右摆、实际频率

这些只是起点,不保证一次可用;调整 seed、提示词和 CFG 做候选对比。fast 不等于指定了体长/秒或摆尾频率。每次 animate 都更新该 job 的动作,每段完成立即下载到不同目录,再做下一个动作。

6.3 长动作、循环与后处理:服务端扩展,非公共 HTTP 参数

项目已有脚本完成以下能力,但尚未封装成统一公共 API,外部项目不能仅传 duration_sec=8 或 loop=true 获得相同结果:

  1. 内部 backend.unimate_runner.submit_unimate_job(duration_sec=...) 支持长动作。超过 60 帧走官方 motion expansion、重叠 10 帧续生成,再裁至目标长度;由维护方纳入资源调度,不让外部项目直接 SSH 调 helper。
  2. 从稳定时段选完整步态/振翅/摆尾周期。四足按同一只脚、同相位选整周期,结合全部关节姿态和速度,避免左右脚交换的半周期。
  3. 检查内部续生成边界。已有实测约第 60/110/160 帧出现过跳变;具体以数据为准,首尾相同不能修复内部跳帧。
  4. 做局部四元数与速度连续修正、必要的周期平滑,保留身体/头/尾与竖直动态;不要冻结全身掩盖问题。变速用完整周期一致重采样。
  5. 比较接缝姿态、速度和加速度与内部帧,导出保留闭环关键帧;循环预览不重复计算末尾闭环帧。
  6. 前进位移另做 root-motion 版本,明确单位或体长/秒,不从原地片段推断真实速度。

已验证经验:橘猫从较长走路片段选稳定整周期;鹰隼的水平飞行成品对原始竖直姿态做过修正,不是 animate 对所有鸟的默认规则;鲨鱼快速循环从长片段 38–87 帧选择周期,修复内部续接、重采样成 16 独立帧加闭环帧(30 FPS、约 1.875 次摆尾/秒),增强后半身波动,另做约 2 体长/秒前进版。它们是生成后的编辑结果,不是未经处理的原始输出或通用默认速度。

维护脚本参考:tests/make_cat_walk_loop.py、cat_loop_blender.py、analyze_cat_walk_cycles.py、eagle_level_flight.py、boost_shark_tail.py、shark_forward_motion.py(均在 LLM3DGraphics 下)。这些脚本有案例目录/状态前置条件,不是外部 SDK 或任意资产通用的一键命令。

7. 产物、下载与目标引擎

读取 job 返回的 downloads、preview_url、anim_preview_url,相对 URL 加 BASE。文件路由:GET /api/jobs/{id}/files/{format}。

键 / 字段 内容
glb / fbx 静态原始高模;fbx 通常是 FBX+贴图 ZIP
glb_ex / fbx_ex 低模、UV 与烘焙贴图,仅实际触发时存在
rigged_glb / rigged_fbx 适配骨架与蒙皮网格,角色资产
mixamo_glb / mixamo_fbx 人形 Mixamo profile 资产,实际成功整理时提供
animated_glb / animated_fbx 当前动作;非人形为骨架动画,GLB 可能含微小代理而非完整角色;人形当前可能包含网格
anim_preview_url 完整蒙皮角色播放动作,检查最终效果优先用它
preview_url 默认预览,可能指向纯骨架,不保证含角色
ao_url 可选烘焙 AO;其他图见 jobs/id/bake/{map_name}

animated_preview_glb 是完整蒙皮预览文件,通常从 downloads 隐藏,但可由 anim_preview_url 获取。不要将 unimate_raw.glb 当最终绑定姿态的动画;正式产物已重定向回角色原始绑定姿态。

不能只看 fbx 键或内部扩展名判断格式:检查响应 Content-Disposition/Content-Type,或头字节 PK\x03\x04。非人形 rigged_fbx 通常是 ZIP;MIA 人形可能是裸 FBX;animated_fbx 通常是裸 FBX。按真实内容命名并保留解压后的贴图结构。

Unity:人形按实际 Mixamo Avatar 设置 Humanoid;动物/非标准骨架用 Generic,角色与动作保持同一层级和绑定姿态。Jaws/Cat 动作不要导成 Humanoid。单位、朝向、根运动与循环范围在目标引擎复核。

每个动作保存 job JSON、提示词、seed、CFG、模板 ID、角色、动作、完整蒙皮预览与后处理说明。重绑骨会清旧动作,重出低模可能重绑骨/重做动作,应先归档。

8. 已有模型:独立人形蒙皮与动作库

“骨骼蒙皮与动画”页使用另一条任务链,不需创建 api/jobs。它接受已有人形 GLB/FBX/OBJ;当前没有公开的任意非人形上传 → TokenRig → UniMate 通用 import API。研究脚本不等于该接口支持动物。

8.1 导入、男女、骨数

GET /api/skinning/catalog
POST /api/skinning/rig
Content-Type: multipart/form-data

model=@person.glb
gender=male
bone_count=41
method=mia
fit_skeleton=true
  • model ≤100 MB;贴图优先 GLB 或内嵌贴图 FBX,OBJ 外置贴图不自动上传。
  • gender 为 male/female,参考骨架 YBot/XBot;bone_count 为 65/49/41/25,默认 65。
  • method=mia、fit_skeleton=true 为当前默认;MIA 预测关节/权重、适配所选骨架、映射和导出,不接受关闭适配。
  • API 仍有历史 accurig 兼容项,推荐流程不需要 AccuRIG,也不自动操作该软件。

返回 skinning task ID,轮询 GET /api/skinning/tasks/{id},不是 api/jobs/id。completed 后读取 preview_url(skinned.glb)与 downloads.fbx(skinned.fbx)。日志:/api/skinning/tasks/{id}/files/process.log。

纯参考骨架:GET /api/skinning/skeletons/{skeleton_id}/{format},例如 YBot41、XBot25;format 为 fbx/glb/json,以 catalog 为准。

8.2 AnimX / AnimY 动作库

POST /api/skinning/animations
Content-Type: application/json

{
  "gender": "male",
  "bone_count": 41,
  "animation_id": "male-walking",
  "rig_task_id": "<SKINNING_RIG_TASK_ID>",
  "generate": true
}

当前每个性别 4 个动作:Atk01、Atk02、BreathingIdle、Walking,共 8 个条目。男性 ID:male-atk01、male-atk02、male-breathingidle、male-walking,女性为 female-*;以 catalog.animations 为准。

  • 使用 assets/Anim/AnimY、AnimX 原始 65 骨动画,按所选骨架和适配骨长重定向并烘焙简化骨数;不是 Kimodo/UniMate 文生动作。
  • rig_task_id 可省略以预览参考骨架;提供时需已完成且性别/骨数一致。
  • generate=false 先预览;generate=true 允许下载纯动画 FBX。相同请求复用缓存,也可将已有预览升级为可下载任务。
  • 轮询新 task ID,完成读取 preview_url 与 downloads.fbx。tasks 列表只列蒙皮及标记生成的动画;未生成预览按 ID 查询。
  • 该链没有转入主 jobs 的桥接,不能拿 skinning task ID 调 jobs/id/animate。

9. 可复制 Python 客户端

依赖 requests,只调用正式 API。同一 Session 也可持有网页混元登录 Cookie;示例末尾调用为注释,接入方选定参数后执行。

import json
import mimetypes
import time
from pathlib import Path
from urllib.parse import urljoin

import requests


class LLM3DClient:
    def __init__(self, base="http://192.168.130.16:8008"):
        self.base = base.rstrip("/") + "/"
        self.session = requests.Session()

    def api(self, method, path, *, timeout=120, **kwargs):
        response = self.session.request(
            method, urljoin(self.base, path), timeout=timeout, **kwargs
        )
        response.raise_for_status()
        return response.json()

    def capabilities(self):
        return self.api("GET", "/api/capabilities")

    def wait(self, path, *, timeout=7200, interval=3):
        deadline = time.monotonic() + timeout
        while True:
            job = self.api("GET", path)
            if job["status"] in ("completed", "failed"):
                if job["status"] != "completed" or job.get("error"):
                    raise RuntimeError(json.dumps(job, ensure_ascii=False))
                return job
            if time.monotonic() >= deadline:
                raise TimeoutError(f"任务仍可能在运行,请保留ID并继续查询:{path}")
            time.sleep(interval)

    def download(self, url, output):
        response = self.session.get(urljoin(self.base, url), timeout=300)
        response.raise_for_status()
        output = Path(output)
        if response.content[:4] == b"PK\x03\x04":
            output = output.with_suffix(".zip")
        output.parent.mkdir(parents=True, exist_ok=True)
        output.write_bytes(response.content)
        return output

    def reference(self, prompt, output="reference.png", *, width=1024, height=1024):
        state = self.api("GET", "/api/local-images/status")
        if not (state.get("connected") and state.get("ready")
                and state.get("models", {}).get("turbo", {}).get("installed")):
            raise RuntimeError(state)
        batch = self.api("POST", "/api/local-images/jobs", data={
            "model": "turbo", "profile": "concept", "prompt": prompt,
            "width": width, "height": height, "count": 1, "seed": 42,
        })
        print("IMAGE_JOB_ID", batch["id"], flush=True)
        batch = self.wait(f"/api/local-images/jobs/{batch['id']}")
        return self.download(batch["images"][0]["url"], output)

    def mesh(self, image, *, engine="dgx", character_type="non_humanoid",
             description="", target_faces=5000, texture_size=1024):
        if engine == "dgx":
            self.api("POST", "/api/local-images/prepare-3d", timeout=360)
        caps = self.capabilities()
        if engine == "dgx" and not caps.get("dgx_ready"):
            raise RuntimeError("DGX Hunyuan3D 未就绪")
        if engine == "hunyuan" and not caps.get("hunyuan_logged_in"):
            raise RuntimeError("当前Session尚未完成混元微信登录")
        image = Path(image)
        mime = mimetypes.guess_type(image.name)[0] or "application/octet-stream"
        with image.open("rb") as handle:
            job = self.api("POST", "/api/jobs", timeout=420, data={
                "engine": engine, "mode": "image", "character_type": character_type,
                "prompt": description, "resolution": 256, "source_faces": 50000,
                "target_faces": target_faces, "texture_size": texture_size,
                "output_format": "fbx",
            }, files={"image": (image.name, handle, mime)})
        print("MESH_JOB_ID", job["id"], flush=True)
        return self.wait(f"/api/jobs/{job['id']}")

    def rig(self, job_id, *, character_type, template="auto"):
        caps = self.capabilities()["dgx"]
        required = ["mia_ready"] if character_type == "humanoid" else ["tokenrig_ready"]
        if character_type == "quadruped":
            required += ["animer35_ready", "animal_templates_ready"]
        if not all(caps.get(key) for key in required):
            raise RuntimeError({key: caps.get(key) for key in required})
        self.api("POST", f"/api/jobs/{job_id}/rig", data={
            "character_type": character_type, "skeleton_template": template,
        })
        job = self.wait(f"/api/jobs/{job_id}")
        if not (job.get("ready_for_motion") and job["result"]["dgx"].get("rigged")):
            raise RuntimeError(job)
        return job

    def animate(self, job_id, prompt, *, seed=42, cfg_scale=5, in_place=True):
        current = self.api("GET", f"/api/jobs/{job_id}")
        key = "kimodo_ready" if current["character_type"] == "humanoid" else "unimate_ready"
        if not self.capabilities()["dgx"].get(key):
            raise RuntimeError(f"动作能力未就绪:{key}")
        self.api("POST", f"/api/jobs/{job_id}/animate", data={
            "motion_prompt": prompt, "seed": seed, "cfg_scale": cfg_scale,
            "in_place": str(in_place).lower(),
        })
        job = self.wait(f"/api/jobs/{job_id}")
        if not job["result"]["dgx"].get("animated"):
            raise RuntimeError(job)
        return job

    def save(self, job, directory):
        folder = Path(directory)
        folder.mkdir(parents=True, exist_ok=True)
        (folder / "job.json").write_text(
            json.dumps(job, ensure_ascii=False, indent=2), encoding="utf-8"
        )
        for key, url in job.get("downloads", {}).items():
            suffix = ".fbx" if "fbx" in key else ".glb" if "glb" in key else ".bin"
            self.download(url, folder / (key + suffix))
        if job.get("anim_preview_url"):
            self.download(job["anim_preview_url"], folder / "skinned_animation.glb")


# client = LLM3DClient()
# ref = client.reference("完整橘猫,四足自然站姿,四腿分离,尾巴完整,纯白背景")
# mesh = client.mesh(ref, character_type="quadruped", description="orange cat")
# rig = client.rig(mesh["id"], character_type="quadruped", template="Cat")
# client.save(rig, "export/cat/character")
# walk = client.animate(mesh["id"], "An object walks forward at a steady pace.")
# client.save(walk, "export/cat/walk")  # 下一次animate前立即归档。
目标 mesh/rig.character_type rig.template motion_prompt
人形 humanoid auto(固定人形分支) A person walks forward at a steady pace.
鹿 quadruped Raindeer 或 Deer,按需求选 An object runs forward at a steady gallop.
鹰隼 non_humanoid Eagle An object flies forward while repeatedly flapping its wings.
鲨鱼 non_humanoid Jaws An object swims fast.
道具 static 不调用 rig 不调用 animate,直接 save(mesh, ...)

已有用户图片直接 mesh("reference.png", ...),不生成新图;网页网格用 engine="hunyuan" 且先让同一 Session 完成扫码,后续三步相同。

10. 排错与部署

现象 处理
401 混元未登录 当前 Session 扫码并保留 Cookie,不能依赖另一浏览器登录
422 仅支持图片 mode=image;文字先生成参考图
422 静物不绑骨/不生成动作 静物只下网格;确为角色时 rig 显式改分类
422 请先绑骨 先 rig;网格完成不代表已蒙皮
422 请先完成混元低模 缺少 model_ex.glb,先重出合适目标的低模
422 未知模板或类别不匹配 从目录取真实 ID;四足分支选择四足模板
503 MIA/TokenRig/Kimodo/UniMate 对应阶段能力未就绪,检查该字段,不盲目重复创建
409 图片/DGX 冲突或任务处理中 等已有阶段结束,不绕过调度器或终止别的项目任务
429 队列满 退避,继续查询已有任务 ID
completed 但 error 非空 软失败、旧资产保留,本次不能算成功
动画只有骨架 非人形角色用 rigged_*,完整效果用 anim_preview_url
蒙皮与骨架预览不同 检查绑定姿态、层级、骨长、权重,不把 raw canonical 动作当正式输出
鸟竖直飞或鱼朝向异常 检查模板、朝向和躯干俯仰,in_place 不修复姿态
动作慢/步态不对/循环跳帧 选择候选、长片段选周期、检查内部续接和接缝
duration/loop/model 不生效 非正式字段,需维护方扩展,不能宣称已经执行
下载 404 阶段未完成或该格式未生成,检查 downloads 和 error
浏览器跨域 POST 403 服务有 Origin 限制;通过接入项目服务端代理调用

跨项目网页推荐:浏览器 → 该项目后端 → LLM3DGraphics。当前 POST Origin 校验只允许自身地址和本机 Vite 开发源;不要伪造 Origin 绕过校验。服务端/curl 通常不发送浏览器 Origin,仍受网络、Host 和队列限制,网页混元需同一服务端 Session 持有 Cookie。

迁移 Windows 主机:

  1. 探测运行在启动后端的 Windows 账号下;复制工程不复制 SSH 身份。配置该账号的 DGXA 别名、授权密钥和 known_hosts,确认 ssh -o BatchMode=yes DGXA "echo READY" 成功。私钥不放工程。
  2. 从 LLM3DGraphics 目录运行只读自检:.venv\Scripts\python.exe deploy\check_dgx_connection.py --output outputs\dgx_connection_check.json,不推理、不打印密钥。
  3. 当前 Blender 5.2:C:\Program Files\Blender Foundation\Blender 5.2\blender.exe;通过 BLENDER_PATH 或 config.json.blender_path 配置。自动化用 blender.exe,不用 blender-launcher.exe。
  4. 当前 DGXA:Hunyuan HTTP http://192.168.132.46:7860,MIA /home/spark/Make-It-Animatable,TokenRig /home/spark/SkinTokens,UniMate 推理 /home/spark/UniMate-v3;旧 /home/spark/UniMate 还保留 I/O 环境。以部署配置为准,调用方无需自行安装。
  5. 项目内 .venv\Scripts\python.exe launcher.py 启动,默认 0.0.0.0:8008,避免重复 worker;已有任务运行时不要重启刷新配置。

Hunyuan HTTP 绿灯而其他 SSH 分支红灯,优先查 Windows 账号、别名、认证、路由与主机指纹;HTTP 可达不表示 SSH 可达,绿灯也不等于执行过 GPU 推理。

11. 给其他项目 Agent 的调用规则

通过配置的BASE调用LLM3DGraphics,先查capabilities;图片能力查local-images/status。
只访问本机API,不直连DGXA worker、SSH或上游,不索取或传播Key。
已有图片复用,只有外貌文字时先本地图像model=turbo/profile=concept,下载选中PNG。
两种建模engine均只支持mode=image;每次显式选dgx或hunyuan,实际默认是hunyuan。
网页混元使用同一Cookie会话扫码,完成低模后也能接rig和animate。
角色必须POST /api/jobs→等网格→POST jobs/id/rig→等绑骨成功→POST jobs/id/animate。
网格阶段ready_for_motion=false正常;completed仍检查error,旧文件不等于本次成功。
人形humanoid:MIA65骨→Kimodo;四足quadruped:SMAL标记+物种模板→TokenRig→UniMate v3。
鸟、鱼和其他生物non_humanoid;已知模板在rig显式指定,如Eagle、Jaws。
Cat43骨、Raindeer35骨、Deer41骨;不改官方ID,不统一所有动物为35骨。
static只生成网格;不调用rig和animate。
UniMate用英文An object ...,只描述动作;seed/CFG/in_place仅作用于UniMate,不作用于Kimodo。
正式animate没有时长、loop、速度或模型切换参数;长片段和闭环需维护方扩展。
每段动作完成立即归档后再生成下一段;非人形角色rigged_*,纯动作animated_*,完整预览anim_preview_url。
FBX键可能返回ZIP,按响应和文件头命名、解压并保留贴图。
已有模型的男女/65/49/41/25骨选项属于api/skinning,其task ID不能用于jobs/id/animate。
轮询至少2秒,遵守资源调度;prepare-3d不创建任务,409等待,429退避。

12. 实现依据与相关说明

内容 当前实现
创建、状态、绑骨、动作、下载 app.py
网格与低模流水线 pipeline.py、hunyuan_studio.py
角色类型分支 rig.py、animate.py
动物模板与适配 animal_templates.py、quadruped_rig.py、avian_rig.py、marine_rig.py
动作参数 unimate_runner.py、kimodo_runner.py
导入人形与动画库 skinning.py、manifest.json
本地图像、资源与 Unity 导出 本地图像说明
SSH 部署诊断 check_dgx_connection.py
深层实现与旧阶段说明 DGX3D生成说明.md,如与本文冲突以当前代码/OpenAPI为准

变更时同步更新参数表、类型映射、下载内容和客户端,不只在文首追加覆盖条款而留下矛盾正文;带Key的运维文件不分发给调用方。