Search Unity

TextMesh Pro How to stop/reset a mesh modification on a text? Using jitter example from extras.

Discussion in 'UGUI & TextMesh Pro' started by FeastSC2, May 26, 2019.

  1. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    978
    There's an example in the extras of TextMeshPro manipulating the mesh with a vertex jitter.

    I would like to know how to properly stop (+reset) a text component after having applied the jitter effect.

    My problem is that after changing the text the mesh of a previous sentence remains and is not being cleaned up as shown in this picture.
    (I tried various various ClearMesh()/ForceMeshUpdate() calls but it didn't fix it, but I had no clue what I was doing ^^).

    upload_2019-5-26_17-16-15.png

    Here's the script:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using Sirenix.OdinInspector;
    4. using UnityEngine.UIElements;
    5.  
    6. namespace TMPro.Examples
    7. {
    8.     public class VertexJitter : MonoBehaviour
    9.     {
    10.         public float AngleMultiplier = 1.0f;
    11.         public float CurveScale = 5f;
    12.  
    13.         private TMP_Text m_TextComponent;
    14.         private bool hasTextChanged;
    15.  
    16.  
    17.         void Awake()
    18.         {
    19.             m_TextComponent = GetComponent<TMP_Text>();
    20.         }
    21.  
    22.         void OnEnable()
    23.         {
    24.             // Subscribe to event fired when text object has been regenerated.
    25.             TMPro_EventManager.TEXT_CHANGED_EVENT.Add(ON_TEXT_CHANGED);
    26.         }
    27.  
    28.         void OnDisable()
    29.         {
    30.             TMPro_EventManager.TEXT_CHANGED_EVENT.Remove(ON_TEXT_CHANGED);
    31.         }
    32.  
    33.         private IEnumerator Coroutine;
    34.         public bool IsJittering { get; private set; }
    35.  
    36.         public void ToggleJitter(bool _on)
    37.         {
    38.             if (_on) StartJitter();
    39.             else StopJitter();
    40.         }
    41.  
    42.         [Button("Start Jitter")]
    43.         public void StartJitter()
    44.         {
    45.             if (IsJittering == false)
    46.             {
    47.                 m_TextComponent.ForceMeshUpdate();
    48.                 IsJittering = true;
    49.                 Coroutine = AnimateVertexColors();
    50.                 StartCoroutine(Coroutine);
    51.             }
    52.         }
    53.  
    54.         [Button("Stop Jitter")]
    55.         public void StopJitter()
    56.         {
    57.             if (IsJittering)
    58.             {
    59.                 IsJittering = false;
    60.                 if (Coroutine != null)
    61.                     StopCoroutine(Coroutine);
    62.                 Coroutine = null;
    63.                 m_TextComponent.ForceMeshUpdate();
    64.             }
    65.         }
    66.  
    67.         void ON_TEXT_CHANGED(Object obj)
    68.         {
    69.             if (obj == m_TextComponent)
    70.                 hasTextChanged = true;
    71.         }
    72.  
    73.         private TMP_MeshInfo[] StartTmpMeshInfo;
    74.  
    75.         /// <summary>
    76.         /// Method to animate vertex colors of a TMP Text object.
    77.         /// </summary>
    78.         /// <returns></returns>
    79.         IEnumerator AnimateVertexColors()
    80.         {
    81.             // We force an update of the text object since it would only be updated at the end of the frame. Ie. before this code is executed on the first frame.
    82.             // Alternatively, we could yield and wait until the end of the frame when the text object will be generated.
    83.             m_TextComponent.ForceMeshUpdate();
    84.  
    85.             TMP_TextInfo textInfo = m_TextComponent.textInfo;
    86.  
    87.             Matrix4x4 matrix;
    88.  
    89.             int loopCount = 0;
    90.             hasTextChanged = true;
    91.  
    92.             // Create an Array which contains pre-computed Angle Ranges and Speeds for a bunch of characters.
    93.             //VertexAnim[] vertexAnim = new VertexAnim[1024];
    94.             //for (int i = 0; i < 1024; i++)
    95.             //{
    96.             //    vertexAnim[i].angleRange = Random.Range(10f, 25f);
    97.             //    vertexAnim[i].speed = Random.Range(1f, 3f);
    98.             //}
    99.  
    100.             // Cache the vertex data of the text object as the Jitter FX is applied to the original position of the characters.
    101.             TMP_MeshInfo[] cachedMeshInfo = textInfo.CopyMeshInfoVertexData();
    102.             StartTmpMeshInfo = textInfo.CopyMeshInfoVertexData();
    103.  
    104.             while (true)
    105.             {
    106.                 // Get new copy of vertex data if the text has changed.
    107.                 if (hasTextChanged)    
    108.                 {
    109.                     // Update the copy of the vertex data for the text object.
    110.                     cachedMeshInfo = textInfo.CopyMeshInfoVertexData();
    111.  
    112.                     hasTextChanged = false;
    113.                 }
    114.  
    115.                 int characterCount = textInfo.characterCount;
    116.  
    117.                 // If No Characters then just yield and wait for some text to be added
    118.                 if (characterCount == 0)
    119.                 {
    120.                     yield return new WaitForSeconds(0.25f);
    121.                     continue;
    122.                 }
    123.  
    124.                 for (int i = 0; i < characterCount; i++)
    125.                 {
    126.                     TMP_CharacterInfo charInfo = textInfo.characterInfo[i];
    127.  
    128.                     // Skip characters that are not visible and thus have no geometry to manipulate.
    129.                     if (!charInfo.isVisible)
    130.                         continue;
    131.  
    132.                     // Retrieve the pre-computed animation data for the given character.
    133.                     //VertexAnim vertAnim = vertexAnim[i];
    134.  
    135.                     // Get the index of the material used by the current character.
    136.                     int materialIndex = textInfo.characterInfo[i].materialReferenceIndex;
    137.  
    138.                     // Get the index of the first vertex used by this text element.
    139.                     int vertexIndex = textInfo.characterInfo[i].vertexIndex;
    140.  
    141.                     // Get the cached vertices of the mesh used by this text element (character or sprite).
    142.                     Vector3[] sourceVertices = cachedMeshInfo[materialIndex].vertices;
    143.  
    144.                     // Determine the center point of each character at the baseline.
    145.                     //Vector2 charMidBasline = new Vector2((sourceVertices[vertexIndex + 0].x + sourceVertices[vertexIndex + 2].x) / 2, charInfo.baseLine);
    146.                     // Determine the center point of each character.
    147.                     Vector2 charMidBasline = (sourceVertices[vertexIndex + 0] + sourceVertices[vertexIndex + 2]) / 2;
    148.  
    149.                     // Need to translate all 4 vertices of each quad to aligned with middle of character / baseline.
    150.                     // This is needed so the matrix TRS is applied at the origin for each character.
    151.                     Vector3 offset = charMidBasline;
    152.  
    153.                     Vector3[] destinationVertices = textInfo.meshInfo[materialIndex].vertices;
    154.  
    155.                     destinationVertices[vertexIndex + 0] = sourceVertices[vertexIndex + 0] - offset;
    156.                     destinationVertices[vertexIndex + 1] = sourceVertices[vertexIndex + 1] - offset;
    157.                     destinationVertices[vertexIndex + 2] = sourceVertices[vertexIndex + 2] - offset;
    158.                     destinationVertices[vertexIndex + 3] = sourceVertices[vertexIndex + 3] - offset;
    159.  
    160. //                    vertAnim.angle = Mathf.SmoothStep(-vertAnim.angleRange, vertAnim.angleRange, Mathf.PingPong(loopCount / 25f * vertAnim.speed, 1f));
    161.                     Vector3 jitterOffset = new Vector3(Random.Range(-.25f, .25f), Random.Range(-.25f, .25f), 0);
    162.  
    163.                     matrix = Matrix4x4.TRS(jitterOffset * CurveScale, Quaternion.Euler(0, 0, Random.Range(-5f, 5f) * AngleMultiplier), Vector3.one);
    164.  
    165.                     destinationVertices[vertexIndex + 0] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 0]);
    166.                     destinationVertices[vertexIndex + 1] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 1]);
    167.                     destinationVertices[vertexIndex + 2] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 2]);
    168.                     destinationVertices[vertexIndex + 3] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 3]);
    169.  
    170.                     destinationVertices[vertexIndex + 0] += offset;
    171.                     destinationVertices[vertexIndex + 1] += offset;
    172.                     destinationVertices[vertexIndex + 2] += offset;
    173.                     destinationVertices[vertexIndex + 3] += offset;
    174.  
    175.                     //vertexAnim[i] = vertAnim;
    176.                 }
    177.  
    178.                 // Push changes into meshes
    179.                 for (int i = 0; i < textInfo.meshInfo.Length; i++)
    180.                 {
    181.                     textInfo.meshInfo[i].mesh.vertices = textInfo.meshInfo[i].vertices;
    182.                     m_TextComponent.UpdateGeometry(textInfo.meshInfo[i].mesh, i);
    183.                 }
    184.  
    185.                 loopCount += 1;
    186.  
    187.                 yield return new WaitForSeconds(0.1f);
    188.             }
    189.         }
    190.  
    191.     }
    192. }
     
    Graham-B likes this.
  2. UtopiaGameStudio

    UtopiaGameStudio

    Joined:
    Aug 4, 2017
    Posts:
    1
    I was having a similar issue working a wave effect. For me, it worked by resenting the vertices positions using something like this:
    Code (CSharp):
    1. public void ResetVertexPositions()
    2.         {          
    3.            Vector3[] newVertexPositions;
    4.            TMP_TextInfo textInfo = _textComponent.textInfo;
    5.            newVertexPositions = textInfo.meshInfo[0].vertices;
    6.            Debug.Log(TextToRender);
    7.  
    8.            for (int i = 0; i < TextToRender.Length; i++)
    9.            {
    10.                if (!textInfo.characterInfo[i].isVisible)
    11.                    continue;
    12.  
    13.                int vertexIndex = textInfo.characterInfo[i].vertexIndex;
    14.  
    15.                float offsetY = 0;                
    16.  
    17.                newVertexPositions[vertexIndex + 0].y += offsetY;
    18.                newVertexPositions[vertexIndex + 1].y += offsetY;
    19.                newVertexPositions[vertexIndex + 2].y += offsetY;
    20.                newVertexPositions[vertexIndex + 3].y += offsetY;
    21.            }
    22.            // Upload the mesh with the revised information
    23.            _textComponent.mesh.vertices = newVertexPositions;
    24.            _textComponent.mesh.uv = _textComponent.textInfo.meshInfo[0].uvs0;
    25.            _textComponent.mesh.uv2 = _textComponent.textInfo.meshInfo[0].uvs2;
    26.            _textComponent.mesh.colors32 = _textComponent.textInfo.meshInfo[0].colors32;
    27.            _textComponent.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32);
    28.            _textComponent.ForceMeshUpdate(); // Generate the mesh and populate the textInfo with data we can use and manipulate.
    29.          
    30.         }
    Still, I am having problems mixing rich texts (like bold and using sprite feature from text mesh pro). If you found a solution, would you mind to tell me what you've done?
     
  3. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    978
    Sorry I kind of gave up on this because there were so many other things I had to do. Getting into other people's scripts can be quite a challenge.

    I had hoped that the creator of TextMeshPro would create a script that showed all the text effects he had created over the years but he stopped answering me.

    Here's the thread, you might find an answer to what you want over there: https://forum.unity.com/threads/wave-example.528635/#post-4628503
     
    UtopiaGameStudio likes this.