Unity 表情状态机的创建与混合步骤
前置条件:已将带 BlendShape 的角色模型导入 Unity,且完成基础表情形状键(微笑、生气、眨眼)的
制作
核心目标:通过 Animator 组件创建表情状态机,实现表情的平滑过渡、状态切换与多表情混合(如 “微
笑 + 眨眼”),适配游戏中复杂的表情交互场景
一、前期准备:Animator 与动画控制器创建
添加 Animator 组件
将角色模型拖入 Hierarchy 面板,选中模型,在 Inspector 面板点击 Add Component,添加 Animator 组件。
Animator 组件参数设置:
Controller:暂时留空,后续创建表情动画控制器后赋值。
Avatar:若角色为 Humanoid 类型,选择自动生成的 Avatar;若为 Generic 类型,保持默认。
Apply Root Motion:取消勾选(表情仅面部变形,无需根运动)。
创建表情动画控制器
在 Project 面板右键→Create→Animator Controller,命名为 ExpressionController,双击打开 Animator 窗口
(负责状态机编辑)。
将创建的 ExpressionController 拖入角色 Animator 组件的 Controller 字段,完成绑定。
二、步骤 1:创建表情参数(控制状态切换)
在 Animator 窗口中,通过参数(Parameters) 定义控制表情切换的变量,支持浮点数、布尔值、触发器
等类型,此处选用浮点数(Float) 控制表情强度,触发器(Trigger) 控制瞬时表情(如眨眼)。
打开 Animator 窗口,点击左侧 Parameters 面板的 **+** 号,创建以下参数:
参数名称 类型 作用 取值范围
SmileWeight Float 控制微笑表情的强度 0(无)-1(满)
AngryWeigh
t
Float 控制生气表情的强度 0(无)-1(满)
BlinkTrigger
Trigge
r
触发单次眨眼表情(触发后自动重置) -
验证参数创建:确保参数列表中显示上述 3 个参数,类型与名称无误。
三、步骤 2:创建表情动画片段(BlendShape 动画)
表情状态机的基础是动画片段,需将 BlendShape 的数值变化录制为动画剪辑,或直接通过 Animation 窗
口创建表情动画。
创建微笑动画片段
在 Project 面板右键→Create→Animation,命名为 SmileAnim,双击打开 Animation 窗口。
选中角色模型,在 Animation 窗口中点击 Add Property,展开 SkinnedMeshRenderer→BlendShapes,选择
微笑对应的形状键(如 Smile),添加到动画轨道。
将动画时间轴拖到 1 秒处,将微笑形状键的数值设为 100(Unity 中 BlendShape 权重 0-100),自动生
成关键帧;时间轴 0 秒处数值为 0,形成 “从平静到微笑” 的动画。
勾选动画剪辑的 Loop Time(循环),设置 Wrap Mode 为 Clamp(保持最终状态)。
创建生气动画片段
重复上述步骤,创建 AngryAnim 动画片段,录制生气形状键从 0 到 100 的数值变化。
创建眨眼动画片段
创建 BlinkAnim 动画片段,时长设为 秒(快速眨眼)。
在 秒处将眨眼形状键设为 100,0 秒和 秒处设为 0,形成 “睁眼→闭眼→睁眼” 的瞬时动画,
取消勾选 Loop Time(眨眼为单次动作)。
四、步骤 3:搭建表情状态机核心结构
Animator 状态机的核心是状态(State) 和过渡(Transition),此处将表情分为基础状态(平静)、表情
状态(微笑、生气) 和瞬时状态(眨眼),实现状态的灵活切换。
1. 基础状态:Idle(平静)
Animator 窗口中,默认的 Entry 节点会指向 Idle 状态(若没有,右键→Create State→Empty,命名为 Idle)。
Idle 状态为默认状态,无任何表情动画(所有 BlendShape 数值为 0)。
2. 添加表情状态(微笑、生气)
右键→Create State→From New Blend Tree,创建两个混合树,分别命名为 SmileBlendTree、AngryBlendTree
(混合树用于控制表情强度的平滑过渡)。
配置微笑混合树:
双击 SmileBlendTree 进入混合树编辑界面,Blend Type 选择 1D,Parameter 选择 SmileWeight(绑定微笑
强度参数)。
点击 Add Motion,选择 SmileAnim 动画片段,设置 Threshold(阈值)为 1(表示 SmileWeight=1 时播放
满强度微笑)。
再添加一个 “空动画”(右键→Create Empty Motion),设置 Threshold 为 0(表示 SmileWeight=0 时回到
平静)。
配置生气混合树:重复上述步骤,混合树 Parameter 选择 AngryWeight,添加 AngryAnim 动画片段,阈值
设为 1,空动画阈值设为 0。
3. 添加瞬时状态(眨眼)
右键→Create State→Motion,命名为 Blink,将 Motion 字段设为 BlinkAnim 动画片段。
Blink 状态的 Exit Time 设为 (与眨眼动画时长一致),Has Exit Time 勾选(动画播放完毕后自动退
出)。
五、步骤 4:设置状态过渡与条件
通过添加过渡(Transitions) 定义状态之间的切换规则,结合参数控制过渡的触发与强度。
1. Idle 与表情混合树的过渡
Idle → SmileBlendTree:右键 Idle→Make Transition,拖到 SmileBlendTree。
过渡设置:取消 Has Exit Time,Conditions(条件)添加 SmileWeight > 0(当微笑强度大于 0 时触发过
渡),Transition Duration 设为 秒(平滑过渡)。
SmileBlendTree → Idle:右键 SmileBlendTree→Make Transition,拖到 Idle。
过渡设置:取消 Has Exit Time,Conditions 添加 SmileWeight == 0,Transition Duration 设为 秒。
Idle ↔ AngryBlendTree:重复上述步骤,条件改为 AngryWeight > 0 和 AngryWeight == 0,过渡时长
秒。
2. 所有状态与眨眼状态的过渡
眨眼是全局瞬时表情,需允许从任意状态切换到 Blink,播放后回到原状态:
添加全局过渡:在 Animator 窗口点击 Settings(齿轮图标)→Add Global Transition,拖到 Blink 状态。
过渡设置:取消 Has Exit Time,Conditions 添加 BlinkTrigger(触发眨眼触发器时切换),Transition Duration
设为 秒(快速切换)。
Blink → Any State:右键 Blink→Make Transition,拖到 Any State(表示播放完眨眼后回到任意原状态)。
过渡设置:勾选 Has Exit Time,Exit Time 设为 1(动画播放完毕后退出),取消 Conditions。
3. 多表情混合(如微笑 + 生气)
若需实现 “微笑 + 生气” 的混合表情,需将 SmileBlendTree 和 AngryBlendTree 放入同一层(Layer),
并设置层的 Blending Mode 为 Additive(叠加模式):
在 Animator 窗口左侧 Layers 面板,点击 **+** 号创建新层,命名为 ExpressionLayer。
将 SmileBlendTree 和 AngryBlendTree 拖入该层,设置层的 Weight 为 1(权重 100%),Blending Mode
为 Additive。
此时调整 SmileWeight 和 AngryWeight 的数值,可实现两种表情的叠加(如
SmileWeight=+AngryWeight=)。
六、步骤 5:编写脚本控制状态机参数
通过 C# 脚本控制 Animator 的参数,实现表情的触发、强度调节与混合,支持按键、UI 按钮等交互方
式。
创建状态机控制脚本在 Project 面板创建 C# 脚本 ,挂载到角色模型上:
csharp
运行
using UnityEngine;using ;
public class ExpressionStateMachine : MonoBehaviour{
[Header("Animator 组件")]
public Animator anim;
[Header("UI 滑块(控制表情强度)")]
public Slider smileSlider;
public Slider angrySlider;
[Header("UI 按钮(触发表情)")]
public Button blinkBtn;
public Button resetBtn;
void Start()
{
// 获取 Animator 组件
if (anim == null)
anim = GetComponent<Animator>();
// 绑定滑块值改变事件(控制表情强度)
(SetSmileWeight);
(SetAngryWeight);
// 绑定按钮点击事件
(TriggerBlink);
(ResetAllExpressions);
}
void Update()
{
// 键盘控制:按 S 键增加微笑强度,按 A 键增加生气强度,按 B 键触发眨眼
if (())
("SmileWeight", (("SmileWeight"), 1,
* 2));
if (())
("AngryWeight", (("AngryWeight"), 1,
* 2));
if (())
("SmileWeight", 0);
if (())
("AngryWeight", 0);
if (())
TriggerBlink();
}
/// <summary>
/// 设置微笑强度
/// </summary>
public void SetSmileWeight(float value)
{
("SmileWeight", value);
}
/// <summary>
/// 设置生气强度
/// </summary>
public void SetAngryWeight(float value)
{
("AngryWeight", value);
}
/// <summary>
/// 触发眨眼表情
/// </summary>
public void TriggerBlink()
{
("BlinkTrigger");
}
/// <summary>
/// 重置所有表情为平静
/// </summary>
public void ResetAllExpressions()
{
("SmileWeight", 0);
("AngryWeight", 0);
("BlinkTrigger");
}}
脚本参数赋值
将角色的 Animator 组件拖入脚本的 anim 字段。
在 Hierarchy 面板创建两个 UI 滑块(控制微笑 / 生气强度)和两个按钮(触发眨眼 / 重置),拖入脚
本对应字段。
运行测试进入 Play 模式,通过以下方式测试表情状态机:
拖动 UI 滑块:调节微笑 / 生气强度,观察表情平滑过渡。
点击眨眼按钮 / 按 B 键:触发瞬时眨眼,播放后回到原表情状态。
同时按 S+A 键:实现微笑与生气的叠加混合。
七、进阶优化:表情与骨骼动画的分层混合
若角色有行走、跑步等骨骼动画,需将表情动画与骨骼动画分层,避免冲突:
在 Animator 的 Layers 面板,将骨骼动画(如行走)放在 Base Layer,表情动画放在 ExpressionLayer。
设置 ExpressionLayer 的 Mask 为面部骨骼遮罩(仅影响面部骨骼),确保表情动画只作用于面部,不干扰
身体动画。
面部骨骼遮罩创建:在 Project 面板右键→Create→Avatar Mask,编辑遮罩并仅勾选面部骨骼(如 Head、
Eye)。
实操小贴士
表情状态机的过渡时长建议设为 秒,过短会导致表情切换生硬,过长会延迟响应。
对于移动端游戏,建议将常用表情动画烘焙为 Humanoid 动画片段,减少实时 BlendShape 计算的性能消
耗。
若需实现表情与口型同步(如对话时的唇形),可将口型动画也加入状态机,通过参数与对话文本联动。