Skip to main content

约束(Constraints)

VRChat 提供自己的自定义约束系统,允许化身或世界中的变换相对于其他变换进行移动、旋转和缩放。

这旨在作为 Unity 约束系统的直接替代品,并基于 VRChat 化身通常使用约束的方式增加了一些额外功能。如果你以前从未使用过约束,可以参考 Unity 的约束文档。

在创建化身时,应使用 VRChat 约束而非 Unity 约束。如果你的化身包含任何 Unity 约束,当你的化身在游戏中加载时,它们将自动转换为 VRChat 约束,因此直接使用 VRChat 约束可以更准确地表示化身的行为方式以及更准确的性能等级。

对于世界,你可以选择使用 VRChat 约束或 Unity 约束,甚至可以混合使用两者。注意不要过度使用 Unity 约束,因为场景中同时包含太多约束可能会导致严重的性能问题。使用 VRChat 约束提供了额外的可选功能,并且与使用 Unity 约束相比,可能会提高世界的性能。

此页面侧重于一般理解和化身性能。如果你想要从 Udon 或使用 C# 编写的 SDK 工具与约束交互,请查看 VRChat 约束的技术 API。

约束类型​

VRChat 目前提供以下约束类型,它们的设计工作方式与 Unity 的六个内置约束相同:

访问上述链接以获取有关每种约束类型可用设置的更多信息。

高级约束设置​

"高级设置"折叠区域包含 VRChat 约束提供的一些额外功能。

目标变换​

Target Transform(目标变换)设置允许你更改此约束所针对的变换。默认情况下,此设置为空,约束应用于附加约束组件的变换。请注意,无法通过动画更改此变换。

如果你希望将化身或世界预制体上的所有约束组件保留在一个位置,或者如果你正在设置使用约束的系统并希望它在不同化身或世界预制体之间可移植,这可能很有用。

在本地空间中求解​

通常,约束在世界空间中求解,这意味着它将匹配其源的世界位置/旋转/缩放。如果启用了 Solve In Local Space(在本地空间中求解)选项,约束将改为匹配其源的本地位置/旋转/缩放。

这在为化身设置额外的虚拟肢体等情况下很有用。例如,你可能有一个本地求解的旋转约束链,引用了化身真实手臂的每个骨骼,这将使该链随着真实手臂的旋转而旋转。然而,这并不仅限于旋转约束——所有类型都可以使用本地求解。

下面的视频以旋转约束为例说明了全局和本地求解之间的差异。在此片段中,中间和右侧的箭头各使用旋转约束来匹配左侧箭头的旋转,其中中间箭头使用世界空间求解,右侧箭头使用本地空间求解。注意世界求解约束始终与世界空间中目标的旋转匹配。相比之下,本地求解约束始终匹配目标相对于其父骨骼的方向。

冻结到世界​

当启用 Freeze To World(冻结到世界)时,约束忽略其所有源,并将其目标变换锁定在世界空间中。变换的位置/旋转/缩放将保持不变,直到 Freeze To World 被禁用。

此设置最适合通过化身动画或世界 Udon 脚本进行切换。例如,在化身上:

  1. 为 Freeze To World 设置一个表情切换,并默认禁用它。
  2. 当动画剪辑中启用 Freeze To World 时,变换被锁定在世界空间中。
  3. 当动画剪辑中禁用 Freeze To World 时,变换再次跟随约束的源。

这允许化身在世界中的固定位置放下一个物体。当你走开时,该物体不会跟随你的化身。父约束最适合此用途,因为它们可以同时冻结目标变换的位置_和_旋转。但是,Freeze To World 也可用于所有其他约束类型。

要在世界中实现此效果,你需要使用 Udon 脚本更改 FreezeToWorld 的值,而不是使用动画剪辑。

Freeze To World 属性仅影响在"约束设置"部分中选择为冻结的轴。如果你想完全将对象固定到位,必须冻结所有轴。否则,这些轴将不会更新,变换将不会保持锁定在世界空间中。

note

启用 Freeze To World 与禁用约束组件不同!

  • 当约束被禁用时,受影响的变换在本地空间中停止移动。它仍然跟随包含它的对象的移动(例如,应用到化身时你的移动)。
  • 当你启用 Freeze To World 时,约束在本地空间中主动移动变换,以防止它在世界空间中移动。

此外,默认开启 Freeze To World 意味着约束将在加载到场景的瞬间冻结在其起始位置/旋转/缩放。这不是将其放置在世界空间中某个特定位置/旋转/缩放的可靠方法。

解冻时重新烘焙偏移​

当启用 Rebake Offsets When Unfrozen(解冻时重新烘焙偏移)时,约束在通过禁用 Freeze To World 解冻时将重新计算其相对于源的偏移,而不是保持其原始偏移的常规行为。

切换此值本身没有效果——它仅决定在禁用 Freeze To World 时应该发生什么。

性能​

此部分仅适用于化身上使用的约束,因为世界没有应用于它们的性能等级。

有两个与约束相关的性能类别。请参阅性能等级页面了解应用于每个平台的限制。

约束数量​

约束数量相当直接——它是附加到化身上的约束总数,包括禁用的约束。这包括 VRChat 约束和 Unity 约束。Unity 约束在化身在游戏中加载时自动转换为 VRChat 约束。

减少约束总数可以提高化身的性能。

约束深度​

当你在化身上设置约束链时(例如,沿额外肢体的旋转约束链),这些约束需要按特定顺序一次评估一个,从链底部的约束运行到链尖端的约束。如果链上有 3 个约束,则意味着该链的约束深度为 3。化身的总体约束深度等级是整个化身中最长的依赖链。

约束深度可以通过减少最长约束链的长度来降低。请记住,此类别搜索的是最长链而不是所有链的总和——如果你的化身有多个深度为 3 的手臂,则化身的总体得分仍为 3(假设化身上没有其他更长的链)。

约束深度很重要,因为它比仅计算总共有多少约束能更好地估计化身约束的性能。通过组织约束以最小化它们之间的依赖关系,许多约束将能够同时运行,与必须依次运行的情况相比,这可以带来更好的性能。

使用 Unity 约束时的约束深度

化身的约束深度只有在完全使用 VRChat 约束时才能准确计算。

如果你的化身包含任何 Unity 约束,约束深度可能会被高估,因为该类别假设 Unity 约束一次只能运行一个。你可以使用 SDK 控制面板中的相关自动修复选项,将化身中的所有 Unity 约束转换为等效的 VRChat 约束。

使用技巧​

  • 如果约束似乎不起作用,请确保它实际正在运行。
    • 应启用 Is Active(已激活)选项。
    • 组件本身应已启用(名称旁边的复选框),并且应附加到活动的游戏对象上。
    • 确保启用了 Lock(锁定)选项。否则,约束将重新评估其 At Rest(静止)和 Offset(偏移)值,而不是影响变换。
  • Target Transform 引用不能通过动画或 Udon 脚本更改。这是因为约束所针对的变换在运行时被缓存以提高性能。如果要更改约束的目标变换,可以尝试在几个具有不同目标变换的不同约束组件之间切换。
  • 如果可以避免,不要使用动画或 Udon 脚本更改约束引用的变换。在运行时更改变换引用可能会导致化身出现性能问题,因为每次引用更改时约束可能需要重新评估。
    • 这特指更改约束对变换的_引用_——对变换的位置、旋转和缩放进行动画是可以的!
    • 在化身上,由于技术限制,无法为单个源动画化变换引用。作为更简单的替代方案,你可以设置多个具有不同变换的源,并对它们的权重进行动画化。