Infected (shader): Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
m (→‎Usage: $cheapdiffuse comment)
(Maximum gradientexture width should probably be a todo)
 
(25 intermediate revisions by 14 users not shown)
Line 1: Line 1:
The <code>Infected</code> shader is used in {{l4d2}} [[Left 4 Dead 2]] to dynamically render wounded zombies and body parts.
The <code>'''Infected'''</code> shader is used in {{l4d2}} [[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.
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.
Line 9: Line 9:
{{note|This shader only works on models.}}
{{note|This shader only works on models.}}


== Usage ==
===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 <code>$basetexture</code>).


{{note|The shader was only tested in Source Filmmaker. As of such, and due to the fact that the source code is inaccessible, many shader parameters and features are not further explained and require further testing (especially inside of the game itself).}}
Here is how the actual base texture is constructed.


Check out <code>left4dead2/materials/models/infected/common/l4d2/bp_head_include.vmt</code> for a sample material that uses the shader.
All of this layer's color is sampled from the <code>$gradienttexture</code>. Two samples are taken from the <code>$gradienttexture</code>:
: <code>PalletRowSelector_A = RandomInteger{from 0 to 7}</code>
: <code>PalletRowSelector_B = RandomInteger{from 0 to 7}</code>
: <code>Sample_A.color = $gradienttexture.sample($basetexture.alphaChannel.sample(u,v), 1/32 + PalletRowSelector_A*1/16)</code>  • Generally used for Clothing
: <code>Sample_B.color = $gradienttexture.sample($basetexture.alphaChannel.sample(u,v), 1/32 + PalletRowSelector_B*1/16 + 0.5)</code> • Generally used for Skin
Note that in DirectX the Y-Axis of Textures is flipped, the snippet here with the 0.5f offset will cause wrong colors when used as is on DirectX.
There are 2 Options to solve this, either flip the Y-Axis ( 1.0f - UV.y ) or give Clothing the 0.5f Y-Offset instead of Skin.


=== General ===
Two Samples are taken from the Gradient Texture. The Code that was on this Page previously said they should be lerped together using the blue channel.
That is untrue.
The lower half of the blue channel ( 0 - 127 ) handles cloth, and the upper half ( 128 - 255 ) handles skin.
The individual masks for cloth and skin can be extracted similarly to how wrinklemapping weights work.


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.
A specific row can be forced for skin and cloth using $colortintgradient and $skintintgradient
A specific corner in the $basetexture can be chosen using $sheetindex
{{todo|What index gives which Panel?}}
==Shader Parameters==
Check out {{path|left4dead2/materials/models/infected/common/l4d2/ci_body_include|vmt}}</code> for a sample material that uses the shader.
===General===
; <code>$basetexture <[[texture]]></code>
; <code>$basetexture <[[texture]]></code>
: Unlike other shaders, this parameter serves a completely different role. It acts as a mask texture, where each channel serves a different purpose:
: Unlike other shaders, this parameter serves a completely different role. The <code>$basetexture</code> acts as an assembly texture, where each channel supplies the information needed to construct one complex texture. It is quite complicated.
: '''Red*:''' Detail blend mask
:[https://steamcommunity.com/sharedfiles/filedetails/?id=1567031703 Here is a tutorial] on how to create such textures properly.
: '''Green*:''' Blood blend mask
: Each channel's functions as a mask, which work as follows:
: '''Blue:''' Skin mask
 
: '''Alpha*:''' Eyeglow mask
:: '''Red:'''
: Additionally, the vtf is split up similarly to a sprite sheet. All channels marked with a * are affected by this.
::: ◘ [000-127] Specularity
: To compensate, scale down these channels to half their size and place them in one of the four quarters of the texture. This allows for more "variations" without using animation frames.
::: ◘ [128-255] Detail, such as swamp mud.
 
:: '''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.
 
:: '''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.
 
:: '''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.
{{note|Since the $basetexture contains masks, it is NOT sRGB. Make sure when saving a custom texture, it is stored in a linear colorspace.}}
 
; <code>$cheapdiffuse <bool></code>
: According to a VMT comment: "test stuff, doesn’t do anything right now".
; <code>[[$bumpmap]] <bool></code>
: 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.
{{note|this is available as per "Last Stand" update.}}
; <code>$disablevariation <bool></code>
: 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.
{{note|Added in "Last Stand" update. Burn detail mask is also disabled when variation is disabled otherwise we'd have crispy skin texture all over the clothing}}
; <code>$gradienttexture <texture></code>
: The color palette, applying its colors to the model via Gradient Mapping.
{{note|The {{code|$gradienttexture}} is indexed via the alpha channel of the $basetexture and random y offsets in the 1/16 range
Due to the random offsets the maximum y resolution of the texture is 16.}}
{{todo|In case of rgba8888 there are 256 sample points, so increasing the width might not give you a different result if the same gradients are used.
Which is probably why a maximum resolution of 256 was assumed. Do other Formats for the $basetexture ( such as [[Valve Texture Format#Image data formats|RGBA16161616F]] ) allow more sample points and thus a higher resolution, Or does the game cap it at 256x16?}}
{{tip|Using [[Valve Texture Format#Image data formats|BGR888]] is ''highly recommended'' to prevent compression from messing up the colors.}}
; <code>[[$nocull]] <[[bool]]></code>
; <code>[[$nocull]] <[[bool]]></code>
: 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.
: 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.
; <code>$rttshadowbuild <bool></code>
: Unknown. May be related to [[Dynamic RTT shadow angles in Source 2007|RTT shadow rendering]]. Default value is 0, setting to 1 changes shader combination and renders the model as white.
; <code>[[$translucent]] <bool></code>
; <code>[[$translucent]] <bool></code>
: Disables dynamic shadows on the model.
: Disables dynamic shadows on the model.
; <code>$cheapdiffuse <bool></code>
: According to a vmt comment: "test stuff, doesn’t do anything right now".
; <code>$rttshadowbuild <bool></code>
: Unknown. May be related to [[Dynamic RTT shadow angles in Source 2007|RTT shadow rendering]]. Default value is 0, setting to 1 changes shader combination and renders the model as white.
; <code>$translucent_material <[[string]]></code>
; <code>$translucent_material <[[string]]></code>
: Unknown. Possibly allows for a translucent render pass.
: Unknown. Possibly allows for a translucent render pass.
; <code>$gradienttexture <texture></code>
: Unknown. Possibly related to wounds.
; <code>$sheetindex <int></code>
; <code>$sheetindex <int></code>
: 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.
; <code>$colortintgradient <int></code>
; <code>$colortintgradient <int></code>
: Unknown. Possibly controlled using code?
: Force a specific horizontal gradient slice for color (lower 8 slices, usually clothing) to be used, instead of randomly picking a slice.
; <code>[[$ambientocclusion]] <bool></code>
; <code>[[$ambientocclusion]] <bool></code>
: Enables ambient occlusion on the model (for example in Source Filmmaker).
: Enables ambient occlusion on the model (for example in Source Filmmaker).


{{note|While this shader supports many of [[VertexLitGeneric]]'s shader parameters, it does not support [[$bumpmap]] due to the complexity of the shader. [https://steamcdn-a.akamaihd.net/apps/valve/2010/GDC10_ShaderTechniquesL4D2.pdf From ''Shading a Bigger, Better Sequel - Techniques in Left 4 Dead 2'']}}
===Wounds===
 
=== Wounds ===
 
The most interesting part of this shader is the wound calculation. Set <code>$wounded 1</code> to enable it.
The most interesting part of this shader is the wound calculation. Set <code>$wounded 1</code> to enable it.


Line 64: Line 109:
: The size of the ellipsoid 2, in local coordinates.
: The size of the ellipsoid 2, in local coordinates.
; <code>$ellipsoid2culltype <int></code>
; <code>$ellipsoid2culltype <int></code>
: Unknown. 0 seems to be regular culling of ellipsoid 2, other values disable the ellipsoid. (This parameter does not exist for ellipsoid 1.)
{{todo|Explain. 0 seems to be regular culling of ellipsoid 2, other values disable the ellipsoid. (This parameter does not exist for ellipsoid 1.)}}
 




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.
The following shader parameters do not influence the debugging ellipsoids but are used for wound rendering.


; <code>$woundcutouttexture <texture></code>
; <code>$woundcutouttexture <texture></code>
: Texture containing masks for blood and shapes of the wounds.
: Texture that gets applied via projection from the culling ellipsoids, likely set in code as you cannot find it in any vmt's
: See the gdc10 talk about this to see how these are applied. ( Although it is missing some code. The UV gets remapped so the center is .5 .5 )
: The Texture masks the shape of the culled areas and applies blood splatters around the culled area.
; <code>$cutouttexturebias <float></code>
; <code>$cutouttexturebias <float></code>
: When the cutout texture should mask the wound. Values below 0.5 hide the entire model when using debugging ellipsoids.
: When the cutout texture should mask the wound. Values below 0.5 hide the entire model when using debugging ellipsoids.
; <code>$cutoutdecalfalloff <float></code>
; <code>$cutoutdecalfalloff <float></code>
: Unknown.
: This does not seem to be a Parameter in old builds of l4d2 or the latest TLS build.
; <code>$cutoutdecalmappingscale <float></code>
; <code>$cutoutdecalmappingscale <float></code>
: Unknown.
: scale factor for the $woundcutouttexture uv. Since the UV for the Texture is created from ellipsoid scale, a custom scaling factor for the texture is needed.
 
=== Phong ===


===Phong===
; <code>[[$phong]] <bool></code>
; <code>[[$phong]] <bool></code>
; <code>[[$phong#Parameters|$phongboost]] <[[float]]></code>
; <code>[[$phong#Parameters|$phongboost]] <[[float]]></code>
Line 90: Line 135:
: Equivalent to $phongexponent, except for any unmasked parts of the texture.
: Equivalent to $phongexponent, except for any unmasked parts of the texture.


=== Detail ===
===Detail===
 
The detail pass is controlled by the top half of the red channel of the <code>$basetexture</code>.
The detail pass is controlled by 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:
 
# Take the original vtf file
# Mirror it horizontally
# Rotate it by 90° counter-clockwise
# Use a [[$detailscale]] of 1
 
Besides these parameters, [[$detailframe]] and $detailblendfactor are also supported.
 
{{todo|How is the alpha channel handled?}}


{{todo|Is the $basetexture transformed like this as well?}}
; <code>&detail <texture></code>
: 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 <code>&basetexture</code>.
: Unlike other textures in Source, this texture is actually transformed differently.


=== Skin ===
: In order to convert a regular <code>$basetexture</code> 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


The skin pass is controlled by the blue channel of the $basetexture. It also is the only channel that does not allow for variation using texture indexes (see below).
; <code>&detailscale</code>
: Scales the <code>&detail</code> texture AND the <code>$burndetailtexture</code>.
{{note|most, if not all, vmt parameters found in [[$detail]] will work for the infected shader as well.}}


===Skin===
; <code>$skintintgradient <int></code>
; <code>$skintintgradient <int></code>
: Unknown. Possibly controlled using code?
: Force a specific horizontal gradient slice for skin to be used, instead of randomly picking a slice.
; <code>$skinphongexponent <float></code>
; <code>$skinphongexponent <float></code>
: Equivalent to $phongexponent, except for skin parts of the texture (blue channel).
: Equivalent to <code>$phongexponent</code>, except for skin parts of the texture (blue channel).
 
=== Blood ===


===Blood===
The blood pass is controlled by the green channel of the $basetexture.
The blood pass is controlled by the green channel of the $basetexture.


; <code>$bloodcolor <color></code>
; <code>$bloodcolor <color></code>
: Color of the blood pass. {{todo|Is this multiplied with anything, or just overlaid as it is?}}
: Color of the blood pass. This gets converted from Gamma to Linear, otherwise blood becomes too saturated (read: bright).
; <code>$bloodphongexponent <float></code>
; <code>$bloodphongexponent <float></code>
: Equivalent to $phongexponent, except for blood parts of the texture (green channel).
: Equivalent to $phongexponent, except for blood parts of the texture (green channel).
; <code>$bloodspecboost <float></code>
; <code>$bloodspecboost <float></code>
: {{todo|Does this increase or set the $phongboost of bloody parts?}}
: Equivalent to $phongboost, except for blood parts of the texture (green channel).
; <code>$bloodmaskrange <vector2></code>
; <code>$bloodmaskrange <vector2></code>
: Unknown. Seems to modify the phong shape on blood.
: Min/Max for the blood mask smoothstep mentioned in the GDC10 presentation. Used to work around blurriness issues caused by the compressed range of the blood mask.
 
=== Burning ===


===Burning===
; <code>$burning <bool></code>
; <code>$burning <bool></code>
: Controls whether the material should appear burning. Does not seem to do anything.
: 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.
; <code>$burnstrength <float></code>
; <code>$burnstrength <float></code>
: Opacity of the burning effect. Defaults to 0.
: Opacity of the burning effect. Defaults to 0.
; <code>$burndetailtexture <texture></code>
; <code>$burndetailtexture <texture></code>
: Unknown. Most likely the texture to use for the burning effect, implemented similarly to how Team Fortress 2 handles burning models (overlaying a $detail texture).
: The texture to apply to the model when the model has been burned. This textures scale is controlled by <code>&detailscale</code>
 
=== Eyeglow ===


The eyeglow pass is controlled by the alpha channel of the $basetexture.
===Eyeglow===
: The eyeglow pass is controlled by the bottom half of the red channel of the <code>$basetexture</code>.
: Originally this was intended to make zombies feel less human, but it was later used for other effects,
: such as retroreflectivity. The construction workers vests use this effect.


; <code>$eyeglow <bool></code>
; <code>$eyeglow <bool></code>
: Set to 1 to enable the effect. Causes an additive color overlay, as well as different phong settings.
: Set to 1 to enable the effect.
; <code>$eyeglowcolor <color></code>
; <code>$eyeglowcolor <color></code>
: Color of the effect.
: Color of reflected light in the masked areas.
; <code>$eyeglowflashlightboost <float></code>
; <code>$eyeglowflashlightboost <float></code>
: Phong boost for the effect, in case the model is hit by projected texture lighting such as the flashlight.
: Phong boost for the effect, in case the model is hit by projected texture lighting such as the flashlight.


== SFM integration ==
==SFM integration==
 
Since Source Filmmaker version 0.9.8.9 (released 27 Aug, 2014), the Infected shader is supported and integrated into the program.
Since Source Filmmaker version 0.9.8.9 (released 27 Aug, 2014), the Infected shader is supported and integrated into the program.


Line 162: Line 201:
: 0 is top left, 1 is top right, 2 is bottom left, 3 is bottom right.
: 0 is top left, 1 is top right, 2 is bottom left, 3 is bottom right.


== See also ==
==See also==
[https://steamcdn-a.akamaihd.net/apps/valve/2010/gdc2010_vlachos_l4d2wounds.pdf ''Rendering Wounds in Left 4 Dead 2'']
 
[https://steamcommunity.com/sharedfiles/filedetails/?id=1567031703&preview=true ''L4D2 CI Texture Guide'']
 
[https://steamcdn-a.akamaihd.net/apps/valve/2010/GDC10_ShaderTechniquesL4D2.pdf ''Shading a Bigger, Better Sequel - Techniques in Left 4 Dead 2'']


[https://steamcdn-a.akamaihd.net/apps/valve/2010/gdc2010_vlachos_l4d2wounds.pdf ''Rendering Wounds in Left 4 Dead 2'']
[https://www.gdcvault.com/play/1012264/Shading-a-Bigger-Better-Sequel GDC Vault - A live presentation of the above PDF with commentary.]


[[Category:List of Shader Parameters|I]]
[[Category:Shaders|I]]

Latest revision as of 11:48, 8 September 2025

The Infected shader is used in Left 4 Dead 2 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.

Todo: Add some images from the game or the presentation here.
Todo: How does this shader relate to $shinyblood of VertexLitGeneric?
Note.pngNote:This shader only works on models.

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 Clothing
Sample_B.color = $gradienttexture.sample($basetexture.alphaChannel.sample(u,v), 1/32 + PalletRowSelector_B*1/16 + 0.5) • Generally used for Skin

Note that in DirectX the Y-Axis of Textures is flipped, the snippet here with the 0.5f offset will cause wrong colors when used as is on DirectX. There are 2 Options to solve this, either flip the Y-Axis ( 1.0f - UV.y ) or give Clothing the 0.5f Y-Offset instead of Skin.

Two Samples are taken from the Gradient Texture. The Code that was on this Page previously said they should be lerped together using the blue channel. That is untrue. The lower half of the blue channel ( 0 - 127 ) handles cloth, and the upper half ( 128 - 255 ) handles skin. The individual masks for cloth and skin can be extracted similarly to how wrinklemapping weights work.

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. A specific row can be forced for skin and cloth using $colortintgradient and $skintintgradient A specific corner in the $basetexture can be chosen using $sheetindex

Todo: What index gives which Panel?

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.
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.
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.
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.
Note.pngNote:Since the $basetexture contains masks, it is NOT sRGB. Make sure when saving a custom texture, it is stored in a linear colorspace.
$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.
Note.pngNote:this is available as per "Last Stand" update.
$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.
Note.pngNote:Added in "Last Stand" update. Burn detail mask is also disabled when variation is disabled otherwise we'd have crispy skin texture all over the clothing
$gradienttexture <texture>
The color palette, applying its colors to the model via Gradient Mapping.
Note.pngNote:The $gradienttexture is indexed via the alpha channel of the $basetexture and random y offsets in the 1/16 range Due to the random offsets the maximum y resolution of the texture is 16.
Todo: In case of rgba8888 there are 256 sample points, so increasing the width might not give you a different result if the same gradients are used. Which is probably why a maximum resolution of 256 was assumed. Do other Formats for the $basetexture ( such as RGBA16161616F ) allow more sample points and thus a higher resolution, Or does the game cap it at 256x16?
Tip.pngTip:Using BGR888 is highly recommended to prevent compression from messing up the colors.
$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>
Todo: Explain. 0 seems to be regular culling of ellipsoid 2, other values disable the ellipsoid. (This parameter does not exist for ellipsoid 1.)


The following shader parameters do not influence the debugging ellipsoids but are used for wound rendering.

$woundcutouttexture <texture>
Texture that gets applied via projection from the culling ellipsoids, likely set in code as you cannot find it in any vmt's
See the gdc10 talk about this to see how these are applied. ( Although it is missing some code. The UV gets remapped so the center is .5 .5 )
The Texture masks the shape of the culled areas and applies blood splatters around the culled area.
$cutouttexturebias <float>
When the cutout texture should mask the wound. Values below 0.5 hide the entire model when using debugging ellipsoids.
$cutoutdecalfalloff <float>
This does not seem to be a Parameter in old builds of l4d2 or the latest TLS build.
$cutoutdecalmappingscale <float>
scale factor for the $woundcutouttexture uv. Since the UV for the Texture is created from ellipsoid scale, a custom scaling factor for the texture is needed.

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:
  1. Mirror it horizontally
  2. Rotate it by 90° counter-clockwise
  3. Use a $detailscale of 1
&detailscale
Scales the &detail texture AND the $burndetailtexture.
Note.pngNote:most, if not all, vmt parameters found in $detail will work for the infected shader as well.

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. This gets converted from Gamma to Linear, otherwise blood becomes too saturated (read: bright).
$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>
Min/Max for the blood mask smoothstep mentioned in the GDC10 presentation. Used to work around blurriness issues caused by the compressed range of the blood mask.

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.
Originally this was intended to make zombies feel less human, but it was later used for other effects,
such as retroreflectivity. The construction workers vests use this effect.
$eyeglow <bool>
Set to 1 to enable the effect.
$eyeglowcolor <color>
Color of reflected light in the masked areas.
$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

L4D2 CI Texture Guide

Shading a Bigger, Better Sequel - Techniques in Left 4 Dead 2

GDC Vault - A live presentation of the above PDF with commentary.