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

TextMesh Pro How to make Curve Text By Using TextMesh Pro?

Discussion in 'UGUI & TextMesh Pro' started by ingle, Feb 20, 2019.

  1. ingle

    ingle

    Joined:
    Jun 26, 2018
    Posts:
    2
    Any suggestion will be appreciate.
     
  2. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    There are several posts about this already on the forum.

    I also added a new example in the TMP Examples & Extras included with version 1.4.0-preview.xx of TextMesh Pro for Unity 2018.3. The example scene is called "25 - Sunny Days Example".

    upload_2019-2-19_20-9-48.png
     
  3. zenasprime

    zenasprime

    Joined:
    Mar 31, 2010
    Posts:
    165
    I don't see this example scene. 25 is currently called TextMeshPro Title.
     
  4. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    This new example is part of the update TMP Examples & Extras included in version 1.4.0 of TMP for Unity 2018.3 or newer.
     
  5. zenasprime

    zenasprime

    Joined:
    Mar 31, 2010
    Posts:
    165
    I'm using Unity 2018.3.5, which lists 1.3.0 as the current stable version. I've updated to 1.4.0 so that first hurdle has been solved.

    My next issue is that this solution seems to only be useful for applying a curve at run time. It doesn't provide any means to apply the curve in the editor so that it can complement existing UI elements. Any suggestions?
     
  6. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    This script was provided to give users some insight on how the vertex attributes of the underlying text object could be modified to achieve various FX.

    I would suggest creating your own script and using this example as a basis. To make the script work in the editor, you can use the [ExecuteAlways] attribute.

    One thing you will have to be mindful of is these modifications of the vertex attributes / geometry being reset anytime the text changes. Ie. the text component will re-layout the text normally when it is changed. Then this script need to subsequently modify it back to curve it.

    Also look at the VertexJitter.cs script ... you should be able to attach to the TEXT_CHANGED_EVENT to detect the re-layout and re-apply your modification.
     
    Nemikolh, yyylny and pouttit like this.
  7. zenasprime

    zenasprime

    Joined:
    Mar 31, 2010
    Posts:
    165
    Well, to be honest, the only reason I'm using a TextMeshProUGUI at all is because the string is going to be constantly changing value. Otherwise I'd just make the text a sprite (or part of a larger sprite) and be done with it. ;)

    Maybe one day Unity will give us the same design tools for text as say Illustrator. (hint hint)

    Until then I'll take a look at the scripts above, but the last thing I'm interested in doing when trying to implement a UI design is write custom code for the pretty standard text treatments I get from the graphic designer. It's hard to have this conversation with the designer, that their design poses some custom problem solving issues when the tools they are using are fairly simple for them to use (all the while their giving you squinty eyes for why it's not so easy in Unity) while at the same time development resources have budget and deadline considerations to keep in mind. *sigh*
     
  8. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    Certainly understandable and thank you for the feedback.

    Adding additional design / layout tools for the text would certainly be a good thing. I don't have the time right now to look / work on this so this could be an opportunity for some Asset Store developers to provide to users.
     
    maewionn likes this.
  9. manawindgames

    manawindgames

    Joined:
    May 27, 2018
    Posts:
    1
    hi, I'm having trouble getting the curved text to stay curved when I change it.

    Even with a simple test -

    TextMeshProUGUI t;
    t.text = "New text";

    where I assign the Sunny Days example scene text object to t then change it - so when it loads with "Sunny Days" text it's curved, after a delay when it changes to "New text" it becomes straight.

    Is there some trick to keeping the curve after updating the text?
     
  10. RGV

    RGV

    Joined:
    Jan 25, 2016
    Posts:
    48
    Example doesn't work to me. Rather I can't see anything but the hierarchy structure.
    • Scene is empty — visually.
    • TMP Submesh UI script has None both in Font Asset and in Sprite Asset.
    • After play, IndexOutOfRangeException appears out.
    I just created a project (Unity 2019.2.0f1) and import TMP Examples.
     
  11. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    In this same new project, first make sure you import the TMP Essential Resources and then the TMP Examples & Extras. Then load the Sunny Days example.
     
    RGV likes this.
  12. TonyVT

    TonyVT

    Joined:
    Sep 11, 2014
    Posts:
    13
    For whoever may be interested, I had to create a text that followed a circle, so I had to bang my head to modify the WarpTextExample... but in the end, I obtained something that worked decently!

    To help other devs in the community in the same situation, I have created a repo with my scripts. I have also filled them with comments so that they are easier to understand. Feel free to use them in your projects!

    https://github.com/TonyViT/CurvedTextMeshPro

    Have fun
     
  13. imerso

    imerso

    Joined:
    May 6, 2011
    Posts:
    278
    Hey, this is neat. I was about to dive into writing a similar helper, but then I found this thread and your post. It worked nicely and saved me probably several hours of work. Thanks! =)
     
  14. KarlKarl2000

    KarlKarl2000

    Joined:
    Jan 25, 2016
    Posts:
    606
    @TonyVT Thanks so much for this! Your demo scene works beautifully, but it doesn't work when I try to use your game object in my own scene. if I try to scale the game object all the fonts seem to overlap each other into one black mess. :oops:
     
  15. Hargol22

    Hargol22

    Joined:
    Feb 11, 2017
    Posts:
    5
    I just wanted to curve some text. Not sure if there's an easy solution for this today, but I came across this post and your script worked like a charm! Thank You!
     
  16. Undertaker-Infinity

    Undertaker-Infinity

    Joined:
    May 2, 2014
    Posts:
    112
    Straightforward to use and works! nice!
     
  17. yyylny

    yyylny

    Joined:
    Sep 19, 2015
    Posts:
    93
    @TonyVT, thanks a lot for sharing your code! It works great and it is just what I was looking for. However, I think the ParametersHaveChanged() method is redundant. I removed it and used OnValidate() instead:

    Code (CSharp):
    1.         private void OnValidate()
    2.         {
    3.             m_forceUpdate = true;
    4.         }
     
  18. francismoy

    francismoy

    Joined:
    Jul 5, 2017
    Posts:
    46
    Thanks for this fantastic tool!

    One question: I would like to curve the text and apply a simple scaling tween (using DoTween in my case) per character. The problem I'm facing is that as soon as the tween starts, the curve of the text is lost. Any ideas on how I can apply a per-character animation without losing the curve?

    EDIT: I've researched a bit more, and the reason seems to be a call to ForceMeshUpdate(true) before applying the tween. If I comment that line out, the tween is applied correctly to the curved text. I'll contact the Dotween's developer to explain the situation and see if it's reasonable to call that line with a flag.
     
    Last edited: Nov 26, 2020
  19. noboRenelieSalazar

    noboRenelieSalazar

    Joined:
    Aug 3, 2021
    Posts:
    3
    Hi, @Stephan_B , I was just wondering if any of the later versions of TextMeshPro still has this "Text along a curve" feature?
     
  20. april_4_short

    april_4_short

    Joined:
    Jul 19, 2021
    Posts:
    489
    Be nice to have the text swell/distort away from the line, on the outer part of curves, and do the inverse on the inner part of curves, too.

    Please.
     
    noboRenelieSalazar likes this.
  21. noboRenelieSalazar

    noboRenelieSalazar

    Joined:
    Aug 3, 2021
    Posts:
    3
    I agree. Like this one feature which @Stephan_B himself made on TextMeshPro a few years back. (his own Twitter post)
     
  22. april_4_short

    april_4_short

    Joined:
    Jul 19, 2021
    Posts:
    489
    I don't see that doing the swell distortion. The tops of the letters are the same width as the bottom, even at the peak of the curve's bend.

    The distortion would expand the tops of the letters as the curve bends.

    The heavy/fat font is hiding the lack of swell distortion.
     
  23. Epsilon_Delta

    Epsilon_Delta

    Joined:
    Mar 14, 2018
    Posts:
    258
    I was just in need of curved text and found this thread. Adapted the script a bit since I did not need animation, just a static curve, but I also wanted to see it in the editor (used [ExecuteAlways])
    Here's the script on github:
    https://github.com/EpsilonD3lta/UnityCollection/blob/master/Scripts/Runtime/TMProWarpText.cs
    And here's the code (the code in github link can be updated in the future):
    Code (CSharp):
    1. using TMPro;
    2. #if UNITY_EDITOR
    3. using UnityEditor.Experimental.SceneManagement;
    4. #endif
    5. using UnityEngine;
    6.  
    7. /// <summary> Adapted from TMPro examples and extras provided by Unity </summary>
    8. [ExecuteAlways]
    9. public class TMProWarpText : MonoBehaviour
    10. {
    11.     [SerializeField]
    12.     private TMP_Text text;
    13.  
    14.     public AnimationCurve vertexCurve = new AnimationCurve(
    15.         new Keyframe(0, 0, 0, 1, 0, 0), new Keyframe(0.5f, 1.0f), new Keyframe(1, 0, 1, 0, 0,0));
    16.     public float yCurveScaling = 50f;
    17.  
    18.     private bool isForceUpdatingMesh;
    19.  
    20.     private void Reset()
    21.     {
    22.         text = gameObject.GetComponent<TMP_Text>();
    23.     }
    24.  
    25.     void Awake()
    26.     {
    27.         if (!text) text = gameObject.GetComponent<TMP_Text>();
    28. #if UNITY_EDITOR
    29.         PrefabStage.prefabStageOpened += PrefabStageOpened;
    30. #endif
    31.     }
    32.  
    33.     private void OnEnable()
    34.     {
    35.         WarpText();
    36.         TMPro_EventManager.TEXT_CHANGED_EVENT.Add(ReactToTextChanged);
    37.     }
    38.  
    39.     private void OnDisable()
    40.     {
    41.         TMPro_EventManager.TEXT_CHANGED_EVENT.Remove(ReactToTextChanged);
    42.         text.ForceMeshUpdate();
    43.     }
    44.  
    45.     //private void OnDidApplyAnimationProperties()
    46.     //{
    47.     //    WarpText();
    48.     //}
    49.  
    50. #if UNITY_EDITOR
    51.     private void OnDestroy()
    52.     {
    53.         PrefabStage.prefabStageOpened -= PrefabStageOpened;
    54.     }
    55.  
    56.     private void PrefabStageOpened(PrefabStage prefabStage)
    57.     {
    58.         WarpText();
    59.     }
    60. #endif
    61.  
    62.     private void OnValidate()
    63.     {
    64.         WarpText();
    65.     }
    66.  
    67.     private void ReactToTextChanged(Object obj)
    68.     {
    69.         TMP_Text tmpText = obj as TMP_Text;
    70.         if (tmpText && text && tmpText == text && !isForceUpdatingMesh)
    71.             WarpText();
    72.     }
    73.  
    74.     /// <summary> Method to curve text along a Unity animation curve. </summary>
    75.     private void WarpText()
    76.     {
    77.         if (!text) return;
    78.         isForceUpdatingMesh = true;
    79.         vertexCurve.preWrapMode = WrapMode.Clamp;
    80.         vertexCurve.postWrapMode = WrapMode.Clamp;
    81.  
    82.         Vector3[] vertices;
    83.         Matrix4x4 matrix;
    84.  
    85.         text.havePropertiesChanged = true; // Need to force the TextMeshPro Object to be updated.
    86.         text.ForceMeshUpdate(); // Generate the mesh and populate the textInfo with data we can use and manipulate.
    87.  
    88.         TMP_TextInfo textInfo = text.textInfo;
    89.         if (textInfo == null) return;
    90.         int characterCount = textInfo.characterCount;
    91.  
    92.         if (characterCount == 0) return;
    93.  
    94.         float boundsMinX = text.bounds.min.x;
    95.         float boundsMaxX = text.bounds.max.x;
    96.  
    97.         for (int i = 0; i < characterCount; i++)
    98.         {
    99.             if (!textInfo.characterInfo[i].isVisible) continue;
    100.  
    101.             int vertexIndex = textInfo.characterInfo[i].vertexIndex;
    102.             // Get the index of the mesh used by this character.
    103.             int materialIndex = textInfo.characterInfo[i].materialReferenceIndex;
    104.             vertices = textInfo.meshInfo[materialIndex].vertices;
    105.  
    106.             // Compute the baseline mid point for each character
    107.             Vector3 offsetToMidBaseline = new Vector2(
    108.                 (vertices[vertexIndex + 0].x + vertices[vertexIndex + 2].x) / 2, textInfo.characterInfo[i].baseLine);
    109.  
    110.             // Apply offset to adjust our pivot point.
    111.             vertices[vertexIndex + 0] += -offsetToMidBaseline;
    112.             vertices[vertexIndex + 1] += -offsetToMidBaseline;
    113.             vertices[vertexIndex + 2] += -offsetToMidBaseline;
    114.             vertices[vertexIndex + 3] += -offsetToMidBaseline;
    115.  
    116.             // Compute the angle of rotation for each character based on the animation curve
    117.             // Character's position relative to the bounds of the mesh.
    118.             float x0 = (offsetToMidBaseline.x - boundsMinX) / (boundsMaxX - boundsMinX);
    119.             float x1 = x0 + 0.0001f;
    120.             float y0 = vertexCurve.Evaluate(x0) * yCurveScaling;
    121.             float y1 = vertexCurve.Evaluate(x1) * yCurveScaling;
    122.  
    123.             Vector3 horizontal = new Vector3(1, 0, 0);
    124.             Vector3 tangent = new Vector3(x1 * (boundsMaxX - boundsMinX) + boundsMinX, y1) -
    125.                 new Vector3(offsetToMidBaseline.x, y0);
    126.  
    127.             float dot = Mathf.Acos(Vector3.Dot(horizontal, tangent.normalized)) * Mathf.Rad2Deg;
    128.             Vector3 cross = Vector3.Cross(horizontal, tangent);
    129.             float angle = cross.z > 0 ? dot : 360 - dot;
    130.  
    131.             matrix = Matrix4x4.TRS(new Vector3(0, y0, 0), Quaternion.Euler(0, 0, angle), Vector3.one);
    132.  
    133.             vertices[vertexIndex + 0] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 0]);
    134.             vertices[vertexIndex + 1] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 1]);
    135.             vertices[vertexIndex + 2] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 2]);
    136.             vertices[vertexIndex + 3] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 3]);
    137.  
    138.             vertices[vertexIndex + 0] += offsetToMidBaseline;
    139.             vertices[vertexIndex + 1] += offsetToMidBaseline;
    140.             vertices[vertexIndex + 2] += offsetToMidBaseline;
    141.             vertices[vertexIndex + 3] += offsetToMidBaseline;
    142.  
    143.             // Upload the mesh with the revised information
    144.             text.UpdateVertexData();
    145.         }
    146.  
    147.         isForceUpdatingMesh = false;
    148.     }
    149. }
     
    Last edited: Oct 16, 2023