Files
product/AVATAR_3D_REFACTOR.md
T
2026-03-27 17:10:41 +08:00

190 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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` 骨骼,找不到时回退调试头像
### 方案 BUnity/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 服务,都可以在这个边界上继续演进。