这篇条目有关 Source引擎。如需详情,点击这里。

$proceduralbones

From Valve Developer Community
< Zh
Jump to navigation Jump to search
English (en)中文 (zh)Translate (Translate)

$proceduralbones是一个QC 命令(en),可在所有的 起源 起源 游戏中使用。 它使用一个特殊的定义文件(VRD)来告诉引擎在运行时自动为某些骨骼生成动画。

概念

程序化骨骼(在其他地方也被称为骨骼“驱动器”(Blender)或“驱动关键帧”(Maya))通过一个骨骼的旋转来驱动另一个骨骼的旋转和位移。第一个骨骼——称为 驱动控制 骨骼——通常由人类动画师进行操作,而第二个骨骼——称为 程序化辅助 骨骼——根据驱动骨骼的旋转,自动旋转和/或位移。特殊的旋转关键帧,在VRD文件中被称为“触发器”,用于将驱动骨骼的运动范围映射到程序化骨骼的运动范围。

带有沿轴扭转骨骼的人的前臂,是Source中程序化骨骼的典型示例。当手部骨骼顺时针旋转时,前臂中的扭转骨骼也会自动顺时针旋转。当手部骨骼逆时针旋转时,扭转骨骼同样会逆时针旋转。这两种旋转的范围都可以在VRD文件中轻松控制。

程序化骨骼的常见应用

thumb(en)

  • 减少完成一个姿势或动画所需的时间,因为艺术家需要操作的骨骼更少。
  • 改善模型在运行时导入动画(例如通过$includemodel(en))时的外观,这些动画可能不会为模型的所有骨骼生成动画(尤其是扭转骨骼)。
  • 对网格应用校正蒙皮,减轻因Source的线性蒙皮模型和动画规则导致的变形问题。

扭转骨骼

在Source中,程序化骨骼最常见的用例是将前两个原则应用于扭转骨骼,例如在人类模型的前臂、上臂、大腿和小腿中。在右侧的示意图中,一个扭转骨骼位于前臂的中部(ValveBiped.Bip01_L_Ulna),另一个扭转骨骼位于手腕(ValveBiped.Bip01_L_Wrist),网格也相应地进行了蒙皮。与其要求动画师同时为手部、手腕和尺骨进行姿势调整,$proceduralbones 可以在动画师仅旋转手部骨骼时,自动旋转尺骨和手腕骨骼。这不仅节省了创建新姿势的时间和精力,还在导入使用更简单的骨骼结构(可能不包含任何扭转骨骼)创建的姿势和动画时同样节省了时间。

校正变形

在应对Source引擎对每个蒙皮顶点仅支持三个骨骼影响的古老限制时,尤其是在双足动物或四足动物的胸部或骨盆等区域,这可能会变得非常困难。程序化骨骼有两种主要方式可以改善这些问题区域的网格变形质量。

叶子骨骼

在Source的线性蒙皮模型导致网格体积丢失的区域,例如肘部或膝部,程序化骨骼可以用来抵消网格的不良收缩或拉伸。在问题区域引入一个或多个叶骨骼,并相应地进行蒙皮。然后,使用$proceduralbones,叶骨骼的旋转和位移可以由肘部或膝部骨骼的旋转驱动。

校正Flex

在某些支持$boneflexdriver(en)的引擎分支中,可以使用程序化骨骼自动淡入和淡出Flex。这种技术最适用于将局部校正或有限的Delta Mush形状应用到网格的某些区域,这些区域在摆出极端姿势时通常会出现低质量的变形。使用此技术时需要注意,因为每个校正Flex都会占用一个Flex控制器槽,并需要模型骨骼中对应的骨骼来驱动。这会迅速累积,从而消耗掉MDL的Flex控制器限制(通常为96或128)和骨骼限制(en)(通常为128),减少模型可用的正常Flex和骨骼数量。

Note.png注意: 偏离官方规范,但已在以下游戏中测试并有效:半衰期2反恐精英:起源军团要塞2传送门Garry's Mod
Warning.png警告: 具有额外要求。请参考本文末尾的章节 使用程序化骨骼驱动Flex(en)

自碰撞近似

程序化骨骼可以快速而粗略地模拟模型部件之间的碰撞。例如,考虑一个穿西装外套的人体模型。西装下摆可以简单地蒙皮到大腿骨骼上,这样当模型抬起膝盖时,下摆会弯曲。或者,下摆可以蒙皮到一个独立的骨骼上,并使用$proceduralbones让下摆骨骼在大腿骨骼旋转时跟着旋转。在后一种情况下,下摆在模型抬起膝盖时仍会弯曲,但动画师现在可以独立地调整大腿和下摆的姿势,从而提高模型的灵活性。更进一步,可以在西装外套的前、侧和后部分别创建多个下摆骨骼,并使用$proceduralbones让模型的大腿移动时,仅移动正确的下摆骨骼。这样,当模型抬起膝盖时,外套的后下摆保持不动,仅前下摆弯曲。此概念还可以应用于变形模型上的刚性配件,特别是在多个骨骼影响变形网格的区域。

语法

$proceduralbones <configuration file>

$proceduralbones唯一有效的参数是一个特殊的VRD(Valve rig data(?))配置文件的名称,该文件指定哪些骨骼是程序化骨骼及其行为。此文件的格式将在下文中详细描述。

VRD文件

VRD文件类似于Maya中的驱动关键帧。首先定义驱动骨骼和程序化骨骼的重要层级关系,然后指定两个或更多的“触发器”。每个触发器将驱动骨骼的一个离散旋转映射到程序化骨骼的一个离散旋转和/或位移。在运行时,引擎会在所有定义的触发器之间自动插值程序化骨骼的姿势,并且偏向于驱动骨骼最接近的触发器。

Tip.png提示:VRD文件支持C风格的注释、制表符、空格等。空行会被忽略,可以用来提高可读性。

定义块

由于$proceduralbonesQC文件中只能使用一次,因此一个VRD文件可以定义多个程序化骨骼。每个定义块都以<helper>行开始,以<basepos>行跟随,并由一个或多个<trigger>行完成。要定义另一个程序化骨骼,只需在上一个<trigger>行之后以新的<helper>行开始一个新的定义块。

示例:HWM Femscout模型的手工VRD文件

以下VRD文件使用Source Filmmaker设置,但你也可以使用支持Source模型的任何建模软件。

<helper> hlp_forearm_L   bip_lowerArm_L   bip_lowerArm_L   bip_hand_L
<basepos> -0.0003 -4.7578 -0.000685692
<trigger> 90 	-0.140879 -7.0729 0.923253 		2.05439e-06 -0.00011566 -0.0109454 	0 0 0
<trigger> 90 	-157.919 -89.6281 158.827 		0.101044 -61.3622 -0.505184 		0 0 0
<trigger> 90 	-0.905463 81.1157 0.0128013 	-1.79037e-05 49.6029 -0.0109647 	0 0 0

<helper> hlp_forearm_R   bip_lowerArm_R   bip_lowerArm_R   bip_hand_R
<basepos> -0.0502548 4.76207 -0.0109539
<trigger> 90 	-0.116485 -7.07782 0.923253 	-26.1455 -71.739 -60.6497 		0 0 0
<trigger> 90 	-0.288436 72.9621 0.610626 		-72.1773 -44.2586 -20.2743 		0 0 0
<trigger> 90 	-179.149 -81.8242 -179.905 		81.3212 -37.0352 -157.273 		0 0 0

此模型的源文件可从 MaxOfS2D的网站 获取。

构建一个定义块

第一步:<helper>

每个定义块都以<helper>行开始。此行指定了驱动骨骼、程序化骨骼及其父骨骼的关系。

<helper> ProceduralBone   ParentOfProceduralBone   ParentOfDriverBone   DriverBone
  • ProceduralBone 是程序化动画的骨骼的名称。在典型的人体前臂设置中,这通常是尺骨扭转骨骼。
  • ParentOfProceduralBone 必须是ProceduralBone的父骨骼。
  • ParentOfDriverBone 必须是DriverBone的父骨骼。
  • DriverBone 是其旋转将导致ProceduralBone动画的骨骼。在典型的人体前臂设置中,这通常是手部骨骼。

示例: <helper> hlp_forearm_L bip_lowerArm_L bip_lowerArm_L bip_hand_L

Warning.png警告:某些字符在骨骼名称中出现会导致studiomdl中止运行。注意,这包括Valve骨骼中常用的.句号字符。为了解决这个问题,在将骨骼名称输入到VRD文件时,删除句号及之前的所有内容。例如,不要写ValveBiped.Bip01_L_Hand,而是输入Bip01_L_Hand

骨骼层级的注意事项

如果ProceduralBoneDriverBone是兄弟节点,则ParentOfProceduralBoneParentOfDriverBone将是同一个骨骼。这种情况常见于手臂和腿部的扭转骨骼设置中。

另外,也可以定义一种程序化规则,其中程序化骨骼和驱动骨骼不是兄弟节点。因此,ParentOfProceduralBoneParentOfDriverBone将是不同的骨骼。在这种情况下,骨架层级中必须存在ParentOfProceduralBoneParentOfDriverBone之间的明确路径。可能的三种情况包括:1) ParentOfProceduralBoneParentOfDriverBone共享一个共同的祖先骨骼;2) ParentOfProceduralBoneParentOfDriverBone的直接父级;或者3) ParentOfDriverBoneParentOfProceduralBone的直接父级。最后,程序化骨骼也可以直接成为驱动骨骼的子节点,在这种情况下,ParentOfProceduralBoneDriverBone将是相同的。

第二步:<basepos>

这是程序化骨骼在其父骨骼的本地坐标系中的参考平移位置。

<basepos> X Y Z

示例: <basepos> -0.0003 -4.7578 -0.000685692

你可以在建模软件中编写或寻找脚本来计算该值。 或者,你可以使用Crowbar工具来获取此值而无需使用建模软件。反编译你的模型,然后找到$definebone行中对应程序化骨骼的定义。前3个数字就是该骨骼在其父骨骼坐标系中的参考位置。

第三步:参考<trigger>

每个<trigger>是一个关键帧,用于将驱动骨骼的观察旋转映射到程序化骨骼的期望旋转。虽然不是绝对必要,但第一个<trigger>应指定驱动骨骼和程序化骨骼的参考姿态旋转。

<trigger> AngleOfInfluence   Vec3_WatchedDriverBoneRotation   Vec3_DesiredProceduralBoneRotation   Vec3_DesiredProceduralBoneTranslation
  • AngleOfInfluence 是以角度(度)为单位,指定驱动骨骼需要旋转多大幅度,才能让程序化骨骼达到其旋转和平移的完全效果。
可以将AngleOfInfluence想象为一个锥体;当驱动骨骼的观察旋转达到或超过锥体的边界时,程序化骨骼将达到其期望的旋转和平移的完全效果。较大的角度(如90度)意味着驱动骨骼需要旋转较大幅度才能达到完全效果,而较小的角度(如30度)则需要较小幅度的旋转。
  • Vec3_WatchedDriverBoneRotation 是驱动骨骼的输入旋转,以为单位,表示为 X Y Z 欧拉角。
  • Vec3_DesiredProceduralBoneRotation 是程序化骨骼的输出旋转,以为单位,表示为 X Y Z 欧拉角。
  • Vec3_DesiredProceduralBoneTranslation 是程序化骨骼的平移值,在其父骨骼的本地坐标系中表示。此值相对于前面定义的<basepos>

将你的模型放置在参考姿态中,然后获取Vec3_WatchedDriverBoneRotationVec3_DesiredProceduralBoneRotation在父骨骼坐标系中的旋转值。此时Vec3_DesiredProceduralBoneTranslation的值将为0 0 0。在VRD文件中输入新的<trigger>行。

示例:

//        AoI 	Vec3_WatchedDriverBoneRotation 	Vec3_DesiredProceduralBoneRotation 	Vec3_DesiredProceduralBoneTranslation
<trigger> 90 	-0.140879 -7.0729 0.923253 		2.05439e-06 -0.00011566 -0.0109454 	0 0 0

选择 Angle of Influence

每个<trigger>可以有不同的AngleOfInfluence值。参考<trigger>AngleOfInfluence通常应该是驱动骨骼可能经历的最大角度偏转值。 最好的方法是先确定每个极限<trigger>AngleOfInfluence(详见后续部分),然后选择拥有最大AngleOfInfluence的极限<trigger>,并将其值复制到参考<trigger>AngleOfInfluence

第四步:极限<trigger>

这是程序化骨骼动画的真正定义步骤。 1. 首先,确定驱动骨骼的运动范围极限。对于不同的模型部分,这一范围会有所不同。例如,人类前臂的手部驱动骨骼通常可以顺时针和逆时针旋转约100度。 2. 在建模软件中,将驱动骨骼旋转到第一个极限位置。这就是观察到的驱动骨骼旋转值。 3. 相应地调整程序化骨骼的位置,使模型看起来“合理”。这就是期望的程序化骨骼旋转和平移值。

获取Vec3_WatchedDriverBoneRotationVec3_DesiredProceduralBoneRotation在父骨骼坐标系中的旋转值。如果没有对程序化骨骼进行平移,则Vec3_DesiredProceduralBoneTranslation将为0 0 0;否则,还需要获取程序化骨骼在父骨骼坐标系中的平移值。最后,确定合适的AngleOfInfluence值;在大多数情况下,可以简单地选择驱动骨骼新旧旋转之间的角度。将新的<trigger>行写入VRD文件。

示例:

//        AoI 	Vec3_WatchedDriverBoneRotation 	Vec3_DesiredProceduralBoneRotation 	Vec3_DesiredProceduralBoneTranslation
<trigger> 90 	-157.919 -89.6281 158.827 		0.101044 -61.3622 -0.505184 		0 0 0

重复上述过程,为驱动骨骼的每个极限姿态创建新的<trigger>。完成后,定义块中应至少包含两个<trigger>:第一个是参考<trigger>,后续的是极限<trigger>

示例:

<helper> hlp_forearm_L   bip_lowerArm_L   bip_lowerArm_L   bip_hand_L
<basepos> -0.0003 -4.7578 -0.000685692
<trigger> 90 	-0.140879 -7.0729 0.923253 		2.05439e-06 -0.00011566 -0.0109454 	0 0 0
<trigger> 90 	-157.919 -89.6281 158.827 		0.101044 -61.3622 -0.505184 		0 0 0
<trigger> 90 	-0.905463 81.1157 0.0128013 	-1.79037e-05 49.6029 -0.0109647 	0 0 0

Template:注意

示例:人类前臂的处理流程

总共需要三个<trigger>:1)参考姿势,2)驱动骨骼(手部)顺时针旋转至最大角度的姿势,以及3)驱动骨骼逆时针旋转至最大角度的姿势。手部应该如何旋转是一个主观决定,具体取决于您的模型。最终目标是通过创建程序化骨骼来改善模型外观,因此请选择看起来最好的选项。

  • 创建参考姿势的<trigger>,方法如上所述。
  • 创建顺时针极限姿势的<trigger>
 # 沿前臂轴线,将手部骨骼顺时针旋转至预期的最大角度。  
 # 沿前臂轴线,将尺骨扭转骨骼顺时针旋转,直到网格的变形效果看起来可以接受。  
 # 为该姿势输入一个<trigger>
  • 将模型恢复到参考姿势。
  • 创建逆时针极限姿势的<trigger>
 # 沿前臂轴线,将手部骨骼逆时针旋转至预期的最大角度。  
 # 沿前臂轴线,将尺骨扭转骨骼逆时针旋转,直到网格的变形效果看起来可以接受。  
 # 为该姿势输入一个<trigger>
Tip.png提示:请参考本文前面提到的 femscout VRD 示例,以确保您的VRD文件布局正确。

收尾与特殊注意事项

对于对称模型(如人类),您需要重复上述流程,为角色的镜像侧创建相同的程序化骨骼布局。除非您完全了解自己在做什么,否则**不要**直接复制左侧骨骼的所有数值到右侧骨骼,或反之亦然。请逐步完成整个流程,并为每一个需要定义的程序化骨骼创建一个新的定义块。

一个程序化骨骼**不能**同时被两个或更多驱动骨骼控制。但反过来是可以的:一个驱动骨骼可以多次被复用,用于控制多个程序化骨骼。

杂项

您可以为一个触发器指定一个无用的名称:

  
<trigger> 90 -6.75868e-015 1.59028e-015 3.18055e-015 0 0 0 0 0 0 UselessTriggerName

此名称没有任何功能意义,并会被忽略。

其他有效关键字

除了<helper><basepos><trigger>,studiomdl 在 VRD 文件中还接受一些其他关键字。

<display>

<display>关键字由 Softimage Mod Tool 使用,用于存储程序化骨骼在 Mod Tool 视口中的外观属性。如果您不使用 Softimage,则它毫无用处。

<rotateaxis> X Y Z

以 X Y Z 欧拉角的形式指定。在所有后续<trigger>行中,Vec3_DesiredProceduralBoneRotation角度会被此角度进行**前**乘。

待完善: 确定此功能的实际用途。

<jointorient> X Y Z

以 X Y Z 欧拉角的形式指定。在所有后续<trigger>行中,Vec3_DesiredProceduralBoneRotation角度会被此角度进行**后**乘。

待完善: 确定此功能的实际用途。

<aimconstraint>

  
<aimconstraint> ProceduralBone ParentOfProceduralBone TargetBoneOrAttachment

与其他关键字<aimvector><upvector>一起工作。据推测,该关键字用于创建一个类似于 Maya 中目标约束的程序化骨骼。

待完善: 进一步研究此功能。


指南

使用程序化骨骼驱动变形

如前所述,使用$proceduralbones自动驱动$boneflexdriver可以实现高级的变形技术,如自动修正形状。在大多数Source游戏和引擎分支中,编译模型时需要额外的两个步骤才能实现这种技术。

步骤1:修改studiomdl

零售版studiomdl拒绝编译任何在$proceduralbones的VRD文件中标记为ProceduralBone的骨骼使用$boneflexdriver。需要额外的努力来修改输出的MDL文件或studiomdl本身,以允许这种组合。后一种方法通常是最简单的路径。

使用您选择的十六进制编辑器,可以修补studiomdl,跳过早期退出并成功编译您的模型。请注意,修改后的studiomdl可能会生成与引擎预期规范不同的MDL文件,这些MDL文件可能在某些游戏或引擎分支中无法使用。

 : 即大多数IDST0游戏,包括半衰期2 半衰期2反恐精英:起源 反恐精英:起源传送门 传送门军团要塞2 军团要塞2Garry's Mod Garry's Mod
 : 搜索唯一的字节序列04 74 25 8D 4F,然后将字节74更改为EB
 : 搜索唯一的字节序列04 74 25 8B,然后将字节74更改为EB
 : 搜索唯一的字节序列04 74 1C 8B 56 5C,然后将字节74更改为EB
 : 搜索唯一的字节序列04 74 28 8B,然后将字节74更改为EB
待完善: 确定其他著名游戏(包括求生之路求生之路2)的补丁位置

步骤2:$bonemerge

在模型的QC文件中,您必须为每个程序化骨骼指定$bonemerge。请参考您的VRD文件,并为每个<helper>行中的ProceduralBone添加$bonemerge行。DriverBone不需要$bonemerge

尚不完全理解为何需要这个看似无关的$bonemerge标志。

步骤3:编译您的模型

修改studiomdl并为所有程序化骨骼指定$bonemerge后,您现在可以编译您的模型。在HLMV中测试并验证一切是否按预期工作。骨骼的动画驱动程序化骨骼,程序化骨骼反过来驱动flexcontroller。