chore(contracts): 同步契约到 0.4.0/0.3.0(GLB/VRM 主力格式、模型审核与骨骼分析)

This commit is contained in:
2026-09-15 20:37:58 +08:00
parent cee82c7b36
commit 5563a78e07
5 changed files with 90 additions and 45 deletions
+25 -19
View File
@@ -1,7 +1,7 @@
openapi: 3.0.3
info:
title: OpenDance Studio Web 管理服务端 API
version: 0.3.0
version: 0.4.0
description: |
OpenDance Studio 的唯一数据源与契约权威。
契约版本见 contracts/VERSION。字段语义见 contracts/data-models.md。
@@ -317,24 +317,26 @@ paths:
schema: { $ref: '#/components/schemas/ModelPage' }
post:
tags: [models]
summary: 上传模型 + 来源信息(VRM 优先;支持 MMD 模型压缩包自动转换)
summary: 上传模型(GLB/VRM 直接导入;PMX/FBX 服务端转 GLB 或 VRM)
description: |
`file` 为单个文件:
系统以 **GLB / VRM 为主力格式**(两个客户端都原生加载):
- `.vrm` / `.glb` / `.gltf` / `.fbx`:直接入库,`format` 由扩展名决定
- `.zip`:视为 MMD 模型包。服务端解压 → 选取 `.pmx`
(优先 `MODEL_CONVERT_PMX` 指定的名字,默认 `Hatsune Miku.pmx`;
否则取目录最浅、文件最大者)→ 调 Assimp 导出 **FBX**,
导出后**回读校验**(Assimp 的 FBX 导出器对带蒙皮的大骨架模型会写出损坏文件),
失败自动回退 **GLB**,并把过程写入 `conversionNote`。
GLB 产物会把 Assimp 写成外部 URI 的贴图内嵌进二进制块,保证单文件可用。
压缩包原件作为 `model-archive` 资产留存以便溯源。
- `.glb` / `.vrm` / `.gltf`:**直接导入**,不重编码
- `.pmx` / `.fbx`:服务端转换,**优先 GLB、其次 VRM**
- `.zip`:**自动搜索包内可用模型** —— `.vrm` → `.glb` → `.gltf`(直接导入)
优先,其次 `.pmx` → `.fbx`(转换)。压缩包原件作为 `model-archive` 资产留存。
转换成功且 `autoDefault` 不为 false 时,该模型会被置为全局默认模型
(`isPrimary=1` + `status=published`),并把身份(名称/格式/**压缩包 sha256**)
写进源码 `web-server/src/config/default-model.ts`。
注意:**转换产物不是字节级确定的**(同一份 zip 每次转换的产物 sha256 都不同),
所以默认模型种子以压缩包 sha256 为匹配键,产物 sha256 只作记录。
转换链路(`model-convert.ts`):`assimp export → .glb` →(失败)`→ .gltf` 后
由服务端自行打包成 GLB →(`MODEL_CONVERT_FORMAT=vrm` 时)在 GLB 之上补
`VRMC_vrm` 扩展产出 VRM 1.0。每一步都 `assimp info` **回读校验**,
并把过程写进 `conversionNote`;贴图会内嵌进 GLB,保证单文件可用。
入库时自动做两件事并写入 `stats` / `thumbnailUrl`:模型分析(面数、骨骼树、
humanoid 覆盖、可驱动性)与缩略图生成。
**状态一律 `pending`(待审核)**:模型必须审核通过后才可能被客户端消费;
设为默认模型请在审核通过时带 `setPrimary=true`,或调用
`POST /api/models/{id}/primary`(仅已发布模型可设)。
requestBody:
required: true
content:
@@ -346,9 +348,7 @@ paths:
file: { type: string, format: binary }
name: { type: string }
isPrimary: { type: boolean }
autoDefault:
type: boolean
description: 仅对 `.zip` 生效;转换成功后是否自动设为默认模型,默认 true
# 注意:上传不再提供"自动发布/自动设为默认",模型一律进入待审核
sourceType: { $ref: '#/components/schemas/SourceType' }
sourceName: { type: string }
sourceUrl: { type: string }
@@ -777,6 +777,12 @@ components:
type: string
nullable: true
description: 模型文件(转换产物)的 sha256 —— 每次转换都会变(Assimp 导出非字节级确定),仅作记录
stats:
type: object
nullable: true
description: >-
模型分析结果(面数 / 顶点数 / 贴图 / 骨骼树 / humanoid 覆盖 / 可驱动性),
审核界面据此判断"能不能驱动与评分"。结构见 contracts/model-formats.md §1.1
sourceSha256:
type: string
nullable: true