Skip to main content

写入默认 (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 的情况下下:

  • 当切换到 Hat On 时,帽子会被打开 
  • 当切换回 Empty State 状态时,帽子会被关闭(因为帽子被写回了默认状态)

禁用 Write Defaults 的情况下:

  • 当切换到Hat On时,帽子会被打开 
  • 当切换到Empty State时,帽子会保持开启状态(因为没有动画将其关闭,也没有写回默认状态)

使用指南

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

  • 不要在同一个控制器中混合使用 Write Defaults。混合使用 Write Defaults 可能使其动画表现得像 Write Defaults Off。
      • 唯一的例外是只有单个状态的动画层。这些层可以使用任意 Write Defaults ON 或者 OFF,并且如果这是一个 Direct Blend Trees 的话,更应该设置为 Write Defaults On。

      • 这样做不会出问题是因为这个动画层只有一个状态,不会受到 Write Defaults On 的影响。

  • 不要将 Direct Blend Trees 设置为 Write Defaults Off。

  • 如果你使用 Write Defaults Off,你的所有状态里都应该包含一个填充动画或一个 Blend Tree。这个填充动画可以是空的,但通常建议使用一个不存在的物体属性,并且有至少两帧(有时候会将这种填充动画称为 Buffer)。

  • 注意,使用 Write Defaults Off 对 Transform 进行动画处理会覆盖所有其他播放的动画控制器中动画化的 Transform。这特别意味着,对于 VRChat,如果你在 FX Layer 中用动画控制任何 Transform,它将覆盖 Gesture layer 中的所有 Transform,除非你设置一个 Avatar Mask,只启用被动画控制的 Transforms 并禁用所有其他 Transforms,并将这个遮罩应用到你的 FX Layer 动画层。有关 Avatar Mask 的更多信息,请参见 Avatar Masks 页面。

译者注释:建议使用一个不存在的物体属性,并且有至少两帧的原因是一个空动画的播放时长大约是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

优点:

  • 更加简单,因为可以使用空状态/ Buffer 状态,这会让物体回到上传时的初始状态。
  • 可以在不覆盖 Gesture 层动画内容的情况下在 FX 层使用 Transform 动画。
  • 在基本的 2 状态切换中,相比于 Write Defaults Off,帧时间消耗少 33%(仅在 Unity 2019)。
  • 可以轻松地修改更改默认状态(如果你依赖于上传时的默认状态的话)。

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

缺点:

  • 依赖于上传时的状态
  • 在混合使用 Write Defaults 时通常会出现问题
  • 在不使用 Parameter Driver 或者 AAP 的情况下无法使用序列操作

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

Write Default Off

优点:

  • 不依赖于上传时的状态
  • 通常可以混合使用 Write Defaults 且不会受到影响
  • 可以使用序列操作

缺点:

  • 在空状态中需要有填充动画
  • 在没有 Avatar Mask 的情况下用动画修改 Transform 时,会覆盖 Gesture 层的所有 Transform 动画。
  • 在基本的 2 状态切换中,相比于 Write Default ON,帧时间消耗多50%(仅在 Unity 2019)。

创作者指南

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

  • 确保每个动画层只对一组属性进行动画(例如,每个状态应对相同的一组属性进行动画)。
  • 如果需要在多个层中对同一属性进行动画,确保每个状态中都有动画,并注意动画器内的靠下的动画层会覆盖靠上的动画层,所以始终在动画器的顶部保留一个 Reset 层作为默认状态。

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

Blendshape 值翻三倍的问题

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

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

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

  • 这个问题似乎是由 Additive 动画层的 Write Defaults Off 引起的。
  • 如果有一个仅包含 Write Defaults Off 状态(如 VRC 提供的默认动画器)的 Gesture 动画层,这个现象就不会发生。但如果有一个正在播放的 Write Defaults On 状态,问题会再次出现。
  • 这个问题与 Avatar Mask 和动画是否实际可达到无关,只要它们存在于动画层上就会引发问题。
  • 如果只使用 0 和 100 的值,它不会影响行为,因为 0.3=0 和 100.3=100(这是由于 Blendshape Camping,你可以在你的 Unity 编辑器中启用这一选项,方法是前往 Project Settings → Player → Other Settings → Clamp Blendshapes(已弃用)。 VRChat 启用了此选项)。
  • 解决这个问题的正确方法是有一个动画始终明确地对 Blendshape 值进行动画处理。
  • 一种快捷且不太完善的解决方法是将空闲层中的状态设置为 Write Defaults On。