情绪脚本 API
ConvaiEmotionController 参考——读取情绪状态、情绪控制、锁定、覆盖、事件以及已知情绪标签。
情绪系统在运行时提供两条路径来响应并控制情绪状态。 检视器路径 使用 ConvaiCharacterEventRelay ——一个将原始情绪回调作为 Unity 事件暴露出来、无需任何代码的组件。 脚本路径 使用 ConvaiEmotionController 直接使用,暴露完整的 C# API,用于读取组合状态、控制心境、注入覆盖以及锁定表情。两条路径可以同时使用。关于瞬时情绪与静息心境之间的概念差异,请参见 心境.
检视器路径 — ConvaiCharacterEventRelay
ConvaiCharacterEventRelay 是一个 MonoBehaviour,用于将角色回调桥接到 Unity 事件,让设计师无需编写任何代码即可在检视器中完成情绪响应的连线。
添加组件: Convai → Events → Convai Character Event Relay
将它放到场景中的任意 GameObject 上。它会自动查找 ConvaiCharacter 同一 GameObject 上的角色,或者你可以通过 Character 字段。
Inspector 字段
Character
(无)
可选的显式引用,指向一个 ConvaiCharacter。留空以使用自动解析。
Auto Resolve Character
true
启用后,中继会自动查找一个 ConvaiCharacter 并自动在同一 GameObject 上找到它。
OnEmotionChanged 事件
该中继暴露一个 On Emotion Changed 每当 Convai 发送原始情绪信号时触发的 Unity 事件。该事件传递一个 CharacterEmotionRelayData 负载:
CharacterId
string
角色的唯一标识符。
CharacterName
string
角色的显示名称(回退为 GameObject 名称)。
情绪
string
原始服务器标签(例如 "happy").
强度
int
Convai 发送的 1–3 整数刻度。
连线示例: 添加一个 ConvaiCharacterEventRelay 到你的 NPC 的 GameObject 上。在 On Emotion Changed 列表中,点击 +,将一个 UI Text 组件拖到对象字段,并选择 Text.text ——标签会在每次情绪变化时自动更新。
ConvaiCharacterEventRelay 会在分类法解析或平滑处理之前基于原始服务器标签触发。可用于 UI 显示、音频提示或简单分支逻辑。对于带分数和保持时间的平滑、解析后状态,请使用 ConvaiEmotionController.Current 改为在脚本中访问。
从脚本访问控制器
取回 ConvaiEmotionController 通过其具体类型——它所实现的跨模块契约(IEmotionStateSource 以及相关接口)属于 SDK 内部实现,不属于公共 API。
读取当前情绪状态
ConvaiEmotionController.Current 返回一个 EmotionReading ——一个仅在组合状态变化时才重建的不可变快照。可在 Update 中轮询它,或在任意事件中对其作出响应。
EmotionReading 属性和方法
DominantLabel
string
最高分瞬时情绪的规范标签(例如 "快乐", "anger").
DominantScore
float
主导瞬时情绪在平滑和 burst 处理后的归一化分数 [0–1]。
AllScores
IReadOnlyDictionary<string, float>
按规范标签键控的完整分数表。分类法中的每种情绪都有一个条目;本帧没有贡献的情绪得分为 0.
MouthInfluence
float
[0–1] 提示,由 LipSync 合成器在非说话帧中读取,用于混合嘴型。
DominantHoldSeconds
float
当前主导标签已连续保持的墙钟秒数。
MoodScore
float
的归一化 [0–1] 强度 MoodLabel.
IsNeutral
bool
true 当主导标签为 "neutral" 或者当 DominantScore ≤ 0.
NeutralLabel
const string
字符串常量 "neutral".
GetScore(string canonicalLabel)
float
返回给定规范标签的平滑分数,或者 0 在缺失时。
CopyScoresTo(IDictionary<string, float> destination)
void
将完整分数表复制到调用方拥有的字典中。复制前会清空目标字典。
CurrentFrame — 零分配帧视图
ConvaiEmotionController.CurrentFrame 返回一个 EmotionStateFrame ——同一组合状态的借用式零分配视图,在控制器下一次 tick 之前有效。对于无需分配调用方副本的每帧热路径场景,优先使用它,而不是 当前 。
版本
int
每次帧内容变化时递增。
DominantLabel, DominantScore
string, float
与 EmotionReading.
上的含义相同, 标签
分数, IReadOnlyList<float>
由控制器拥有、与索引对齐的标签/分数列表,覆盖分类法中的每种情绪。
MoodLabel, MoodScore
string, float
与 EmotionReading.
MouthInfluence, DominantHoldSeconds
float
与 EmotionReading.
IsNeutral
bool
与 EmotionReading.
GetScore(int index) / GetScore(string canonicalLabel)
float
通过索引查找 上的含义相同/标签中的分数,或者按规范标签查找。
解析后的状态和心境
CurrentResolvedEmotion
string
在分类法解析、平滑和配置组合之后的规范标签——等同于 Current.DominantLabel.
CurrentNormalizedIntensity
float
的组合归一化强度 [0, 1] CurrentResolvedEmotion.
CurrentMoodLabel
string
角色人格/气质静息心境的规范标签。明确地 不会 瞬时主导情绪。
CurrentMoodScore
float
的归一化 [0, 1] 强度 CurrentMoodLabel.
KnownEmotionLabels
分数
该角色当前生效分类法所识别的非中性规范标签,按分类法编排顺序排列。流水线构建之前为空。
TryResolveEmotionLabel(string label, out string canonicalLabel)
bool
在以下情况下解析 label 在当前分类法中匹配(规范标签和别名),返回规范的非中性标签。返回 false 对于空标签、无法解析的标签、解析到分类法中中性条目的标签,或在流水线尚未构建之前的情况。调用 SetMood/SetEmotionOverride之前,请先用它验证标签;否则系统会把未知标签静默降级为中性,而不是报错。
作者阶段锁定
控制器有三个序列化字段,可直接在检视器中将表情固定为某个特定情绪——这在创作和调试时非常有用,也可在不进入播放模式的情况下在场景视图中预览表情结果。
lockEmotion
bool
false
启用后,所有传入的服务器情绪事件都会被忽略,角色将保持锁定的情绪。
lockedEmotionLabel
string
"neutral"
在 lockEmotion 处于激活状态时保持的分类法规范标签。
lockedIntensity
float
1.0
锁定情绪的强度 [0–1]。
ConvaiEmotionController 继承自 [ExecuteAlways] 来自其基类,因此设置 lockEmotion = true 会让检视器中的表情立即更新到场景视图,而无需进入播放模式。
lockEmotion 是一个 序列化字段 ——其值会与场景或预制体一起保存。如果你一直保持它开启却忘记重置,那么在生产构建中,角色会静默忽略所有实时情绪信号,不会有运行时错误或警告。构建前务必关闭它。
SetEmotionOverride 和 ClearEmotionOverride
SetEmotionOverride 在 Convai 正在发送的内容之上,向累加器注入一个额外的瞬时分数。该覆盖仍然受平滑处理影响——它会以 lerpSpeed的速度混入,而不是立即生效。当应用逻辑需要响应场景中的事件来放大或引导瞬时情绪时使用它。
ClearEmotionOverride 移除覆盖,并将累加器恢复为服务器驱动状态。返回过程会经过平滑处理。
LockEmotion 和 UnlockEmotion
LockEmotion 完全绕过累加器,直接把角色切换到某个特定表情并将其保持在那里,不受 Convai 发送内容的影响。当脚本序列需要一个可保证的、稳定的表情时使用它。
UnlockEmotion 释放锁定,并恢复锁定前处于活动状态的目标——如果有活动的 SetEmotionOverride 则恢复它,否则恢复为中性。累加器会重新开始响应服务器事件。
API 签名:
运行时心境控制
SetMood 和 ClearMood 更改角色的 静息心境 在运行时——即脸部在瞬时情绪之间停靠的心境,与 SetEmotionOverride的瞬时通道不同。两者都会平滑交叉淡入淡出,而不是突然切换。关于心境及其相对于配置文件人格基线优先级的概念模型,请参见 心境.
API 签名:
SetMood解析为label通过角色的活动分类法。空标签或中性标签、无法识别的标签(每个标签只记录一次警告,然后回退),或者非正的强度都会平滑过渡到“无心境”,而不是抛出异常。ClearMood会过渡回作者设定的基线——即该角色自身设置的静息心境覆盖,或者配置文件的人格基线——不一定回到零。在流水线尚未构建之前(例如在禁用的组件上),两者都属于安全的空操作,且绝不会抛出异常。
会话重置(断开连接或出错)总会丢弃运行时
SetMood覆盖,并无论LockEmotion.
解析后的情绪和心境事件
两个具备滞回意识的事件,让游戏逻辑能够响应角色实际表达出来的内容,而无需重新实现平滑逻辑:
DominantEmotionChanged当平滑后的主导(瞬时)情绪标签——CurrentResolvedEmotion——发生变化时触发,并携带新的标签及其CurrentNormalizedIntensity.MoodChanged当CurrentMoodLabel发生变化时触发,并携带新的标签及其CurrentMoodScore。它涵盖了所有会推动心境变化的来源:作者设定的基线首次生效、SetMood/ClearMood以及心境漂移接管或释放。两者都只在标签转换时触发——标签持续存在时不会每个 tick 都触发,也不会仅因分数变化而在标签不变时触发。
两者都会在
当前/CurrentMoodLabel已经更新之后触发,因此处理程序始终观察到一致的状态。流水线尚未构建或正在拆除时,两者都不会触发;若某个订阅者抛出异常,也会被捕获并记录,而不会破坏当前 tick。这与
ConvaiManager.Events.OnCharacterEmotionChanged不同,后者会在接收到原始后端数据包时立即转发,且在应用平滑、滞回或人格基线之前触发。
订阅原始情绪事件
若要响应 Convai 发送的每个原始情绪信号——用于日志、分析或自适应场景逻辑——请订阅 OnCharacterEmotionChanged 在 ConvaiManager.Events。这是一个标准 C# 事件;在 OnEnable 并在 OnDisable.
CharacterEmotionChanged 属性
CharacterId
string
其情绪发生变化的角色的唯一标识符。
情绪
string
原始服务器标签(例如 "happy",而不是规范的 "快乐").
强度
int
Convai 发送的 1–3 整数刻度(已钳制)。
NormalizedIntensity
float
Intensity / 3f ——将 1–3 刻度映射到 (0, 1]。细微(刻度 1)的信号仍然映射到 0.33,而不是 0.
时间戳
DateTime
事件创建时的 UTC 时间戳。
Sequence
long
用于排序的可选服务器序列号, -1 当后端省略它时。这样可让延迟到达的数据包被忽略,而不是回滚角色的表情。
UtteranceId
string
将情绪与特定回复相关联的可选标识符。省略时为空。
Confidence
float
可选的 [0, 1] 检测置信度, 1 在省略时。
DurationMilliseconds
int
来自后端的可选持续时间提示, 0 在省略时。
IsNeutral
bool
true 如果 情绪 为 "neutral".
IsHighIntensity
bool
true 如果 Intensity >= 3.
IsLowIntensity
bool
true 如果 Intensity <= 1.
CharacterEmotionChanged.Emotion 包含 原始服务器标签 (例如 "happy"),而不是规范的分类法标签("快乐")。如果你需要规范标签——例如,想在 Current.AllScores 中查找分数——请通过 TryResolveEmotionLabel.
情绪维度
EmotionDimensions 是一种跨模块的连续情感信号—— 效价, 唤醒度, 能动性,以及 趋近,每个维度都在 [-1, 1] ——由 Emotion、Gaze、Body Language 和 locomotion 共享。分类标签仍然是作者设定面部表情配方的权威来源;维度则提供一个统一的调制信号,供其他模块在其上进行混合。
效价
-1 – 1
这个情绪有多愉快。 +1 表示喜悦, -1 表示痛苦。
唤醒度
-1 – 1
这个情绪有多激动。 +1 表示亢奋且快速, -1 表示低调且缓慢。
能动性
-1 – 1
角色感觉自己有多能掌控局面。 +1 表示掌控局面, -1 表示任由事件摆布。
趋近
-1 – 1
表示这种情绪是让角色趋近其触发源,还是远离它。 +1 倾向靠近, -1 拉开距离。
从 CurrentFrame.Dimensions读取主导情绪的维度。内置标签会解析为保守默认值;自定义分类法条目可以按标签覆盖它们——参见 情绪分类法.
TryGetMouthWeight
bool TryGetMouthWeight(BlendshapeTargetKey key, out float weight) 返回本帧合成器为特定 Blendshape 目标解析出的、由情绪驱动的嘴部权重,或者 false 当没有任何面部输出为该目标解析出嘴部权重时返回。LipSync 正是读取这里作为交接点,在非主动说话期间把自己的嘴型与情绪姿态进行混合;大多数应用代码不会直接调用它,除非它实现了自定义面部输出消费者。
下一步
情绪状态情绪示例情绪故障排查最后更新于
这有帮助吗?