Left 4 Dead 2

Left 4 Dead 2

Not enough ratings
Color RNG (2.0) (Modders Guide)
By Ellie
This Guide aims to teach Modders about Color RNG, an efficient and low level crashing way of implementing randomized colors on survivors (and other models).
   
Award
Favorite
Favorited
Unfavorite
⛔️ Warning ⛔️
General Information
Difficulty :
Note that the difficulty only comes from the fact that you need to edit textures in a 2D Graphics Software. If you know how to do this, the rest is very easy.

Short description : Color RNG (2.0) is a way to randomize the colors of textures, such as (mainly) clothes for survivors. It's possible to make different textures (VMTs) randomize separately or together without having to make UV-Map edits.

🛠️ Important : It is required to have basic knowledge in a 2D Graphics Software, such as Photoshop or Gimp. This is required because the textures need to be edited.

Needed skills :
  • Knowing how to edit a VMT file
  • Knowing how to import a VTF file
  • Basic 2D Graphics Software skills (best if you know how to edit an alpha channel)
What is Color RNG (2.0) ?
What is it ?
Color RNG (2.0) is a way to randomize the color of a texture (or part of said texture). It allows to have (almost) infinite colors on a texture. Imagine a character whose vest color would change every map, or the handle of a shovel that would be of a different color each time you load a map.

What's new in 2.0 ?
Color RNG is not something new, but the version 2.0 is better in every way:
- No more color flickering glitches
- Easy way to tell which VMTs needs to share the same color and what ones should not
- The color will now be random for each entity (Real - Color - RNG)
- Allows the user to choose his own color with console (and it stays between maps this way)

Questions and Answers (Q&A)
Q : On what does it work ?
On most things, but this guide is only for entities (Survivors / Guns / Items / Infected etc.)
Q : What is the advantage of this ?
Unlike classic RNG (Randomization), this only uses one texture, and therefore, reduces the possible crashes a lot (having a lot of RNG mods, and a lot of textures that load at start, can cause crashes).
Q : Is it possible to select only certain colors to be randomized ?
Sadly no, or that would be too complicated to implement.
Q : What is this console color change module ?
You can implement a console color change module so the user can set his color using console (this is just an additional feature atop of the RNG). What’s cool is that if the color is set this way, it stays between maps and games, as long as the user does not left L4D2.

How much time does it take to add this to a mod ?
Converting the textures is what takes the most time. It depends on the texture, but when you're used to it, it takes approximately 5 minutes per texture, and 1 or 2 minutes to change the VMTs with the code for color RNG.
📁Convert the textures
The main and most complicated step is to convert the VTF files (textures) so that only specific parts of the model change color. This requires two big steps :
① : Change the color (albedo) of the parts that need to be colored to white
② : Create an alpha channel that is all black except for the parts that need to be colored (these need to be full white instead)

As a practical example thorough this Guide, I'll show you how to convert the following mod to Color RNG. The goal is to make the blue parts of her clothes randomize and take other colors than just blue.
https://steamhost.cn/steamcommunity_com/sharedfiles/filedetails/?id=140555769 This means changing these 2 textures so they are Color RNG'd :
- pl0590_00shirts_bm
- pl0590_00pants_bm

https://steamhost.cn/steamcommunity_com/sharedfiles/filedetails/?id=2292818158
① Change the color (albedo)
STEP 1
Extract the VTF textures to a folder using GCFScape, then, using VTFEdit, export these VTF textures to .tga files.

STEP 2
Open one of the .tga texture into Photoshop (or equivalent).

STEP 3
Select all the parts that need to change color in the texture you're working on (use the Lasso, the Magic Wand, or the Select Color Range tools), and copy them as a new layer.

Here, I selected all the blue parts in my first texture, then I copied the selection as a new layer (the second picture only shows the new layer, but what's on the left still exists but is (yet) hidden).

STEP 4
Turn the new layer to black and white (CTRL+ALT+SHIFT+B in Photoshop)

STEP 5
Adjust the curves (CTRL+M in Photoshop) so that the layer becomes white and not grey or black.

The left picture is the result after STEP 4, and the right one after STEP 5

STEP 6
Toggle back the visibility of the layer underneath (the one that still has the colored clothes).

② Create an alpha channel
STEP 1
Create a new channel (≠ a new layer) for the texture you are currently editing in Photoshop/Gimp and name it Alpha.

STEP 2
Make that new Alpha channel all black.

STEP 3
Copy the layer that has your white clothes only (the one with transparency that's still at the top of the original texture) and paste it in the Alpha channel.

STEP 4
Position the newly copied shape so that the alpha channel aligns perfectly with the other RGB (Red/Green/Blue) channels (you might not need this step if everything is perfectly aligned in the alpha channel).

STEP 5
Increase the brightness of the Alpha channel multiple times up to the point that the (originally) grey shapes become all white.
If you want the colors to be less flashy/saturated on your model, do not do this step fully and only increase the brightness a few times up until you get a light grey.

The left image is the Alpha channel after STEP 4, and the right image after STEP 5

STEP 6
Save the result as a .tga file (32bits).

This is what the texture looks like just before saving with the RGB and the Alpha channel view enabled (the red tones is just the way Photoshop shows where the alpha channel is)

STEP 7
Import the .tga file in VTFEdit and press CTRL+M. If you did everything right, you should now only see the white parts that need to change color on a checkered background.

If the result looks like this, you did everything right and the VTF is ready.

STEP 8
Save (and replace) the (old) original VTF file that is in your mod.

STEP ↻
Repeat everything (including ➀) for every other VTF that needs to be converted to change color.
⚙️Edit the VMTs
The next steps are the easy ones. It almost only requires you to copy some stuff in the VMT. You might need to remove / replace stuff first though. The parts are the following :
① : Remove any patch { } or proxies in the VMT
② : Copy&Paste the code in the VMT
➂ : Tweak some minor options (Boomer effects / Linked color parts)
① Remove incompatible things
STEP 1
Look for this in the VMT of the texture you are editing (the file path under 'include' can be different)
patch { include "materials/models/survivors/survivors_it_shared.vmt" insert {
If you do not see this, just go to STEP 2.
If you see this, replace what's above with that :
VertexLitGeneric {
And (still if you saw this), remove one...
}
... at the end of the VMT.

STEP 2
Look for this in the VMT of the texture you are editing:
Proxies {
If you do not see this, just go to the next section
If you see this, remove it and also remove everything that is below it in the VMT.

Then (if you removed it), add one...
}
... at the end of the VMT.
➁ Copy the code
STEP 1
Copy this in the VMT of the texture that needs to change color (at the end, above the last })
/////////////////////////////////////////////////////// // COLOR RNG 2020 - By Ellie /////////////////////////////////////////////////////// $number1 "11" $number2 "13" $number3 "17" $onePerMap "0" $rngSkins "0" $boomerEffects "0" // $detail "models/survivors/survivor_it" // $detailscale 3 // $detailblendfactor ".001" // $detailblendmode 0 $meleeBloodEffects "0" // $detail "models/infected/hunter/hunter_01_detail" // $detailscale "1.75" // $detailblendfactor .001 // $detailblendmode 0 //----------------------------------------------------------- // Codes variables (do not modify) //----------------------------------------------------------- $model 1 $color "[1 1 1]" $blendtintbybasealpha "1" $zero "0" $one "1" $ten "10" $tff "255" $pos "[0 0 0]" $posX .0 $posXStored .0 $posY .0 $posYStored .0 $posZ .0 $posZStored .0 $ENTJustSpawned "0" $ismoving "0" $rand "0.0" $randStored "1000.0" $randRNG "0.0" $multFactorRNG "0.0" $posINT .0 $posD .0 $posDFRAC .0 $posDF .0 $posADD .0 $pos_R .0 $pos_G .0 $pos_B .0 $Mf1 .0 $Mf2 .0 $Mf3 .0 $cReds "1000.0" $cGreens "1000.0" $cBlues "1000.0" $cRedsDIV .0 $cGreensDIV .0 $cBluesDIV .0 $boomerAmount .0 $bloodAmount .0 $randSK .0 $randSKStored 1000 $randSKInject .0 //----------------------------------------------------------- // Proxies (modify only if told to) //----------------------------------------------------------- Proxies { PlayerPosition { scale 1 resultVar "$pos" } Clamp { srcVar1 "$zero" min "$pos[0]" max "$pos[0]" resultVar "$posX" } Clamp { srcVar1 "$zero" min "$pos[1]" max "$pos[1]" resultVar "$posY" } Clamp { srcVar1 "$zero" min "$pos[2]" max "$pos[2]" resultVar "$posZ" } Abs { srcVar1 "$posX" resultVar "$posX" } Abs { srcVar1 "$posY" resultVar "$posY" } Abs { srcVar1 "$posZ" resultVar "$posZ" } LessOrEqual { LessEqualVar "$posX" greaterVar "$posXStored" srcVar1 "$posXStored" srcVar2 "$zero" resultVar "$posXStored" } LessOrEqual { LessEqualVar "$posY" greaterVar "$posYStored" srcVar1 "$posYStored" srcVar2 "$zero" resultVar "$posYStored" } LessOrEqual { LessEqualVar "$posZ" greaterVar "$posZStored" srcVar1 "$posZStored" srcVar2 "$zero" resultVar "$posZStored" } LinearRamp { rate "-1" initialValue "30" resultVar "$ENTJustSpawned" } EntitySpeed { resultVar "$ismoving" } EntityRandom { scale "$one" resultVar "$rand" } LessOrEqual { LessEqualVar "$randStored" greaterVar "$rand" srcVar1 "$randStored" srcVar2 "$tff" resultVar "$randStored" } LessOrEqual { LessEqualVar "$rand" greaterVar "$randStored" srcVar1 "$onePerMap" srcVar2 "$zero" resultVar "$randRNG" } LessOrEqual { LessEqualVar "$multFactorRNG" greaterVar "$randRNG" srcVar1 "$ENTJustSpawned" srcVar2 "$zero" resultVar "$multFactorRNG" } LessOrEqual { LessEqualVar "$multFactorRNG" greaterVar "$randRNG" srcVar1 "$ismoving" srcVar2 "$zero" resultVar "$multFactorRNG" } LessOrEqual { LessEqualVar "$multFactorRNG" greaterVar "$randRNG" srcVar1 "$randRNG" srcVar2 "$zero" resultVar "$multFactorRNG" } Multiply { srcVar1 "$multFactorRNG" srcVar2 "$number1" resultVar "$Mf1" } Multiply { srcVar1 "$multFactorRNG" srcVar2 "$number2" resultVar "$Mf2" } Multiply { srcVar1 "$multFactorRNG" srcVar2 "$number3" resultVar "$Mf3" } Frac { srcVar1 "$Mf1" resultVar "$Mf1" } Frac { srcVar1 "$Mf2" resultVar "$Mf2" } Frac { srcVar1 "$Mf3" resultVar "$Mf3" } Int { srcVar1 "$posXStored" resultVar "$posINT" } Divide { srcVar1 "$posINT" srcVar2 "$ten" resultVar "$posD" } Frac { srcVar1 "$posD" resultVar "$posDFRAC" } Add { srcVar1 "$posDFRAC" srcVar2 "$Mf1" resultVar "$posADD" } Frac { srcVar1 "$posADD" resultVar "$pos_R" } Equals // [X-Reds] { srcVar1 "$pos_R" resultVar "$color[0]" } Int { srcVar1 "$posYStored" resultVar "$posINT" } Divide { srcVar1 "$posINT" srcVar2 "$ten" resultVar "$posD" } Frac { srcVar1 "$posD" resultVar "$posDFRAC" } Add { srcVar1 "$posDFRAC" srcVar2 "$Mf2" resultVar "$posADD" } Frac { srcVar1 "$posADD" resultVar "$pos_G" } Equals // [X-Greens] { srcVar1 "$pos_G" resultVar "$color[1]" } Int { srcVar1 "$posZStored" resultVar "$posINT" } Divide { srcVar1 "$posINT" srcVar2 "$ten" resultVar "$posD" } Frac { srcVar1 "$posD" resultVar "$posDFRAC" } Add { srcVar1 "$posDFRAC" srcVar2 "$Mf3" resultVar "$posADD" } Frac { srcVar1 "$posADD" resultVar "$pos_B" } Equals // [X-Blues] { srcVar1 "$pos_B" resultVar "$color[2]" } IT { resultVar "$boomerAmount" } LessOrEqual { LessEqualVar "$detailblendfactor" greaterVar "$boomerAmount" srcVar1 "$boomerEffects" srcVar2 "$zero" resultVar "$detailblendfactor" } BloodyHands { resultVar "$bloodAmount" } LessOrEqual { LessEqualVar "$detailblendfactor" greaterVar "$bloodAmount" srcVar1 "$meleeBloodEffects" srcVar2 "$zero" resultVar "$detailblendfactor" } Multiply { srcVar1 "$rand" srcVar2 "$rngSkins" resultVar "$randSK" } LessOrEqual { LessEqualVar "$randSKStored" greaterVar "$randSK" srcVar1 "$randSKStored" srcVar2 "$tff" resultVar "$randSKStored" } LessOrEqual { LessEqualVar "$randSK" greaterVar "$randSKStored" srcVar1 "$onePerMap" srcVar2 "$zero" resultVar "$randSKInject" } LessOrEqual { LessEqualVar "$frame" greaterVar "$randSKInject" srcVar1 "$rngSkins" srcVar2 "$zero" resultVar "$frame" } // [CSELECT] }
➂ Optional tweaks
Define what textures should have the same color
In the code, you can see this.
$number1 "11" $number2 "13" $number3 "17"
All the VMTs on your model that have the same values for these numbers will share the same color (but different models will not share their colors even if they have the same numbers).

Therefore :
  • If you want 2 VMTs on your model to share the same color, make sure these values are the same for both of them.
  • If you want 2 VMTs on your model to have different colors, make sure these values are different (you can swap them or input new numbers)
If possible, try using prime numbers. They will ensure maximal randomization.

No multiple skins per map
If you want the selected color to be the same on every iteration of your model within the map, just change this line...
$onePerMap "0"
... into this.
$onePerMap "1"
Note that this is recommended for survivors mods, since each survivor is unique, and that setting this to 1 will prevent the dead corpse of the survivor from taking a random color.

Boomer effects
To display the boomer effects, set the value of $boomerEffects to 1 and unquote the things under it. It should look like this at the end...
$boomerEffects "1" $detail "models/survivors/survivor_it" $detailscale 3 $detailblendfactor ".001" $detailblendmode 0
... instead of this.
$boomerEffects "0" // $detail "models/survivors/survivor_it" // $detailscale 3 // $detailblendfactor ".001" // $detailblendmode 0

Blood on melee weapon effects
To display blood on the melee weapon, set the value of $meleeBloodEffects to 1 and unquote the things under it. It should look like this at the end...
$meleeBloodEffects "1" $detail "models/infected/hunter/hunter_01_detail" $detailscale "1.75" $detailblendfactor .001 $detailblendmode 0
... instead of this.
$meleeBloodEffects "0" // $detail "models/infected/hunter/hunter_01_detail" // $detailscale "1.75" // $detailblendfactor .001 // $detailblendmode 0
📟 Console color change module
A new feature that you can implement as a module is the possibility to change the color of the clothes using the console. It works atop of the Color RNG, and will not interfere with it.

The reason why it's not included in the code itself is that it will flag an error in console if the variables are not defined (the error won't have any other consequence though).

① : Copy&Paste the module in the VMT
② : Change the variables names
➂ : Determine the console code to change the texture

Note that uniquely, the color that is set this way stays the same between maps and games, as long as the person does not exit L4D2.
Therefore, it is possible for the user to start the game, go in мяFunreal's TUMTaRA maps. Select the color he wants, then to start a real game where his/her survivor will still have the same color. He could even bind the selected color change code (or even all selected colors for all mods he has) to one key that he just presses to change all his survivors to its likings each time the game starts.
➀ Copy the module
STEP 1
Copy this in the VMTs of the textures that the user will be able to change with the console, just below // [CSELECT] (look at the end of the VMTs that have the code you copied).
ConVar { convar "TEST_r" resultVar "$cReds" } ConVar { convar "TEST_g" resultVar "$cGreens" } ConVar { convar "TEST_b" resultVar "$cBlues" } Divide { srcVar1 "$cReds" srcVar2 "$tff" resultVar "$cRedsDIV" } Divide { srcVar1 "$cGreens" srcVar2 "$tff" resultVar "$cGreensDIV" } Divide { srcVar1 "$cBlues" srcVar2 "$tff" resultVar "$cBluesDIV" } LessOrEqual { LessEqualVar "$cRedsDIV" greaterVar "$pos_R" srcVar1 "$cReds" srcVar2 "$tff" resultVar "$color[0]" } LessOrEqual { LessEqualVar "$cGreensDIV" greaterVar "$pos_G" srcVar1 "$cGreens" srcVar2 "$tff" resultVar "$color[1]" } LessOrEqual { LessEqualVar "$cBluesDIV" greaterVar "$pos_B" srcVar1 "$cBlues" srcVar2 "$tff" resultVar "$color[2]" }
➁ Change the variables names
STEP 1
In the code you just copied, you can see these:
TEST_r
TEST_g
TEST_b

For each one, change the TEST to some name that goes well with your mod.

For example, if you make a mod for Sherry, as in my example, you could change these to
Sherry_r
Sherry_g
Sherry_b
➂ Determine the code
STEP 1
The basic code you'll need to input in console (you can also bind it to a key) is the following, but you'll need to change some things in it.
setinfo TEST_r 255;setinfo TEST_g 255;setinfo TEST_b 255;mat_reloadmaterial ##########;

STEP 2
Like in the previous step, replace TEST_r, TEST_g and TEST_b by the name you choose.
For example, for me, it would be this :
setinfo Sherry_r 255;setinfo Sherry_g 255;setinfo Sherry_b 255;mat_reloadmaterial ##########;

STEP 3
Modify the ########## to the path of one of your materials that is on your model and that changes color.

For example, if your mod has the following material: models/re6l4d2/sherry_omake00/pl0590_00shirts_bm.vmt, just input this, like that :
setinfo Sherry_r 255;setinfo Sherry_g 255;setinfo Sherry_b 255; mat_reloadmaterial models/re6l4d2/sherry_omake00/pl0590_00shirts_bm;
Note that you must not write the .vmt extension
Note that you must not put materials/ at the beginning, but start with /models

STEP 4
If you have more than one VMT that needs to change color, you now need to add one extra mat_reloadmaterial ############; line at the end of your code for each of these.

For example, I also have the the following material (pl0590_00pants_bm.vmt), so I need to write this
setinfo Sherry_r 255;setinfo Sherry_g 255;setinfo Sherry_b 255; mat_reloadmaterial models/re6l4d2/sherry_omake00/pl0590_00shirts_bm; mat_reloadmaterial models/re6l4d2/sherry_omake00/pl0590_00pants_bm;
This is the final code that the subscribers can use to change the colors.
Note that if the color is changed this way, it will stay the same for all maps as long as the user does not exit L4D2.

STEP 5
Tell your subscribers what the final code is. To use it, just replace the 255's by whatever (RGB) value you want between 0 and 255 for reds (_r), greens (_g) and blues (_b).
🎞️ Basetexture RNG
You might want to have texture RNG atop of all this color RNG, for example, if you have two different sets of clothes with different parts that should be colored.

If so, just make sure that all your different designs are in different frames of your $basetexture. If you do not know how to do that, go to this Guide and to Steps 1-5 of [Easy] : Animated textures.

Then, look a this line in the code
$rngSkins "0"
Change the 0 to the number of different skins you have for your VMT.

For example, if you have 2 sets of clothes that can change color (plain and dotted), just write...
$rngSkins "2"