在Unity中实现BlendShape表情和骨骼动画混合的实践

在Unity中实现BlendShape表情和骨骼动画混合的实践

https://zhuanlan.zhihu.com/p/71544395

表情实现机制

一般都是三种中选一种

1 换模型面部贴图,UV动画实现

优点:换贴图的话,如果做得精细,可以表现得内容特别多,表情丰富,2D、3D都可以使用

缺点:贴图内存占用是个问题,美术制作麻烦,还需要代码逻辑实现

2 面部骨骼动画

缺点:动作美术工作量问题,权重分配受限,可能没啥突出优点,都没在网上找到过类似例子......

3 BlendShape表情

优点:美术控制Morphing参数,每个表情额外只占用一个动画信息,10-20K,表情也可以很精细,导出表情动画不需要代码,动画状态机控制

缺点:2D不能用

综上,选用了BlendShape表情,网上已有关于BlendShape表情的文章,都是代码来控制SkinnedMeshRenderer上BlendShape的权重,表现很僵硬。所以,为了要生动的表情动画,本文直接使用美术导出的表情动画,而不是程序控制,这样就会完美还原美术制作的表情动画。

先放一张效果图,希望大家多多关注我们公司的游戏《王牌御史》~

在Unity中实现BlendShape表情和骨骼动画混合的实践_第1张图片

 

 

代码很少,下面直接上教程。

BlendShape表情

BlendShape表情,主要工作量在美术,美术制作好表情动画之后,导入Unity中按照下面设置播放即可

表情动画制作

美术方面:美术额外导出一个FBX,带有蒙皮信息、骨骼动画只保留一个造型、单独面部的动画信息(Morphing)

经过测试,只有美术网格、骨骼、蒙皮、Morphing动画一起导出来的Fbx才能保留表情动画信息

表情动画导入

导入到Unity中,基础模型要开启Import BlendShape

对应的面部SkinnedMeshRenderer上会多出BlendShape的配置(调整这些值就可以看到表情变化了)

在Unity中实现BlendShape表情和骨骼动画混合的实践_第2张图片

ModelImporter

在Unity中实现BlendShape表情和骨骼动画混合的实践_第3张图片

SkinnedMeshRenderer

按照美术的制作,裁切动画片段,下面的每一个动画片段,就包含了美术制作的表情动画

在Unity中实现BlendShape表情和骨骼动画混合的实践_第4张图片

动画导入拆分

 

也可以每个表情动画导出一个fbx,根据项目选择一个FBX然后拆分多个动画 或 每个动画单独一个FBX 都可以

设置动画状态机

正确设置Layer

双层状态机:为了面部表情独立出来,不与基础动作绑定死,可以通过代码逻辑自由组合播放

左图第一层控制角色动作,基础骨骼动画(跑、跳、肢体的害羞动作等)

右图第二层控制表情动画,表情动画(面部表情,开心 难过 眨眼 等)

在Unity中实现BlendShape表情和骨骼动画混合的实践_第5张图片

基础动画状态机

在Unity中实现BlendShape表情和骨骼动画混合的实践_第6张图片

表情动画层

使用AvatarMask

对于上面第二层状态机,需要有一点注意一下,小齿轮中Mask,需要制定一个AvatarMask,受这层状态机影响的骨骼或蒙皮

在Unity中实现BlendShape表情和骨骼动画混合的实践_第7张图片

AvatarMask(动画遮罩):可以控制哪部分骨骼或蒙皮受影响

FaceLayer中的Mask只需要开启面部蒙皮,这样只有面部受第二层状态机影响

在Project试图 右键 然后 Create/Avatar Mask 可以创建AvatarMask,然后指定对应Fbx中的avatar,就可以导入模型骨骼蒙皮信息

设置如下图,只需要选择面部的蒙皮

在Unity中实现BlendShape表情和骨骼动画混合的实践_第8张图片

播放逻辑

控制播放的逻辑,播放基础动作的时候,配套播一个面部表情,这里可以根据项目情况,角色动作和表情自行组合

animator.Play(actionState, layerIndex); 可以播放指定层的动画

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayAnimation : MonoBehaviour {

    private Animator animator;

    private int faceLayer;

    private void Awake()
    {
        animator = GetComponent();
        faceLayer = animator.GetLayerIndex("FaceLayer");
    }

    private void OnGUI()
    {
        GUILayout.BeginVertical();


        if (GUILayout.Button("表情1", GUILayout.Width(20.0f), GUILayout.Height(20.0f)))
        {
	    //播放基础动作
            animator.Play("tr1");
	    //通知指定播放第二层的表情动作
            animator.Play("Emojitr1", faceLayer);
        }

        if (GUILayout.Button("表情2", GUILayout.Width(20.0f), GUILayout.Height(20.0f)))
        {
            animator.Play("tr2");
            animator.Play("Emojitr2", faceLayer);
        }

        GUILayout.EndVertical();
    }
}

 

在Unity中实现BlendShape表情和骨骼动画混合的实践_第9张图片

 

Over~


2019-8-1更新

上面的这种方式由美术制作表情动画导入,动画信息中可能会产生多余的骨骼动画信息,所以这里通过导入器导入动画FBX的时候,动态删除多余的骨骼信息,参考另一个文章

范世青:Unity通过导入器优化动画关键帧数据​zhuanlan.zhihu.com

 


另一个偶现的BUG,是表情很奇怪,发现问题是播放表情动画的时候SkinnedMeshRenderer上的BlendShape某一个权重超过了100,但是美术制作的时候确定最大不会超过100

最后发现是动画导入器的ResampleCurve导致的,重采样动画曲线,使某一小段曲线采样超过了100,导致表情错误,参考另一篇文章

范世青:关于UnityAnimation ResampleCurves的优缺点分析​

zhuanlan.zhihu.com

取消掉导入器的ResampleCurve解决

在Unity中实现BlendShape表情和骨骼动画混合的实践_第10张图片

 

编辑于 2019-08-01

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(Unity)