Notes on Decals. Author: JbP Date: 28 October 2000

Notes on decals: Author: JbP Email: jbp@planetunreal.com Date: 28th October 2000 Decal basics

> 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.

Runtime customisations:

> 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.

Tricks

> 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?