Infected (shader)
The Infected
shader is used in Left 4 Dead 2 to dynamically render wounded zombies and body parts.
Instead of relying on gibbed variations of all models, this shader is used on the models to remove whichever body part was shot at to look more realistic, and allows for adding different types of slashes and dynamic gore and flesh effects.
The model will simply render hollow, however. So the programmer or artist would need to place skeleton and flesh models inside of the holes that were created, in order to create a convincing effect.
Contents
How the Shader Constructs the actual Base Texture
This shader is quite complex and no texture supplied to this shader is actually a base texture (despite the name of $basetexture
).
Here is how the actual base texture is constructed.
All of this layer's color is sampled from the $gradienttexture
. Two samples are taken from the $gradienttexture
:
PalletRowSelector_A = RandomInteger{from 0 to 7}
PalletRowSelector_B = RandomInteger{from 0 to 7}
Sample_A.color = $gradienttexture.sample($basetexture.alphaChannel.sample(u,v), 1/32 + PalletRowSelector_A*1/16)
• Generally used for ClothingSample_B.color = $gradienttexture.sample($basetexture.alphaChannel.sample(u,v), 1/32 + PalletRowSelector_B*1/16 + 0.5)
• Generally used for Skin
Notice Sample_B is always sampled 0.5 above Sample_A. The blue channel from $basetexture
is then used to linearly interpolate between these 2 colors.
- A blue value of 0.00 will return the color of Sample_A.
- A blue value of 1.00 will return the color of Sample_B.
- A blue value of 0.35 will return 65% of Sample_A and 35% of Sample_B mixed together.
Each of these samples are always taken from the same row of pixels. From row 0 to 7 for Sample_A and from row 8 to 15 for Sample_B. This allows for variation of color between otherwise duplicate models.
Shader Parameters
Check out left4dead2/materials/models/infected/common/l4d2/ci_body_include.vmt
for a sample material that uses the shader.
General
$basetexture <texture>
- Unlike other shaders, this parameter serves a completely different role. The
$basetexture
acts as an assembly texture, where each channel supplies the information needed to construct one complex texture. It is quite complicated. - Here is a tutorial on how to create such textures properly.
- Each channel's functions as a mask, which work as follows:
- Red:
- ◘ [000-127] Specularity
- ◘ [128-255] Detail, such as swamp mud.
- Red:
- Green:
- ◘ [000-127] Reflectivity, such as eyes and reflective parts on Roadworkers, CEDA and Riot police. Only works if $eyeglow is enabled.
- ◘ [128-255] Blood. It seems to blend similar to the "color burn" method.
- Green:
- Blue:
- ◘ [000-127] Clothing. Values closer to 127 make color less saturated. Useful sun-faded clothing, without editing the luminosity. Valve's default is 0.
- ◘ [128-255] Skin. Values closer to 127 make color less saturated. Useful for tanlines, without editing the luminosity. Valve's default is 255.
- Blue:
- Alpha: Luminosity and Color-Mapping. Used to map the palette onto the basetexture via a "Gradient Mapping" process
- ◘ Functions marked with a '◘' are split up into quadrants similar to a sprite sheet. This allows for more variations without using animation frames. A random quadrant per model will be chosen during runtime (when the models spawns in game).
- RGB channels use the grey color 127 as middlepoint between both uses of the channel, the closer to 0 or 255 makes the effect of the respective effect stronger.
$cheapdiffuse <bool>
- According to a VMT comment: "test stuff, doesn’t do anything right now".
$bumpmap <bool>
- The bump map's alpha channel is used as the exponent map if it is enabled. If the bump map is not enabled, $defaultphongexponent is used.
$disablevariation <bool>
- Turns off all the diffuse variation features, effectively turning it into a regular $basetexture. The new diffuse map's alpha channel can be used as a specular mask.
$gradienttexture <texture>
- The color palette, applying its colors to the model via Gradient Mapping.
$gradienttexture
must be 256x16; other resolutions such as 512x32 will not work! [todo tested in?]$nocull <bool>
- Determines whether the backsides of faces can be seen. If a model is sliced open, you will see the insides of the model as well.
$rttshadowbuild <bool>
- Unknown. May be related to RTT shadow rendering. Default value is 0, setting to 1 changes shader combination and renders the model as white.
$translucent <bool>
- Disables dynamic shadows on the model.
$translucent_material <string>
- Unknown. Possibly allows for a translucent render pass.
$sheetindex <int>
- Pick a specific corner of the basetexture to be used, as opposed to randomly picking one. Those corners would be the four variants in the Red and Green channels.
$colortintgradient <int>
- Force a specific horizontal gradient slice for color (lower 8 slices, usually clothing) to be used, instead of randomly picking a slice.
$ambientocclusion <bool>
- Enables ambient occlusion on the model (for example in Source Filmmaker).
Wounds
The most interesting part of this shader is the wound calculation. Set $wounded 1
to enable it.
To debug the wounds, you can use following shader parameters:
$debugellipsoids <bool>
- Enables debugging ellipsoids. These can be positioned using other shader parameters to mess with the effect.
- There are two debugging ellipsoids with different functionality. Only the second one is currently known to work: it bursts a hole into the model where it intersects.
- Leaving out the 2 from the next four shader parameters controls the ellipsoid 1, but no effects could be seen.
$ellipsoidcenter2 <vector>
- Center of the ellipsoid 2, in local space (0 0 0 should be the entity's origin).
$ellipsoidup2 <vector>
- The up axis of ellipsoid 2. Z-up (0 0 1) by default.
$ellipsoidlookat2 <vector>
- The direction that the ellipsoid 2 faces.
$ellipsoidscale2 <vector>
- The size of the ellipsoid 2, in local coordinates.
$ellipsoid2culltype <int>
The following shader parameters are unknown in function, but seem to be related to the wound rendering. They do not seem to influence the debugging ellipsoid culling at all.
$woundcutouttexture <texture>
- Texture containing masks for blood and shapes of the wounds.
$cutouttexturebias <float>
- When the cutout texture should mask the wound. Values below 0.5 hide the entire model when using debugging ellipsoids.
$cutoutdecalfalloff <float>
$cutoutdecalmappingscale <float>
Phong
$phong <bool>
$phongboost <float>
$phongtint <vector>
$phongfresnelranges <vector>
$halflambert <bool>
- See the relevant articles for these commands. They function identically to VertexLitGeneric's counterparts. However, $phongexponent related options do not work. See below for replacement options.
$defaultphongexponent <float>
- Equivalent to $phongexponent, except for any unmasked parts of the texture.
Detail
The detail pass is controlled by the top half of the red channel of the $basetexture
.
&detail <texture>
- The texture to use to add some detail to the model. Blended onto the model using the top half of the red channel of the
&basetexture
. - Unlike other textures in Source, this texture is actually transformed differently.
- In order to convert a regular
$basetexture
to the equivalent $detail texture (with same UV mapping), you will need to:- Mirror it horizontally
- Rotate it by 90° counter-clockwise
- Use a $detailscale of 1
&detailscale
- Scales the
&detail
texture AND the$burndetailtexture
.
Skin
$skintintgradient <int>
- Force a specific horizontal gradient slice for skin to be used, instead of randomly picking a slice.
$skinphongexponent <float>
- Equivalent to
$phongexponent
, except for skin parts of the texture (blue channel).
Blood
The blood pass is controlled by the green channel of the $basetexture.
$bloodcolor <color>
- Color of the blood pass.
$bloodphongexponent <float>
- Equivalent to $phongexponent, except for blood parts of the texture (green channel).
$bloodspecboost <float>
- Equivalent to $phongboost, except for blood parts of the texture (green channel).
$bloodmaskrange <vector2>
Burning
$burning <bool>
- Controls whether the material should appear burning. It needs to be in a different VMT with a "_burning" prefix. The game will switch to this other VMT on frame 0 after detecting that the model has caught fire. Opacity starts with 0 and it slowly increases based on $burnstrength.
$burnstrength <float>
- Opacity of the burning effect. Defaults to 0.
$burndetailtexture <texture>
- The texture to apply to the model when the model has been burned. This textures scale is controlled by
&detailscale
Eyeglow
The eyeglow pass is controlled by the bottom half of the red channel of the $basetexture
.
$eyeglow <bool>
- Set to 1 to enable the effect. Causes an additive color overlay, as well as different phong settings.
$eyeglowcolor <color>
- Color of the effect.
$eyeglowflashlightboost <float>
- Phong boost for the effect, in case the model is hit by projected texture lighting such as the flashlight.
SFM integration
Since Source Filmmaker version 0.9.8.9 (released 27 Aug, 2014), the Infected shader is supported and integrated into the program.
Creating an animation set with the shader will automatically generate the following attributes as part of the DmeGameModel:
infectedSkinTint <int>
infectedClothesTint <int>
- Unknown. May be related to the gradient texture controls.
infectedTextureIndex <int>
- Controls which of the four quarters of the $basetexture get selected for display (see above for detailed information).
- 0 is top left, 1 is top right, 2 is bottom left, 3 is bottom right.
See also
Rendering Wounds in Left 4 Dead 2
Shading a Bigger, Better Sequel - Techniques in Left 4 Dead 2
GDC Vault - A live presentation of the above PDF with commentary.