其他 Avatar 相关知识

章节转载自 https://notes.sleightly.dev 的多个页面

本译文封面图标来自Flaticon

译者前文

  1. 本书由 LIII Works 你亲爱的酒保K 完成后续翻译以及由 VRCD Cocoa 及 SKP 起草。
  2. 本书翻译自 VRCLibrary 的 Miscellaneous Avatar Knowledge
  3. 本书翻译工作截止于2024年9月5日下午18点41分。

本书在译者监督下由人工智能翻译并由译者根据自身知识审阅和调整,翻译可能出现错误,如有疑问,请参阅原文 Miscellaneous Avatar Knowledge

写入默认 (Write Defaults)

原文出处:https://notes.sleightly.dev/write-defaults/

写入默认 (Write Defaults)

Write Defaults 是 Animator States 中的一个选项,对于许多 Avatar 创作者来说,它可能会造成困扰,因为其行为有时非常奇怪和出乎意料。预期的行为如下:

Write Defaults 选项决定了通过这个动画所做的更改是否保持不变。

译者注释:Write Defaults 选项决定了当前播放的动画对物体所做的更改是否在当前动画结束和离开状态保持不变。

如果启用了 Write Defaults 选项,动画属性在离开 Animator 状态时将返回到默认状态。

译者注释:默认状态指的是当 Avatar 在上传时,一个物体所处的状态。比如一个方块在上传时的缩放是 (1 | 1.5 | 2),并且是启用的,那么这个方块的默认状态就是缩放 (1 | 1.5 | 2) 并且启用。

如果禁用了 Write Defaults 选项,更改将保持不变。

译者注释:如果禁用了 Write Defaults 选项,当前播放的动画对物体所做的更改将保留下来。

默认情况下,Unity 在新创建的状态上会启用 Write Defaults,但 VRChat 提供的默认 Animator Controllers 中是关闭 Write Defaults 的。

Untitled.png

新建状态默认启用 Write Defaults。

举例:

如果你在上传时将帽子关闭(即帽子的默认状态是关闭),如下所示:

Untitled.png

启用 Write Defaults 的情况下下:

禁用 Write Defaults 的情况下:

使用指南

在使用 Write Defaults Off 时,请遵循以下几条规则。为了规整起见,我会在稍后作出解释:

译者注释:建议使用一个不存在的物体属性,并且有至少两帧的原因是一个空动画的播放时长大约是1秒,而具有空属性2帧的动画大约是0.0167秒 (如果你没有修改过动画的采样率)

注意:如果你因为需要使用 WD Off 的修改 Transform 的动画从而必须在 Gesture 和 FX 层中使用 Avatar Mask 的话,你只能用动画修改被遮罩影响的 Mesh 的第一个材质球而不能修改其他的,因为被遮罩影响的 Mesh(无论在有 Avatar Mask 的情况下 WD 是启用还是禁用)不能用动画修改除了第一个之外的材质球。

VRLabs 的 Avatar 3.0 Manager 可以帮助你检查你的设计是否违反了以上规则(至少能检查第一条和第三条)。在该工具的 Write Defaults 选项卡中,它会告诉你是否混用了 Write Defaults,并帮助你统一设置。请注意,它不会把 Direct Blend Trees 当作例外,所以任何刻意设置为 Write Defaults On 的状态都必须在状态名称中添加 (WD On) 来标记为启用 Write Defaults 从而让工具不要修改它的 Write Default 状态。

 

上述规则的解释

 

不要在一个控制器中混合使用 Write Defaults

播放单个 Write Defaults Off 的状态会导致所有其他 Write Defaults On 的状态无法写入其默认值,从而使其表现得像 Write Defaults Off 一样。

 

不要在 Direct Blend Trees 中使用 Write Defaults Off

Write Defaults Off 的 Direct Blend Trees 会产生奇怪的行为,比如影响使用相同参数的其他 Direct Blend Trees,并且随着时间的推移,动画结果会乘以一个因子,使得最终结果变得非常奇怪。一般情况下都不应该使用 Write Defaults Off 的 Direct Blend Trees。

为了更清楚地说明这种乘法行为,对结果来说,在禁用 Write Defaults 的 Blend Tree 中,最终权重会被一个 x/(1-yx) 的因子所乘,其中 x 是当前子项的权重,y 是其他子项的权重之和,除以当前子项的权重。注意,如果这个分数的分母为 0 或更小,值会趋向于无穷大并不断增加。这意味着,如果你有 n 个子项,并且将每个子项的权重设置为 1/n,那么最终结果是乘数为 1,因此这允许你使用禁用 Write Defaults 的 Direct Blend Trees。然而,这并不意味着这是个值得推荐的做法,因为这会影响其他 Blend Trees 和导致其他奇怪的结果。启用 Write Defaults 会让一切都更简单可控。

 

如果你使用 Write Defaults Off,所有状态都应该包含一个动画或一个 Blend Tree

如果一个 Write Defaults Off 的状态没有包含动画,它可能会用之前动画层中的状态的动画默认值覆盖之前层中的动画。

优点/缺点

Write Default On

优点:

译者注释:另一种控制默认状态的方法是在之前的动画层中用动画锁定一个默认状态,这对 Write Default On 有效,也是在 Write Default Off 情况下实现 Write Default On 的还原效果的办法,在稍后的创作者指南部分你会看到类似的内容。

缺点:

译者注释:序列操作指的是将一段复杂的动画拆解成多个动画依次执行,这样将极大地减轻单个动画的复杂度以及减少维护和修改的难度。例如,将一扇有门把手的门打开再关上可以拆解成四个部分:1. 门把手下压 2. 门打开 3. 门把手松开 4. 门关上。

Write Default Off

优点:

缺点:

创作者指南

这些指南适用于制作应同时兼容 Write Defaults On 和 Write Defaults Off 的预制件:

如果遵循本文中概述的指南,每个属性都会被动画化,你的动画系统就可以同时兼容 Write Defaults On 和 Write Defaults Off。

Blendshape 值翻三倍的问题

在非常特定的条件下,当依赖于 Write Defaults On 时,Blendshape 的值会增加三倍。

(例如:你有一个空的 Write Defaults On 状态,它会过渡到一个 Blendshape 动画的 Write Defaults On 状态。在空的 Write Defaults On 状态中,动画 Blendshape 的默认值会被乘以 3。)

这个问题比其他问题更复杂和不明确,因此请将本文和以下内容视为观察结果,而非事实:

人形遮罩 (Avatar Mask)

原始页面:https://notes.sleightly.dev/animator-masks/

Unity 行为

Avatar Mask 会基于在遮罩中启用和禁用的选项,阻止或允许 Humanoid Muscle 数值、材质球替换和 Transform 的动画处理。如果一个动画层具有一个启用了特定值的 Avatar Mask,那么该层的动画可以对该值进行动画处理。如果一个动画层具有一个禁用了特定值的 Avatar Mask,那么该层的动画则不能对该值进行动画处理。具体而言:

其他内容(如 blendshapes 和任何其他组件)不会受到 Avatar Mask 的影响。

设置 Avatar Mask 的原因在于,如果你在一个层中控制一个 Humanoid Muscle 数值,然后在另一个层中控制同一个 Humanoid Muscle 数值,(无论是在 Animator 中更低的动画层还是在不同的 Playable Layers 中),前者的动画会被后者覆盖(除非另一个层是 Additive 层,在这种情况下,它会叠加在前者之上)。

对于 Transform,这种情况仅在第二个动画使用 WD off 并且位于一个稍后应用的 Playable Layer 时发生。

例如,如果没有 Avatar Mask,如果你在 Gesture Layer 中用动画控制手部动作,而在 FX Layer 中使用了不同的动画控制面部表情(同时也控制了 Humanoid Muscle),那么手部的值将被 FX Layer 覆盖。

注意:这意味着,如果你有一个 Humanoid 动画,没有进行适当的 Avatar Mask 以启用所需的 Humanoid Muscle 数值并禁用其他数值的情况下,所有其他 Humanoid Muscle 数值将会被覆盖。

这也意味着,如果你在 Gesture Layer 中有 Transform 动画,而在 FX Layer 中有一个未被遮罩应下的 WD Off 的控制 Transform 的动画,所有 Gesture Layer 中的 Transform 动画都会被覆盖。

默认的 VRChat FX Layer 使用了未被遮罩影响的 WD off 的混合树。如果你使用 VRChat 默认的 FX Layer,这可能导致在 VRChat 中 Transform 动画无法播放。如果你想在 Gesture Layer 中使用控制 Transform 的动画,你必须使用你自己的 FX Layer。

VRChat Playable Layers 行为

所有 Playable Layers 会依次播放。首先是 Base 层,然后是 Additive 层,接着是 Gesture 层,然后是 Action 层,最后是 FX 层。

在前四个层(Base、Additive、Gesture 和 Action)中,你应该只使用影响 Transform(无论是 Humanoid Muscle 还是 Transform 动画)和开关 GameObject 的动画。

这不是因为 Avatar Mask,而是因为这四个层只在你的本地 Avatar 克隆体上播放,而不会在你的镜像和阴影克隆体上播放。VRChat 复制本地 Avatar 上每个物体的 Transform 和开关状态,并将它们应用到 Avatar 的镜像和阴影克隆体上。然而,VRChat 不会复制除了 Transform 和每个 GameObject 的开关状态之外的任何内容,这意味着如果你的动画控制了其他内容,如 blendshapes、材质球替换或着色器设置,VRChat 不会将这些属性复制到镜像和阴影克隆体上。克隆体会播放自己的 FX Layer,这就是为什么除了 Transform 和物体的开关状态之外的一切都应该在 FX Layer 中控制的原因。

例如:如果你在 Base Layer 中进行材质球替换,它不会在镜像和阴影克隆体上生效。

本文仅详细讨论了 Avatar Mask 和行为。如果你想了解更多关于 VRChat 层的内容或 VRChat 推荐的层使用方法,你可以在以下页面找到更多信息:

Playable Layers | VRChat Creation

基本动画层

Base

Base 该层应仅动画处理 Transform(无论是直接还是通过 Humanoid Muscle)和/或物体的开关状态。

VRChat 推荐将此层用于运动等只控制 Humanoid Muscle 的动画。

Additive

Additive 该层应仅使用控制 Transform 的动画和/或控制物体开关状态的动画。它是以叠加混合的方式进行的,这意味着任何动画不会替换基础层的动画,而是将值叠加。

VRChat 推荐将此层用于运动的调整,如呼吸效果,并且只应该使用控制 Humanoid Muscle 的动画。

Gesture

该层应当只使用控制 Transform 和/或物体的开关状态的动画。Gesture 有一些特殊的性质,即 VRChat 会将 Gesture 的第一个动画层的 Avatar Mask 应用到其下所有的动画层上,如果在第一层的 Avatar Mask 或某一层的 Avatar Mask 中禁用了动画控制(无论是 Humanoid 还是 Transform),它就无法被动画控制。

因此,如果你想使用任何控制 Humanoid Muscle 的动画,你必须制作一个专门允许这些 Humanoid Muscle 的 Avatar Mask 并将其放在第一层中。

如果你想你想使用任何 WD Off 的控制 Transform 的动画,你必须制作一个专门允许这些 Transform 并禁用其他部分的 Avatar Mask,并将其放在第一层中。

VRChat 推荐将此层用于控制 Transform 和仅影响特定身体部位的 Humanoid 动画。

Action

该层应仅使用控制 Transform 和/或物体的开关状态的动画。Action 在默认情况下的权重为零。在你在 Action 层中进行任何操作之前,你需要使用 Playable Layer Control State Behavior 将该层的权重混合到一个有效数值,然后再过渡到你要执行的实际操作。当你完成后,确保将其权重调整回零,否则其他层的动画将会全部被覆盖。

VRChat 推荐将此层用于覆盖前面层中的任何 Humanoid 动画,例如动作表情或 AFK 动画。

FX

由于该层会在所有克隆体上运行,因此这是你可以运行任何动画的地方。请注意,你仍然可以在这一层控制 Transform,只要设定了适当的 Avatar Mask。

如果第一个动画层没有设定 Avatar Mask,它将创建一个默认的 Avatar Mask,禁用所有 Humanoid Muscle 数值和启用所有 Transform,并将其应用到所有层上,使其在这个 Avatar Mask 或层的 Avatar Mask 中禁用的内容会被禁用。

如果第一个动画层中使用了任何 Avatar Mask,第一层的 Avatar Mask 也会应用到所有层。

因此,如果你想在 FX 控制 Humanoid Muscle,你必须制作一个专门允许你想控制的 Humaniod Muscle 的 Avatar Mask 并将其放在最顶层。如果你不关闭不需要的 Humaniod Muscle,Gesture 中的动画内容就会全部被覆盖。

如果你使用 WD off,同样的逻辑也适用于 Transform。

VRChat 的默认 FX 层有一个混合树,Write Default 为 Off,这可能会使得一些 Transform 动画出问题。如果你想在任何其他 Playable Layers 中使用 Transform 动画,请不要使用默认的 FX 层。

VRChat 推荐将此层用于所有非 Transform 动画的内容,例如启用/禁用物体、组件、材质球替换、着色器动画、粒子系统动画等。

特殊层

T-pose:

T-Pose 用于确定 Avatar 的各种测量值,特别是视点(或视角球)的放置。它是独立的,因此 Avatar Mask 并不重要。

IK Pose:

IK Pose 用于确定主要关节的弯曲。在 IK 姿势中,你的关节应该略微弯曲,以符合其弯曲方向。它是独立的,因此 Avatar Mask 并不重要。

Sitting Pose:

这个控制器用于控制坐下时的姿势。当你坐下时,Avatar 的视点会用于校准。你可以创建一个“坐下”动画以及一个“坐着”的动画来让 Avatar 看起来像是坐下了。这一层类似 Action,会覆盖所有的 Humanoid 动画,以使角色坐下。

参数类型不一致 (Expression Parameter Mismatch)

原文出处:https://notes.sleightly.dev/parameter-mismatching/

译者注释:Bool 布尔 (True/False)

译者注释:Int 整数/整形 (0, 1, 2, 3, 4, 5...)

译者注释:Float 浮点/小数 (0.13, 0.45, 0.255...)

译者注释动画器参数 指的是 Animator 内的参数;Expression 参数 指的是 VRC Expression Parameter List 内的参数

在一般的 VRChat Avatars 3.0 创作过程中,VRChat Expression Parameters 的参数类型应该设置为与 Animator 内相同的类型(BoolIntFloat)。

然而,Expression Parameters 和 Animator 参数之间的参数类型在不一致的情况下也仍能正常工作。这种行为因参数类型的不同而有所差异,具体如下所述。

image.png

一个标记为 Toggle 的参数被添加到 VRChat Expression Parameters 中,类型为 Bool

image.png

一个标记为 Toggle 的参数被添加到 local Animator 参数中,类型为 Float

已知互相兼容的参数类型及其行为

Expression Parameter Bool

动画器参数 → Expression 参数 Expression Bool = False Expression Bool = True
Bool → Bool Bool = False Bool = True
Bool → Int Int = 0 Int = 1
Bool → Float Float = 0.0 Float = 1.0

Expression Parameter Int

动画器参数 → Expression 参数 行为
Int → Bool 任何大于 0Int 值将使 bool 为 True
Int → Int 预期行为
Int → Float 直接转换:例如 Int = 2Float = 2.0


Expression Parameter Float

动画器参数 → Expression 参数 行为
Float → Bool 任何大于 0Float 值将使 bool 为 True
Float → Int 四舍五入转换:≥0.51 ; <0.50
Float → Float 预期行为

为什么 Avatar 参数类型之间互相兼容?

Unity Animators 在 C# 后端使用浮点数处理参数,而 VRChat 则使用 SBytes 代替 bool、int 或 float。

Animator 和 VRCSDK 通过允许你从界面中选择参数类型来优化用户体验。

如果这样来看的话,参数并不是被转换,而是不一致

这种不一致的兼容性同样适用于 VRChat 的内置参数

目前,AV3 Emulator 和 GestureManager 已经实现了模拟参数类型兼容的功能。

使用混合树来合并多个动画层

原文出处:https://notes.sleightly.dev/dbt-combining/

由于 Animator Controller 中 Animator Layers 对性能的影响较大,一个对性能更友好的做法是通过使用 Direct Blend Tree 将切换开关和转轮开关等功能合并到同一个 Animator Layer 中。

译者注释:转轮开关指的是一种圆形的轮盘菜单操作模式,通过类似进度条的菜单来控制一个数值从 0% - 100%

理解什么是 Direct Blend Trees

Direct Blend Trees 允许你为其内的每一个 Animation 或 Blend Tree 分支设置参数。这让你能够在同一个 Blend Tree 中同时控制多个动画。

译者注释:有时候 Direct Blend Trees 也被称为 DBT

对于 VRChat,我们可以利用这一特性,在单个 Direct Blend Tree 中制作多个切换开关和转轮开关,类似于在多个动画层中进行的操作。

Direct Blend Tree 的结构和功能与 Animator Controller 非常相似,因此将它们视作 Animator Controllers 可能会更容易理解。这是一种简化的理解 Direct Blend Trees 的方式,但需要注意的是,尽管它与 Animator Controllers 非常相似,但并不完全相同!

两者之间存在一些关键差异,这些差异在很大程度上限制了 Direct Blend Trees 的使用场景和实现方式。有关更多信息,请参阅“限制和已知问题”部分。

image.png

一个包含 3 个服装组件切换开关的 Direct Blend Tree

译者注释:

 

创建切换开关和转轮开关

在 Direct Blend Tree 中制作切换开关和转轮开关与在 Animator Layer 中制作常规切换开关并无太大区别,也不会更为复杂。

 

步骤 1

image.png

译者注释:无论你的其他动画层是否使用 Write Default,只要你的这个动画层只有这一个Direct Blend Tree并且只有这一个 State,在这样的情况下单独启用 Write Default 不会影响你的动画器,也不会造成任何问题无需担心启用 Write Default会造成问题。

 

image.png

步骤 2

步骤 3

image.png

步骤 4

仅使用一个动画片段(如 WD On 工作流程中那样)是行不通的!你需要单独的动画或一个合并动画。

译者注释:合适 1D Blend Tree 的动画指的是,例如你的动画有4个帧,对应4套服装的开启,那么你需要将这4个帧做成4个独立的动画,每个动画控制一套服装的开启,这样才能分散在 1D Blend Tree 上。传统的 Motion Time 式做法不能在 Blend Tree 中直接套用。


image.png

步骤 5

译者注释:如果你的设计中具有多余2个状态,将不合适 参数类型不一致 的做法,你需另外设计一个合适的方法来驱动。

image.png

image.png


写入默认(Write Defaults)

在处理写入默认(Write Defaults)时,Direct Blend Trees 是一个例外。它的 Write Defaults 值可以和 Animator Controller 的其他部分的设定不同,这意味着你可以混合使用 Write Defaults,只要不在同一个动画层中混用即可。

对于 Direct Blend Trees 来说,即使 Animator Controller 的其他动画层使用 Write Defaults Off,我们也可以安全地使用 Write Defaults On。能够在 Direct Blend Trees 使用 Write Default On 可以帮助我们避免以下 Write Default Off 的 Blend Tree 具有的问题:

Write Defaults Off 的 Direct Blend Trees 的问题:

因此,不建议使用 Write Defaults Off 的 Direct Blend Trees,因为它们比 Write Defaults On 的版本更不稳定且更难以处理。即使 Animator Controller 的其他部分使用 Write Defaults Off,使用 Write Defaults On 的 Direct Blend Trees 也是完全安全的。

译者注释:无论你的其他动画层是否使用 Write Default,只要你的这个动画层只有这一个Direct Blend Tree并且只有这一个 State,在这样的情况下单独启用 Write Default 不会影响你的动画器,也不会造成任何问题无需担心启用 Write Default会造成问题。

你可以在 Blend Tree 的名称前添加前缀(WD On),这样在使用 https://github.com/VRLabs/Avatars-3.0-Manager 批量设置 Animator Controllers 的 Write Defaults 值时不会受到影响。

这对于希望确保他们产品的用户在使用类似工具时不会意外关闭 Write Defaults 的 Avatar 和 Prefab 创作者特别有用。

将 Write Defaults 值从 On 更改为 Off 将会使得 Blend Tree 出错,直到 Write Defaults 被设置为 On!

image.png

嵌套 Direct Blend Trees

如果你有很多切换开关和转轮开关,你的 Direct Blend Tree 可能很快就会变得庞大且难以管理。你可以通过将 Direct Blend Trees 嵌套在一起,模拟文件夹的结构,从而提高组织性

如果你在嵌套之前已经创建了所有的切换开关和转轮开关,你需要把他们全部删除,然后在文件夹里重新制作,因此最好预先考虑好这一点(除非你有工具可以重新排列 Blend Trees)。

译者注释:确实有一个美妙的工具可以重新排列 Blend Trees,但是纸张的空间太小了,就不在此多赘述了

如图所示,我们有一个包含九个子项的 Direct Blend Tree。我们可以通过利用更多的 Direct Blend Trees 将它们组织成文件夹。

image.png

首先,你想制作几个文件夹,就新建几个 Blend Tree,方法与创建切换开关或转轮开关时相同。

接下来,选择每个子项,并在检查器中将 Blend Type 更改为 Direct。

image.png

然后,按照前文所述的办法制作切换开关和转轮开关,只不过现在你是在文件夹内部制作。

为了更方便维护,你还可以选中文件夹,然后在检查器顶部重命名这些文件夹。

你可以给子文件夹设置和根 Direct Blend Tree 的相同 Weight 参数,如前文第3步所述。

有关将多个转轮开关和切换开关合并在一起的示例,请参见 Direct Blend Tree Radials and Toggles (Nested)

image.png

你可以双击任何一个 Direct Blend Tree 来在一个独立窗口中打开它,这在你的 Blend Tree 规模巨大,以至于出现性能问题的时候尤其有用。

image.png

你可以通过点击左上角的箭头返回到完整的 Blend Tree 视图。

image.png


进阶 Blend Tree 技术

Blend Trees 的应用远不止简单的切换开关和转轮开关,还包括:

截至目前,这些技术相对缺乏详细文档,超出了本指南的范围。

如果需求足够大,未来可能会添加相关的扩展文章。


当前限制和已知问题

译者注释:排他性切换指的是,例如有3套服装,同时间只应该启用一个,而不是有2个或3个同时启动用。例如 Int 天然的具备排他性,但你不能直接在 Direct Blend Trees 中使用整数。一些特性需要设计额外的功能模块或者逻辑才能在 Direct Blend Trees 中使用。