I programmed the following script to make a rainbow and wobble effect on my TMpro text using the “Link” tag (code might be irrelevant for this problem?):
[...]
private void Update() {
textComponent.ForceMeshUpdate();
Mesh cachedMesh = textComponent.mesh;
Vector3[] newVerticles = cachedMesh.vertices;
Color[] newColors = cachedMesh.colors;
// Loop on each link
foreach (TMP_LinkInfo link in textComponent.textInfo.linkInfo) {
// Rainbow effect
if (link.GetLinkID() == "rainbow") {
// Loop on each character
for (int i = link.linkTextfirstCharacterIndex; i < link.linkTextfirstCharacterIndex + link.linkTextLength; i++)
{
// Loop on all vertexes
for (int j = 0; j < 4; j++)
{
int vertexIndex = (i * 4) + j;
Vector3 offset = new Vector2(Mathf.Sin((Time.realtimeSinceStartup * movementSpeed) + (vertexIndex * movementStrength.x)), Mathf.Cos((Time.realtimeSinceStartup * movementSpeed) + (vertexIndex * movementStrength.y))) * 10f;
Color rainbow = Color.HSVToRGB(((Time.realtimeSinceStartup * movementSpeed) + (vertexIndex * (0.001f * rainbowStrength))) % 1f, 1f, 1f);
newColors[vertexIndex] = rainbow;
newVerticles[vertexIndex] += offset;
}
}
}
}
cachedMesh.vertices = newVerticles;
cachedMesh.colors = newColors;
textComponent.canvasRenderer.SetMesh(cachedMesh);
}
It seems to work well, however, I just found out that TextMeshPro doesn’t count spaces as characters (at least when using linkTextfirstCharacterIndex, unsure if linkTextLength has the same effect), meaning that the effect is being offset by how many spaces there are on the left
I am trying to figure out by myself a way to make effects using links, so I’m also not sure if this is the best way to do what I’m trying to do, there’s almost no documentation on how to make custom tags.
Since spaces have no geometry, you need to skip non visible characters.
To make sure you modify the correct vertices, you need to check the first character index (as you are doing already) but then get the vertexIndex of that character by checking textInfo.characterInfo[indexOfCharacter].vertexIndex.
Take a look at the example called “Animating Vertex Attributes” which is included in the TMP Examples & Extras. More specifically look at the VertexColorCycler.cs script which is a good example of this.
Thanks for the reply! I managed to fix the problem by using vertexIndex, sorry for the misspellings!
I’m going to look furthermore at some of the built-in examples that TMpro has, the way I’m currently implementing effects is not efficient, tags would be the better way to do it and “hacking” the mesh is not a good idea.
For now, here’s the new code if anyone is interested, though some cleanup is needed since the tag effects are hardcoded
!!! EDIT: PLEASE LOOK FOR THE NEW SCRIPT BELOW THIS POST !!!
[...]
private void Update() {
textComponent.ForceMeshUpdate();
Mesh cachedMesh = textComponent.mesh;
Vector3[] newVertices = cachedMesh.vertices;
Color[] newColors = cachedMesh.colors;
// Loop each link
foreach (TMP_LinkInfo link in textComponent.textInfo.linkInfo) {
// Is it a rainbow tag?
if (link.GetLinkID() == "rainbow") {
// Loop all characters containing the rainbow link.
for (int i = link.linkTextfirstCharacterIndex; i < link.linkTextfirstCharacterIndex + link.linkTextLength; i++)
{
// Gets info on the current character
TMP_CharacterInfo charInfo = textComponent.textInfo.characterInfo[i];
// Loop all vertexes of the current char.
for (int j = 0; j < 4; j++)
{
if (charInfo.character == ' ') continue;
int vertexIndex = charInfo.vertexIndex + j;
// Offset and Rainbow effects, replace it with any other effect you want.
Vector3 offset = new Vector2(Mathf.Sin((Time.realtimeSinceStartup * movementSpeed) + (vertexIndex * movementStrength.x)), Mathf.Cos((Time.realtimeSinceStartup * movementSpeed) + (vertexIndex * movementStrength.y))) * 10f;
Color rainbow = Color.HSVToRGB(((Time.realtimeSinceStartup * movementSpeed) + (vertexIndex * (0.001f * rainbowStrength))) % 1f, 1f, 1f);
newColors[vertexIndex] = rainbow;
newVertices[vertexIndex] += offset;
}
}
}
}
cachedMesh.vertices = newVertices;
cachedMesh.colors = newColors;
textComponent.canvasRenderer.SetMesh(cachedMesh);
}
Here’s the updated script, it now uses the correct (I suppose?) way to update text vertex data:
using UnityEngine;
using TMPro;
public class TextmeshproEffect : MonoBehaviour
{
public TMP_Text textComponent;
public Vector2 movementStrength = new(0.1f, 0.1f);
public float movementSpeed = 1f;
public float rainbowStrength = 10f;
private void Update() {
textComponent.ForceMeshUpdate();
// Loops each link tag
foreach (TMP_LinkInfo link in textComponent.textInfo.linkInfo) {
// Is it a rainbow tag? (<link="rainbow"></link>)
if (link.GetLinkID() == "rainbow") {
// Loops all characters containing the rainbow link.
for (int i = link.linkTextfirstCharacterIndex; i < link.linkTextfirstCharacterIndex + link.linkTextLength; i++)
{
TMP_CharacterInfo charInfo = textComponent.textInfo.characterInfo[i]; // Gets info on the current character
int materialIndex = charInfo.materialReferenceIndex; // Gets the index of the current character material
Color32[] newColors = textComponent.textInfo.meshInfo[materialIndex].colors32;
Vector3[] newVertices = textComponent.textInfo.meshInfo[materialIndex].vertices;
// Loop all vertexes of the current characters
for (int j = 0; j < 4; j++)
{
if (charInfo.character == ' ') continue; // Skips spaces
int vertexIndex = charInfo.vertexIndex + j;
// Offset and Rainbow effects, replace it with any other effect you want.
Vector3 offset = new Vector2(Mathf.Sin((Time.realtimeSinceStartup * movementSpeed) + (vertexIndex * movementStrength.x)), Mathf.Cos((Time.realtimeSinceStartup * movementSpeed) + (vertexIndex * movementStrength.y))) * 10f;
Color32 rainbow = Color.HSVToRGB(((Time.realtimeSinceStartup * movementSpeed) + (vertexIndex * (0.001f * rainbowStrength))) % 1f, 1f, 1f);
// Sets the new effects
newColors[vertexIndex] = rainbow;
newVertices[vertexIndex] += offset;
}
}
}
}
textComponent.UpdateVertexData(TMP_VertexDataUpdateFlags.All); // IMPORTANT! applies all vertex and color changes.
}
}