Decals: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
No edit summary
Line 1: Line 1:
When the player shoots his or her weapon into a wall, the marks left by the bullet impacts are called "decals". These are most easily thought of as materials that are applied to a surface and remain there as an indelible mark on the world. Posters, scorch marks, and stenciled letters can all be created using this type of graphic. Decals will ''clip'' their extents to whatever surface they are placed on to. For example, a decal applied to a staircase would cascade down on to each stair surface instead of hanging out into space. You can also think of this as how a stencil would apply a mark to the world.
[[File:Decal06.jpg|thumb|A decal placed by a level designer.]] [[File:Decal03.jpg|thumb|Bullet impacts generated by the game.]]


Creating decals is straightforward: they are simply materials generally having an ''alpha channel mask'' of some sort, and possible using the <code>[[DecalModulate]]</code> shader. Before reading this article, please read about the basics of [[Material Creation|material creation]].
'''Decals''' are materials projected onto existing surfaces. They can be placed by the level designer, and are also generated by the engine for bullet impacts, blood, and other effects.


== Standard decals ==
{{note|Each decal affects ''one entity only''. ([[The world]] is one big entity.)}}
The most simple type of decal is one that simply acts like a true decal or stencil: source art is clipped and projected on to the world within some mask, specified via the material's alpha channel (centre):


<div style="text-align:center;">[[Image:decal04.jpg|128px|Source color channels]] [[Image:decal05.jpg|128px|Source alpha channel]] [[Image:Decal06.jpg|128px|Decal in the world]]</div>
Decals are "sprayed" from a location and mark every surface in their path. For instance, a decal applied downward onto a staircase would cascade down onto the top (but not front) of each step.
 
== Using ==
 
{{note|[[VertexLitGeneric]] decals won't show up on brushes, and [[LightmappedGeneric]] ones won't appear on models (unless they define a <code>$modelmaterial</code>, [[#Creating|see below]]).}}
 
=== Hammer ===


===Material parameters===
{{tip|If a decal entity has a name it will appear when [[use]]d (i.e. blank input) or on receiving the <code>activate</code> input, instead of when the map starts.}}
A decal's [[material]] looks something like this:


[[LightmappedGeneric]]
; '''{{hammer decal}}'''
{
: Creates [[infodecal]] entities, which decal [[brush]]es and [[displacement]]s.
[[$basetexture]] decals\mydecal
; '''[[info_projecteddecal]]'''
$decal 1
: An entity that decals [[model]]s or displacements (but ''not'' brushes). The angle of projection can be set, allowing for distortion.
$decalscale 0.1
; '''{{hammer overlay}}'''
[[$translucent]] 1
: Overlays are more [[expensive]] decals that offer level designers more control.
$modelmaterial decals\mydecal_model
}


; <code>$decal <[[bool]]></code>
=== C++ ===
: Marks the material as a decal. Without it, the decal will not be clipped or projected onto the world properly.
; <code>$decalscale <[[float]]></code>
: Important because its default is one pixel to one inch. If the source texture for this decal is 128 pixels, a value of <code>0.1</code> will cause it to be 12.8 inches in size in the engine (about a foot).
:{{tip|A decal can't be drawn at a higher resolution that the texture it's applied to. [[Hammer Overlay Tool|Overlays]] can, but they are more [[expensive]].}}
; <code>$translucent <bool></code>
: See <code>[[$translucent]]</code>.
; <code>$modelmaterial <material></code>
: Separate <code>[[VertexLitGeneric]]</code> material to apply to models, if applicable.
; <code>$decalfadeduration <float></code>
: Amount of time to spend fading out. Requires <code>[[$vertexcolor]]</code>.
; <code>$decalfadetime <float></code>
: Delay before fadeout begins.
; <code>$decalsecondpass</code>
: {{TODO|??}}


== Application ==
==== Standard ====


{{note|Decals that are meant to be applied to [[model]]s (such as blood) must use the <code>[[VertexLitGeneric]]</code> or <code>[[DecalModulate]]</code> shaders. <code>[[LightmappedGeneric]]</code> only works on [[brush]]es.}}
Created in response to impacts, blood, and so on. Limited in number by the value of [[r_decals]], [[CRecipientFilter#Reliable vs. Unreliable|unreliable]] when transmitted, and not transmitted to players who connect after creation.


=== Hammer ===
{{note|Only materials registered in <code>scripts/decals_subrect.txt</code> can be used!}}


*Decals can be placed on [[brush]]es in Hammer with the '''[[Hammer Overlay Tool|Overlay]]''' or '''[[Hammer Decal Tool|Decal]]''' tools. These decals will exist when the map loads.
; <code>CBaseEntity::DecalTrace([[trace_t]]* pTrace, const char* decalName)</code>
*The [[info_projecteddecal]] entity can be used to apply decals to both brushes and models at any time.
: Shared code. The trace defines where the decal is projected from and its location. {{todo|How to avoid transmission being suppressed due to prediction?}}
; <code>C_BaseEntity::AddDecal( <lots of args> );</code>
: Client function where the decal is actually created. In most cases you are better off just calling <code>DecalTrace()</code>.


=== C++ ===
==== Static ====


Decals can be created in on the client with <code>C_BaseEntity::AddDecal()</code>. Internally this calls <code>AddStudioDecal()</code> or <code>AddBrushModelDecal()</code> depending on whether the entity has a brush or model. Parameters for these functions:
Normally created by the level designer. These decals last forever and are always transmitted, including to players who connect later on. Any material can be used.


<source lang=cpp>void C_BaseEntity::AddDecal( const Vector& rayStart, const Vector& rayEnd, const Vector& decalCenter,
; <code>engine->StaticDecal( Vector localOrigin, int decalIndex, int entityIndex, int modelIndex, bool lowpriority )</code>
int hitbox, int decalIndex, bool doTrace, trace_t& tr, int maxLODToDecal );
: Server only.
:; <code>Vector localOrigin</code>
:: Where the decal will be created, relative to the target's origin.
:; <code>int decalIndex</code>
:: A value received from <code>UTIL_PrecacheDecal()</code>. ''Don't'' use <code>GetDecalIndexForName()</code>.
:; <code>int entityIndex</code>
:; <code>int modelIndex</code>
:: Information about the target entity.
:; <code>bool lowpriority</code>
:: Low priority decals are not saved, and can be "re-used on the client preferentially".
; <code>UTIL_PrecacheDecal(const char *filename, bool preload)</code>
: Returns a decal index for use with <code>StaticDecal()</code>. If this is in <code>[[precache()]]</code>, remember that it may be called statically; store the result in a global var.


void C_BaseEntity::AddBrushModelDecal( const Ray_t& ray, const Vector& decalCenter,
== Creating ==
int decalIndex, bool doTrace, trace_t& tr );


void C_BaseEntity::AddStudioDecal( const Ray_t& ray, int hitbox, int decalIndex,
: ''This section assumes that you understand the basics of [[Material Creation|material creation]].''
bool doTrace, trace_t& tr, int maxLODToDecal );</source>


This can be achieved on the server with <code>engine->StaticDecal</code>:
Any material can be used as a decal. They generally have an [[alpha channel]] however, and can use some special parameters and/or the <code>[[#DecalModulate|DecalModulate]]</code> shader.


<source lang=cpp>void IVEngineServer::StaticDecal( const Vector &originInEntitySpace, int decalIndex, int entityIndex, int modelIndex, bool lowpriority );</source>
<div style="text-align:center;">[[Image:decal04.jpg|128px|Source color channels]] [[Image:decal05.jpg|128px|Source alpha channel]] [[Image:Decal06.jpg|128px|Decal in the world]]</div>


Decal indices can be obtained by calling <code>decalsystem->GetDecalIndexForName</code> or <code>UTIL_PrecacheDecal()</code>:
=== Material parameters ===


<source lang=cpp>int IDecalEmitterSystem::GetDecalIndexForName( char const *decalname ); // Valid decalnames are defined in scripts/decals_subrect.txt
; <code>$decal <[[bool]]></code>
int UTIL_PrecacheDecal( const char *filename, bool preload );</source>
: Effect unknown.
; <code>$decalscale <[[float]]></code>
: Same as a brush face's texture scale value: the number of [[unit]]s that each [[texel]] covers. Normally 0.25 or lower.
; <code>$modelmaterial <material></code>
: A separate <code>[[VertexLitGeneric]]</code> material to that will replace this one if the decal hits a [[model]].
; <code>$decalfadeduration <float></code>
: Amount of time to spend fading out. Requires <code>[[$vertexcolor]]</code>.
; <code>$decalfadetime <float></code>
: Delay before fadeout begins.
; <code>$decalsecondpass</code>
: {{todo}}


== Using modulation ==
=== DecalModulate ===
For decals intended to mimic the look of pock marks or dents in a surface, the <code>[[DecalModulate]]</code> (a.k.a. mod2x) shader is especially suitable: it lightens destination pixels for every source pixel that is over mid-range gray (128) and darkens any destination pixels for every source pixel that is below mid-range gray. This effect can be used to give the impression of depth when applied to a surface.
For decals intended to mimic the look of pock marks or dents in a surface, the <code>[[DecalModulate]]</code> (a.k.a. mod2x) shader is especially suitable: it lightens destination pixels for every source pixel that is over mid-range gray (128) and darkens any destination pixels for every source pixel that is below mid-range gray. This effect can be used to give the impression of depth when applied to a surface.


Line 80: Line 88:
<div style="text-align:center;">[[Image:decal01.jpg|128px|Source color channels]] [[Image:decal02.jpg|128px|Source alpha channel]] [[Image:decal03.jpg|128px|Decal in the world]]</div>
<div style="text-align:center;">[[Image:decal01.jpg|128px|Source color channels]] [[Image:decal02.jpg|128px|Source alpha channel]] [[Image:decal03.jpg|128px|Decal in the world]]</div>


Finally, you must create a material that uses the <code>[[DecalModulate]]</code> shader. Neither <code>$translucent</code> nor <code>$decal</code> are needed this time.
Finally, you must create a material that uses the <code>DecalModulate</code> shader. Neither <code>$translucent</code> nor <code>$decal</code> are needed this time.


== See also ==
== See also ==

Revision as of 08:15, 3 April 2011

A decal placed by a level designer.
Bullet impacts generated by the game.

Decals are materials projected onto existing surfaces. They can be placed by the level designer, and are also generated by the engine for bullet impacts, blood, and other effects.

Note.pngNote:Each decal affects one entity only. (The world is one big entity.)

Decals are "sprayed" from a location and mark every surface in their path. For instance, a decal applied downward onto a staircase would cascade down onto the top (but not front) of each step.

Using

Note.pngNote:VertexLitGeneric decals won't show up on brushes, and LightmappedGeneric ones won't appear on models (unless they define a $modelmaterial, see below).

Hammer

Tip.pngTip:If a decal entity has a name it will appear when used (i.e. blank input) or on receiving the activate input, instead of when the map starts.
Decal tool Mt-decal.png
Creates infodecal entities, which decal brushes and displacements.
info_projecteddecal
An entity that decals models or displacements (but not brushes). The angle of projection can be set, allowing for distortion.
Overlay tool Mt-overlay.png
Overlays are more expensive decals that offer level designers more control.

C++

Standard

Created in response to impacts, blood, and so on. Limited in number by the value of r_decals, unreliable when transmitted, and not transmitted to players who connect after creation.

Note.pngNote:Only materials registered in scripts/decals_subrect.txt can be used!
CBaseEntity::DecalTrace(trace_t* pTrace, const char* decalName)
Shared code. The trace defines where the decal is projected from and its location.
Todo: How to avoid transmission being suppressed due to prediction?
C_BaseEntity::AddDecal( <lots of args> );
Client function where the decal is actually created. In most cases you are better off just calling DecalTrace().

Static

Normally created by the level designer. These decals last forever and are always transmitted, including to players who connect later on. Any material can be used.

engine->StaticDecal( Vector localOrigin, int decalIndex, int entityIndex, int modelIndex, bool lowpriority )
Server only.
Vector localOrigin
Where the decal will be created, relative to the target's origin.
int decalIndex
A value received from UTIL_PrecacheDecal(). Don't use GetDecalIndexForName().
int entityIndex
int modelIndex
Information about the target entity.
bool lowpriority
Low priority decals are not saved, and can be "re-used on the client preferentially".
UTIL_PrecacheDecal(const char *filename, bool preload)
Returns a decal index for use with StaticDecal(). If this is in precache(), remember that it may be called statically; store the result in a global var.

Creating

This section assumes that you understand the basics of material creation.

Any material can be used as a decal. They generally have an alpha channel however, and can use some special parameters and/or the DecalModulate shader.

Source color channels Source alpha channel Decal in the world

Material parameters

$decal <bool>
Effect unknown.
$decalscale <float>
Same as a brush face's texture scale value: the number of units that each texel covers. Normally 0.25 or lower.
$modelmaterial <material>
A separate VertexLitGeneric material to that will replace this one if the decal hits a model.
$decalfadeduration <float>
Amount of time to spend fading out. Requires $vertexcolor.
$decalfadetime <float>
Delay before fadeout begins.
$decalsecondpass
[Todo]

DecalModulate

For decals intended to mimic the look of pock marks or dents in a surface, the DecalModulate (a.k.a. mod2x) shader is especially suitable: it lightens destination pixels for every source pixel that is over mid-range gray (128) and darkens any destination pixels for every source pixel that is below mid-range gray. This effect can be used to give the impression of depth when applied to a surface.

To begin, create a source image whose color channel will be used for the modulation's source values. Again, light values will lighten pixels they're drawn over, while dark values will darken the destination pixels. Mid-gray values will be treated as translucent.

Next, create an alpha channel that defines a mask for the decal. Because modulation cannot have an exact middle value currently, the mask is necessary to prevent "bordering" from occurring around the decal.

Tip.pngTip:You can avoid "bordering" without creating an alpha channel simply by using BGR888 format instead of DXT1 when you create your VTF. Left 4 Dead 2 It has also been observed in Left 4 Dead 2 that DXT1 compressed textures using DecalModulate shader (such as blood splatters and "graffiti wall writing") with background colors RGB 124 126 124 are considered alpha, alleviating "bordering". L4D2's vtex will output that specific color from the source image pixels are gray RGB 127 127 127. This solution may also apply to other engines (and other versions of vtex) that use RGB 124 126 124 as the color indicating alpha in-game, but needs further testing.
Todo: Try converting source images with background colors RGB 127 127 127 with vtex found in other games other than L4D2 and see if it results in a background with RGB 124 126 124. Also, does RGB 124 126 124 apply to other versions of the Source engine as alpha for DXT1 compression?
Source color channels Source alpha channel Decal in the world

Finally, you must create a material that uses the DecalModulate shader. Neither $translucent nor $decal are needed this time.

See also