Search Unity

TextMesh Pro TextMeshProUGUI & IMeshModifier

Discussion in 'UGUI & TextMesh Pro' started by dotsquid, Oct 12, 2020.

  1. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    Hi.
    I'm currently in the process of switching from UI.Text to TextMesh Pro in the live project and I encountered a problem with that TextMeshProUGUI does not work with IMeshModifier.
    Some of the text effects in our game relate on IMeshModifier. Specifically one of the implementations provides a subdivided mesh with quad indices in uv2. This is required for the following effect https://twitter.com/dotsquid/status/849931157315649536
    I tried some custom hacky implementations of BaseMeshEffect which intended to work with TextMesh Pro, but they are not perfect: poor performance due to constant mesh rebuilding in LateUpdate, random errors inside TMP due to mismatching of vertices / indices size, randomly fail in case several effects are using on the same game object.
    Since TextMesh Pro is a part of Unity and should be fully integrated, is it possible to make it work with IMeshModifier please?
     
  2. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    Take a look at the example scene Animating Vertex Attributes and related scripts included in the TMP Examples & Extras. This provides a good example of how to modify the text geometry.

    There is also a new callback OnPreRenderText() referenced in the following thread.

    Using the above callback would enable you to modify the text geometry when the text changes. This works with both <TextMeshPro> and <TextMeshProUGUI> text components.
     
  3. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    Thank you Stephan. I'll give it a try.
    However I still don't understand why TextMeshProUGUI does not respect IMeshModifier like other UGUI components?
     
  4. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    One of the text effects used in our game requires subdividing mesh quads into subquads and filling extra information into uv3 (while uv0 and uv2 are internally used by TMP). So I can't modify TMP_MeshInfo like it's done in VertexJitter example because it does not contain a required uv-set.
    That's why I try to modify the mesh directly after TMP fills it.
    Code (CSharp):
    1. TMPro_EventManager.TEXT_CHANGED_EVENT.Add(OnTextChanged);
    2.  
    3. private void OnTextChanged(Object obj)
    4. {
    5.     if (obj == _text)
    6.         SubdivideText();
    7. }
    8.  
    9. private void SubdivideText()
    10. {
    11.     if (!_isModifying && _text != null)
    12.     {
    13.         _isModifying = true;
    14.         //_text.ForceMeshUpdate();
    15.         _text.UpdateVertexData();
    16.         var textInfo = _text.textInfo;
    17.         var meshInfo = textInfo.meshInfo;
    18.         for (int i = 0, count = meshInfo.Length; i < count; ++i)
    19.         {
    20.             var mesh = meshInfo[i].mesh;
    21.             using (var vh = new VertexHelper(mesh))
    22.             {
    23.                 SubdivideMesh(vh, _subdivisionLevel);
    24.                 vh.FillMesh(mesh);
    25.                 _text.UpdateGeometry(mesh, i);
    26.             }
    27.         }
    28.         _isModifying = false;
    29.     }
    30. }
    Everything looks fine until I change the text in the Inspector. The mesh becomes more and more subdivided like if TMP does not fill it from scratch. I tried to force TMP to update the mesh by calling ForceMeshUpdate and UpdateVertexData without any luck.
     
    Last edited: Oct 16, 2020
  5. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
  6. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    I'll try taking a closer look later today / within the next day or so and follow up with you shortly thereafter.
     
    dotsquid likes this.
  7. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    Hi, any luck?
     
  8. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
  9. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
  10. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    It's totally a NOT working solution. I just decided to share the entire script, not the short extract as above.
    So I'm passionately awaiting for your example.
     
  11. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    Sorry for pushing, but it's been two weeks and this problem is kinda important and urgent.
     
  12. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    New version of TMP has been released. I will work on this tonight and over the weekend if needed.
     
    Last edited: Oct 31, 2020
  13. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    Had a chance to look at this last night and a bit today.

    The subdivision is now working as seen in the image below.

    upload_2020-10-31_18-38-37.png
    upload_2020-10-31_18-42-1.png

    There are still changes / improvements that I want to make. I am planning on working some more on this later tonight but should have something for you for Monday.
     
    dotsquid likes this.
  14. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    Here is a revised script using the new OnPreRenderText callback which should enable you to move forward.

    Further improvements and optimizations could be made to reduce allocations but again, this should enable you to move forward.

    Currently, the OnPreRenderText callback allows a user to modify an existing textInfo which is fine for many uses cases but not ideal in this case where we would want to return a copy while having the text object continue to reference the source textInfo. This is something that I will explore when I have time and perhaps make changes to this callback.

    In terms of why you initial script was resulting in increased subdivision of subsequent characters, it was due to the first character subdividing the geometry of subsequent characters which would then further subdivide the next and so on.
     

    Attached Files:

  15. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    Thanks. But how can I use an extra uv-set which I mentioned here?
     
  16. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    Also how to force subdivision whenever I want (not in OnPreRenderText)?
    This is required because of 2 reasons:
    1) I want subdivision to reset when my component is disabled;
    2) I want to force subdivision in OnEnable. Consider a situation when the text for TextMeshPro is provided by serialization from the scene and not changed via scripts. In this case my subdivision will work only if OnEnable of my component will be executed before OnPreRenderText is invoked. Otherwise my component will subscribe this event behind time. I'm not aware of the execution order of TMP's insides, so it's just a concern.
     
  17. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    Whenever text objects are awaken or enabled or any of the properties changed, the text object will be marked as dirty and get updated / processed which happens just before culling and the camera is rendered. This update process consists of a text parsing and layout phase which ends with the resulting geometry getting pushed to the renderer.

    OnPreRenderText() is called at the end of the above process and just before the geometry is pushed to the renderer. This is great for cases like in the VertexJitter example where you are modifying the existing geometry. However, this does not provide for the opportunity to add new vertex attributes like extra UV set.

    In your case, in OnEnable() or OnDisable() you should be able to call ForceMeshUpdate() to force the text object to be updated. Be sure to check the overloads for that function.