Text Animation Effects in Unreal Engine

· Read in about 7 min · (1312 Words)

Intro

You can do some quite nice text effects with Unreal Engine’s UMG Rich Text Block. Coloured text, outlines, shadows, even embed images in the text. But what if you wanted to do things like this to your text:

Animated text effects

When I was looking for information on how to do this kind of animated effect, I didn’t find very much. So now I’ve figured it out, here’s the information I wish I’d been able to find.

Setting Up Animated Text Styles

The first thing to do is set up your Rich Text styles as you usually would, following the official Rich Text Block documentation. Short version, it’s just a Datatable of row type Rich Text Style Row, and the key for each row is the tag you use in your text to delimit text of that style, e.g. <Pulse>Pulsing text</>

The important part for our animated text is to use a Font Material; this allows us a great amount of control over the shading and transformation of text with this specific tag. The official documentation for Font Materials is pretty sparse and completely undersells the capabilities of this feature!

You assign the font material in the details of your style row, like this:

Assigning a Font Material

If you’re using outlines, you should set the same font material for that as well. Outlines are automatically expanded and their vertex colours set to reflect the outline colour so the same material will generally work for both; with some caveats.

But, how do you write these font materials?

Creating Font Materials To Animate Vertices

How precisely you modify the positions of glyph vertices in a rich text block is very badly documented; not at all, in fact. So here we go:

The Basics

We’ll create a master material to serve as the basis for our animated text effects.

  1. Create a new material
  2. Select the output node
  3. In the Details tab, set:
    • Material Domain: User Interface
    • Blend Mode: Opaque, unless you want partially transparent text

Setting the blend mode to opaque might seem odd, because surely the text glyphs are alpha masked? Well, at least at the point that the Font Material is invoked, the glyph shapes do not require alpha rejection. I’m not sure of the exact pipeline but I suspect the glyph shape masking comes after this Font Material step.

The Outputs

This blog is mostly about moving text around in an animated fashion, we won’t spend any time colouring it in any differently. So for the “Final Color” output, we’ll just use the vertex colour, which will be the face colour or the outline colour, depending on what context it’s being run in.

Font Material Outputs

The output we’re most interested in is “Screen Position”. If you assign nothing to it, the text will render in place as usual. But how do we calculate modified positions?

The answer is not what you would think. If you right-click the material canvas to create a new node, there is one called “ScreenPosition”, so you’d naturally assume that you should begin with that. But nope, that would be far too logical 😜

If fact, the correct coordinates to use are “Absolute World Position”, which you can find named “WorldPosition” in the create node list. Yes, really, this will essentially create the same no-op result as not assigning anything to “Screen Position”:

Absolute World Position: Yes, really

It took me far too long to figure that out, because it’s not documented anywhere as far as I can tell, and is completely unintuitive. Hey ho I guess… 😣

My First Text Animation

OK so now we know our starting point, it’s fairly easy to start experimenting with altering those values. Lets make the tagged text float up and down as a single unit for now, like this:

Simple text float animation

The way we achieve this is to feed time, plus some tweakable parameters, into a sine wave, and use that to offset the vertex positions of the text in the Y direction:

Simple text float material setup

Of course we can then create material instances of this with different variables of Speed and Magnitude to tweak how it looks. The colour of the text face and outline are coming from the colours in the rich text style, which arrive via vertex colours. To repeat, this material is being executed separately for the font face and the font outline, but because we’re using consistent calculations they stay together while animating - this can be more difficult as your effects become more extravagant.

Varying animation across words / phrases

OK so that’s fine for animating the text as a single block, but what if we want to do something more interesting, like making each letter move at a slightly different offset, making something like a “wave” effect? For that, we need more variables than just time, we need something that varies across the different letters in the text.

We actually have two things we can draw on to add variation:

Using Position

If we use the position on the screen, every letter (in fact, every vertex of every letter) has a unique combination of X and Y that we can use to add variation.

So we use “Absolute World Position” again but as a variant to our animation as well as a position base. It just needs to be scaled down or fractional parts used to make it useful. Here’s an example:

Wavy text float material setup

By changing the “Position Sine Y Scale”, you can change the wavelength of the wave that the text follows. With the value shown here we get this:

Wavy text float animation

Notice how, because each vertex is being animated separately, the text itself actually distorts to follow the wave, rather than each letter just moving up and down, which I really like.

Using Texture Coordinates

The other thing you can do to vary things within the text is to use the UVs. However, there are a couple of things to understand. Firstly, the range of UVs depends on how you tag your text. Let’s take this text:

<Debug>Some text where we enclose the entire sentence in a single tag.</>
<Debug>Some</> <Debug>text</> <Debug>where</> <Debug>every</> <Debug>word</> <Debug>is</> <Debug>separately</> <Debug>tagged</>

The UV pattern for this text is:

Text debug UVs

Notice how there’s a full range of UVs for each tagged area; on the first line, the UVs stretch across the entire sentence, but on the second line there’s a complete UV range per word. So it appears that the way UE renders text means that each tagged area will have its own UV space.

This can be useful if you want to animate effects that match at the start / end of tags, regardless of where they are in physical space. Re-implementing the offset material like this:

Text wave using UVs

Results in:

Text wave animation using UVs

SUPER IMPORTANT

To drive Screen Position you must use UV1, not UV0. You can do this by selecting the texcoord node and changing Coordinate Index to 1.

This will not agree with anything you feed into Final Color, which seems to be UV0! For example, for this debug view, I passed UV0 into “Final Color”. Simple! BUT, if you use UV0 to alter Screen Position, it won’t do what is suggested by that.

I assume what’s happening is that UV1 contains these tag ranged texture coordinates in the vertex shader (which is what Screen Position uses), but the pixel shader puts them in UV0 (which is what Final Color is driven by). Very confusing until I figured that out!!

Bottom line: Any inputs to Screen Position must use UV1, not UV0!!

The End

By adding noise components and other kinds of displacements, you can create all sorts of effects like the ones shown at the top of this article using just a small number of parameters. Doing so can give your dialogue and other text driven aspects of your game more character and customisable emphasis.

I hope this blog post helps you do that, I sure wish someone else had written something like this before I started! 😄