Version: 6000.2+
The TextElement.PostProcessTextVertices
API lets you modify the meshThe main graphics primitive of Unity. Meshes make up a large part of your 3D worlds. Unity supports triangulated or Quadrangulated polygon meshes. Nurbs, Nurms, Subdiv surfaces must be converted to polygons. More info
See in Glossary vertices of each glyph immediately before UI Toolkit renders them. You can use this callback to customize the position, tint, and UV coordinates of the text at a low level.
This example creates a custom Editor window that animates text by fading glyphs in and out when you press Spacebar. It uses the TextElement.PostProcessTextVertices
API to modify the vertex data of the text glyphs.
You can find the completed files that this example creates in this GitHub repository.
This guide is for developers familiar with the Unity Editor, UI Toolkit, and C# scripting. Before you start, get familiar with the following:
Create a C# script for a custom Editor window. Use a scheduled job to track animation time. In the OnPostProcessTextVertices
method, iterate through GlyphsEnumerable
and adjust each vertex tint’s alpha channel until the fade completes.
Editor
if you don’t have one.Editor
folder, create a C# script named TextAnimation.cs
with the following content:using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using TextElement = UnityEngine.UIElements.TextElement;
public class TextAnimation : EditorWindow
{
[MenuItem("Window/UI Toolkit/TextAnimation")]
public static void ShowExample()
{
TextAnimation wnd = GetWindow<TextAnimation>();
wnd.titleContent = new GUIContent("TextAnimation");
}
Label label;
float animationDuration = 10f;
float elapsed = 0f;
IVisualElementScheduledItem animationJob;
bool isTextVisible = true;
public void CreateGUI()
{
VisualElement root = rootVisualElement;
var container = new VisualElement()
{
style =
{
flexGrow = 1,
top = 0,
bottom = 0,
right = 0,
left = 0
},
focusable = true // We can only receive key events on a window with a focusable element.
};
label = new Label("Hello ❤️ World!") { style = { flexGrow = 1, fontSize = 24, unityTextAlign = TextAnchor.MiddleCenter } };
container.Add(label);
root.Add(container);
rootVisualElement.RegisterCallback<KeyDownEvent>(evt => OnSpacebarPressed(evt), TrickleDown.TrickleDown);
label.PostProcessTextVertices += OnPostProcessTextVertices;
animationJob = label.schedule.Execute(UpdateTime).Every(1000 / 60); // 60 FPS
animationJob.Pause(); // Pause the job until the animation starts
}
private void UpdateTime()
{
elapsed += Time.deltaTime;
if (elapsed >= animationDuration)
{
elapsed = animationDuration; // Cap at max duration
animationJob.Pause();
}
label.MarkDirtyRepaint();
}
public void OnSpacebarPressed(KeyDownEvent evt)
{
if (evt.keyCode != KeyCode.Space || animationJob.isActive)
return;
elapsed = 0f;
animationJob.Resume();
isTextVisible = !isTextVisible;
}
void OnPostProcessTextVertices(TextElement.GlyphsEnumerable glyphs)
{
int glyphsToToggle = (int)(elapsed * glyphs.Count / animationDuration);
int toggled = 0;
foreach (TextElement.Glyph glyph in glyphs)
{
if (toggled++ >= glyphsToToggle)
break;
var verts = glyph.vertices;
for (int i = 0; i < verts.Length; i++)
{
var v = verts[i];
var tint = v.tint;
tint.a = isTextVisible ? (byte)255 : (byte)0;
v.tint = tint;
verts[i] = v;
}
}
}
}
Test the text animation sample in the custom Editor window.