Label text wave animation effect in Unity UI Toolkit

I found a way to animate individual glyphs in UI Toolkit. All we have to do is to write a callback function for the action/event “PostProcessTextVertices” of the label. This function receives a list of all glyphs that we can iterate over and change their individual positions, uvs and tints. Here is the full source code of a script that animates every Label with the class name “wave-effect”.

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;

public class LabelWaveEffect : MonoBehaviour
{
    [SerializeField] private float _frequency = 1.0f;
    [SerializeField] private float _amplitude = 5.0f;

    private List<Label> _labels;

    private void Awake()
    {
        if (TryGetComponent(out UIDocument document))
        {
            _labels = document.rootVisualElement.Query<Label>(className: "wave-effect").ToList();
        }
    }

    private void Start()
    {
        if (_labels != null)
        {
            foreach (Label label in _labels)
            {
                if (label != null)
                {
                    label.PostProcessTextVertices += OnPostProcessVertices;
                }
            }
        }
    }

    private void OnDestroy()
    {
        if (_labels != null)
        {
            foreach (Label label in _labels)
            {
                if (label != null)
                {
                    label.PostProcessTextVertices -= OnPostProcessVertices;
                }
            }
        }
    }

    private void Update()
    {
        if (_labels != null)
        {
            foreach (Label label in _labels)
            {
                if (label != null)
                {
                    label.MarkDirtyRepaint();
                }
            }
        }
    }

    private void OnPostProcessVertices(TextElement.GlyphsEnumerable glyphs)
    {
        int glyphIndex = 0;

        foreach(TextElement.Glyph glyph in glyphs)
        {
            var vertices = glyph.vertices;

            for (int i = 0; i < vertices.Length; i++)
            {
                var vertex = vertices[i];

                vertex.position += _amplitude * Mathf.Sin(glyphIndex + Time.timeSinceLevelLoad * _frequency) * new Vector3(0.0f, 1.0f, 0.0f);

                vertices[i] = vertex;
            }

            glyphIndex++;
        }
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *