190 lines
5.8 KiB
Markdown
190 lines
5.8 KiB
Markdown
# 3D 数字人驱动重构方案
|
||
|
||
## 1. 目标变更
|
||
|
||
原链路:
|
||
|
||
ASR -> LLM -> TTS -> MuseTalk/图片或视频驱动 -> WebRTC 视频轨 -> 前端播放
|
||
|
||
新链路:
|
||
|
||
ASR -> LLM -> TTS -> 音频特征/viseme/blendshape 控制数据 -> 前端 3D 渲染引擎 -> 浏览器展示
|
||
|
||
核心变化:
|
||
- 后端不再负责生成数字人视频帧
|
||
- 后端保留实时语音、时序仲裁、字幕、音频下行
|
||
- 后端新增 3D 控制流输出能力
|
||
- 3D 模型渲染放到前端或独立渲染端
|
||
|
||
## 2. 为什么要这样改
|
||
|
||
MuseTalk 这类方案适合“2D 说话视频合成”,但不适合 3D 模型系统:
|
||
- 输出形态是视频帧,不是骨骼或 blendshape 控制数据
|
||
- 一旦换 3D 模型,原本的视频生成结果无法直接复用
|
||
- 每轮都做视频推理,延迟、GPU 占用、链路复杂度都偏高
|
||
- 3D 系统通常需要的是时间序列控制参数,而不是渲染后的像素
|
||
|
||
因此,3D 化的正确边界是:
|
||
- 后端负责“说什么、怎么说、何时说”
|
||
- 渲染端负责“模型如何动、如何显示”
|
||
|
||
## 3. 本次代码重构内容
|
||
|
||
当前代码已调整为:
|
||
- WebRTC 下行仅保留音频轨
|
||
- 新增 `/ws/animation` WebSocket,下发 3D 动画控制数据
|
||
- `services/avatar.py` 改为音频到控制参数的驱动服务
|
||
- `/avatar/schema` 暴露控制协议说明
|
||
- 前端采用 Three.js + GLTFLoader + VRM loader,直接在浏览器渲染 3D 模型
|
||
- 支持加载本地 VRM/GLB 文件,也支持加载 URL 形式的 VRM/GLB/GLTF
|
||
- 若未加载模型,页面会回退到一个调试用的 3D 头像,便于联调口型和头部姿态
|
||
|
||
当前控制协议字段包括:
|
||
- `jawOpen`
|
||
- `mouthClose`
|
||
- `mouthFunnel`
|
||
- `mouthPucker`
|
||
- `viseme_aa`
|
||
- `viseme_ee`
|
||
- `viseme_oh`
|
||
- `headYaw`
|
||
- `headPitch`
|
||
- `headRoll`
|
||
|
||
输出包结构示例:
|
||
|
||
```json
|
||
{
|
||
"type": "animation_chunk",
|
||
"driver": "arkit-blendshape-v1",
|
||
"mode": "blendshape_stream",
|
||
"schema": "arkit",
|
||
"chunk_index": 0,
|
||
"total_chunks": 3,
|
||
"sample_rate": 24000,
|
||
"fps": 25,
|
||
"text": "你好,欢迎使用系统。",
|
||
"frame_count": 18,
|
||
"duration_ms": 720,
|
||
"frames": [
|
||
{
|
||
"seq": 102,
|
||
"time_ms": 0,
|
||
"speaking": true,
|
||
"controls": {
|
||
"jawOpen": 0.41,
|
||
"mouthClose": 0.66,
|
||
"mouthFunnel": 0.27,
|
||
"mouthPucker": 0.19,
|
||
"viseme_aa": 0.41,
|
||
"viseme_ee": 0.24,
|
||
"viseme_oh": 0.31,
|
||
"headYaw": 0.004,
|
||
"headPitch": 0.009,
|
||
"headRoll": 0.001
|
||
}
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
## 4. 当前实现的定位
|
||
|
||
当前实现是“联调级骨架”,作用是:
|
||
- 先把系统边界改对
|
||
- 让前后端可以并行开发
|
||
- 让 3D 引擎接入方尽快有稳定协议可以消费
|
||
|
||
它不是最终口型算法,原因很明确:
|
||
- 目前控制值来自音频能量和频谱特征
|
||
- 没有做 phoneme 强制对齐
|
||
- 没有做语言相关 viseme 映射
|
||
- 没有结合 3D 模型自身 rig 约束做校准
|
||
|
||
所以这版适合:
|
||
- 打通链路
|
||
- 调接口
|
||
- 验证时序
|
||
- 校验驱动字段
|
||
|
||
不适合直接作为最终高保真口型方案。
|
||
|
||
## 5. 推荐的生产化方案
|
||
|
||
### 方案 A:前端 Three.js / React Three Fiber
|
||
|
||
适合:
|
||
- 浏览器直接渲染 WebGL 角色
|
||
- glTF/VRM 模型
|
||
- ARKit blendshape 或自定义 morph target
|
||
|
||
建议做法:
|
||
- 前端加载 3D 模型
|
||
- 建立 `controlsKey -> morphTargetInfluence` 映射表
|
||
- `/ws/animation` 按时间戳缓冲一小段再播放
|
||
- 音频继续使用 WebRTC 远端音频轨
|
||
- 前端用远端音频播放时间作为动画时钟基准
|
||
|
||
当前仓库已经按这个方向落地了第一版:
|
||
- 静态页面通过 import map 从 CDN 引入 `three`、`GLTFLoader`、`@pixiv/three-vrm`
|
||
- VRM 优先使用 `expressionManager` 写入 `aa/ee/oh/ou`
|
||
- 普通 glTF 则尝试把控制字段映射到 morph target
|
||
- 头部姿态优先驱动 `head/neck` 骨骼,找不到时回退调试头像
|
||
|
||
### 方案 B:Unity/Unreal 渲染端
|
||
|
||
适合:
|
||
- 更复杂的材质、灯光、骨骼、表情系统
|
||
- 要求更强的 3D 表现力
|
||
|
||
建议做法:
|
||
- 浏览器只做 UI 和音频交互
|
||
- Unity/Unreal 作为单独渲染客户端消费 `/ws/animation`
|
||
- 浏览器与渲染端通过流媒体或共享画面集成
|
||
|
||
### 方案 C:专用音频驱动服务
|
||
|
||
适合:
|
||
- 追求更准的嘴型
|
||
- 后端可以接受增加一个模型服务
|
||
|
||
可以考虑接入:
|
||
- phoneme 对齐模型
|
||
- viseme 预测模型
|
||
- NVIDIA Audio2Face 类服务
|
||
- 自研 `audio -> blendshape` 网络
|
||
|
||
推荐协议保持不变:
|
||
- 外部模型服务可以替换 `services/avatar.py`
|
||
- 对外仍输出统一 `frames[].controls`
|
||
|
||
## 6. 推荐的下一步实施顺序
|
||
|
||
1. 先确定 3D 模型和渲染端技术栈
|
||
2. 固定一份 blendshape 映射表
|
||
3. 把当前前端调试面板替换成真实 3D 场景
|
||
4. 增加时间同步与缓冲策略
|
||
5. 再替换掉启发式控制算法,接入更强的 viseme 模型
|
||
|
||
## 7. 接口约束建议
|
||
|
||
为了后续可替换,建议保持这些约束不变:
|
||
- 下行动画通道继续使用 `/ws/animation`
|
||
- 每条消息包含 `frame_count`、`fps`、`frames`
|
||
- 每帧保留 `seq` 和 `time_ms`
|
||
- `controls` 使用稳定字段名,不轻易改动
|
||
- 新增字段时只追加,不破坏已有字段
|
||
|
||
## 8. 风险与注意事项
|
||
|
||
- 真实 3D 模型的 blendshape 命名不一定和当前字段一致,需要做一次映射层
|
||
- 如果模型是骨骼嘴型而不是 morph target,需要把 `controls` 转成骨骼驱动参数
|
||
- 浏览器渲染时要注意音频时钟和动画时钟一致,否则会出现“听起来对,但嘴型慢半拍”
|
||
- 如果后续改成 phoneme/viseme 对齐,建议在包里增加 phoneme 片段和置信度字段
|
||
|
||
## 9. 结论
|
||
|
||
这次重构的重点不是“把 2D 数字人继续硬改下去”,而是把系统边界调整到适合 3D 模型的形态。
|
||
|
||
现在的系统已经从“视频合成型数字人”切到了“控制流型数字人”,后续无论接 Three.js、Unity、Unreal,还是专门的 Audio2Face/viseme 服务,都可以在这个边界上继续演进。
|