Search Unity

TextMesh Pro Teletype interfering with Vertex Jitter

Discussion in 'Unity UI (uGUI) & TextMesh Pro' started by hoperin, Jan 11, 2019.

  1. hoperin

    hoperin

    Joined:
    Feb 9, 2014
    Posts:
    50
    I'm trying to figure out how to get something to work that I'm sure other people must have tried to accomplish, but that I haven't seen any solutions for -- teletyping with vertexjitter effects. All our text is using Teletype, where the core code is

    m_textMeshPro.maxVisibleCharacters = visibleCount;

    When I try to add on an effect that modifies the vertexes ie the VertexJitter example included w TMPro, I get a very jagged, janky effect where it sort of jitters while it types, but its clear once it finishes typing and jitters properly that it was not behaving as it should.

    https://forum.unity.com/threads/typewriter-jitter-and-wave-effects-at-once.532184/ This thread makes it clear that the issue is that when changing .maxVisibleCharacters, the vertexes are reset. My own testing has confirmed this -- when i drastically slow down my Teletype update speed, the issue is undetectable. Ideally one could just make it not do this reset behaviour, but I can't figure out where to get at that.

    I thought that if I saved the vertex info everytime Jitter updated, and forced that saved vertex info back in after each maxVisibleCharacter change, I could override the vertex reset that happens after maxVisibleCharacter, but no such luck.

    https://imgur.com/liQpPCZ Here's a 60fps gif of the behaviour I'm getting.

    I had hoped it wouldn't be this tricky to get vertex effects working alongside a teletype effect. Any help greatly appreciated.

    VertexJitter Snippet:
    Code (CSharp):
    1. // Push changes into meshes
    2.                 for (int i = 0; i < textInfo.meshInfo.Length; i++)
    3.                 {
    4.                     textInfo.meshInfo[i].mesh.vertices = textInfo.meshInfo[i].vertices;
    5.                     m_TextComponent.UpdateGeometry(textInfo.meshInfo[i].mesh, i);
    6.  
    7.  
    8.                 }
    9.  
    10.                 PublicMeshInfo = textInfo.meshInfo;
    Teletype Snippet:
    Code (CSharp):
    1. while (reading && m_textMeshPro.maxVisibleCharacters != m_textMeshPro.textInfo.characterCount)
    2.             {
    3.  
    4.                 if (!Mgr_PlayState.Instance.Paused){
    5.  
    6.                     visibleCount += 1;
    7.  
    8.                     //this is the problem point...
    9.                     m_textMeshPro.maxVisibleCharacters = visibleCount; // How many characters should TextMeshPro display?
    10.  
    11.                     //try to update back to the vertex
    12.                     for (int i = 0; i < m_textMeshPro.textInfo.meshInfo.Length; i++)
    13.                     {
    14.                          m_textMeshPro.textInfo.meshInfo[i].mesh.vertices = this.GetComponent<VertexJitter>().PublicMeshInfo[i].vertices;
    15.                          m_textMeshPro.UpdateGeometry(m_textMeshPro.textInfo.meshInfo[i].mesh, i);
    16.                     }
    17.                     m_textMeshPro.ForceMeshUpdate();
    18.  
    19.                     // Once the last character has been revealed, wait 1.0 second and start over.
    20.                     if (visibleCount >= totalVisibleCharacters)
    21.                     {
    22.                         ShowAllText();
    23.                     }
    24.              
    25.                 }
    26.  
    27.                 yield return new WaitForSeconds(textReadSpeed);
    28.  
    29.             }
     
  2. Stephan_B

    Stephan_B

    Unity Technologies

    Joined:
    Feb 26, 2017
    Posts:
    2,801
    Since you are already having to iterate over each of the characters to add the Jitter, I would suggest controlling the visibility of each character in the same fashion instead of using .maxVisibleCharacters which ends up forcing a regeneration of the text object which in turn resets the geometry.

    In other words, as you iterate over (only the visible) characters, to add the Jitter FX also control their vertex color alpha to do the Teletype FX. Since this won't be setting the text object dirty, it won't reset the geometry.

    See the following post which is another example of sort of a Teletype FX with color.

    See the following post which might prove helpful.
     
  3. Stephan_B

    Stephan_B

    Unity Technologies

    Joined:
    Feb 26, 2017
    Posts:
    2,801
    In case, you can't see that post on the old TMP user forum. This is an old post so some of the code might need tweaks but the idea remains the same.

    Here is an example where the text is faded per character with control over the number of characters the fade occurs over + tint control.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. namespace TMPro.Examples
    5. {
    6.     public class RollingTextFade : MonoBehaviour
    7.     {
    8.         private TMP_Text m_TextComponent;
    9.         public float FadeSpeed = 1.0F;
    10.         public int RolloverCharacterSpread = 10;
    11.         public Color ColorTint;
    12.         void Awake()
    13.         {
    14.             m_TextComponent = GetComponent<TMP_Text>();
    15.         }
    16.         void Start()
    17.         {
    18.             StartCoroutine(AnimateVertexColors());
    19.         }
    20.         /// <summary>
    21.         /// Method to animate vertex colors of a TMP Text object.
    22.         /// </summary>
    23.         /// <returns></returns>
    24.         IEnumerator AnimateVertexColors()
    25.         {
    26.             // Need to force the text object to be generated so we have valid data to work with right from the start.
    27.             m_TextComponent.ForceMeshUpdate();
    28.             TMP_TextInfo textInfo = m_TextComponent.textInfo;
    29.             Color32[] newVertexColors;
    30.             int currentCharacter = 0;
    31.             int startingCharacterRange = currentCharacter;
    32.             bool isRangeMax = false;
    33.             while (!isRangeMax)
    34.             {
    35.                 int characterCount = textInfo.characterCount;
    36.                 // Spread should not exceed the number of characters.
    37.                 byte fadeSteps = (byte)Mathf.Max(1, 255 / RolloverCharacterSpread);
    38.                 for (int i = startingCharacterRange; i < currentCharacter + 1; i++)
    39.                 {
    40.                     // Skip characters that are not visible
    41.                     if (!textInfo.characterInfo[i].isVisible) continue;
    42.                     // Get the index of the material used by the current character.
    43.                     int materialIndex = textInfo.characterInfo[i].materialReferenceIndex;
    44.                     // Get the vertex colors of the mesh used by this text element (character or sprite).
    45.                     newVertexColors = textInfo.meshInfo[materialIndex].colors32;
    46.                     // Get the index of the first vertex used by this text element.
    47.                     int vertexIndex = textInfo.characterInfo[i].vertexIndex;
    48.                     // Get the current character's alpha value.
    49.                     byte alpha = (byte)Mathf.Clamp(newVertexColors[vertexIndex + 0].a - fadeSteps, 0 , 255);
    50.                     // Set new alpha values.
    51.                     newVertexColors[vertexIndex + 0].a = alpha;
    52.                     newVertexColors[vertexIndex + 1].a = alpha;
    53.                     newVertexColors[vertexIndex + 2].a = alpha;
    54.                     newVertexColors[vertexIndex + 3].a = alpha;
    55.                     // Tint vertex colors
    56.                     // Note: Vertex colors are Color32 so we need to cast to Color to multiply with tint which is Color.
    57.                     newVertexColors[vertexIndex + 0] = (Color)newVertexColors[vertexIndex + 0] * ColorTint;
    58.                     newVertexColors[vertexIndex + 1] = (Color)newVertexColors[vertexIndex + 1] * ColorTint;
    59.                     newVertexColors[vertexIndex + 2] = (Color)newVertexColors[vertexIndex + 2] * ColorTint;
    60.                     newVertexColors[vertexIndex + 3] = (Color)newVertexColors[vertexIndex + 3] * ColorTint;
    61.                     if (alpha == 0)
    62.                     {
    63.                         startingCharacterRange += 1;
    64.                         if (startingCharacterRange == characterCount)
    65.                         {
    66.                             // Update mesh vertex data one last time.
    67.                             m_TextComponent.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32);
    68.                             yield return new WaitForSeconds(1.0f);
    69.                             // Reset the text object back to original state.
    70.                             m_TextComponent.ForceMeshUpdate();
    71.                             yield return new WaitForSeconds(1.0f);
    72.                             // Reset our counters.
    73.                             currentCharacter = 0;
    74.                             startingCharacterRange = 0;
    75.                             //isRangeMax = true; // Would end the coroutine.
    76.                         }
    77.                     }
    78.                 }
    79.                 // Upload the changed vertex colors to the Mesh.
    80.                 m_TextComponent.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32);
    81.                 if (currentCharacter + 1 < characterCount) currentCharacter += 1;
    82.                 yield return new WaitForSeconds (0.25f - FadeSpeed * 0.01f);
    83.             }
    84.         }
    85.     }
    86. }
    87.  
     
    yuliyF, nvekmauvia and hoperin like this.
  4. nvekmauvia

    nvekmauvia

    Joined:
    Mar 19, 2013
    Posts:
    2
    Hi there, fantastic script! Is there a way to prevent the meshInfo/vertex colors from being reset each time tmp.maxVisibleCharacters is changed though? Or does changing maxVisibleCharacters force a recreation of the mesh?

    If so, I was thinking of making a dummy Color32[] the real one references, and having the script change the dummy while the tmp constantly refreshes to reflect the dummy. Would that work with tmp?

    Thank you!

    EDIT: Nevermind I just uh read through the forum and it basically answers this (this is why you don't just skip to the code)
     
    Last edited: Feb 28, 2019
  5. nvekmauvia

    nvekmauvia

    Joined:
    Mar 19, 2013
    Posts:
    2
    An update on this for anyone with the same question: using a dummy Color32[] works!

    Not sure if it's the best method, but it runs pretty smoothly :)