版权声明:Davidwang原创文章,严禁用于任何商业途径,授权后方可转载。
苹果公司在iPhone X及后续机型上添加了一个深度摄像机(TrueDepth Camera),利用这个深度摄像机可以更加精准捕捉用户的面部表情,提供更详细的面部特征点信息。
利用深度摄像机采集到用户面部表情特征,ARKit提供了一种更加抽象的表示面部表情的方式,这种表示方式就叫Blend Shapes。Blend Shapes在技术上是一组存储了用户面部表情特征运动因子的字典,共包含52组特征运动数据,ARKit会根据深度摄像机采集的用户表情特征值实时的设置相对应的运动因子。利用这些运动因子可以驱动2D或者3D模型,这些模型会实时的展现与用户一致的表情。
ARKit实时提供全部52组运动因子,这52组运动因子中包括7组左眼运动因子数据、7组右眼运动因子数据、27组嘴与下巴运动因子数据、10组眉毛脸颊鼻子运动因子数据、1组舌头运动因子数据。但在使用时可以选择利用全部或者只利用一部分,如只关注眼睛运动,则只利用眼睛相关运动因子数据即可。
每一组运动因子表示一个ARKit识别的人脸表情特征,每一组运动因子都包括一个表示人脸特定表情的定位符与一个表示表情程度的浮点类型值,表情程度值的范围为[0,1],0表示没有表情,1表示完全表情,如在下图中,这个表情定位符为mouthSmileRight,代表右嘴角的表情定位,左图中表情程度值为0,即没有任何右嘴角表情,右图中表情值为1,即为最大的右嘴角表情运动,而0到1中间值则会对网格进行融合,形成一种过渡表情,这也是BlendShapes名字的来历。ARKit会实时捕捉到这些运动因子,利用这些运动因子我们即可以驱动2D、3D模型,这些模型会同步用户的面部表情,当然,我们可以只取其中的一部分所关注的运动因子,但如果想精确的模拟用户的表情,建议使用全部这52组运动因子数据。
在ARKit中,对表情特征位置定义了52组运动因子数据,使用了BlendShapeLocation来作为表情定位符,表情定位符定义了特定表情属性,如mouthSmileLeft、mouthSmileRight等,与其对应的运动因子则表示表情运动范围。这52组运动因子数据如下表所示。
表情定位符 | 描述 |
---|---|
eyeBlinkLeft | 左眼眨眼 |
eyeLookDownLeft | 左眼目视下方 |
eyeLookInLeft | 左眼注视鼻尖 |
eyeLookOutLeft | 左眼向左看 |
eyeLookUpLeft | 左眼目视上方 |
eyeSquintLeft | 左眼眯眼 |
eyeWideLeft | 左眼睁大 |
eyeBlinkRight | 右眼眨眼 |
eyeLookDownRight | 右眼目视下方 |
eyeLookInRight | 右眼注视鼻尖 |
eyeLookOutRight | 右眼向左看 |
eyeLookUpRight | 右眼目视上方 |
eyeSquintRight | 右眼眯眼 |
eyeWideRight | 右眼睁大 |
jawForward | 努嘴时下巴向前 |
jawLeft | 撇嘴时下巴向左 |
jawRight | 撇嘴时下巴向右 |
jawOpen | 张嘴时下巴向下 |
mouthClose | 闭嘴 |
mouthFunnel | 稍张嘴并双唇张开 |
mouthPucker | 抿嘴 |
mouthLeft | 向左撇嘴 |
mouthRight | 向右撇嘴 |
mouthSmileLeft | 左撇嘴笑 |
mouthSmileRight | 右撇嘴笑 |
mouthFrownLeft | 左嘴唇下压 |
mouthFrownRight | 右嘴唇下压 |
mouthDimpleLeft | 左嘴唇向后 |
mouthDimpleRight | 右嘴唇向后 |
mouthStretchLeft | 左嘴角向左 |
mouthStretchRight | 右嘴角向右 |
mouthRollLower | 下嘴唇卷向里 |
mouthRollUpper | 下嘴唇卷向上 |
mouthShrugLower | 下嘴唇向下 |
mouthShrugUpper | 上嘴唇向上 |
mouthPressLeft | 下嘴唇压向左 |
mouthPressRight | 下嘴唇压向右 |
mouthLowerDownLeft | 下嘴唇压向左下 |
mouthLowerDownRight | 下嘴唇压向右下 |
mouthUpperUpLeft | 上嘴唇压向左上 |
mouthUpperUpRight | 上嘴唇压向右上 |
browDownLeft | 左眉向外 |
browDownRight | 右眉向外 |
browInnerUp | 蹙眉 |
browOuterUpLeft | 左眉向左上 |
browOuterUpRight | 右眉向右上 |
cheekPuff | 脸颊向外 |
cheekSquintLeft | 左脸颊向上并回旋 |
cheekSquintRight | 右脸颊向上并回旋 |
noseSneerLeft | 左蹙鼻子 |
noseSneerRight | 右蹙鼻子 |
tongueOut | 吐舌头 |
需要注意的是,在上表中表情定位符的命名是基于人脸的,如eyeBlinkRight定义的是人脸右眼,在呈现3D模型时我们镜像了模型,看到的人脸模型右脸其实在左边。
有了表情特征运动因子后,就需要使用到Unity的SkinnedMeshRenderer.SetBlendShapeWeight()方法,该方法原型为:
public void SetBlendShapeWeight(int index, float value);
该方法有两上参数,index参数为需要融合的网格索引,其值必须小于Mesh.blendShapeCount值;value为需要设置的BlendShape权重值,这个值与模型设定值相关,可以是[0,1],也可以是[0-100]等等。
该方法主要就是用于设置指定网格索引的BlendShape权重值,这个值表示从源网格到目标网格的过滤(源网格与目标网格拥有同样的拓扑结构,但顶点位置两者有差异),最终值符合以下公式:
V f i n = ( 1 − v a l u e ) ∗ V s r c + v a l u e ∗ V d e s Vfin = (1-value)*Vsrc + value*Vdes Vfin=(1−value)∗Vsrc+value∗Vdes
因此,通过设置网格的BlendShape权重值可以将网格从源网格过渡到目标网格。如下图所示。
从上文可以看出,想要使用ARKit的BlendShapes功能需要满足两个条件:第一是有带有深度摄像机的移动设备,第二是有一个BlendShape已定义好的模型,这个模型BlendShape定义最好与上表中对应一致。
为模型添加BlendShape可以在3dMax软件中定义变形器,并做好对应的网格变形,如下图所示。
在满足以上两个条件后,使用BlendShapes就变得相对简单了,实现的思路是:
(1)获取到ARKit表情特征运动因子,这可以使用ARKitFaceSubsystem.GetBlendShapeCoefiicients()方法获取到,这会返回一个Unity NativeArray数组,里面即包括所有52组表情特征运动因子数据。
(2)模型挂载Skinned Mesh Renderer组件,其BlendShape与模型中定义折BlendShape标记符一致,如下图所示,绑定ARKit的表情特征定位符与Skinned Mesh Renderer中的BlendShape,使其保持一致。
(3)在Face数据发生改变时更新所有的表情特征运动因子,示例代码如下所示:
void UpdateFaceFeatures()
{
if (skinnedMeshRenderer == null || !skinnedMeshRenderer.enabled || skinnedMeshRenderer.sharedMesh == null)
{
return;
}
using (var blendShapes = m_ARKitFaceSubsystem.GetBlendShapeCoefficients(m_Face.trackableId, Allocator.Temp))
{
foreach (var featureCoefficient in blendShapes)
{
int mappedBlendShapeIndex;
if (m_FaceArkitBlendShapeIndexMap.TryGetValue(featureCoefficient.blendShapeLocation, out mappedBlendShapeIndex))
{
if (mappedBlendShapeIndex >= 0)
{
skinnedMeshRenderer.SetBlendShapeWeight(mappedBlendShapeIndex, featureCoefficient.coefficient * coefficientScale);
}
}
}
}
}
1、blendshapelocation blendshapelocation