Skip to content

虚拟形象 Unity → Three.js 迁移 ​

主导 B 站用户虚拟形象从 Unity WebGL 到 Three.js 的技术选型与迁移,机型覆盖率从 30% 拉到 93%,解决 WebGL 在移动端的性能天花板。

机型覆盖率30% → 93%
低端机帧率30fps
启动速度10s+ → <3s

背景 ​

B 站用户虚拟形象 1.0 用 Unity WebGL 方案。问题在移动端集中爆发:编译体积大、启动 10 秒以上、内存占用高,机型覆盖率只有 30%——七成用户根本打不开自己的虚拟形象。2.0 的目标是覆盖更多低端机型,Unity WebGL 撞到了天花板。

问题 ​

  1. 覆盖率是生死线:30% 意味着功能对大多数用户不存在,再优化细节都没意义。
  2. 启动慢:10s+ 的冷启动,用户等不到加载完就退了。
  3. 包体积大:10-20MB+ 的 WebGL 构建产物,移动端流量和加载时间都扛不住。

方案 ​

技术选型 ​

维度Unity WebGLThree.js
渲染效果⭐⭐⭐⭐⭐⭐⭐⭐(可塑性高)
机型覆盖率30%目标 90%+
启动速度慢(10s+)快(< 3s)
包体积大(10-20MB+)小(< 2MB JS)
开发效率中(导出调试慢)高(HMR)
生态3D 游戏Web 原生

最终选 Three.js:渲染效果可塑性高,且 Web 原生——没有 Unity 那层运行时,启动和体积天然占优。

迁移路径 ​

mermaid
flowchart TD
    A["Unity 资产与逻辑"] --> B["模型转换<br>GLB/GLTF 导出"]
    A --> C["渲染对齐<br>Shader / 光照 / 贴图"]
    A --> D["面捕移植<br>解算器 C# → JS"]
    B --> E["Three.js GLTFLoader"]
    C --> F["MeshStandardMaterial<br>+ 手写卡通 Shader"]
    D --> G["MorphTarget 驱动"]
    E --> H["Three.js 虚拟形象 2.0"]
    F --> H
    G --> H

原则:迁移不是重写。面捕核心算法直接平移,资产转换做成工具自动化,只有平台强相关的部分(Shader、加载、驱动接口)重写。

关键实现 ​

1. 模型转换 ​

  • Unity 模型 → GLB/GLTF 导出 → Three.js GLTFLoader 加载;
  • Unity Animator → Three.js AnimationMixer,BlendShape → MorphTarget;
  • 骨骼动画映射验证:抽检 20 个动画确保无变形。

模型侧的另一个配套工作是 Unity 运行时把 VRM 模型文件里的动画数据转成 AnimationClip(详见 GLB/GLTF/VRM 动画转 AnimationClip),让动画资产能在管线里标准化流转。

2. 渲染效果对齐 ​

  • Unity Standard Shader → MeshStandardMaterial,PBR 参数逐项调优对齐;
  • Unity Toon Shader → 手写 Three.js 卡通渲染 Shader;
  • 贴图格式 PNG → KTX2(GPU 原生压缩),显存占用显著下降。

3. 面捕接入 ​

Mediapipe Web SDK → CompatibleFaceData 协议 → Three.js MorphTarget 驱动

面捕解算器从 C# 移植到 JavaScript,核心算法(归纳 + 卡尔曼/低通滤波)保持一致——协议层 CompatibleFaceData 不变,所以驱动端只是换了个语言绑定。

4. 改 Three.js 底层源码 ​

WebGLMotionVector 内存泄漏修复:

  • 根因:换装部件切换时,旧 Mesh 的 WebGL 资源(纹理、Buffer)未正确释放;
  • 修复:在 dispose() 方法中增加 gl.deleteTexture() 和 gl.deleteBuffer() 的级联调用;
  • 验证:连续换装 100 次,内存稳定无泄漏。

5. 性能优化 ​

FPS 从 11 提到 30、WebGL 覆盖率从 30% 提到 93% 的完整优化过程,见 Web 端 11→30 FPS 和 WebGL 覆盖率 30%→93%。

指标 ​

指标Unity WebGLThree.js
覆盖率30%93%
低端机帧率—30fps
启动速度10s+< 3s
包体积10-20MB+< 2MB JS
内存高可控

复盘 ​

  • 技术选型不是「哪个技术更好」,是「哪个技术更适合当前的用户设备分布」。Unity WebGL 在 PC 上没问题,但 B 站用户在移动端、在低端机上。
  • 不要害怕改底层源码。Three.js 的 WebGLMotionVector 不改,内存泄漏就只能绕过不能根治;改了对上游提 issue,社区也受益。
  • 协议层设计在迁移时兑现价值。CompatibleFaceData 与引擎解耦,面捕从 Unity 迁到 Web 只换了语言绑定,这是当初做通用协议时没想到的回报。

罗子初 · AI 座舱专家 · 8年端侧研发

Lv.1