Skip to main content

写入默认值(Write Defaults)

概述

Write Defaults(写入默认值)是动画状态中的一个选项,也是许多虚拟形象创作者的头痛之源,因为它们的行为常常出乎意料且难以理解。其预期行为如下:

Write Defaults(写入默认值)字段决定此动画所做的更改是否持久化。

  • 如果启用了 Write Defaults(写入默认值),则在离开动画状态时,动画字段将返回到其默认状态。

  • 如果禁用了 Write Defaults(写入默认值),则更改将保持不变。

默认情况下,Unity 会在新创建的状态上启用 Write Defaults(写入默认值),但 VRChat 提供的示例动画控制器是写入默认值关闭的。

image.png

默认的动画状态,默认启用写入默认值

示例:

如果你有一个帽子,在上传过程中默认是禁用的(即默认关闭),并且你有一个如下所示的层:

image.png

Write Defaults On写入默认值启用)的情况下:

  • 当进入帽子开启状态时,帽子会启用。

  • 当返回到空状态时,帽子会关闭(因为默认状态被写回)。

Write Defaults Off写入默认值关闭)的情况下:

  • 当进入帽子开启状态时,帽子会启用。

  • 当返回到空状态时,帽子会保持启用状态(因为你没有显式地将其关闭或写回默认值)。

指南

在使用 Write Defaults Off写入默认值关闭)时,需要遵循一些指南。以下是这些指南及其存在的原因:

  • 不要在单个控制器中混合使用 Write Defaults Off(写入默认值关闭),混合使用写入默认值会导致所有 Write Defaults On写入默认值启用)的状态无法写入其默认值,从而表现得像写入默认值关闭一样。

    • 唯一的例外是仅包含单一状态的层。这些层可以(并且在直接混合树的情况下,应该)设置为写入默认值启用
    • 这样做是可以的,因为它们永远不会离开其状态,因此我们永远不会依赖写入默认值启用的行为。
  • 不要在 Direct Blend Trees(直接混合树)上使用 Write Defaults Off(写入默认值关闭)

  • 如果使用 Write Defaults Off(写入默认值关闭),所有状态都应包含动画片段或 Blend Tree,这些动画片段可以是空的,但通常建议使用一个动画片段(Animation Clip)来动画化一个不存在的游戏对象(有时称为缓冲片段)。

  • 注意:使用 Write Defaults Off(写入默认值关闭)的变换动画会覆盖其他正在播放的动画控制器中的所有变换动画。具体来说,对于 VRChat,如果你在 FX 层中动画化任何变换,它将覆盖手势层中的所有变换,除非你应用一个 Avatar Mask(虚拟形象遮罩),仅启用动画化的变换并禁用其他所有变换,并将此遮罩应用于你的 FX 层动画层。有关遮罩的更多信息,请参阅虚拟形象遮罩页面。

如果你由于手势层和 FX 层中的写入默认值关闭变换动画而必须使用遮罩,则除了第一个插槽外,你不能在任何插槽上使用材质替换,因为遮罩的变换(无论是启用还是禁用)除了第一个材质插槽外,不能有动画化的材质替换。

一个有用的工具是 VRLabs’ Avatar 3.0 Manager,它可以帮助你检查是否违反了这些规则(至少是第一条和第三条)。在该工具的写入默认值选项卡中,它会告诉你是否混合使用了写入默认值,并在你按下相应按钮时为你设置。请注意,它不会对直接混合树做例外处理,因此它们的动画状态名称中必须包含 (WD On) 以标记为写入默认值启用

image.png

一个确保没有空状态的动画片段示例。

解释

不要在单个控制器中混合使用 Write Defaults(写入默认值)

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

不要在直接 Blend Tree(混合树)上使用 Write Defaults Off(写入默认值关闭)

使用 Write Defaults Off(写入默认值关闭)的直接混合树会表现出奇怪的行为,例如影响其他使用相同参数的直接混合树,并且随着时间的推移会叠加结果,导致意外行为。通常应避免使用。

为了更清楚地解释这种乘法行为,最终结果是,在 Write Defaults Off(写入默认值关闭)的混合树中,最终权重会乘以一个因子 x/(1-yx),其中 x 是当前子节点的权重,y 是其他子节点权重之和除以当前子节点的权重。需要注意的是,如果这个分数的分母为0或更小,值将趋向于无穷大,并且永远不会停止叠加。这意味着,如果你有 n 个子节点,并且将每个子节点的权重设置为 1/n,那么最终结果将是乘数为1,因此这允许你使用 Write Defaults Off(写入默认值关闭)的直接混合树。然而,这并不意味着建议这样做,因为影响其他混合树以及其他奇怪的行为使得直接使用 Write Defaults On写入默认值启用)更加简单。

使用写入默认值关闭时,所有状态都应包含动画片段或混合树

没有动画片段的 Write Defaults Off(写入默认值关闭)状态可能会用其默认值覆盖前一层中的动画片段。

优缺点

Write Defaults On(写入默认值启用)

优点

  • 更简单,因为你可以有空状态/缓冲状态,这些状态会回退到默认的上传行为。

  • 允许在 FX 层上进行变换动画而不会覆盖手势层。

  • 在 Unity 2019 中,基本的两状态切换帧时间减少 33%。

  • 更容易更改默认值(如果你依赖上传状态)。

缺点

  • 依赖上传状态。

  • 通常在使用混合写入默认值时会出问题。

  • 不允许在没有参数驱动器或 AAP 的情况下进行顺序操作。

Write Defaults Off(写入默认值关闭)

优点

  • 不依赖上传状态。

  • 通常可以很好地处理混合写入默认值。

  • 允许顺序操作。

缺点

  • 需要在空状态中使用缓冲动画。

  • 在没有遮罩的情况下动画化变换时,会覆盖所有手势层的变换。

  • 在 Unity 2019 中,基本的两状态切换帧时间增加 50%。

创作者指南

这些指南在创建应同时兼容 Write Defaults On写入默认值启用)和 Write Defaults Off(写入默认值关闭)的预制件时非常有用:

  • 始终让每一层只动画化一组属性(例如,层中的每个状态都应动画化相同的属性集)。

  • 如果需要在多个层上动画化一个属性,请确保每个状态都有一个动画,知道较低的层会覆盖较高的层,并始终在顶部有一个带有默认状态的重置层

如果你遵循本文中概述的指南,每个属性都会被动画化,你的系统将始终适用于 Write Defaults On写入默认值启用)和 Write Defaults Off(写入默认值关闭)

Blendshape(混合形状)值三倍化

在非常特定的条件下,混合形状值在使用 Write Defaults On写入默认值启用)时会变为三倍。

(例如:你有一个空的 Write Defaults On写入默认值启用)状态,它过渡到一个动画化混合形状的 Write Defaults On写入默认值启用)状态。在空的 Write Defaults On写入默认值启用)状态中,动画化 Blend Shape 的默认值会被乘以 3)。

这个问题比其他问题更复杂且不太明确,因此不要将我们在这里所说的视为事实,而应视为观察结果:

  • 它似乎是由 Write Defaults Off(写入默认值关闭)的叠加层引起的。

  • 它可以通过仅包含 Write Defaults Off(写入默认值关闭)状态的手势层(如默认层)来阻止。一个正在播放的 Write Defaults On写入默认值启用)状态会再次导致此问题。

  • 它与任何遮罩以及动画是否可达无关。只要存在于层上就足够了。

  • 只要你只使用值 0 和 100,它不会影响行为,因为 03=0 和 1003=100(由于 Clamp Blendshapes(钳制混合形状),你可以在 Unity 项目中启用此功能:项目设置 → 玩家 → 其他设置 → Clamp Blendshapes(钳制混合形状)(已弃用)。这在 VRChat 中是启用的)。

  • 正确的修复方法是始终显式地动画化混合形状值。
  • 一个快速但不完美的修复方法是将空闲层中的状态设置为 Write Defaults On写入默认值启用)