Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

[FIXED] Change color of individual characters in TextMeshPro - Text (UI)

Discussion in 'UGUI & TextMesh Pro' started by Splosions, May 9, 2022.

  1. Splosions

    Splosions

    Joined:
    Apr 29, 2017
    Posts:
    30
    When it comes to Text (UI) objects it looks like Vertex Color does noting, faceColor does change the color, but for the entire material.

    The only way I have found to be able to change color of individual characters in a Text (UI) is to change the text itself IE:
    Code (CSharp):
    1. <color="red">This color is Red
    I have to loop through all the characters and add a color code before each character.
    And I have to do it in Update()

    Code (CSharp):
    1.  
    2. string newText = "";
    3. for (int i = 0; i < m_TextComponent.textInfo.characterCount; i++)
    4. {
    5.     string c = m_TextComponent.textInfo.characterInfo[i].character.ToString();
    6.     newText += "<color=" + Rainbow(characterCount * 5, i + count + (int)Time.deltaTime) + ">" + c;
    7. }
    8. count++;
    9. m_TextComponent.text = newText;
    10.  
    This feels hacky. And it seems to cause problems elsewhere.

    If I try to use a vertex effect via a core routine IE:
    Code (CSharp):
    1.  
    2.     IEnumerator Wobble()
    3.     {
    4.         m_TextComponent.ForceMeshUpdate();
    5.         Mesh mesh = m_TextComponent.mesh;
    6.         Vector3[] vertices = mesh.vertices;
    7.         while (true)
    8.         {
    9.             for (int i = 0; i < m_TextComponent.textInfo.characterCount; i++)
    10.             {
    11.                 TMP_CharacterInfo c = m_TextComponent.textInfo.characterInfo[i];
    12.                 int index = c.vertexIndex;
    13.                 Vector3 offset = Wobble((Time.time + i) / SpeedMultiplier);
    14.                 vertices[index] += offset;
    15.                 vertices[index + 1] += offset;
    16.                 vertices[index + 2] += offset;
    17.                 vertices[index + 3] += offset;
    18.             }
    19.             mesh.vertices = vertices;
    20.             m_TextComponent.canvasRenderer.SetMesh(mesh);
    21.             yield return new WaitForSeconds(0.025f);
    22.         }
    23.     }
    24.  

    after I disable the core routine via StopAllCoroutines(), I am unable to get the colors to work again. I can see the text changing in the TMP editor, but in game the text is frozen.

    So I need to figure out 1 of 2 ways to fix this.

    Get the text to update during a core routine so I can use core routines for all effects.
    Or figure out why the text stops updating after a core routine has run and stopped.

    Thank you
     
    Liderangel and bobsjobisfob like this.
  2. Splosions

    Splosions

    Joined:
    Apr 29, 2017
    Posts:
    30
    HOLY BALLS ON TOAST I DID IT!



    To start......
    I had to check the "Override Tags" box in the TMP. Apparently that allows "Vertex Color" to be used instead of the material color
    upload_2022-5-8_19-7-48.png

    NOW changing the vertex color of the individual letters works in a core routine!

    Code (CSharp):
    1.  
    2.  
    3.     IEnumerator ColorRainbow()
    4.     {
    5.         while (true)
    6.         {
    7.             for (int i = 0; i < m_TextComponent.textInfo.characterCount; ++i)
    8.             {
    9.                 string hexcolor = Rainbow(m_TextComponent.textInfo.characterCount * 5, i + count + (int)Time.deltaTime);
    10.                 Color32 myColor32 = hexToColor(hexcolor);
    11.                 int meshIndex = m_TextComponent.textInfo.characterInfo[i].materialReferenceIndex;
    12.                 int vertexIndex = m_TextComponent.textInfo.characterInfo[i].vertexIndex;
    13.                 Color32[] vertexColors = m_TextComponent.textInfo.meshInfo[meshIndex].colors32;
    14.                 vertexColors[vertexIndex + 0] = myColor32;
    15.                 vertexColors[vertexIndex + 1] = myColor32;
    16.                 vertexColors[vertexIndex + 2] = myColor32;
    17.                 vertexColors[vertexIndex + 3] = myColor32;
    18.             }
    19.             count++;
    20.             m_TextComponent.UpdateVertexData(TMP_VertexDataUpdateFlags.All);
    21.             yield return new WaitForSeconds(refreshSpeed);
    22.         }
    23.     }
    24.  
    25.     public static Color32 hexToColor(string hex)
    26.     {
    27.         hex = hex.Replace("0x", "");//in case the string is formatted 0xFFFFFF
    28.         hex = hex.Replace("#", "");//in case the string is formatted #FFFFFF
    29.         byte a = 255;//assume fully visible unless specified in hex
    30.         byte r = byte.Parse(hex.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
    31.         byte g = byte.Parse(hex.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
    32.         byte b = byte.Parse(hex.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
    33.         //Only use alpha if the string has enough characters
    34.         if (hex.Length == 8)
    35.         {
    36.             a = byte.Parse(hex.Substring(6, 2), System.Globalization.NumberStyles.HexNumber);
    37.         }
    38.         return new Color32(r, g, b, a);
    39.     }
    40.  
    41.     public static string Rainbow(int numOfSteps, int step)
    42.     {
    43.         var r = 0.0;
    44.         var g = 0.0;
    45.         var b = 0.0;
    46.         var h = (double)step / numOfSteps;
    47.         var i = (int)(h * 6);
    48.         var f = h * 6.0 - i;
    49.         var q = 1 - f;
    50.         switch (i % 6)
    51.         {
    52.             case 0:
    53.                 r = 1;
    54.                 g = f;
    55.                 b = 0;
    56.                 break;
    57.             case 1:
    58.                 r = q;
    59.                 g = 1;
    60.                 b = 0;
    61.                 break;
    62.             case 2:
    63.                 r = 0;
    64.                 g = 1;
    65.                 b = f;
    66.                 break;
    67.             case 3:
    68.                 r = 0;
    69.                 g = q;
    70.                 b = 1;
    71.                 break;
    72.             case 4:
    73.                 r = f;
    74.                 g = 0;
    75.                 b = 1;
    76.                 break;
    77.             case 5:
    78.                 r = 1;
    79.                 g = 0;
    80.                 b = q;
    81.                 break;
    82.         }
    83.         return "#" + ((int)(r * 255)).ToString("X2") + ((int)(g * 255)).ToString("X2") + ((int)(b * 255)).ToString("X2");
    84.     }
    85.  
    86.  
     
    Last edited: May 9, 2022
    WQ23, mowax74, Spodea and 5 others like this.
  3. Kytra

    Kytra

    Joined:
    Aug 3, 2018
    Posts:
    3
    Nice job! This helped me out!
     
  4. benryhenson

    benryhenson

    Joined:
    Dec 21, 2021
    Posts:
    4
  5. Timwillhack

    Timwillhack

    Joined:
    Jun 3, 2018
    Posts:
    1
    This really helped me figure out how to get access to the textmesh pro vertex data, so thank you (I know this is an old post). There is one bug with the rainbow code that has to do with 'vertexIndex'. If you don't have this section in, every space character will be modifying the first character in the textbox. See my comment in my updated version:
    Code (CSharp):
    1. IEnumerator ColorRainbow()
    2.     {
    3.      
    4.         while (true)
    5.         {
    6.             for (int i = 0; i < txtMshComp.textInfo.characterCount; ++i)
    7.             {
    8.                 // if the character is a space, the vertexIndex will be 0, which is the same as the first character. If you don't leave here, you'll keep modifying the first character's vertices, I believe this is a bug in the text mesh pro code
    9.                 if (!txtMshComp.textInfo.characterInfo[i].isVisible){
    10.                     continue;
    11.                 }
    12.                 string hexcolor = Rainbow(txtMshComp.textInfo.characterCount * 5, i + count + (int)Time.deltaTime);
    13.                 Color32 myColor32 = hexToColor(hexcolor);
    14.                 int meshIndex = txtMshComp.textInfo.characterInfo[i].materialReferenceIndex;
    15.                 int vertexIndex = txtMshComp.textInfo.characterInfo[i].vertexIndex;
    16.                 Color32[] vertexColors = txtMshComp.textInfo.meshInfo[meshIndex].colors32;
    17.                 vertexColors[vertexIndex + 0] = myColor32;
    18.                 vertexColors[vertexIndex + 1] = myColor32;
    19.                 vertexColors[vertexIndex + 2] = myColor32;
    20.                 vertexColors[vertexIndex + 3] = myColor32;
    21.             }
    22.             count++;
    23.             txtMshComp.UpdateVertexData(TMP_VertexDataUpdateFlags.All);
    24.             yield return new WaitForSeconds(refreshSpeed);
    25.         }
    26.     }
     
    mowax74, Spodea and Hozgen90 like this.
  6. Hozgen90

    Hozgen90

    Joined:
    Jan 20, 2021
    Posts:
    19
    another treasure :D thanks!
     
  7. viet2007ht

    viet2007ht

    Joined:
    May 28, 2021
    Posts:
    3
    I was thought it was Color Gradient on top of that was the way to do it easier. Now I was wrong. Thanks for all.