This article's documentation is for anything that uses the Source engine. Click here for more information.

$proceduralbones: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
m (Instruction and warning revisions; language & grammar; formatting)
(Document <aimconstraint> w/ original research & effectively re-wrote most of this page to more clearly & concisely explain how this system works.)
 
(17 intermediate revisions by 8 users not shown)
Line 1: Line 1:
'''$proceduralbones''' uses a special definition file (VRD) to tell the engine to automatically animate certain bones at runtime.
{{LanguageBar}}


{{toc-right}}
{{this is a|QC command|name=$proceduralbones}} It uses a special definition file (VRD) to tell the engine to automatically animate certain bones procedurally/at runtime.


== Concept ==
== Usage ==
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" in the VRD, are used to map a range of motion in the driver bone to a range of motion in the procedural bone.
<source lang=php>
$proceduralbones "<file name>.vrd"
</source>
{{bug|While the quotation marks are optional provided the file has no spaces in its name, the file extension is NOT optional. Code exists in StudioMDL to read an older, unsupported format if the .vrd file extension is excluded.|tested={{src13}}}}
{{bug|StudioMDL will not throw an error if the file specified does not exist.|tested={{src13}}}}


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.
VRD files work similarly to driven keys in Maya, or transform modifiers in Blender. There are two types of procedural bone:
: '''Helper bones''', which consist of a number of keyframes (called "triggers") that tell the engine which angles it should look out for, and as the target bone approaches an angle, its trigger will be blended in proportionally.
: '''Aim constraints''', which will always point a bone towards a specified attachment point on the model.


{{tip|VRD files support C-style comments, tabs, spaces, etc. but do NOT support multi-line comments.}}


== 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 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 ====
== Guides ==
In some engine branches<sup>†</sup> that support <code>[[$boneflexdriver]]</code>, it is possible to use procedural bones to automatically fade in and fade out flexes<sup>‡</sup>. This technique lends itself most to applying local corrective or limited delta mush shapes to parts of a mesh that experience low-quality deformations, typically when put into extreme poses. Care must be taken when using this technique, since each corrective flex takes up a flexcontroller slot and requires a corresponding bone in the model's skeleton to drive it. This can quickly add up, counting against the MDL flexcontroller limit (usually 96 or 128) and [[Skeleton#Bone_count_limit|bone limit]] (usually 128) and reducing the number of normal flexes and bones available to the model.
* 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]].
{{ModernNote|<sup>†</sup> Tested in: {{hl2}}, {{css}}, {{tf2}}, {{portal}}, {{gmod}}}}
* This [https://steamcommunity.com/sharedfiles/filedetails/?id=3485026924 Steam Guide] shows how to do this in entirely in [[Blender]], with the help of an addon.
{{ModernWarning|<sup>‡</sup> With additional requirements. Refer to section [[$proceduralbones#Driving_Flexes_with_Procedural_Bones|Driving Flexes with Procedural Bones]] at the end of this article.}}


=== 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 ==
== VRD file syntax & parameters ==
<source lang=php>
$proceduralbones <configuration file>
</source>


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.
; <code><helper> HelperName HelperParent DriverParent DriverName</code>
: {{note|This marks the beginning of a new procedural bone, and ends the previous one, making it mutually exclusive with <code><aimconstraint></code>.}}
: <code>HelperName</code> - The name of the helper bone being driven
: <code>HelperParent</code> - The name of the helper bone's parent
: <code>DriverParent</code> - The name of the driver bone's parent
: <code>DriverName</code> - The name of the bone that drives this helper (is effectively being "watched" to see what angle it has)
:: {{note|The parent bones '''must''' match their respective bones' parents. The compile will fail if they do not match.}}
:: May have up to 32 <code><trigger></code> definitions, each of which define a pose to blend <code>HelperName</code> towards based on the rotation of <code>DriverName</code> within its <code>AngleOfInfluence</code>.
:: In short, each <code><trigger></code> is a unique pose that <code>HelperName</code> will translate to whenever <code>DriverName</code> approaches the <code><trigger></code>'s defined watch angle.
:: Example: <source><helper>  hlp_forearm_L  bip_lowerArm_L  bip_lowerArm_L  bip_hand_L</source>


; <code><aimconstraint> HelperName HelperParent TargetAttachment</code>
: {{note|This marks the beginning of a new procedural bone, and ends the previous one, making it mutually exclusive with <code><helper></code>.}}
: <code>HelperName</code> - The name of the helper bone being driven
: <code>HelperParent</code> - The name of the helper bone's parent
: <code>TargetAttachment</code> - Then name of the [[$attachment]] to always point towards
:: Causes <code>HelperName</code> to always face <code>TargetAttachment</code>. The angle it faces can be modified with <code><aimvector></code>.
:: Example: <source><aimconstraint>  hlp_piston_R  hlp_lowerArm_R  attach_upperArm_piston_R</source>
:: {{bug|The lexer suggests <code>TargetAttachment</code> should also accept a bone, but no code implements this - using a bone here will throw an error.|tested={{src13}}}}
:: {{bug|The <code>TargetAttachment</code> will appear to visibly lag behind by one frame depending on how much movement occurs, which will have more or less impact depending on the client's FPS.|tested={{src13}}}}


== VRD files ==
; <code><basepos> <[[float]]|X> <[[float]]|Y> <[[float]]|Z></code>
VRD files work similarly to driven keys in Maya. The important hierarchy of the driver bone and procedural bone 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.
:: Used to declare the starting position of a procedural bone, relative to its parent.
:: For <code><helper></code>, this is not necessarily required, as each <code><trigger></code> also includes a location. If specified anyway, all <code><trigger></code> locations will become relative to this one.
:: For <code><aimconstraint></code>, this is basically a necessity, as there is no other way to specify where the bone should be.
:: Example: <source><basepos> 15.003496 0.0043543 3.9911634</source>
:: {{tip|To avoid using external tools or scripts, you can find the correct coordinates by first exporting your model in its reference position as an SMD file, then load this file into any text editor of your choosing. Locate the desired bone in the <code>nodes</code> list; to the left of the name will be its ID, used in the <code>skeleton</code> section of this file. Find <code>time 0</code> (the first and ideally only frame of animation), and look for the bone ID on the left - the three numbers following this ID are the base pose of this bone relative to its parent.}}


{{ModernTip|VRD files support C-style comments, tabs, spaces, etc. Empty lines are ignored and can be used to improve readability.}}
; <code><trigger> AngleOfInfluence DriverRotation_XYZ HelperRotation_XYZ HelperLocation_XYZ</code>
: <code>AngleOfInfluence</code> - A single number representing a cone of influence around this trigger (beyond the cone = 0%, center of the cone = 100%)
: <code>DriverRotation_XYZ</code> - A 3D vector representing the rotation of the driver bone (relative to its parent) that represents the center of this trigger's cone
: <code>HelperRotation_XYZ, HelperLocation_XYZ</code> - A pair of 3D vectors that respectively represent rotation & location of this helper bone as the driver approaches the center of this trigger's cone
:: Used by <code><helper></code> to declare a specific rotation being watched, and the resulting rotation & location of the helper when the watched bone approaches this rotation.
:: There can be up to 32 <code><trigger></code> lines per <code><helper></code>, and all rotations are Euler rotations expressed in degrees.
:: The angle of influence refers to how far the bone must be from this rotation for this <code><trigger></code> to have fully faded out; as it approaches <code>DriverRotation_XYZ</code>, the procedural bone will approach <code>HelperRotation_XYZ</code> and <code>HelperLocation_XYZ</code>
:: Example: <source><trigger>  60  -26.5650735797  -14.4773829758  -26.5652454670      -26.5650162839  -14.4773829758  -26.5651881712      0.000000000  0.000000000  0.000000000</source>
:: {{Warning|The same trick above works here too, the three numbers after the bone ID and position are the rotation, but the rotations are in '''RADIANS''' - convert to '''degrees''' before using them in a <code><trigger></code>}}


=== The Definition Block ===
; <code><aimvector> <[[float]]|X> <[[float]]|Y> <[[float]]|Z></code>
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.
:: Used by <code><aimconstraint></code> to declare the direction a <code><aimconstraint></code> will face as it tracks its <code>TargetAttachment</code>.
:: This vector is normalized, but does support any arbitrary orientation. Most commonly, bones will face a particular axis.
:: Example: <source><aimvector> 0 0 -1</source> (causes the bone to face -Z, or Z always faces opposite the <code>TargetAttachment</code>)


==== Example: Hand-made VRD file for HWM Femscout model ====
; <code><upvector> <[[float]]|X> <[[float]]|Y> <[[float]]|Z></code>
Source Filmmaker was used to set up this VRD file, but you can use any modeling software that supports Source models.
:: Used to clarify which axis on the <code>TargetAttachment</code> is considered "up".
:: Example: <source><upvector> 0 1 0</source> (causes the bone to rotate with the attachment if it rotates along its local Y axis)


<source lang=xml>
<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
; <code><display><[[float]]|X> <[[float]]|Y> <[[float]]|Z> <[[float]]|distance></code>
<basepos> -0.0502548 4.76207 -0.0109539
:: Used by the Softimage Mod Tool to store the attributes for procedural bone's appearance in Mod Tool's viewport, but has no purpose outside of it.
<trigger> 90 -0.116485 -7.07782 0.923253 -26.1455 -71.739 -60.6497 0 0 0
:: Example: <source><display> -12.64333 4.33348 0.63611 4.45</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
</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>


== Building a Definition Block ==
; <code><rotateaxis> <[[float]]|X> <[[float]]|Y> <[[float]]|Z></code>
:: Used to specify a '''pre'''-multiplied angle for all <code><trigger></code> definitions.
:: Example: <source><rotateaxis> 0.0004010705  -119.9998795417  89.9996375014</source>
:: {{note|This may have been meant to compliment <code><basepos></code> in setting a default angle, but no retail game ever uses it.}}


=== Step 1: <helper> ===
; <code><jointorient> <[[float]]|X> <[[float]]|Y> <[[float]]|Z></code>
Every definition block starts with a <code><helper></code> line. It specifies the driver bone, the procedural bone, and their parents.
:: Used to specify a '''post'''-multiplied angle for all <code><trigger></code> definitions.
:: Example: <source><jointorient> 56.3101202181  -154.3411936127  16.1020048039</source>
:: {{note|This may have been meant to compliment <code><basepos></code> in setting a default angle, but no retail game ever uses it.}}


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


{{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''. }}
== Common applications ==
[[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 that will be procedurally driven by the rotation of the hand bone.]]


==== Notes on Bone Hierarchy ====
The most common use case of procedural bones is to automatically rotate forearms, upper arms, thighs, and shins of character models. In the diagram to the right, the mesh is weighted to both a twist bone placed in the middle of the forearm (''ValveBiped.Bip01_L_Ulna''), and a twist bone located on the wrist (''ValveBiped.Bip01_L_Wrist''). Rather than require the animator to pose the hand, wrist, and ulna all together (which would not animate in the ragdoll anyway), the ulna & wrist are given procedural bone definitions that allow them to automatically rotate with the hand.
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.  


Alternatively, it is possible to define a procedural rule wherein the procedural bone and driver bone are not siblings. Accordingly, <code>ParentOfProceduralBone</code> and <code>ParentOfDriverBone</code> will be different bones. In this case, however, there must be a clear path in the skeleton's hierachy between <code>ParentOfProceduralBone</code> and <code>ParentOfDriverBone</code>. Three scenarios are possible: '''1)''' <code>ParentOfProceduralBone</code> and <code>ParentOfDriverBone</code> share a common ancestor bone; '''2)''' <code>ParentOfProceduralBone</code> is the immediate parent of <code>ParentOfDriverBone</code>; or '''3)''' <code>ParentOfDriverBone</code> is the immediate parent of <code>ParentOfProceduralBone</code>. Lastly, it is also possible for the procedural bone to be a direct child of the driver bone, in which case <code>ParentOfProceduralBone</code> and <code>DriverBone</code> will be the same.
=== Corrective bones ===
In areas where rotating weighted bones causes a noticeable loss in mesh volume, such as on the exteriors of elbows & knees, a procedural bone can be used to better maintain the volume. By adding a helper in the same position as the elbow/knee and weighting the vertices nearest the apex of the joint to it, the mesh can be made to deform in a way that doesn't noticeably shrink.


=== Step 2: <basepos> ===
In {{tf2}}, the Engineer's character model uses a pair of procedural bones to keep his knee pads from deforming poorly when his knees bend, by watching the angle of the knee & rotating about half the distance to both keep the knee pads in the correct orientation and avoid visible shrinking.
This is the '''reference''' translation of the procedural bone in the local coordinate system of its parent bone.


<source lang=xml>
=== Corrective flexes ===
<basepos> X Y Z
In some engine branches<sup>†</sup> that support <code>[[$boneflexdriver]]</code>, it is possible to use procedural bones to automatically fade in and fade out flexes<sup>‡</sup>. This technique lends itself most to applying local corrective or limited delta mush shapes to parts of a mesh that experience low-quality deformations, typically when put into extreme poses. Care must be taken when using this technique, since each corrective flex takes up a flexcontroller slot and requires a corresponding bone in the model's skeleton to drive it. This can quickly add up, counting against the MDL flexcontroller limit (usually 96 or 128) and [[Skeleton#Bone_count_limit|bone limit]] (usually 128) and reducing the number of normal flexes and bones available to the model.
</source>
{{note|<sup>†</sup> Deviates from official spec, but tested and working in: {{hl2}}, {{css}}, {{tf2}}, {{portal}}, {{gmod}}}}
{{warning|<sup>‡</sup> With additional requirements. Refer to section [[$proceduralbones#Driving_Flexes_with_Procedural_Bones|Driving Flexes with Procedural Bones]] at the end of this article.}}


''Example:'' <code><basepos> -0.0003 -4.7578 -0.000685692</code>
=== 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.


Find or create a script to calculate this value in your modeling software.
=== Mechanical armatures ===
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.
It's desirable for a mechanical linkage to always point in the correct direction, say for instance in a piston that connects a lower armature to an upper armature. While you can manually animate this, it will neither work with a ragdoll nor during transitions of different animations. You can either manually define a set of known good frames, or an endpoint that the piston should always point towards.


=== 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>
<trigger> AngleOfInfluence  Vec3_WatchedDriverBoneRotation  Vec3_DesiredProceduralBoneRotation  Vec3_DesiredProceduralBoneTranslation
</source>


* <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 rotates such that it reaches or exceeds the bounds of the cone.
* <code>Vec3_WatchedDriverBoneRotation</code> is the input rotation of the driver bone, specified in '''degrees''' as X Y Z Euler angles.
* <code>Vec3_DesiredProceduralBoneRotation</code> is the output rotation of the procedural  bone, specified in '''degrees''' as X Y Z 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.
== VRD file examples ==


''Example:''
=== HWM Femscout forearm twists ===
<source lang=xml>
{{note|Source Filmmaker was used to set up this VRD file, but you can use any modeling software that supports Source models.}}
//        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
</source>
 
==== Choosing an Angle of Influence ====
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>
//        AoI Vec3_WatchedDriverBoneRotation Vec3_DesiredProceduralBoneRotation Vec3_DesiredProceduralBoneTranslation
<trigger> 90 -157.919 -89.6281 158.827 0.101044 -61.3622 -0.505184 0 0 0
</source>
 
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.
 
''Example:''
<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
Line 140: Line 126:
<trigger> 90 -157.919 -89.6281 158.827 0.101044 -61.3622 -0.505184 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
<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 model with source files is available [http://source.maxofs2d.net/index.php?dir=models%2Ftf_femscout_enhanced%2F here] on MaxOfS2D's website.


{{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.


{{ModernTip|Refer to the femscout VRD example earlier in this article to ensure the layout of your VRD file is correct.}}
=== Crossbow string ===
<source lang=xml>
<aimconstraint> hlp_bow_L hlp_bowflex_L attach_string_L
<basepos>      15.070189000 0.000035000 -5.834238000
<aimvector> -1 0 0 // Causes hlp_bow_L to face away from attach_string_L on the X axis
<upvector> 0 1 0


=== Wrapping Up and Idiosyncrasies ===
<aimconstraint> hlp_bow_R hlp_bowflex_R attach_string_R
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 and create a new definition block for every procedural bone you need to define.
<basepos>      15.069914000 0.000015000 -5.834859000
<aimvector> -1 0 0 // Causes hlp_bow_R to face away from attach_string_R on the X axis
<upvector> 0 1 0
</source>


A procedural bone '''cannot''' be controlled by two or more driver bones. The reverse, however, is possible: one driver bone can be re-used multiple times to control more than one procedural bone.




=== Miscellaneous ===
=== Detailed right wrist created from an SMD animation ===
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
<helper>        hlp_wrist_R    bip_lowerArm_R  bip_lowerArm_R  bip_hand_R
<basepos>      8.643163000 -0.000000000 0.000021000
<trigger>      60      0.0001718873    150.0000642864  -90.0000958676  0.0001145916    150.0000642864  -90.0001531634  0.000000000    0.000000000    0.000000000      // time 0
<trigger>      60      0.0001718873    -149.9998923990 -90.0002677549  0.0001145916    -149.9998923990 -90.0003250507  0.000000000    0.000000000    0.000000000      // time 1
<trigger>      60      -52.0251407557  -89.9998666845  -38.2358227960  -48.7844914664  -89.9998666845  -38.7109193998  0.000000000    0.000000000    0.000000000      // time 2
<trigger>      60      -0.0001145916  -29.9999555615  -90.0001531634  -0.0001145916  -29.9999555615  -90.0002104591  0.000000000    0.000000000    0.000000000      // time 3
<trigger>       60      -0.0001145916  30.0001274488  -90.0002104591  -0.0001145916  30.0001274488  -90.0002677549  0.000000000    0.000000000    0.000000000      // time 4
<trigger>      60      153.4350608597  14.4776121589  26.5649016923  164.0022360669  26.1849160826  61.2785237386  -0.209301000    -0.381664000    0.031250000      // time 5
<trigger>      60      -153.4347743808 -14.4773829758  26.5648443966  -171.5899734436 -29.0682115950  68.3158205615  -0.189188000    -0.685485000    -0.609611000    // time 6
<trigger>      60      -89.9999239803  -29.9998982657  -0.0002291831  -90.0125290517  -70.4192059232  0.4019298933    -0.103786000    -0.028785000    -0.800817000    // time 7
<trigger>      60      -26.5650735797  -14.4773829758  -26.5652454670  -10.9441241406  -28.1016317947  -66.4090170193  -0.138767000    0.601700000    -0.401906000    // time 8
<trigger>      60      26.5651308755  14.4776121589  -26.5651881712  14.4604807209  26.7658952869  -68.4830096461  -0.374143000    0.995121000    0.171281000      // time 9
<trigger>      60      26.5651308755  165.5226941678  -26.5651881712  2.8720655397    150.2507333217  -86.7703900722  -0.108041000    0.564029000    -0.252821000    // time 10
<trigger>      60      -26.5651308755  -165.5223503931 -26.5652454670  3.3628038912    -149.6761139490 -92.8659161673  -0.211483000    0.771767000    0.567706000      // time 11
<trigger>      60      -90.0001531634  -149.9998923990 -0.0001145916  -86.2042504748  -94.3424857011  -7.0959104054  -0.224750000    0.172373000    0.564973000      // time 12
<trigger>      60      26.5649589881  -14.4775548631  -153.4351181555 3.6163950113    -29.7311237640  -95.1886297730  -0.084996000    -0.475180000    0.216209000      // time 13
<trigger>      60      -26.5651881712  14.4774402716  -153.4351181555 -5.6986955262  28.7843110076  -111.9647767186 -0.068011000    0.295446000    -0.111653000    // time 14
<trigger>      60      -119.9998795417 29.9999555615  89.9999239803  16.3264896680  144.2979310134  -91.0288988845  0.029360000    -0.468964000    -0.863318000    // time 15
<trigger>      60      -119.9998222460 -30.0000701530  89.9996947971  -158.5945458049 -15.7165760951  87.5142038819  -0.044148000    0.546487000    -0.608450000    // time 16
<trigger>      60      7.7956064648    -89.9998666845  -38.1285650968  30.3528975633  -87.9546938348  -100.1075870357 -0.292867000    0.814450000    -0.029658000    // time 17
<trigger>      60      59.9998538272  -29.9998982657  -90.0001531634  19.9532552154  -29.4507755149  -90.1107913136  -0.195600000    0.410349000    0.696194000      // time 18
<trigger>      60      59.9997965314  30.0000701530  -90.0002104591  19.3298771343  19.5167759671  -88.2561842266  -0.296514000    -0.591582000    0.830669000      // time 19
<trigger>      60      120.0001660206  29.9999555615  89.9999239803  156.9124563099  22.1676797978  88.3612073904  -0.348013000    0.475677000    0.507207000      // time 20
<trigger>      60      120.0002233164  -30.0000701530  89.9996947971  -18.0940644660  -137.9124309783 -92.6856636449  -0.288719000    -0.342254000    0.879168000      // time 21
<trigger>      60      -112.4273255466 -89.9998666845  -38.0887445300  -33.8569355510  -95.9927187426  -78.7788893373  -0.413648000    -0.655860000    -0.128256000    // time 22
<trigger>      60      -60.0000257145  -29.9999555615  -90.0001531634  -21.5571359713  -30.0129617034  -90.0030179523  -0.272500000    -0.344648000    -0.597419000    // time 23
<trigger>      60      -60.0000830103  30.0001274488  -90.0002104591  -19.7873839337  32.3326959286  -89.5132536291  -0.207348000    0.373764000    -0.711022000    // time 24
</source>
</source>
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> ====
== Miscellaneous ==
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.
When StudioMDL parses <code><trigger></code> lines, all characters after the 10th space-delineated number are ignored. This can be used to place comments at the end of the line, like so:
<source lang=xml>
<trigger> 90  -6.75 1.59 3.18  0 0 0  0 0 0  this text is ignored
</source>


==== <rotateaxis> X Y Z ====
For symmetrical models (such as humans) it's very common for left/right bones to have completely different local rotations & locations. As such, copying & pasting the procedural bone data from one side to the other will typically not work.
Specified as an X Y Z 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 ====
A procedural bone '''cannot''' be controlled by two or more driver bones. However, one driver bone can be re-used multiple times to control more than one procedural bone.
Specified as an X Y Z 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.}}




== 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.




== Driving Flexes with Procedural Bones ==
== Driving Flexes with Procedural Bones ==
As noted earlier, using <code>$proceduralbones</code> to automatically drive a <code>$boneflexdriver</code> allows for advanced deformation techniques, such as automatic corrective shapes. <b>Two extra steps are required when compiling your model to achieve this technique in most Source games and engine branches.</b>
Using <code>$proceduralbones</code> to automatically drive a <code>$boneflexdriver</code> allows for advanced deformation techniques, such as automatic corrective shapes, but this functionality is not officially supported. As such, retail releases of StudioMDL refuse to compile models that use <code>$boneflexdriver</code> on any bone which is marked as the <code>ProceduralBone</code> in <code>$proceduralbones</code>'s VRD file. To fix this, StudioMDL may be directly patched using a hex editor, thus allowing it to skip the early exit and successfully compile the model.
 
{{warning|Modified instances of StudioMDL often produce models that deviate from the format expected by the engine - this may cause issues on specific games or engine branches.}}
=== Step 1: Modifying studiomdl ===
Retail releases of studiomdl refuse to compile models that use <code>$boneflexdriver</code> on any bone which is marked as the <code>ProceduralBone</code> in <code>$proceduralbones</code>'s VRD file. Extra effort is required to modify either the output [[MDL]] file or studiomdl itself into allowing this combination. The latter is typically the path of least resistance.
 
Using the hex editor of your choice, studiomdl can be patched into skipping the early exit and successfully compiling your model. Be aware that modified studiomdls might produce MDLs which deviate from the specification expected by the engine, and these MDLs may or may not work in any given game or engine branch.


* <b>{{Game name|src13|name=Source 2013}} branch studiomdls</b>
=== Engine-specific patches ===
: <i>Aka most IDST0 games, including {{Game name|hl2|name=Half-Life 2}}, {{Game name|css|name=Counter-Strike: Source}}, {{Game name|portal|name=Portal}}, {{Game name|tf2|name=Team Fortress 2}}, and {{Game name|gmod|name=Garry's Mod}}.</i>
* '''{{src13|4}} branch'''
: ''Includes most games where the model format's header begins with <code>IDST0</code>, including {{Half-Life 2|4}}, {{Counter-Strike: Source|4}}, {{Portal|4}}, {{Team Fortress 2|4}}, and {{gmod|4}}.''
: Search for the unique byte sequence <code>04 74 25 8D 4F</code>, then change the byte <code>74</code> to <code>EB</code>.
: Search for the unique byte sequence <code>04 74 25 8D 4F</code>, then change the byte <code>74</code> to <code>EB</code>.


* <b>{{Game name|as|name=Alien Swarm}}'s studiomdl</b>
* '''{{as|4}}'''
: Search for the unique byte sequence <code>04 74 25 8B</code>, then change the byte <code>74</code> to <code>EB</code>.
: Search for the unique byte sequence <code>04 74 25 8B</code>, then change the byte <code>74</code> to <code>EB</code>.


* <b>{{Game name|sfm|name=Source Filmmaker}}'s studiomdl</b>
* '''{{sfm|4}}'''
: Search for the unique byte sequence <code>04 74 1C 8B 56 5C</code>, then change the byte <code>74</code> to <code>EB</code>.
: Search for the unique byte sequence <code>04 74 1C 8B 56 5C</code>, then change the byte <code>74</code> to <code>EB</code>.


* <b>{{Game name|portal2|name=Portal 2}}'s studiomdl</b>
* '''{{Portal 2|4}}'''
: Search for the unique byte sequence <code>04 74 28 8B</code>, then change the byte <code>74</code> to <code>EB</code>.
: Search for the unique byte sequence <code>04 74 28 8B</code>, then change the byte <code>74</code> to <code>EB</code>.


{{ModernTodo|Determine the patch location for other notable games, including {{l4d}} and {{l4d2}}}}
{{todo|Determine the patch location for other notable games, including {{l4d}} and {{l4d2}}}}


=== Step 2: $bonemerge ===
=== Important QC modification ===
In your model's [[QC]] file, you <b>must</b> specify <code>[[$bonemerge]]</code> on every bone that you make procedural. Refer to your VRD file, and add <code>$bonemerge</code> line(s) to your QC for the <code>ProceduralBone</code> of every <code><helper></code> line. The <code>DriverBone</code>s do not need <code>$bonemerge</code>.
In your model's [[QC]] file, you '''must''' specify <code>[[$bonemerge]]</code> on every bone that you make procedural. Refer to your VRD file, and add <code>$bonemerge</code> line(s) to your QC for the <code>ProceduralBone</code> of every <code><helper></code> line. The <code>DriverBone</code>s do not need <code>$bonemerge</code>.


The reasoning behind the requirement of the seemingly unrelated <code>$bonemerge</code> flag is not yet fully understood.
The reasoning behind the requirement of the seemingly unrelated <code>$bonemerge</code> flag is not yet fully understood.


=== Step 3: Compile your model ===
=== Confirmation ===
With studiomdl modified, and <code>$bonemerge</code> specified for all procedural bones, you can now compile your model. Test it in HLMV and verify that everything works as intended. The animation of the skeleton drives the procedural bone(s), which in turn drive the flexcontroller(s).
Once the model has been compiled, you can test it in HLMV to verify that everything works as intended. The skeletal animation should now be able to drive the desired procedural bone(s), which in turn drive the flexcontroller(s).
 
 
[[Category:QC Commands|proceduralbones]]

Latest revision as of 23:13, 28 October 2025

English (en)中文 (zh)Translate (Translate)

$proceduralbones is a QC command available in all Source Source games. It uses a special definition file (VRD) to tell the engine to automatically animate certain bones procedurally/at runtime.

Usage

$proceduralbones "<file name>.vrd"
Icon-Bug.pngBug:While the quotation marks are optional provided the file has no spaces in its name, the file extension is NOT optional. Code exists in StudioMDL to read an older, unsupported format if the .vrd file extension is excluded.  (tested in: Source 2013)
Icon-Bug.pngBug:StudioMDL will not throw an error if the file specified does not exist.  (tested in: Source 2013)

VRD files work similarly to driven keys in Maya, or transform modifiers in Blender. There are two types of procedural bone:

Helper bones, which consist of a number of keyframes (called "triggers") that tell the engine which angles it should look out for, and as the target bone approaches an angle, its trigger will be blended in proportionally.
Aim constraints, which will always point a bone towards a specified attachment point on the model.
Tip.pngTip:VRD files support C-style comments, tabs, spaces, etc. but do NOT support multi-line comments.



Guides


VRD file syntax & parameters

<helper> HelperName HelperParent DriverParent DriverName
Note.pngNote:This marks the beginning of a new procedural bone, and ends the previous one, making it mutually exclusive with <aimconstraint>.
HelperName - The name of the helper bone being driven
HelperParent - The name of the helper bone's parent
DriverParent - The name of the driver bone's parent
DriverName - The name of the bone that drives this helper (is effectively being "watched" to see what angle it has)
Note.pngNote:The parent bones must match their respective bones' parents. The compile will fail if they do not match.
May have up to 32 <trigger> definitions, each of which define a pose to blend HelperName towards based on the rotation of DriverName within its AngleOfInfluence.
In short, each <trigger> is a unique pose that HelperName will translate to whenever DriverName approaches the <trigger>'s defined watch angle.
Example:
<helper>   hlp_forearm_L   bip_lowerArm_L   bip_lowerArm_L   bip_hand_L
<aimconstraint> HelperName HelperParent TargetAttachment
Note.pngNote:This marks the beginning of a new procedural bone, and ends the previous one, making it mutually exclusive with <helper>.
HelperName - The name of the helper bone being driven
HelperParent - The name of the helper bone's parent
TargetAttachment - Then name of the $attachment to always point towards
Causes HelperName to always face TargetAttachment. The angle it faces can be modified with <aimvector>.
Example:
<aimconstraint>   hlp_piston_R   hlp_lowerArm_R   attach_upperArm_piston_R
Icon-Bug.pngBug:The lexer suggests TargetAttachment should also accept a bone, but no code implements this - using a bone here will throw an error.  (tested in: Source 2013)
Icon-Bug.pngBug:The TargetAttachment will appear to visibly lag behind by one frame depending on how much movement occurs, which will have more or less impact depending on the client's FPS.  (tested in: Source 2013)
<basepos> <float|X> <float|Y> <float|Z>
Used to declare the starting position of a procedural bone, relative to its parent.
For <helper>, this is not necessarily required, as each <trigger> also includes a location. If specified anyway, all <trigger> locations will become relative to this one.
For <aimconstraint>, this is basically a necessity, as there is no other way to specify where the bone should be.
Example:
<basepos> 15.003496 0.0043543 3.9911634
Tip.pngTip:To avoid using external tools or scripts, you can find the correct coordinates by first exporting your model in its reference position as an SMD file, then load this file into any text editor of your choosing. Locate the desired bone in the nodes list; to the left of the name will be its ID, used in the skeleton section of this file. Find time 0 (the first and ideally only frame of animation), and look for the bone ID on the left - the three numbers following this ID are the base pose of this bone relative to its parent.
<trigger> AngleOfInfluence DriverRotation_XYZ HelperRotation_XYZ HelperLocation_XYZ
AngleOfInfluence - A single number representing a cone of influence around this trigger (beyond the cone = 0%, center of the cone = 100%)
DriverRotation_XYZ - A 3D vector representing the rotation of the driver bone (relative to its parent) that represents the center of this trigger's cone
HelperRotation_XYZ, HelperLocation_XYZ - A pair of 3D vectors that respectively represent rotation & location of this helper bone as the driver approaches the center of this trigger's cone
Used by <helper> to declare a specific rotation being watched, and the resulting rotation & location of the helper when the watched bone approaches this rotation.
There can be up to 32 <trigger> lines per <helper>, and all rotations are Euler rotations expressed in degrees.
The angle of influence refers to how far the bone must be from this rotation for this <trigger> to have fully faded out; as it approaches DriverRotation_XYZ, the procedural bone will approach HelperRotation_XYZ and HelperLocation_XYZ
Example:
<trigger>   60   -26.5650735797   -14.4773829758   -26.5652454670      -26.5650162839   -14.4773829758   -26.5651881712      0.000000000   0.000000000   0.000000000
Warning.pngWarning:The same trick above works here too, the three numbers after the bone ID and position are the rotation, but the rotations are in RADIANS - convert to degrees before using them in a <trigger>
<aimvector> <float|X> <float|Y> <float|Z>
Used by <aimconstraint> to declare the direction a <aimconstraint> will face as it tracks its TargetAttachment.
This vector is normalized, but does support any arbitrary orientation. Most commonly, bones will face a particular axis.
Example:
<aimvector> 0 0 -1
(causes the bone to face -Z, or Z always faces opposite the TargetAttachment)
<upvector> <float|X> <float|Y> <float|Z>
Used to clarify which axis on the TargetAttachment is considered "up".
Example:
<upvector> 0 1 0
(causes the bone to rotate with the attachment if it rotates along its local Y axis)


<display><float|X> <float|Y> <float|Z> <float|distance>
Used by the Softimage Mod Tool to store the attributes for procedural bone's appearance in Mod Tool's viewport, but has no purpose outside of it.
Example:
<display> -12.64333 4.33348 0.63611 4.45
<rotateaxis> <float|X> <float|Y> <float|Z>
Used to specify a pre-multiplied angle for all <trigger> definitions.
Example:
<rotateaxis> 0.0004010705   -119.9998795417   89.9996375014
Note.pngNote:This may have been meant to compliment <basepos> in setting a default angle, but no retail game ever uses it.
<jointorient> <float|X> <float|Y> <float|Z>
Used to specify a post-multiplied angle for all <trigger> definitions.
Example:
<jointorient> 56.3101202181   -154.3411936127   16.1020048039
Note.pngNote:This may have been meant to compliment <basepos> in setting a default angle, but no retail game ever uses it.


Common applications

The forearm of a full Valve biped skeleton. Note the ulna and wrist bones, both of which are "twist" bones that will be procedurally driven by the rotation of the hand bone.

The most common use case of procedural bones is to automatically rotate forearms, upper arms, thighs, and shins of character models. In the diagram to the right, the mesh is weighted to both a twist bone placed in the middle of the forearm (ValveBiped.Bip01_L_Ulna), and a twist bone located on the wrist (ValveBiped.Bip01_L_Wrist). Rather than require the animator to pose the hand, wrist, and ulna all together (which would not animate in the ragdoll anyway), the ulna & wrist are given procedural bone definitions that allow them to automatically rotate with the hand.

Corrective bones

In areas where rotating weighted bones causes a noticeable loss in mesh volume, such as on the exteriors of elbows & knees, a procedural bone can be used to better maintain the volume. By adding a helper in the same position as the elbow/knee and weighting the vertices nearest the apex of the joint to it, the mesh can be made to deform in a way that doesn't noticeably shrink.

In Team Fortress 2, the Engineer's character model uses a pair of procedural bones to keep his knee pads from deforming poorly when his knees bend, by watching the angle of the knee & rotating about half the distance to both keep the knee pads in the correct orientation and avoid visible shrinking.

Corrective flexes

In some engine branches that support $boneflexdriver, it is possible to use procedural bones to automatically fade in and fade out flexes. This technique lends itself most to applying local corrective or limited delta mush shapes to parts of a mesh that experience low-quality deformations, typically when put into extreme poses. Care must be taken when using this technique, since each corrective flex takes up a flexcontroller slot and requires a corresponding bone in the model's skeleton to drive it. This can quickly add up, counting against the MDL flexcontroller limit (usually 96 or 128) and bone limit (usually 128) and reducing the number of normal flexes and bones available to the model.

Note.pngNote: Deviates from official spec, but tested and working in: Half-Life 2, Counter-Strike: Source, Team Fortress 2, Portal, Garry's Mod
Warning.pngWarning: With additional requirements. Refer to section Driving Flexes with Procedural Bones at the end of this article.

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.

Mechanical armatures

It's desirable for a mechanical linkage to always point in the correct direction, say for instance in a piston that connects a lower armature to an upper armature. While you can manually animate this, it will neither work with a ragdoll nor during transitions of different animations. You can either manually define a set of known good frames, or an endpoint that the piston should always point towards.



VRD file examples

HWM Femscout forearm twists

Note.pngNote: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.


Crossbow string

<aimconstraint>	hlp_bow_L		hlp_bowflex_L	attach_string_L
<basepos>       15.070189000 0.000035000 -5.834238000
<aimvector>		-1 0 0 // Causes hlp_bow_L to face away from attach_string_L on the X axis
<upvector>		0 1 0

<aimconstraint>	hlp_bow_R		hlp_bowflex_R	attach_string_R
<basepos>       15.069914000 0.000015000 -5.834859000
<aimvector>		-1 0 0 // Causes hlp_bow_R to face away from attach_string_R on the X axis
<upvector>		0 1 0


Detailed right wrist created from an SMD animation

<helper>        hlp_wrist_R     bip_lowerArm_R  bip_lowerArm_R  bip_hand_R
<basepos>       8.643163000 -0.000000000 0.000021000
<trigger>       60      0.0001718873    150.0000642864  -90.0000958676  0.0001145916    150.0000642864  -90.0001531634  0.000000000     0.000000000     0.000000000      // time 0
<trigger>       60      0.0001718873    -149.9998923990 -90.0002677549  0.0001145916    -149.9998923990 -90.0003250507  0.000000000     0.000000000     0.000000000      // time 1
<trigger>       60      -52.0251407557  -89.9998666845  -38.2358227960  -48.7844914664  -89.9998666845  -38.7109193998  0.000000000     0.000000000     0.000000000      // time 2
<trigger>       60      -0.0001145916   -29.9999555615  -90.0001531634  -0.0001145916   -29.9999555615  -90.0002104591  0.000000000     0.000000000     0.000000000      // time 3
<trigger>       60      -0.0001145916   30.0001274488   -90.0002104591  -0.0001145916   30.0001274488   -90.0002677549  0.000000000     0.000000000     0.000000000      // time 4
<trigger>       60      153.4350608597  14.4776121589   26.5649016923   164.0022360669  26.1849160826   61.2785237386   -0.209301000    -0.381664000    0.031250000      // time 5
<trigger>       60      -153.4347743808 -14.4773829758  26.5648443966   -171.5899734436 -29.0682115950  68.3158205615   -0.189188000    -0.685485000    -0.609611000     // time 6
<trigger>       60      -89.9999239803  -29.9998982657  -0.0002291831   -90.0125290517  -70.4192059232  0.4019298933    -0.103786000    -0.028785000    -0.800817000     // time 7
<trigger>       60      -26.5650735797  -14.4773829758  -26.5652454670  -10.9441241406  -28.1016317947  -66.4090170193  -0.138767000    0.601700000     -0.401906000     // time 8
<trigger>       60      26.5651308755   14.4776121589   -26.5651881712  14.4604807209   26.7658952869   -68.4830096461  -0.374143000    0.995121000     0.171281000      // time 9
<trigger>       60      26.5651308755   165.5226941678  -26.5651881712  2.8720655397    150.2507333217  -86.7703900722  -0.108041000    0.564029000     -0.252821000     // time 10
<trigger>       60      -26.5651308755  -165.5223503931 -26.5652454670  3.3628038912    -149.6761139490 -92.8659161673  -0.211483000    0.771767000     0.567706000      // time 11
<trigger>       60      -90.0001531634  -149.9998923990 -0.0001145916   -86.2042504748  -94.3424857011  -7.0959104054   -0.224750000    0.172373000     0.564973000      // time 12
<trigger>       60      26.5649589881   -14.4775548631  -153.4351181555 3.6163950113    -29.7311237640  -95.1886297730  -0.084996000    -0.475180000    0.216209000      // time 13
<trigger>       60      -26.5651881712  14.4774402716   -153.4351181555 -5.6986955262   28.7843110076   -111.9647767186 -0.068011000    0.295446000     -0.111653000     // time 14
<trigger>       60      -119.9998795417 29.9999555615   89.9999239803   16.3264896680   144.2979310134  -91.0288988845  0.029360000     -0.468964000    -0.863318000     // time 15
<trigger>       60      -119.9998222460 -30.0000701530  89.9996947971   -158.5945458049 -15.7165760951  87.5142038819   -0.044148000    0.546487000     -0.608450000     // time 16
<trigger>       60      7.7956064648    -89.9998666845  -38.1285650968  30.3528975633   -87.9546938348  -100.1075870357 -0.292867000    0.814450000     -0.029658000     // time 17
<trigger>       60      59.9998538272   -29.9998982657  -90.0001531634  19.9532552154   -29.4507755149  -90.1107913136  -0.195600000    0.410349000     0.696194000      // time 18
<trigger>       60      59.9997965314   30.0000701530   -90.0002104591  19.3298771343   19.5167759671   -88.2561842266  -0.296514000    -0.591582000    0.830669000      // time 19
<trigger>       60      120.0001660206  29.9999555615   89.9999239803   156.9124563099  22.1676797978   88.3612073904   -0.348013000    0.475677000     0.507207000      // time 20
<trigger>       60      120.0002233164  -30.0000701530  89.9996947971   -18.0940644660  -137.9124309783 -92.6856636449  -0.288719000    -0.342254000    0.879168000      // time 21
<trigger>       60      -112.4273255466 -89.9998666845  -38.0887445300  -33.8569355510  -95.9927187426  -78.7788893373  -0.413648000    -0.655860000    -0.128256000     // time 22
<trigger>       60      -60.0000257145  -29.9999555615  -90.0001531634  -21.5571359713  -30.0129617034  -90.0030179523  -0.272500000    -0.344648000    -0.597419000     // time 23
<trigger>       60      -60.0000830103  30.0001274488   -90.0002104591  -19.7873839337  32.3326959286   -89.5132536291  -0.207348000    0.373764000     -0.711022000     // time 24


Miscellaneous

When StudioMDL parses <trigger> lines, all characters after the 10th space-delineated number are ignored. This can be used to place comments at the end of the line, like so:

<trigger> 90  -6.75 1.59 3.18  0 0 0  0 0 0   this text is ignored

For symmetrical models (such as humans) it's very common for left/right bones to have completely different local rotations & locations. As such, copying & pasting the procedural bone data from one side to the other will typically not work.

A procedural bone cannot be controlled by two or more driver bones. However, one driver bone can be re-used multiple times to control more than one procedural bone.



Driving Flexes with Procedural Bones

Using $proceduralbones to automatically drive a $boneflexdriver allows for advanced deformation techniques, such as automatic corrective shapes, but this functionality is not officially supported. As such, retail releases of StudioMDL refuse to compile models that use $boneflexdriver on any bone which is marked as the ProceduralBone in $proceduralbones's VRD file. To fix this, StudioMDL may be directly patched using a hex editor, thus allowing it to skip the early exit and successfully compile the model.

Warning.pngWarning:Modified instances of StudioMDL often produce models that deviate from the format expected by the engine - this may cause issues on specific games or engine branches.

Engine-specific patches

Includes most games where the model format's header begins with IDST0, including Half-Life 2 Half-Life 2, Counter-Strike: Source Counter-Strike: Source, Portal Portal, Team Fortress 2 Team Fortress 2, and Garry's Mod Garry's Mod.
Search for the unique byte sequence 04 74 25 8D 4F, then change the byte 74 to EB.
Search for the unique byte sequence 04 74 25 8B, then change the byte 74 to EB.
Search for the unique byte sequence 04 74 1C 8B 56 5C, then change the byte 74 to EB.
Search for the unique byte sequence 04 74 28 8B, then change the byte 74 to EB.
Todo: Determine the patch location for other notable games, including Left 4 Dead and Left 4 Dead 2

Important QC modification

In your model's QC file, you must specify $bonemerge on every bone that you make procedural. Refer to your VRD file, and add $bonemerge line(s) to your QC for the ProceduralBone of every <helper> line. The DriverBones do not need $bonemerge.

The reasoning behind the requirement of the seemingly unrelated $bonemerge flag is not yet fully understood.

Confirmation

Once the model has been compiled, you can test it in HLMV to verify that everything works as intended. The skeletal animation should now be able to drive the desired procedural bone(s), which in turn drive the flexcontroller(s).