For the complete documentation index, see llms.txt. This page is also available as Markdown.

凝视如何工作

了解 Gaze 模块如何选择目标、让眼睛、头部和身体共享目光,以及如何响应对话状态。

ConvaiGazeController 决定角色看向什么以及投入多深,然后按固定顺序将其贯穿整个身体,使眼睛、头部和躯干对目标始终不会产生分歧。本页解释了这一决定背后的流水线:如何选择目标,如何让角色的 对话状态 改变其投入强度,以及为什么眼球运动和身体转身会像一个动作,而不是两个独立系统。


三阶段流水线

每个认知 tick,Gaze 都按相同的三个阶段依次运行。

阶段
问题
由什么决定

目标选择

角色应该看向谁或什么?

由目标提供器发布的候选对象,以及任何脚本化的 GazeAt 请求,由优先级解析。

策略

角色应当投入多少?

配置文件状态策略表中当前对话状态对应的条目,并根据情绪和说话活动进行调整。

求解器

这个注视如何到达那里?

躯干,然后颈部和头部,再然后眼睛,最后眼睑——每一层都叠加在角色的 Animator 姿势之上。

将目标选择与策略分离的原因在于,「什么」和「多少」会因不同原因而变化:新的候选对象可以在任何时刻出现,但角色对它投入多深应当跟随对话的走向,而不是候选对象出现的那一刻。


目标如何被选定

目标提供器每个 tick 发布候选对象,仲裁器按优先级而不是按谁先注册来解析它们。

  1. 一个脚本化的 GazeAt() 请求首先获胜 当角色处于 自然社交-保真度关注——见 脚本化注视。一个 精确-保真度关注会拒绝脚本化请求,除非 AllowScriptedOverridesDuringExactFocus 已启用。

  2. 优先级层决定其他一切。 玩家锚点以优先级 10 发布,其他 Convai 角色以优先级 7 发布,世界对象以优先级 5 发布。更高层级总会抢占更低层级。

  3. 在同一层级内,当前目标具有粘性。 只有当其对所保持目标的兴趣耗尽,或达到保持时间上限时,角色才会瞥向一个同优先级的替代目标。

因为玩家锚点以最高层级发布,只要当前对话状态的策略允许,玩家就是角色的主要目标。若要把角色的注意力引向别处——过场动画摄像机、分屏中的第二位玩家——则要么在玩家目标提供器上设置显式锚点,要么注册你自己的 IGazeTargetProvider ,并赋予更高优先级。见 Gaze 目标与提供器.


对话状态如何改变投入程度

ConvaiGazeController 不会把对话中的每一刻都同等对待。其配置文件的状态策略表将每个 对话状态 与一个参与度级别、玩家是否算作有效目标,以及是否允许身体转身相匹配:

对话状态
参与度
玩家是有效目标
允许身体转身

空闲

最低

否——改为环境式环顾四周

没有

关注中

倾听

最高

思考

降低

没有

说话

完全

反应 / 被打断

完全 / 接近完全

平复

降低

没有

配置文件表中未列出的状态将回退到 空闲 这一行。这就是为什么角色在 空闲时忽略玩家,在 关注中, 倾听,以及 说话时加深投入,并在 思考平复 期间再次放松接触——同一张表驱动所有状态转换,而不是每个状态一条手写规则。 配置眼神接触 涵盖 GazeEyeContactMode 设置,它可以完全覆盖此表,适用于必须始终与玩家对视的角色。


注视如何穿过身体移动

一旦设置好目标和投入程度,求解器阶段就会按固定顺序让角色朝它移动:先躯干,然后颈部和头部,再然后眼睛,最后眼睑。眼睛会先投入到新目标,头部则稍后跟上——这与真人使用的眼睛先于头部的顺序相同,而不是整个身体一次性猛地转向新的朝向。对于足够大的角度——例如玩家站在角色身后——身体本身会转动,把目标重新带回正前方,使用角色自己的原地转身动画,或平滑的程序化旋转,具体取决于角色携带了哪些实体化模块。

这套分层顺序也解释了为什么 gaze 与角色的 Animator 姿势永远不会冲突:每个求解器阶段都在 Animator 为该帧摆好骨骼之后运行,因此由 gaze 驱动的头部旋转是在调整已动画化的姿势,而不是与之竞争。见 实体化如何运作 每个实体化模块运行所共享的 tick 顺序。


下一步

Gaze 快速入门配置眼神接触凝视目标与提供器

最后更新于

这有帮助吗?