当前位置:   article > 正文

Unity & FACEGOOD Audio2Face 通过音频驱动面部BlendShape

audio2face

目录

Audio2Face简介

在Unity中应用


Audio2Face简介

元宇宙的热潮下,为了让AI数字人渗透到更多的领域中,FACEGOOD已经将语音驱动口型的算法技术开源,开源地址:

https://github.com/FACEGOOD/FACEGOOD-Audio2Face

该技术可以实时将音频数据转换为驱动数字人面部BlendShape的权重数据,不同于ARKit中的52个BlendShape,它的数量多达116个,我们可以通过对应关系得到相应的数值,对应关系如下:

ARKitVoice2Face
eyeBlinkLefteye_blink2_l
eyeLookDownLefteye_lookDown2_l
eyeLookInLefteye_lookRight_l
eyeLookOutLefteye_lookLeft_l
eyeLookUpLefteye_lookUp_l
eyeSquintLefteye_shutTight_l
eyeWideLeftmax(eye_downLidRaise_l,eye_upLidRaise_l)
eyeBlinkRighteye_blink2_r
eyeLookDownRighteye_lookDown2_r
eyeLookInRighteye_lookRight_r
eyeLookOutRighteye_lookLeft_r
eyeLookUpRighteye_lookUp_r
eyeSquintRighteye_shutTight_r
eyeWideRightmax(eye_downLidRaise_r,eye_upLidRaise_r)
jawForwardjaw_thrust_c
jawLeftjaw_sideways_l
jawRightjaw_sideways_r
jawOpenmouth_stretch_c
mouthClosemouth_chew_c
mouthFunnelmax(mouth_funnel_dl,mouth_funnel_dr,mouth_funnel_ul,mouth_funnel_ur)
mouthPuckermax(mouth_pucker_l,mouth_pucker_r)
mouthLeftmouth_sideways_l
mouthRightmouth_sideways_r
mouthSmileLeftmouth_lipCornerPull_l
mouthSmileRightmouth_lipCornerPull_r
mouthFrownLeftmax(mouth_lipCornerDepress_l,mouth_lipCornerDepressFix_l)
mouthFrownRightmax(mouth_lipCornerDepress_r,mouth_lipCornerDepressFix_r)
mouthDimpleLeftmouth_dimple_l
mouthDimpleRightmouth_dimple_r
mouthStretchLeftmouth_lipStretch_l
mouthStretchRightmouth_lipStretch_r
mouthRollLowermax(mouth_suck_dl,mouth_suck_dr)
mouthRollUppermax(mouth_suck_ul,mouth_suck_ur)
mouthShrugLowermouth_chinRaise_d
mouthShrugUppermouth_chinRaise_u
mouthPressLeftmouth_press_l
mouthPressRightmouth_press_r
mouthLowerDownLeftmouth_lowerLipDepress_l
mouthLowerDownRightmouth_lowerLipDepress_r
mouthUpperUpLeftmouth_upperLipRaise_l
mouthUpperUpRightmouth_upperLipRaise_r
browDownleftbrow_lower_l
browDownRightbrow_lower_r
browInnerUpbrow_raise_c
browOuterUpLeftbrow_raise_l
browOuterUpRightbrow_raise_r
cheekPuffmax(cheek_puff_l,cheek_puff_r)
cheekSquintLeftcheek_up
cheekSquintRightcheek_up
noseSneerLeftnose_out_l
noseSneerRightnose_out_r
tongueOut

生产的数据结果如下图所示,可见是116个取值范围为-1~1的小数:

这116个数值依次对应下面116个BlendShape名称:

  1. brow_lower_l
  2. tongue_Scale__X
  3. tongue_Scale_Y
  4. tongue_Scale__Y
  5. tongue_Scale_Z
  6. tongue_Scale__Z
  7. nose_out_l
  8. nose_out_r
  9. tongue_u
  10. tongue_u_u
  11. brow_raise_d
  12. cheek_suck_r
  13. mouth_stretch_u
  14. tongue_u_d
  15. tooth_d_d
  16. tongue_d
  17. tooth_r
  18. tooth_d_u
  19. cheek_UP
  20. eye_blink1_l
  21. eye_blink1_r
  22. eye_blink2_l
  23. eye_blink2_r
  24. eye_lidTight_l
  25. eye_lidTight_r
  26. eye_shutTight_l
  27. eye_shutTight_r
  28. brow_lower_r
  29. eye_upperLidRaise_l
  30. eye_upperLidRaise_r
  31. eye_downLidRaise_l
  32. eye_downLidRaise_r
  33. jaw_sideways_l
  34. jaw_sideways_r
  35. jaw_thrust_c
  36. mouth_chew_c
  37. mouth_chinRaise_d
  38. mouth_chinRaise_u
  39. brow_raise_c
  40. mouth_dimple_l
  41. mouth_dimple_r
  42. mouth_funnel_dl
  43. mouth_funnel_dr
  44. mouth_funnel_ul
  45. mouth_funnel_ur
  46. mouth_lipCornerDepressFix_l
  47. mouth_lipCornerDepressFix_r
  48. mouth_lipCornerDepress_l
  49. mouth_lipCornerDepress_r
  50. brow_raise_l
  51. mouth_lipCornerPullOpen_l
  52. mouth_lipCornerPullOpen_r
  53. mouth_lipCornerPull_l
  54. mouth_lipCornerPull_r
  55. mouth_lipStretchOpen_l
  56. mouth_lipStretchOpen_r
  57. mouth_lipStretch_l
  58. mouth_lipStretch_r
  59. mouth_lowerLipDepress_l
  60. mouth_lowerLipDepress_r
  61. brow_raise_r
  62. mouth_lowerLipProtrude_c
  63. mouth_oh_c
  64. mouth_oo_c
  65. mouth_pressFix_c
  66. mouth_press_l
  67. mouth_press_r
  68. mouth_pucker_l
  69. mouth_pucker_r
  70. mouth_screamFix_c
  71. mouth_sideways_l
  72. cheek_puff_l
  73. mouth_sideways_r
  74. mouth_stretch_c
  75. mouth_suck_dl
  76. mouth_suck_dr
  77. mouth_suck_ul
  78. mouth_suck_ur
  79. mouth_upperLipRaise_l
  80. mouth_upperLipRaise_r
  81. nose_wrinkle_l
  82. nose_wrinkle_r
  83. cheek_puff_r
  84. tooth_l
  85. eye_lookDown1_l
  86. eye_lookDown2_l
  87. eye_lookLeft_l
  88. eye_lookRight_l
  89. eye_lookUp_l
  90. eye_lookDown1_r
  91. eye_lookDown2_r
  92. eye_lookLeft_r
  93. eye_lookRight_r
  94. cheek_raise_l
  95. eye_lookUp_r
  96. tongue_Rot_1X
  97. tongue_Rot__1X
  98. tongue_Rot_2X
  99. tongue_Rot__2X
  100. tongue_Rot_3X
  101. tongue_Rot__3X
  102. tongue_Rot_1Y
  103. tongue_Rot__1Y
  104. tongue_Rot_2Y
  105. cheek_raise_r
  106. tongue_Rot__2Y
  107. tongue_Rot_3Y
  108. tongue_Rot__3Y
  109. tongue_Rot_1Z
  110. tongue_Rot__1Z
  111. tongue_Rot_2Z
  112. tongue_Rot__2Z
  113. tongue_Rot_3Z
  114. tongue_Rot__3Z
  115. tongue_Scale_X
  116. cheek_suck_l

Unity中应用

可以用过构建python服务,Unity客户端开启麦克风录制音频,将音频数据发送给python服务端,服务端转换为驱动BlendShape的权重数据后,返回给Unity客户端进行驱动。需要注意的是Unity中BlendShape的权重范围并不是[-1,1],因此需要进行映射。

 例如:

  1. //将[-1,1]映射到[-100,100]
  2. private float Remap(float v)
  3. {
  4. return v * 100f;
  5. }

下面是一段测试音频产生的bs权重数据文件,每一行包含116个权重数值,我们拿来进行测试,将其放到StreamingAssets文件夹下。

测试模型:

测试代码:

  1. using System.IO;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. public class TEST : MonoBehaviour
  6. {
  7. private Coroutine coroutine;
  8. private SkinnedMeshRenderer smr;
  9. private readonly List<List<float>> valueList = new List<List<float>>();
  10. private IEnumerator Start()
  11. {
  12. smr = GetComponent<SkinnedMeshRenderer>();
  13. string path = Path.Combine(Application.streamingAssetsPath, "weight.txt");
  14. using (StreamReader streamReader = new StreamReader(path))
  15. {
  16. string content;
  17. while ((content = streamReader.ReadLine()) != null)
  18. {
  19. List<float> list = new List<float>();
  20. content = content.Trim();
  21. string[] splitArray = content.Split(' ');
  22. for (int i = 0; i < splitArray.Length; i++)
  23. {
  24. float.TryParse(splitArray[i], out float result);
  25. list.Add(result);
  26. }
  27. valueList.Add(list);
  28. yield return null;
  29. }
  30. }
  31. }
  32. private IEnumerator ExecuteCoroutine()
  33. {
  34. for (int i = 0; i < valueList.Count; i++)
  35. {
  36. List<float> list = valueList[i];
  37. smr.SetBlendShapeWeight(0, Remap(list[49])); //brow_raise_l
  38. smr.SetBlendShapeWeight(1, Remap(list[60])); //brow_raise_r
  39. smr.SetBlendShapeWeight(2, Remap(list[25])); //eye_shutTight_l
  40. smr.SetBlendShapeWeight(3, Remap(list[26])); //eye_shutTight_r
  41. smr.SetBlendShapeWeight(4, Remap(list[87])); //eye_lookRight_l
  42. smr.SetBlendShapeWeight(5, Remap(list[86])); //eye_lookLeft_l
  43. smr.SetBlendShapeWeight(6, Remap(list[92])); //eye_lookRight_r
  44. smr.SetBlendShapeWeight(7, Remap(list[91])); //eye_lookLeft_r
  45. smr.SetBlendShapeWeight(8, Remap(list[88])); //eye_lookUp_l
  46. smr.SetBlendShapeWeight(9, Remap(list[94])); //eye_lookUp_r
  47. smr.SetBlendShapeWeight(10, Remap(list[85])); //eye_lookDown2_l
  48. smr.SetBlendShapeWeight(11, Remap(list[90])); //eye_lookDown2_r
  49. smr.SetBlendShapeWeight(12, Mathf.Max(Remap(list[71]), Remap(list[82]))); //cheek_pull_l cheek_pull_r
  50. smr.SetBlendShapeWeight(13, Remap(list[18])); //cheek_UP
  51. smr.SetBlendShapeWeight(14, Remap(list[18])); //cheek_UP
  52. smr.SetBlendShapeWeight(15, Remap(list[6])); //nose_out_l
  53. smr.SetBlendShapeWeight(16, Remap(list[7])); //nose_out_r
  54. smr.SetBlendShapeWeight(17, Remap(list[70])); //mouth_sideways_l
  55. smr.SetBlendShapeWeight(18, Remap(list[72])); //mouth_sideways_r
  56. smr.SetBlendShapeWeight(19, Mathf.Max(Remap(list[67]), Remap(list[68]))); //mouth_pucker_l mouth_pucker_2
  57. smr.SetBlendShapeWeight(20, Mathf.Max(Remap(list[41]), Remap(list[42]), Remap(list[43]), Remap(list[44]))); //mouth_funnel_dl dr ul ur
  58. smr.SetBlendShapeWeight(21, Remap(list[52])); //mouth_lipCornerPull_l
  59. smr.SetBlendShapeWeight(22, Remap(list[53])); //mouth_lipCornerPull_r
  60. smr.SetBlendShapeWeight(23, Mathf.Max(Remap(list[47]), Remap(list[45]))); //mouth_lipCornerDepress_l mouth_lipCornerDepressFix_l
  61. smr.SetBlendShapeWeight(24, Mathf.Max(Remap(list[48]), Remap(list[46]))); //mouth_lipCornerDepress_r mouth_lipCornerDepressFix_r
  62. smr.SetBlendShapeWeight(25, Remap(list[39])); //mouth_dimple_l
  63. smr.SetBlendShapeWeight(26, Remap(list[40])); //mouth_dimple_r
  64. smr.SetBlendShapeWeight(27, Remap(list[65])); //mouth_press_l
  65. smr.SetBlendShapeWeight(28, Remap(list[66])); //mouth_press_r
  66. smr.SetBlendShapeWeight(29, Remap(list[36])); //mouth_chinRaise_d
  67. smr.SetBlendShapeWeight(30, Remap(list[37])); //mouth_chinRaise_u
  68. smr.SetBlendShapeWeight(31, Remap(list[56])); //mouth_lipStretch_l
  69. smr.SetBlendShapeWeight(32, Remap(list[57])); //mouth_lipStretch_r
  70. smr.SetBlendShapeWeight(33, Remap(list[78])); //mouth_upperLipRaise_l
  71. smr.SetBlendShapeWeight(34, Remap(list[79])); //mouth_upperLipRaise_r
  72. smr.SetBlendShapeWeight(35, Remap(list[58])); //mouth_lowerLipDepress_l
  73. smr.SetBlendShapeWeight(36, Remap(list[59])); //mouth_lowerLipDepress_r
  74. smr.SetBlendShapeWeight(37, Mathf.Max(Remap(list[76]), Remap(list[77]))); //mouth_suck_ul mouth_suck_ur
  75. smr.SetBlendShapeWeight(38, Mathf.Max(Remap(list[74]), Remap(list[75]))); //mouth_suck_dl mouth_suck_dr
  76. smr.SetBlendShapeWeight(39, Remap(list[35])); //mouth_chew_c
  77. smr.SetBlendShapeWeight(40, Remap(list[34])); //jaw_thrust_c
  78. smr.SetBlendShapeWeight(41, Remap(list[73])); //mouth_stretch_c
  79. smr.SetBlendShapeWeight(42, Remap(list[32])); //jaw_sideways_l
  80. smr.SetBlendShapeWeight(43, Remap(list[33])); //jaw_sideways_r
  81. smr.SetBlendShapeWeight(44, Remap(list[38])); //brow_raise_c
  82. smr.SetBlendShapeWeight(45, Remap(list[22])); //eye_blink2_r
  83. smr.SetBlendShapeWeight(46, Remap(list[21])); //eye_blink2_l
  84. smr.SetBlendShapeWeight(47, Remap(list[0])); //brow_lower_l
  85. smr.SetBlendShapeWeight(48, Remap(list[27])); //brow_lower_r
  86. smr.SetBlendShapeWeight(49, Mathf.Max(Remap(list[31]), Remap(list[29]))); //eye_downLidRaise_r eye_upLidRaise_r
  87. smr.SetBlendShapeWeight(50, Mathf.Max(Remap(list[30]), Remap(list[28]))); //eye_downLidRaise_l eye_upLidRaise_l
  88. yield return new WaitForSeconds(.07f);
  89. }
  90. coroutine = null;
  91. }
  92. private float Remap(float v)
  93. {
  94. return v * 100f;
  95. }
  96. private void OnGUI()
  97. {
  98. GUI.enabled = coroutine == null;
  99. if (GUILayout.Button("Begin", GUILayout.Width(200f), GUILayout.Height(50f)))
  100. {
  101. coroutine = StartCoroutine(ExecuteCoroutine());
  102. }
  103. GUI.enabled = coroutine != null;
  104. if (GUILayout.Button("Stop", GUILayout.Width(200f), GUILayout.Height(50f)))
  105. {
  106. StopCoroutine(coroutine);
  107. coroutine = null;
  108. }
  109. }
  110. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/367731
推荐阅读
相关标签
  

闽ICP备14008679号