$proceduralbones: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(added link to guide making procedurals entirely in blender. Swapped "Wayback machine" link with backup on steam guides)
(Overall article rework. (Much) more verbose, more topics covered, (much) more coverage of existing topics, and more accurate technical information.)
Line 1: Line 1:
'''$proceduralbones''' tells the engine to animate certain bones itself. See [https://web.archive.org/web/20170521072846/http://forums.steampowered.com/forums/showthread.php?t=651604 this thread] for details.
'''$proceduralbones''' uses a special definition file (VRD) to tell the engine to automatically animate certain bones at runtime.
 
 
== Concept ==
Procedural bones, elsewhere known as bone "drivers" (Blender) or "driven keys" (Maya), use the rotation of one bone to drive the rotation and translation of another bone. The first bone - called the '''''driver''''' or ''control'' bone - is typically animated by a human, while the second bone - called the '''''procedural''''' or ''helper'' bone - automatically rotates and/or translates itself, according to the rotation of the driver bone. Special rotation keyframes, called "triggers", are used to specify and map a range of motion in the driver bone to a range of motion in the procedural bone.
 
The human forearm, skinned with along-axis twist bones, is the poster child of procedural bones in Source. When the hand bone rotates clockwise, the twist bone in the forearm automatically rotates clockwise as well. When the hand bone rotate counterclockwise, the twist bone also rotates counterclockwise. The extents of both rotations can be easily controlled in the VRD file.
 
 
== Common applications of procedural bones ==
[[File:Valve_biped_forearm_with_twist_bones.png|thumb|240px|The forearm of a full Valve biped skeleton. Note the ulna and wrist bones, both of which are "twist" bones and may be procedurally driven by the rotation of the hand bone.]]
* Reduce the time required to complete a pose or animation, since fewer bones need to be manipulated by the artist.
* Improve the appearance of a model when it imports an animation at runtime, i.e. via [[$includemodel]], that does not animate all of the model's bones (notably, twist bones).
* Apply corrective skinning and/or corrective flexes to the mesh, mitigating deformities caused by Source's linear skinning model and animation rules.
 
=== Twist bones ===
The most common use-case of procedural bones in Source is to apply the first two principles to twist bones, such as in the forearms, upper arms, thighs, and shins of human models. In the diagram at the right, a twist bone is placed in the middle of the forearm (''ValveBiped.Bip01_L_Ulna''), another twist bone is located on the wrist (''ValveBiped.Bip01_L_Wrist''), and the mesh is skinned accordingly. Rather than require the animator to pose the hand, wrist, and ulna all together, <code>$proceduralbones</code> can be used to automatically rotate the ulna and wrist bones when the animator rotates only the hand bone. This saves time and effort not just when creating new poses, but also when importing poses and animations that were created on a simpler skeleton which might not include any twist bones.
 
=== Corrective Deformations ===
Working around Source's archaic limit of three bone influences per skinned vertex can be difficult, especially in regions such as the chest or pelvis of a biped or quadruped. There are two major ways that procedural bones can be used to improve the quality of mesh deformation in these problematic areas.
 
==== Leaf Bones ====
In areas where Source's linear skinning model causes loss of mesh volume, such as the elbows or knees, procedural bones can be used to counteract the undesirable pinching or stretching of the mesh. Introduce one or more leaf bones in the problematic area, and skin the mesh accordingly. Then, using <code>$proceduralbones</code>, the rotation and translation of the leaf bones can be driven by the rotation the elbow or knee bone.
 
==== Corrective Flexes ====
In engine branches that support [[$boneflexdriver]], procedural bones can be used to automatically fade in and fade out flexes without any need for programming. A flex can be created which adds volume to the elbow or knee joint, and a dummy child bone can be created under the joint. Then, using <code>$boneflexdriver</code> on the dummy bone and <code>$proceduralbones</code>, the rotation of the elbow or knee bone can drive the translation of the dummy bone, which in turn will fade-in the corrective flex as the mesh deforms. This technique is often superior to the use of procedural leaf bones, but every corrective flex counts towards the [[MDL]] flex limit of 96 or 128, possibly reducing the number of regular, non-corrective flexes that can fit on the model.
 
=== Self-collision Approximation ===
Procedural bones can simulate a quick and dirty approximation of collision between a model's parts. For example, consider a human model wearing a suit jacket. The hem of the jacket could be simply skinned to the thigh bones, such that the hem bends when the model lifts its knee. Alternatively, the hem could be skinned to a separate bone, and <code>$proceduralbones</code> could be used to tell the hem bone to rotate when the thigh bone rotates. In the latter scenario, the hem still bends when the model lifts its knee, but the animator can now pose the thigh and hem independently, improving the model's versatility. Going a step further, several hem bones can be created on the front, sides, and back of the suit jacket, and <code>$proceduralbones</code> can be used to only move the correct hem bone when the model's thigh moves. This way, when the model lifts its knee, the back hem of the jacket remains stationary, with only the front hem bending. This concept can also be applied to rigid accessories on a deforming model, especially in areas where multiple bones exert influence over the deforming mesh.
 


== Syntax ==
== Syntax ==
<source lang=php>
<source lang=php>
$proceduralbones <configuration file>
$proceduralbones <configuration file>
</source>
</source>


Configuration files are special VRD ('''V'''alve '''r'''ig '''d'''ata (?)) files. They are described below.
The only valid argument to <code>$proceduralbones</code> is the name of a special VRD ('''V'''alve '''r'''ig '''d'''ata (?)) configuration file, which specifies which bones are procedural and their behavior. The format of this file is described in the sections below.




== VRD files ==
== VRD files ==
VRD files are essentialy keyframe animations for the helper bone with 'triggers' as keyframes. When Source sees that your control bone (e. g. the wrist) is closing towards a specified rotation, it will start rotating and translating (lerp) the helper bone (e. g. the forearm) towards the 'keyframed'  position and rotation. E. g. forearm twist has three keyframes, one for the base position and two extremes. IF the hand is twisted right, the forearm twist right too and vice versa.
VRD files work similarly to driven keys in Maya. The important hierarchy of the driver and procedural bones are defined, then two or more "triggers" are specified. Each trigger maps a discrete rotation of the driver bone to a discrete rotation and/or translation of the procedural bone. At runtime, the engine automatically interpolates the pose of the procedural bone between all of the defined triggers, biasing most towards whichever trigger the driver bone is closest to.
 
{{ModernTip|VRD files support C-style comments, tabs, spaces, etc. Empty lines are ignored and can be used to improve readability.}}


VRD files support C++-style comments, tabs, spaces, etc.
=== The Definition Block ===
Since <code>$proceduralbones</code> can only be used once in your [[QC]] file, a single VRD file can define multiple procedural bones. Each definition block starts with a <code><helper></code> line, a <code><basepos></code> line, and is finished by one or more <code><trigger></code> lines. To start a new definition block and define another procedural bone, simply start with a new <code><helper></code> line after the last <code><trigger></code> line.
 
==== Example: Hand-made VRD file for HWM Femscout model ====
Source Filmmaker was used to set up this VRD file, but you can use any modeling software that supports Source models.


==== Declaring a procedural bone ====
<source lang=xml>
<source lang=xml>
<helper> hlp_forearm_L bip_lowerArm_L bip_lowerArm_L bip_hand_L
<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
</source>
</source>
This tells the engine that we want a procedural bone <code>hlp_forearm_L</code>, its root bone is <code>bip_lowerArm_L</code>, its parent is <code>bip_lowerArm_L</code>, too, and its movements will be driven by <code>bip_hand_L</code>.
This model with source files is available [http://source.maxofs2d.net/index.php?dir=models%2Ftf_femscout_enhanced%2F here] on MaxOfS2D's website.<br>
{{note| It is not possible for one helper bone being controlled by two bones, even if you list it once with one control bone and a second time with another. Rigging one mesh to two bones won't help either. }}
 
== Building a Definition Block ==
 
=== Step 1: <helper> ===
Every definition block starts with a <code><helper></code> line. It specifies the driver bone, the procedural bone, and their parents.
 
<source lang=xml>
<helper> ProceduralBone  ParentOfProceduralBone  ParentOfDriverBone  DriverBone
</source>
* <code>ProceduralBone</code> is the name of the bone which will be procedurally animated. In a typical human forearm setup, this would be the ulna twist bone.
* <code>ParentOfProceduralBone</code> must be the parent of <code>ProceduralBone</code>.
* <code>ParentOfDriverBone</code> must be the parent of <code>DriverBone</code>.
* <code>DriverBone</code> is the name of the bone whose rotation will cause <code>ProceduralBone</code> to animate. In a typical human forearm setup, this would be the hand bone.
 
''Example:'' <code><helper> hlp_forearm_L  bip_lowerArm_L  bip_lowerArm_L  bip_hand_L</code>
 
{{ModernNote|If <code>ProceduralBone</code> and <code>DriverBone</code> are siblings, then <code>ParentOfProceduralBone</code> and <code>ParentOfDriverBone</code> will be the same bone. This is often the case for twist bone setups in arms and legs. It is possible, however, to define a procedural bone wherein the procedural and driver bones are not siblings. In this case, <code>ParentOfProceduralBone</code> and <code>ParentOfDriverBone</code> will be different bones. When the driver bone and procedural bone are not siblings, they must share a common ancestor bone!}}
 
{{ModernWarning|The presence of certain characters in any of the bone names will cause studiomdl to abort. Note that this includes the <code>.</code> period character, which is commonly used in Valve's skeletons. To work around this, simply strip everything up to and including the period when you enter your bone names into the VRD file. For example, instead of writing ''ValveBiped.Bip01_L_Hand'', put ''Bip01_L_Hand''. }}
 
=== Step 2: <basepos> ===
This is the '''reference''' translation of the procedural bone in the local coordinate system of its parent bone.


==== Declaring a base position ====
<source lang=xml>
<source lang=xml>
<basepos> X Y Z
<basepos> X Y Z
</source>
</source>
Basepos specifies the base translation of the helper bone. It should normally correspond to the helper's default position in your model's default state. Use a 3D editor to read the values or write a script/plugin.<br>
The numbers can also be found as the first three numbers in the $definebone line of that bone.<br>
NB: All translation values and rotation angles are in parent bone's space. All angles are Euler rotations, and are in degrees.


==== Declaring a keyframe (trigger) ====
''Example:'' <code><basepos> -0.0003 -4.7578 -0.000685692</code>
 
Find or create a script to calculate this value in your modeling software.
Alternatively, you can use [[Crowbar]] to get this value without needing modeling software. Decompile your model, then find the <code>[[$definebone]]</code> line for the procedural bone. The first 3 numbers are the bone's reference position in parent-bone-space.
 
=== Step 3: The Reference <trigger> ===
Each <code><trigger></code> is a keyframe that maps a desired rotation of the procedural bone to a watched rotation of the driver bone. The first <code><trigger></code> should specify the reference pose of the procedural bone and driver bone.
 
<source lang=xml>
<source lang=xml>
<trigger> AngleOfInfluence Vec3D_WatchedControlBoneRotation Vec3D_DesiredHelperRot Vec3D_DesiredHelperPos
<trigger> AngleOfInfluence   Vec3_WatchedDriverBoneRotation  Vec3_DesiredProceduralBoneRotation  Vec3_DesiredProceduralBoneTranslation
</source>
</source>


For every keyframe Source checks if the difference between  the control bone's ''current'' rotation and <code> WatchedControlBoneRotation </code> is smaller than the <code> AngleOfInfluence </code> (think of this angle as a cone). If it is smaller, then Source 'lerps' the helper's rotation and position towards <code> DesiredHelperRot </code> and <code> DesiredHelperPos</code>. <code> DesiredHelperPos </code> is given as an offset from basepos. The closer is the control bone's rotation to the <code> WatchedControlBoneRotation</code>, the closer will the helper's rotation and position be to <code> DesiredHelperRot </code> and <code> DesiredHelperPos </code>.
* <code>AngleOfInfluence</code> is in degrees and specifies how far the driver bone must rotate in order for the procedural bone to reach the extent of its keyframed pose. With a larger angle, like 90 degrees, the driver bone must rotate a great deal before the procedural bone reaches its keyframed pose. With a smaller angle, like 30 degrees, the driver bone does not need to rotate very far in order for the procedural bone to reach its keyframed pose. Think of this angle like a cone; the procedural bone reaches the full extent of its keyframed pose when the driver bone reaches or exceeds the bounds of the cone.
* <code>Vec3_WatchedDriverBoneRotation</code> is the input rotation of the driver bone, specified in '''degrees''' as XYZ Euler angles.
* <code>Vec3_DesiredProceduralBoneRotation</code> is the output rotation of the procedural  bone, specified in '''degrees''' as XYZ Euler angles.
* <code>Vec3_DesiredProceduralBoneTranslation</code> is the translation of the procedural bone, in the local coordinate system of its parent bone. This value is relative to the <code><basepos></code> defined earlier!
 
Place your model in its reference pose, then gather the parent-bone-space rotations for <code>Vec3_WatchedDriverBoneRotation</code> and <code>Vec3_DesiredProceduralBoneRotation</code>. <code>Vec3_DesiredProceduralBoneTranslation</code> will be <code>0 0 0</code>. Type out the new <code><trigger></code> line in your VRD file.


Example keyframe:
''Example:''
<source lang = xml>
<source lang=xml>
//             AoI     Watched control rotation        Desired helper rotation          Desired helper translation
//       AoI Vec3_WatchedDriverBoneRotation Vec3_DesiredProceduralBoneRotation Vec3_DesiredProceduralBoneTranslation
<trigger> 90 -179.149 -81.8242 -179.905 81.3212 -37.0352 -157.273        0 0 0
<trigger> 90 -0.140879 -7.0729 0.923253 2.05439e-06 -0.00011566 -0.0109454 0 0 0
</source>
</source>


==== Example: Hand-made VRD file for HWM Femscout model ====
==== Choosing an Angle of Influence ====
Source Filmmaker was used to setup keyframes for that model, but you can use any 3D app that supports Source models in some flavor.
You can specify a different <code>AngleOfInfluence</code> for every <code><trigger></code> in your definition block, but in practice, your procedural bone will be limited by the smallest <code>AngleOfInfluence</code>. The ideal angle of influence is the same amount by which you are rotating your driver bone to produce the extreme <code><trigger></code>s for your procedural bone. For example, consider a human forearm. If you plan to rotate the hand bone +90 and -90 degrees for your two extreme <code><trigger></code>s, then you should specify 90 for your <code>AngleOfInfluence</code> for every trigger. If you only plan to rotate the driver bone ±45 degrees, put 45 for your <code>AngleOfInfluence</code>.
 
=== Step 4: The Extreme <trigger>s ===
There is where the procedural animation of your procedural bone is finally defined. First, determine the extreme(s) of your driver bone's range of motion. Then, in your modeling software, rotate the driver bone to one extreme, and pose the procedural bone accordingly. Gather the parent-bone-space rotations for <code>Vec3_WatchedDriverBoneRotation</code> and <code>Vec3_DesiredProceduralBoneRotation</code>. If you did not translate the procedural bone, then <code>Vec3_DesiredProceduralBoneTranslation</code> will be <code>0 0 0</code>; otherwise, also gather the parent-bone-space translation of the procedural bone. Type out the new <code><trigger></code> line in your VRD file.


''Example:''
<source lang=xml>
<source lang=xml>
<helper> hlp_forearm_R bip_lowerArm_R bip_lowerArm_R bip_hand_R
//        AoI Vec3_WatchedDriverBoneRotation Vec3_DesiredProceduralBoneRotation Vec3_DesiredProceduralBoneTranslation
<basepos> -0.0502548 4.76207 -0.0109539
<trigger> 90 -157.919 -89.6281 158.827 0.101044 -61.3622 -0.505184 0 0 0
<trigger> 90 -0.116485  -7.07782 0.923253 -26.1455 -71.739 -60.6497 0 0 0
</source>
<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
Repeat this process and create a new <code><trigger></code> for each extreme of the driver bone. When you are done, you should have at least two <code><trigger></code>s in your definition block. The first is the reference <code><trigger></code>, the subsequent ones are the extremes.


<helper> hlp_forearm_L bip_lowerArm_L bip_lowerArm_L bip_hand_L
''Example:''
<basepos> -0.0003 -4.7578 -0.000685692
<source lang=xml>
<trigger> 90 -0.140879 -7.0729 0.923253 2.05439e-06 -0.00011566 -0.0109454 0 0 0
<helper> hlp_forearm_L   bip_lowerArm_L   bip_lowerArm_L   bip_hand_L
<trigger> 90     -157.919 -89.6281 158.827 0.101044 -61.3622 -0.505184 0 0 0
<basepos> -0.0003 -4.7578 -0.000685692
<trigger> 90 -0.905463 81.1157 0.0128013 -1.79037e-05 49.6029 -0.0109647 0 0 0
<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
</source>
</source>
This model with source files is available [http://source.maxofs2d.net/index.php?dir=models%2Ftf_femscout_enhanced%2F here] on MaxOfS2D's website.<br>
 
This [https://steamcommunity.com/sharedfiles/filedetails/?id=1776518541 Facepunch guide] (backed up on steam) describes the process of crafting such a file, using [[Source Filmmaker]] in detail. However, it is easier to do it entirely in [[Blender]] as this [https://steamcommunity.com/sharedfiles/filedetails/?id=2415253996 Steam Guide] shows.
{{ModernNote|Determining the extremes of your character's bones and creating <code><trigger></code>s for them is a subjective process! It will vary between different characters and different parts of the same character.}}
 
=== Example process with a human forearm ===
Three <code><trigger></code>s are required in total: 1) the reference pose, 2) one pose where the driver bone (the hand) is rotated clockwise as far as it should go, and 3) one pose where the driver bone is rotated counterclockwise as far as it should go. Determining how far the hand should rotate both ways is subjective and depends on your model. Ultimately, you are creating procedural bones to improve your model's appearance, so pick what looks best.
* Create the <code><trigger></code> for the reference pose, as detailed above.
* Create the <code><trigger></code> for the clockwise extreme.
# Rotate the hand bone clockwise along the forearm's axis, as far as it is supposed to go.
# Rotate the ulna twist bone clockwise along the forearm's axis until the mesh's deformation looks acceptable.
# Type out a <code><trigger></code> for this pose.
* Return your model to its reference pose.
* Create the <code><trigger></code> for the counterclockwise extreme.
# Rotate the hand bone counterclockwise along the forearm's axis, as far as it is supposed to go.
# Rotate the ulna twist bone counterclockwise along the forearm's axis until the mesh's deformation looks acceptable.
# Type out a <code><trigger></code> for this pose.
 
=== Wrapping Up and Idiosyncrasies ===
For symmetrical models, such as humans, you will want to repeat the above process to create the same procedural bone layout on the mirrored side of your character. Unless you know exactly what you are doing, do '''not''' simply copy and paste all of the numbers from the left side bones to the right side bones, or vice versa. Go through every step of the entire process for every procedural bone you need to create.
{{ModernWarning|It is not possible for one procedural bone to controlled by more than one driver bone.}}




== Misc ==
=== Miscellaneous ===
You can specify a useless name for a trigger:
You can specify a useless name for a trigger:
<source lang=xml>
<source lang=xml>
<trigger> 90 -6.75868e-015 1.59028e-015 3.18055e-015 0 0 0 0 0 0 UselessTriggerName
<trigger> 90 -6.75868e-015 1.59028e-015 3.18055e-015 0 0 0 0 0 0 UselessTriggerName
</source>
</source>
As this example highlights, that is completely useless in-engine and does nothing.
This name has no functional bearing and is ignored.
 
=== Other Valid Keywords ===
Aside from <code><helper></code>, <code><basepos></code>, and <code><trigger></code>, studiomdl accepts a few other keywords in VRD files.
 
==== <display> ====
The <code><display></code> keyword is used by Softimage Mod Tool to store the attributes for procedural bone's appearance in Mod Tool's viewport. Useless to anyone who doesn't use Softimage.
 
==== <rotateaxis> X Y Z ====
Specified as an XYZ Euler angle. The <code>Vec3_DesiredProceduralBoneRotation</code> angle in all subsequent <code><trigger></code> lines is '''pre'''-multiplied by this angle.
{{ModernTodo|Determine the practical purpose of this.}}
 
==== <jointorient> X Y Z ====
Specified as an XYZ Euler angle. The <code>Vec3_DesiredProceduralBoneRotation</code> angle in all subsequent <code><trigger></code> lines is '''post'''-multiplied by this angle.
{{ModernTodo|Determine the practical purpose of this.}}
 
==== <aimconstraint> ====
Works with other keywords <code><aimvector></code> and <code><upvector></code>. Presumably creates a procedural bone that functions like an aim constraint in Maya.
{{ModernTodo|Investigate this further.}}


There is a <display> keyword. This is used by Softimage Mod Tool to store the attributes for helper's appearance in Mod Tool's viewport. Useless to anyone who doesn't use Softimage.


== Bugs ==
== Guides ==
* This [https://steamcommunity.com/sharedfiles/filedetails/?id=1776518541 Facepunch guide] (backed up on steam) describes the process of crafting a VRD file, using [[Source Filmmaker]].
* This [https://steamcommunity.com/sharedfiles/filedetails/?id=2415253996 Steam Guide] shows how to do this in entirely in [[Blender]], with the help of an addon.


Certain characters in any of the bone names used will cause the compiler to abort. Note that this includes the "." character (a "period") that is commonly used in the naming of certain Valve bone sets.


[[Category:QC Commands|proceduralbones]]
[[Category:QC Commands|proceduralbones]]

Revision as of 17:21, 9 December 2022

$proceduralbones uses a special definition file (VRD) to tell the engine to automatically animate certain bones at runtime.


Concept

Procedural bones, elsewhere known as bone "drivers" (Blender) or "driven keys" (Maya), use the rotation of one bone to drive the rotation and translation of another bone. The first bone - called the driver or control bone - is typically animated by a human, while the second bone - called the procedural or helper bone - automatically rotates and/or translates itself, according to the rotation of the driver bone. Special rotation keyframes, called "triggers", are used to specify and map a range of motion in the driver bone to a range of motion in the procedural bone.

The human forearm, skinned with along-axis twist bones, is the poster child of procedural bones in Source. When the hand bone rotates clockwise, the twist bone in the forearm automatically rotates clockwise as well. When the hand bone rotate counterclockwise, the twist bone also rotates counterclockwise. The extents of both rotations can be easily controlled in the VRD file.


Common applications of procedural bones

The forearm of a full Valve biped skeleton. Note the ulna and wrist bones, both of which are "twist" bones and may be procedurally driven by the rotation of the hand bone.
  • Reduce the time required to complete a pose or animation, since fewer bones need to be manipulated by the artist.
  • Improve the appearance of a model when it imports an animation at runtime, i.e. via $includemodel, that does not animate all of the model's bones (notably, twist bones).
  • Apply corrective skinning and/or corrective flexes to the mesh, mitigating deformities caused by Source's linear skinning model and animation rules.

Twist bones

The most common use-case of procedural bones in Source is to apply the first two principles to twist bones, such as in the forearms, upper arms, thighs, and shins of human models. In the diagram at the right, a twist bone is placed in the middle of the forearm (ValveBiped.Bip01_L_Ulna), another twist bone is located on the wrist (ValveBiped.Bip01_L_Wrist), and the mesh is skinned accordingly. Rather than require the animator to pose the hand, wrist, and ulna all together, $proceduralbones can be used to automatically rotate the ulna and wrist bones when the animator rotates only the hand bone. This saves time and effort not just when creating new poses, but also when importing poses and animations that were created on a simpler skeleton which might not include any twist bones.

Corrective Deformations

Working around Source's archaic limit of three bone influences per skinned vertex can be difficult, especially in regions such as the chest or pelvis of a biped or quadruped. There are two major ways that procedural bones can be used to improve the quality of mesh deformation in these problematic areas.

Leaf Bones

In areas where Source's linear skinning model causes loss of mesh volume, such as the elbows or knees, procedural bones can be used to counteract the undesirable pinching or stretching of the mesh. Introduce one or more leaf bones in the problematic area, and skin the mesh accordingly. Then, using $proceduralbones, the rotation and translation of the leaf bones can be driven by the rotation the elbow or knee bone.

Corrective Flexes

In engine branches that support $boneflexdriver, procedural bones can be used to automatically fade in and fade out flexes without any need for programming. A flex can be created which adds volume to the elbow or knee joint, and a dummy child bone can be created under the joint. Then, using $boneflexdriver on the dummy bone and $proceduralbones, the rotation of the elbow or knee bone can drive the translation of the dummy bone, which in turn will fade-in the corrective flex as the mesh deforms. This technique is often superior to the use of procedural leaf bones, but every corrective flex counts towards the MDL flex limit of 96 or 128, possibly reducing the number of regular, non-corrective flexes that can fit on the model.

Self-collision Approximation

Procedural bones can simulate a quick and dirty approximation of collision between a model's parts. For example, consider a human model wearing a suit jacket. The hem of the jacket could be simply skinned to the thigh bones, such that the hem bends when the model lifts its knee. Alternatively, the hem could be skinned to a separate bone, and $proceduralbones could be used to tell the hem bone to rotate when the thigh bone rotates. In the latter scenario, the hem still bends when the model lifts its knee, but the animator can now pose the thigh and hem independently, improving the model's versatility. Going a step further, several hem bones can be created on the front, sides, and back of the suit jacket, and $proceduralbones can be used to only move the correct hem bone when the model's thigh moves. This way, when the model lifts its knee, the back hem of the jacket remains stationary, with only the front hem bending. This concept can also be applied to rigid accessories on a deforming model, especially in areas where multiple bones exert influence over the deforming mesh.


Syntax

$proceduralbones <configuration file>

The only valid argument to $proceduralbones is the name of a special VRD (Valve rig data (?)) configuration file, which specifies which bones are procedural and their behavior. The format of this file is described in the sections below.


VRD files

VRD files work similarly to driven keys in Maya. The important hierarchy of the driver and procedural bones are defined, then two or more "triggers" are specified. Each trigger maps a discrete rotation of the driver bone to a discrete rotation and/or translation of the procedural bone. At runtime, the engine automatically interpolates the pose of the procedural bone between all of the defined triggers, biasing most towards whichever trigger the driver bone is closest to.

Template:ModernTip

The Definition Block

Since $proceduralbones can only be used once in your QC file, a single VRD file can define multiple procedural bones. Each definition block starts with a <helper> line, a <basepos> line, and is finished by one or more <trigger> lines. To start a new definition block and define another procedural bone, simply start with a new <helper> line after the last <trigger> line.

Example: Hand-made VRD file for HWM Femscout model

Source Filmmaker was used to set up this VRD file, but you can use any modeling software that supports Source models.

<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

This model with source files is available here on MaxOfS2D's website.

Building a Definition Block

Step 1: <helper>

Every definition block starts with a <helper> line. It specifies the driver bone, the procedural bone, and their parents.

<helper> ProceduralBone   ParentOfProceduralBone   ParentOfDriverBone   DriverBone
  • ProceduralBone is the name of the bone which will be procedurally animated. In a typical human forearm setup, this would be the ulna twist bone.
  • ParentOfProceduralBone must be the parent of ProceduralBone.
  • ParentOfDriverBone must be the parent of DriverBone.
  • DriverBone is the name of the bone whose rotation will cause ProceduralBone to animate. In a typical human forearm setup, this would be the hand bone.

Example: <helper> hlp_forearm_L bip_lowerArm_L bip_lowerArm_L bip_hand_L

Template:ModernNote

Template:ModernWarning

Step 2: <basepos>

This is the reference translation of the procedural bone in the local coordinate system of its parent bone.

<basepos> X Y Z

Example: <basepos> -0.0003 -4.7578 -0.000685692

Find or create a script to calculate this value in your modeling software. Alternatively, you can use Crowbar to get this value without needing modeling software. Decompile your model, then find the $definebone line for the procedural bone. The first 3 numbers are the bone's reference position in parent-bone-space.

Step 3: The Reference <trigger>

Each <trigger> is a keyframe that maps a desired rotation of the procedural bone to a watched rotation of the driver bone. The first <trigger> should specify the reference pose of the procedural bone and driver bone.

<trigger> AngleOfInfluence   Vec3_WatchedDriverBoneRotation   Vec3_DesiredProceduralBoneRotation   Vec3_DesiredProceduralBoneTranslation
  • AngleOfInfluence is in degrees and specifies how far the driver bone must rotate in order for the procedural bone to reach the extent of its keyframed pose. With a larger angle, like 90 degrees, the driver bone must rotate a great deal before the procedural bone reaches its keyframed pose. With a smaller angle, like 30 degrees, the driver bone does not need to rotate very far in order for the procedural bone to reach its keyframed pose. Think of this angle like a cone; the procedural bone reaches the full extent of its keyframed pose when the driver bone reaches or exceeds the bounds of the cone.
  • Vec3_WatchedDriverBoneRotation is the input rotation of the driver bone, specified in degrees as XYZ Euler angles.
  • Vec3_DesiredProceduralBoneRotation is the output rotation of the procedural bone, specified in degrees as XYZ Euler angles.
  • Vec3_DesiredProceduralBoneTranslation is the translation of the procedural bone, in the local coordinate system of its parent bone. This value is relative to the <basepos> defined earlier!

Place your model in its reference pose, then gather the parent-bone-space rotations for Vec3_WatchedDriverBoneRotation and Vec3_DesiredProceduralBoneRotation. Vec3_DesiredProceduralBoneTranslation will be 0 0 0. Type out the new <trigger> line in your VRD file.

Example:

//        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

Choosing an Angle of Influence

You can specify a different AngleOfInfluence for every <trigger> in your definition block, but in practice, your procedural bone will be limited by the smallest AngleOfInfluence. The ideal angle of influence is the same amount by which you are rotating your driver bone to produce the extreme <trigger>s for your procedural bone. For example, consider a human forearm. If you plan to rotate the hand bone +90 and -90 degrees for your two extreme <trigger>s, then you should specify 90 for your AngleOfInfluence for every trigger. If you only plan to rotate the driver bone ±45 degrees, put 45 for your AngleOfInfluence.

Step 4: The Extreme <trigger>s

There is where the procedural animation of your procedural bone is finally defined. First, determine the extreme(s) of your driver bone's range of motion. Then, in your modeling software, rotate the driver bone to one extreme, and pose the procedural bone accordingly. Gather the parent-bone-space rotations for Vec3_WatchedDriverBoneRotation and Vec3_DesiredProceduralBoneRotation. If you did not translate the procedural bone, then Vec3_DesiredProceduralBoneTranslation will be 0 0 0; otherwise, also gather the parent-bone-space translation of the procedural bone. Type out the new <trigger> line in your VRD file.

Example:

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

Repeat this process and create a new <trigger> for each extreme of the driver bone. When you are done, you should have at least two <trigger>s in your definition block. The first is the reference <trigger>, the subsequent ones are the extremes.

Example:

<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:ModernNote

Example process with a human forearm

Three <trigger>s are required in total: 1) the reference pose, 2) one pose where the driver bone (the hand) is rotated clockwise as far as it should go, and 3) one pose where the driver bone is rotated counterclockwise as far as it should go. Determining how far the hand should rotate both ways is subjective and depends on your model. Ultimately, you are creating procedural bones to improve your model's appearance, so pick what looks best.

  • Create the <trigger> for the reference pose, as detailed above.
  • Create the <trigger> for the clockwise extreme.
  1. Rotate the hand bone clockwise along the forearm's axis, as far as it is supposed to go.
  2. Rotate the ulna twist bone clockwise along the forearm's axis until the mesh's deformation looks acceptable.
  3. Type out a <trigger> for this pose.
  • Return your model to its reference pose.
  • Create the <trigger> for the counterclockwise extreme.
  1. Rotate the hand bone counterclockwise along the forearm's axis, as far as it is supposed to go.
  2. Rotate the ulna twist bone counterclockwise along the forearm's axis until the mesh's deformation looks acceptable.
  3. Type out a <trigger> for this pose.

Wrapping Up and Idiosyncrasies

For symmetrical models, such as humans, you will want to repeat the above process to create the same procedural bone layout on the mirrored side of your character. Unless you know exactly what you are doing, do not simply copy and paste all of the numbers from the left side bones to the right side bones, or vice versa. Go through every step of the entire process for every procedural bone you need to create. Template:ModernWarning


Miscellaneous

You can specify a useless name for a trigger:

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

This name has no functional bearing and is ignored.

Other Valid Keywords

Aside from <helper>, <basepos>, and <trigger>, studiomdl accepts a few other keywords in VRD files.

<display>

The <display> keyword is used by Softimage Mod Tool to store the attributes for procedural bone's appearance in Mod Tool's viewport. Useless to anyone who doesn't use Softimage.

<rotateaxis> X Y Z

Specified as an XYZ Euler angle. The Vec3_DesiredProceduralBoneRotation angle in all subsequent <trigger> lines is pre-multiplied by this angle. Template:ModernTodo

<jointorient> X Y Z

Specified as an XYZ Euler angle. The Vec3_DesiredProceduralBoneRotation angle in all subsequent <trigger> lines is post-multiplied by this angle. Template:ModernTodo

<aimconstraint>

Works with other keywords <aimvector> and <upvector>. Presumably creates a procedural bone that functions like an aim constraint in Maya. Template:ModernTodo


Guides