Creating a decal in-game:
Just spawn it. There are two important things to consider when
spawning a Decal.
- that you assign it a rotation FACING the surface you want
it to attach to.
- that you spawn it within the correct
distance from the surface you want it to attach to. The "correct
distance" for the Decal class itself is 100 units -- this can
vary in subclasses as explained below. If you take some control
over the Attachment process, you can define the distance
yourself (see below).
eg:
/* you might find a line like this in a projectile's
HitWall() or Landed() function. It spawns the decal at the
actor's location and in the direction the actor is facing -- the
decal will then trace 100 units in this direction and place
itself on the solid surface if it finds (virtually guaranteed in
this case, since we already know the surface is there in
HitWall() or Landed()). */
Spawn( class'Scorch',,, Location,
Rotation );
/* Incidentally, since the default values for the
Loc and Rot parameters to Spawn() are the actor's Location and
Rotation, this can be simplified just to Spawn( class'Scorch' );
*/
By default, decals that do not find a surface within the given
distance (default: 100 units) are immediately destroyed. This
behaviour is easily overriden in subclasses, however.
How it works:
- Decals have two key native functions, AttachDecal() and
DetachDecal(). They can be called any time after the decal has
been spawned.
- AttachDecal() performs a trace TraceDistance
units in:
1) DecalDir direction if that argument is provided (it is
optional); otherwise
2) the direction the decal is
facing.
If it finds a (solid) surface, the decal is attached to that
surface.
- DetachDecal() removes decal from the
surface.
- When a decal is detached, it is not
visible.
- Calling AttachDecal() in a decal that is already
attached has no effect.
- If you take a look at Decal.uc,
you'll note that this class seeks a surface in PostBeginPlay(),
and if it can't find anything to attach itself to, it destroys
itself. You'll also note that in this search, it traces 100 units.
Both of these things can be changed in a subclass by simply
overriding PostBeginPlay().
How decals differ from a plane mesh:
- Decals are always drawn as modulated, irrespective of what
you set as the Decal's Style. I haven't come up with a good
definition of STY_Modulated, but it's essentially a kind of
translucency centred around the mid-grey (128,128,128) color. It
has a kind of glassy effect.
- Decals have DT_None. They're not a "Mesh" (ie, the Unreal
class Mesh), although they are technically a mesh (ie, a related
collection of vertices).
- Decals won't show up in the software renderer at all. Plane
meshes will, but my experimentation with them has resulted in lots
of visual ugliness.
- Decals are especially supported by the rendering code and
will be optimised. Also, kinda obviously, decals wrap and clip to
non-coplanar surfaces, whereas a plane mesh will
not.
Detaching decals:
- To make ANY changes to the decal,
you need to detach it from any surface it has attached to. To do
this, just tell it to DetachDecal(). Examples are shown
below.
Changing the decal's texture at runtime:
-
Simple enough; just set the decal's Texture variable to your
chosen texture. The decal must be detached to avoid
oddities.
eg:
// changes the decal's texture.
function
SetNewTexture( Texture T )
{
DetachDecal();
Texture = T;
AttachDecal( 100
);
}
Changing the decal's size at runtime:
- The
size of the decal (as with the other render modes) is determined
by the Decal's drawscale variable. Again, modifying this var will
have no apparent effect if the decal is attached to a surface, so
detach it first.
eg:
//changes the decal's size.
function
SetNewScale( float NewScale )
{
DetachDecal();
DrawScale =
NewScale;
AttachDecal( 100 );
}
Changing the decal's location after it has already
been attached to a surface.
eg:
// places the decal at
the given location.
function Place( vector Loc, rotator Dir
)
{
DetachDecal();
SetLocation( Loc );
SetRotation( Dir
);
AttachDecal( 100 );
}
Note that the decal won't BE at the location you set
when this function returns -- it has simply started it's
attachment trace from that location. That is incidentally why the
rotation arg is necessary here.
How to make an
appropriate decal texture:
The key to a good decal texture
is (128,128,128) rgb. This color (mid-grey) is completely
transparent. Colors nearer to mid-grey are more translucent than
colors distant to it. So use strong colors - dark or bright.
Modulation provides a good solution to the aliasing (jaggies) that
you see with masked textures, and to the faintness that typifies
translucent textures. Just remember: (128,128,128) is completely
transparent on decals.
I have encountered an exception to
that rule above, which is that on some video cards mid-grey isn't
completely transparent. It's been noted on a Savage board. This is
a driver problem, as far as I know.
Using decals to find world textures
- Decals, since
about UT 413, have had an interesting quirk. They are the only
means (in unrealscript) of determining the Texture of a surface.
When you call AttachDecal(), and the attachment succeeds, the
Texture of the surface to which the centre of the decal was
applied is returned.
So? Well, one of the reasons this
change was made was to enable realistic footstep sounds. The
playershadow decal can monitor the texture it attaches itself to
and have an appropriate sound played. There are a lot of other
uses for this feature of decals; the potential increases if you
co-operate with level designers to place certain versions of
textures where a particular (code-based) effect is required.
Overcoming limitations.
- Decals don't work
with the software renderer, and they don't work in fog. Decals can
also be turned off by users with a frames per second budget. For
these reasons, it is dangerous to rely on decals for game-relevant
displays. Blood splatters aren't really game-relevant -- you can
play the game just as well without them. But if, for example, the
domination control points were decals rather than meshes, gameplay
would be greatly affected in the above conditions. There is no way
to fix this, but there is a way to detect each of these
conditions. If you can detect them, you can replace your decal
effect with another effect that isn't limited in this way (a
sprite? a lighting effect?).
- User is using the software renderer if this condition is
true: ConsoleCommand( "get ini:Engine.Engine.GameRenderDevice
Class" ) ~= "SoftDrv.SoftwareRenderDevice";
- User has turned
off decals if: !( bool( ConsoleCommand( "get
ini:Engine.Engine.ViewportManager Decals" ) ) );
- Decal is in
a fogzone if: Region.Zone.bFogZone;
- Note that, by default, decals are only shown if the user
has not turned off HighDetail in Preferences, or the framerate has
dropped to a point where HighDetail mode has been temporarily
turned off by the engine to get a speed up. This will not happen
if you set the decal's bHighDetail var to FALSE. To check whether
the user or the engine has turned off HighDetail mode, evaluate
(Level.bHighDetailMode).
Animated decals
- just a reminder. What about
scriptedtextures, as
well?