Left 4 Dead 2

Left 4 Dead 2

127 ratings
BodyGroup Randomization for Modders
By Zetnus
A modder's guide to explain the use of BodyGroups to randomize survivor and infected models.
   
Award
Favorite
Favorited
Unfavorite
Preface
Is this guide for you?

This guide will teach you how to use BodyGroups to randomize your custom models.

This guide assumes that you are familiar with modding custom models for L4D2 (not just retexturing, but actual model editing). Specifically, you should know how to decompile, edit in a 3D program and recompile player models. Furthermore you should have some basic knowledge of the stuff you find in *.qc files so that you can tweak it as needed.

If this all sounds unfamiliar, then you should first learn how to work with modding models before dealing with things like randomization.
Introduction
BodyGroup Randomization is a way to randomize parts of a model (or the whole model) using entirely model-based techniques. It should not be confused with material proxy-based Model RNG, which is explained by Ellie in this guide: http://sp.zhabite.com/sharedfiles/filedetails/?id=668958242

Where BodyGroup randomization comes from
The basis of BodyGroup Randomization comes from the common (and uncommon) infected. The game randomly chooses head models for the common infected so as to increase the variation in the horde and make it less likely that players think they are encountering the same zombie again and again. The actual mechanism for this is that a given common infected model contains several head submodels in the “Head” BodyGroup. The server you are playing on will then randomly pick one of those heads each time a zombie spawns. Furthermore many of the zombies also have random bodies, which are similarly selected at random (and independently from the heads).

What I discovered is that this same technique used by the game for the common infected also works for the special infected and for survivors (with the caveat that it doesn’t randomize in online multiplayer).

Pros and Cons
These are the benefits and drawbacks of BodyGroup Randomization:

Pros/advantages
+++ Ragdoll always matches the killed infected
+++ No texture flickering issues
+++ No glow outline issues
++ Able to stack many variations without causing in-game crashes
+ Randomization works in online multiplayer (for common/uncommon infected)
+ Easy to make your mod fully compatible with retexture mods

Cons/limitations
--- No randomization in online multiplayer (for special infected and survivors)
--- Only works for players and NPCs (NOT weapons/props/foliage or ANYTHING else)
-- Facial flexes cannot be applied to BodyGroups; thus faces with flexes cannot be randomized
-- Only 3 BodyGroups can be randomized
- Does not work for viewmodels (first person arms)
- Each BodyGroup randomizes separately (ex. no way to do linked randomization without merging meshes)


When to use BodyGroup Randomization

+++ Common and uncommon infected A better choice than attempting to use Model RNG

+/- Special Infected Lets you avoid glow outline issues and ragdoll issues. However, in online multiplayer it will always chose the first available submodel; so if online randomization is important to you, then use Model RNG instead.

+/- Survivors Lets you avoid glow outline issues. However, in online multiplayer it will always chose the first available submodel; so if online randomization is important to you, then use Model RNG instead.

--- Anything that isn’t an infected or a survivor BodyGroup Randomization will have NO EFFECT. Choose Model RNG instead!
Example 1: More Common Infected Heads
Let’s start with something basic. We know that the common infected already randomize BodyGroups, so let us look at how this is done. Here is the first part of the common_male_ceda.qc

$ModelName "infected/common_male_ceda.mdl" $BodyGroup "UpperBody" { studio "common_male_ceda_cim_ceda_full.smd" } $BodyGroup "Head" { studio "common_male_ceda_cim_head_bald01.smd" studio "common_male_ceda_cim_head_bald02.smd" studio "common_male_ceda_cim_head_bald03.smd" studio "common_male_ceda_cim_head_shaggy01.smd" studio "common_male_ceda_cim_head_shaggy02.smd" studio "common_male_ceda_cim_head_shaggy04.smd" } $BodyGroup "LowerBody" { blank }


So, what we see here is that the CEDA hazmat suit is in $BodyGroup “UpperBody” and six possible heads are in $BodyGroup “Head”. $BodyGroup “LowerBody” contains no meshes. LowerBody is included in all the common infected, but is always blank because the whole body is always in UpperBody.

If we, for example, want to add some additional heads, we first need to prepare the relevant .smd files. For example, we could decompile a female common infected and grab the head meshes. We then reference them under $BodyGroup "Head".

If we wanted to, we could add new body variations under $BodyGroup "UpperBody", but in for this example we will only do heads.

$ModelName "infected/common_male_ceda.mdl" $BodyGroup "UpperBody" { studio "common_male_ceda_cim_ceda_full.smd" } $BodyGroup "Head" { studio "common_male_ceda_cim_head_bald01.smd" studio "common_male_ceda_cim_head_bald02.smd" studio "common_male_ceda_cim_head_bald03.smd" studio "common_male_ceda_cim_head_shaggy01.smd" studio "common_male_ceda_cim_head_shaggy02.smd" studio "common_male_ceda_cim_head_shaggy04.smd" studio "common_female_tanktop_jeans_cif_head_longhair01.smd" studio "common_female_tanktop_jeans_cif_head_longhair02.smd" studio "common_female_tanktop_jeans_cif_head_pony_bangs.smd" studio "common_female_tanktop_jeans_cif_head_layers.smd" } $BodyGroup "LowerBody" { blank }

Then recompile your model. Now, if you test it in game or in Half Life Model Viewer, you will be able to see the new variations. In hlmv, this is what you need to click to cycle through the variations:
.
.
In game I suggest using the TUMTaRA infected map, because it will autogenerate all the possible common infected combinations, including any new ones you have added.
https://sp.zhabite.com/sharedfiles/filedetails/?id=469986973


Finishing Touches

$LOD
You may have noticed a load of $LOD lines in the .qc file. If you wanted, you could reference the LOD meshes for your new heads as well. However, as far as I can tell, the LOD meshes barely make any difference at all when it comes to common infected, so you can safely ignore this step, or even delete all the existing LOD lines.

$TextureGroup "skinfamilies"
This part of the qc file lets the game load new textures for wounded or burning infected. In our case, it looks like this to start with:
.
We will simply go to our source .qc of our female heads, and grab the relevant lines and add them to the existing skinfamilies matrix. Important: add them as new columns to the right and not as new rows further below.
.
.
Making it Fit
Not all heads fit seamlessly onto all bodies. For example, you may need to flatten the head/hair of any heads that are going on a body with a hat/helmet or else it will stick out the top. Adjust the head meshes in a 3D editing program as needed.

Warnings
Certain of the uncommon body meshes are not amenable to any sort of adjustment. If the faces become weirdly stretched or if ragdoll issues start popping up, then it means you’ve modified a body mesh in a way you should not have. I don’t fully understand this yet, so my best recommendation is to adjust the heads to fit the bodies rather than the other way around. That seemed to prevent these issues for me.

The riot police and mudmen are a special case. Their body meshes will always cause ragdoll issues; even if it is recompiled after no modifications whatsoever. I have no idea why. So just be aware of this if you intend to use those meshes.
This isssue is solved by using Crowbar v0.52 or later!

Final mod
Here is what our male/female CEDA mod looks like when it is done:
https://sp.zhabite.com/sharedfiles/filedetails/?id=727150143
Example 2: Whole Model Randomization
Next, let us use BodyGroup Randomization on a whole model. In our example we will do this for a special infected, because those don’t have pesky things like facial animations to worry about. Here is the first part of the hunter .qc file:
$ModelName "infected/hunter.mdl" $BodyGroup "hunter_model" { studio "hunter_reference.smd" } $LOD 30 { replacemodel "hunter_reference.smd" "hunter_reference_lod1.smd" } $SurfaceProp "flesh" $Contents "solid" $EyePosition 0 0 73 $MaxEyeDeflection 90 $AmbientBoost $Opaque $CDMaterials "models\infected\hunter\" $CDMaterials ""

We want the hunter to use an entirely new mesh half the time. So we reference the new mesh right after the existing one. However, we must also rename the BodyGroup. The $BodyGroup "hunter_model" is not one that the game will automatically randomize for you. It will only do that for “Head”, “UpperBody” and “LowerBody”.

We happen to have a low poly LOD mesh for our new hunter, so let’s add that to the $LOD. If we didn’t have one, we would just leave $LOD as it is (it would only affect the default mesh in that case).

Finally, we need to make sure that the game knows where to find the textures for our new hunter, so we add a relevant $CDMaterials line.

Here is what the new .qc file looks like:
$ModelName "infected/hunter.mdl" $BodyGroup "LowerBody" { studio "hunter_reference.smd" studio "awesome_new_hunter.smd" } $LOD 30 { replacemodel "hunter_reference.smd" "hunter_reference_lod1.smd" replacemodel "awesome_new_hunter.smd" "awesome_new_hunter_lod1.smd" } $SurfaceProp "flesh" $Contents "solid" $EyePosition 0 0 73 $MaxEyeDeflection 90 $AmbientBoost $Opaque $CDMaterials "models\infected\hunter\" $CDMaterials "models\infected\awesome_hunter\" $CDMaterials ""

And that is it! It really is that easy. The game will now randomly pick one of the two hunter models each time a new hunter spawns. Keep in mind that when playing in online multiplayer, it will always choose the first one in the list – in this case the default hunter model.

Multiple Meshes (ex. Witches)
If our special infected consisted of multiple meshes we would have to do a bit more work. For example, the witch and her hair are separate .smd files. Since we always want the witch and her hair to be together, they cannot be listed under separate BodyGroups because then they would randomize independently of each other. But if we list both .smd files in the same BodyGroup, then it will be either the body OR the hair that is chosen, which is not at all what either.

The solution is to merge the two smd files in your 3D editing program and export them as one single .smd file. You can then randomize the model as we did with the hunter.

Example 3: Survivor BodyGroup Combinations
Finally let us consider how to do BodyGroup Randomization for survivors.
The first part of the .qc file for the Zoey mesh looks like this:
$ModelName "survivors/survivor_TeenAngst.mdl" $Model "TeenAngst" "survivor_teenangst_reference.smd" { eyeball "eye_right" "ValveBiped.Bip01_Head1" -1.110000 -3.499979 62.600012 "models\survivors\teenangst\teenangst_eyeball_r" 1 5 "iris_unused" 0.6 eyeball "eye_left" "ValveBiped.Bip01_Head1" 1.110000 -3.499979 62.600012 "models\survivors\teenangst\teenangst_eyeball_l" 1 -5 "iris_unused" 0.6 eyelid upper_right "survivor_teenangst.vta" lowerer 43 -0.22 neutral 0 0.09 raiser 44 0.34 split 1 eyeball "eye_right" eyelid lower_right "survivor_teenangst.vta" lowerer 45 -0.39 neutral 0 -0.22 raiser 46 -0.11 split 1 eyeball "eye_right" eyelid upper_left "survivor_teenangst.vta" lowerer 47 -0.27 neutral 0 0.05 raiser 48 0.29 split -1 eyeball "eye_left" eyelid lower_left "survivor_teenangst.vta" lowerer 49 -0.43 neutral 0 -0.27 raiser 50 -0.16 split -1 eyeball "eye_left" mouth 0 "mouth" "ValveBiped.Bip01_Head1" 0 1 0 flexfile "survivor_teenangst.vta" { // lots and lots of flex file stuff
… and it goes on and on and on with details of the flexfile.
In any case, you will notice that $Model is used instead of $BodyGroup. That is because $Model support eyelids and flexfiles and everything you need for facial animation, while $BodyGroup does not support those things. This means that you CANNOT use BodyGroup Randomization for faces.

By default, the entire Zoey mesh is in the survivor_teenangst_reference.smd file. So how do we randomize anything here?

The answer is that we import the mesh into our 3D editing program and split up the mesh into multiple .smd files. Usually, only the face is affected by the flexfile, so other parts of the body can be safely split off from the main model and turned into BodyGroups.

In our case, we are going to leave the entire head intact in $Model with all the facial information. The upper torso will be a BodyGroup and the legs will be a different BodyGroup. Finally we will use the third BodyGroup slot to add hats. Of course we first need to obtain/produce the necessary model variations, but that is simply modeling work and is beyond the scope of this guide.

$ModelName "survivors/survivor_TeenAngst.mdl" $Model "TeenAngst" "survivor_teenangst_reference_head.smd" { eyeball "eye_right" "ValveBiped.Bip01_Head1" -1.110000 -3.499979 62.600012 "models\survivors\teenangst\teenangst_eyeball_r" 1 5 "iris_unused" 0.6 eyeball "eye_left" "ValveBiped.Bip01_Head1" 1.110000 -3.499979 62.600012 "models\survivors\teenangst\teenangst_eyeball_l" 1 -5 "iris_unused" 0.6 eyelid upper_right "survivor_teenangst.vta" lowerer 43 -0.22 neutral 0 0.09 raiser 44 0.34 split 1 eyeball "eye_right" eyelid lower_right "survivor_teenangst.vta" lowerer 45 -0.39 neutral 0 -0.22 raiser 46 -0.11 split 1 eyeball "eye_right" eyelid upper_left "survivor_teenangst.vta" lowerer 47 -0.27 neutral 0 0.05 raiser 48 0.29 split -1 eyeball "eye_left" eyelid lower_left "survivor_teenangst.vta" lowerer 49 -0.43 neutral 0 -0.27 raiser 50 -0.16 split -1 eyeball "eye_left" mouth 0 "mouth" "ValveBiped.Bip01_Head1" 0 1 0 flexfile "survivor_teenangst.vta" { // lots and lots of flex file stuff } } $BodyGroup "UpperBody" { studio "survivor_teenangst_default_body.smd" studio "survivor_teenangst_body_jacketopen.smd" studio "survivor_teenangst_body_nojacket.smd" studio "survivor_teenangst_body_jacket_tied.smd" studio "survivor_teenangst_body_jacketrolledsleeves.smd" } $BodyGroup "LowerBody" { studio "survivor_teenangst_body_default_legs.smd" studio "survivor_teenangst_body_shorts_med.smd" studio "survivor_teenangst_body_shorts_long.smd" studio "survivor_teenangst_body_shorts_short.smd" } $BodyGroup "Head" { studio "blank.smd" studio "baseball_cap.smd" studio "cowboy_hat.smd" }
Make sure that all BodyGroups come AFTER $Model, or else it will mess things up horribly!

In single player, the game will randomly choose an upper body, lower body, and maybe a hat for Zoey each time you start a new map or spawn a new Zoey. It will also do this each time you use the console to switch control to Zoey or away from Zoey using sb_takecontrol. <--Good for testing purposes!

In online multiplayer, it will always pick the first thing in each BodyGroup. In this case the default body, default legs and “blank” for the hat (meaning no hat). We could reorder the submodels if we wanted something else to be picked by default.

Notice that the head is always selected because it’s not one of our randomizing BodyGroups. If we had anything listed as $BodyGroup "TeenAngst", that mesh would also be chosen every time, because “TeenAngst” is not a BodyGroup that randomizes.

I believe that covers everything …

Making it fit
One last point to remember is that every combination must fit together – make sure that each submodel fits with all other BodyGroups without any gaps. This is where your experience with your 3D modeling program comes into play. For the common infected heads it was easy, because they all fit very well on most of the bodies with only minor edits needed (if any at all), but for combinatorial survivor mods you may need to modify things to fit properly together.

Ultimately, you can make something like this:
https://sp.zhabite.com/sharedfiles/filedetails/?id=737510918
Conclusion
Using BodyGroup Randomizations for survivors and special infected is a new discovery and not fully understood yet. That means that this guide is still a work-in-progress and may be updated as more becomes known or new tricks are discovered.

I hope this guide was helpful to you. Feel free to ask any questions or provide feedback in the comments below!
75 Comments
聖(せい), zaq1234sd 19 Aug, 2024 @ 3:01am 
i was wondering why game can't read my sub model, After reading I'm assuming that cuz iv used a different bodygroup name. thx a lot
MRcedaguy 2 Mar, 2022 @ 11:05pm 
can you help me to find infected model on left 4 dead 2 authoring tool model viewer because for some reason there is no infected model, can you know how to find any infected model
Zetnus  [author] 9 Feb, 2022 @ 7:46am 
You can have duplicates, especially if you use different names
Trinity 9 Feb, 2022 @ 7:16am 
So, if I wanted to do a rng model that had a very low chance of spawning one of the meshes out of two possible meshes then I would have to duplicate the smd references in the bodygroup section? For instance, making the first mesh duplicated 9 times and then the special mesh 1 time. Or is there a way to do this through 1 simple line? Maybe this wouldn't even work because you cannot have duplicates?
Zetnus  [author] 22 Nov, 2020 @ 11:48am 
Ah, I'll correct that in the guide
Shakes 22 Nov, 2020 @ 11:43am 
Ah! I think I found the solution. Blank bodygroups are overlooked when the game randomly picks one to draw. This makes sense as allowing them could easily mean a missing head, legs, etc. on common infected. The workaround is to use an "empty" SMD mesh instead of the "blank" bodygroup option. By this I mean opening your existing mesh in a text editor and deleting all of the "triangle" entries, leaving the skeleton and keyframe information intact and using this new mesh as a bodygroup.
Zetnus  [author] 21 Nov, 2020 @ 8:02am 
hmmm that is wierd
Shakes 21 Nov, 2020 @ 6:57am 
A survivor mod I made recently seems to be picking the 2nd or third bodygroup nearly 100% of the time. One bodygroup is glasses and the other is a combined glasses+mask mesh. I tried adding a second "blank" bodygroup to give it a more even chance of not having the glasses on but the only time I don't see the mask is the non-player test mesh when using TUMTARA. The model controlled by an actual player or a bot always has the glasses on.

In addition, the L4D2 version of studiomdl seems to have broken bodygroup compilation and so I've had to resort to using the version of studiomdl from SFM.
CuldeeFell4 30 Aug, 2020 @ 12:14pm 
thanks for the tip mate. keep up the good work
Zetnus  [author] 30 Aug, 2020 @ 11:48am 
You should be able to just add them as bodygroups and toggle through bodygroups in SFM. That being said, I've never used SFM, so I can't do it for you.