Search Unity

  1. New Unity Live Help updates. Check them out here!

    Dismiss Notice

Collider to TextMesh Pro text

Discussion in 'UGUI & TextMesh Pro' started by Nadan, Sep 26, 2018.

  1. Nadan

    Nadan

    Joined:
    Jan 20, 2013
    Posts:
    341
    I need collider for the text. Is it possible to do somehow?
     
    Last edited: Sep 26, 2018
  2. Stephan_B

    Stephan_B

    Unity Technologies

    Joined:
    Feb 26, 2017
    Posts:
    3,974
    Are you talking about a collider for each individual letters?

    If so, it can actually be done. Please note this was done just for fun and requires some tweaking of source code of TMP.

    The first step is to modify the code designed to get over the 65,535 vertices limit. This code, breaks the text object into sub meshes whenever the text would exceed this 65,535 vertices limit. However, in our case, we actually want to force TMP to create a sub mesh per character so we can add a collider to each of them and control them separately.

    Depending on the version of TMP that you are using (which needs to be a source code version. Any of the new versions of TMP provided via the package manager for 2018.1 + include source code).

    In the TMPro_Private.cs file around line 1272, is where these vertices limit is handled. Change the 16383 to a value of 1. This will force TMP to create a new sub mesh object for each character.

    Code (csharp):
    1.  
    2. if (!char.IsWhiteSpace((char)unicode) && unicode != 0x200B)
    3. {
    4.     // Limit the mesh of the main text object to 65535 vertices and use sub objects for the overflow.
    5.     if (m_materialReferences[m_currentMaterialIndex].referenceCount < 16383)
    6.         m_materialReferences[m_currentMaterialIndex].referenceCount += 1;
    7.     else
    8.     {
    9.         m_currentMaterialIndex = MaterialReference.AddMaterialReference(new Material(m_currentMaterial), m_currentFontAsset, m_materialReferences, m_materialReferenceIndexLookup);
    10.         m_materialReferences[m_currentMaterialIndex].referenceCount += 1;
    11.     }
    12. }
    13.  
    Then at line 3820 or thereabout, uncomment the following line which will automatically add / size the colliders on these characters.

    Code (csharp):
    1.  
    2. // Update the collider on the sub text object
    3. m_subTextObjects[i].UpdateColliders(m_textInfo.meshInfo[i].vertexCount);
    4.  
    Next in the TMP_SubMesh.cs file at around line 184 uncomment the following property and serialized field.

    Code (csharp):
    1.  
    2. public BoxCollider boxCollider
    3. {
    4.     get
    5.     {
    6.         if (m_boxCollider == null)
    7.         {
    8.             //
    9.             m_boxCollider = GetComponent<BoxCollider>();
    10.             if (m_boxCollider == null)
    11.             {
    12.                 m_boxCollider = gameObject.AddComponent<BoxCollider>();
    13.                 gameObject.AddComponent<Rigidbody>();
    14.             }
    15.         }
    16.         return m_boxCollider;
    17.     }
    18. }
    19. [SerializeField]
    20. private BoxCollider m_boxCollider;
    21.  
    Lastly, uncomment function at line 558 as follows.

    Code (csharp):
    1.  
    2. public void UpdateColliders(int vertexCount)
    3. {
    4.     if (this.boxCollider == null) return;
    5.     Vector2 bl = TMP_Math.MAX_16BIT;
    6.     Vector2 tr = TMP_Math.MIN_16BIT;
    7.     // Compute the bounds of the sub text object mesh (excluding the transform position).
    8.     for (int i = 0; i < vertexCount; i++)
    9.     {
    10.         bl.x = Mathf.Min(bl.x, m_mesh.vertices[i].x);
    11.         bl.y = Mathf.Min(bl.y, m_mesh.vertices[i].y);
    12.         tr.x = Mathf.Max(tr.x, m_mesh.vertices[i].x);
    13.         tr.y = Mathf.Max(tr.y, m_mesh.vertices[i].y);
    14.     }
    15.     Vector3 center = (bl + tr) / 2;
    16.     Vector3 size = tr - bl;
    17.     size.z = .1f;
    18.     this.boxCollider.center = center;
    19.     this.boxCollider.size = size;
    20. }
    21.  
    This should do the trick.

    Again this was just experimental stuff for fun. Some new property should be added to the text object to control this vertices limit as with this change all text objects will have this 1 character limit which is most likely not want you want in all instances.
     
    Nadan likes this.
  3. drougyL

    drougyL

    Joined:
    Jun 26, 2019
    Posts:
    1
    Hello Stephan, i tried your solution and it work at beginning but when i try to put a lot of characters (more than 32) it show some errors in the console and didnt work :

    IndexOutOfRangeException: Index was outside the bounds of the array.
    TMPro.MaterialReference.AddMaterialReference (UnityEngine.Material material, TMPro.TMP_FontAsset fontAsset, TMPro.MaterialReference[] materialReferences, System.Collections.Generic.Dictionary`2[TKey,TValue] materialReferenceIndexLookup) (at Packages/com.unity.textmeshpro@2.0.1/Scripts/Runtime/MaterialReferenceManager.cs:596)


    and

    NullReferenceException: Object reference not set to an instance of an object
    TMPro.TextMeshPro.GenerateTextMesh () (at Packages/com.unity.textmeshpro@2.0.1/Scripts/Runtime/TMPro_Private.cs:1864)


    can you explain what is the problem and what can i do to solve it.
    Thank you.
    Loïs
     
  4. Stephan_B

    Stephan_B

    Unity Technologies

    Joined:
    Feb 26, 2017
    Posts:
    3,974
    Most likely the array allocations for the sub mesh objects (1 per character) is not being resized when you get above 32.

    A quick and dirty solution is to increase the default allocation to 64 in the TMP_Text.cs as follows:

    protected MaterialReference[] m_materialReferences = new MaterialReference[64];

    This is assuming you will be using less than 64 characters.

    Note: When I have time, I'll take a closer look at this implementation to make sure it behaves as expected by default.
     
  5. Sparkline

    Sparkline

    Joined:
    Feb 8, 2013
    Posts:
    81
    Hi. I have a lot of objects with TextMeshUGUI components with only 1 charater in each. Is there any way to create polygon collider with script that will repeat character mesh? The main reason is to detect mouse click at exact letter. As you can see in my project simple box colliders will overlap each other. And IPointerClick wont work properly.
    2020-03-25_181948.png
     
    Last edited: Mar 25, 2020
  6. Stephan_B

    Stephan_B

    Unity Technologies

    Joined:
    Feb 26, 2017
    Posts:
    3,974
    Adding a Collider per character to detect mouse clicks is not necessary.

    Please see example "12 - Link Example" and "12a - Text Interactions" which provides examples of potential interactions with characters, words, links, etc. These examples are included in the TMP Examples & Extras. Please review the included scripts to learn how you can use this existing functionality.
     
  7. Sparkline

    Sparkline

    Joined:
    Feb 8, 2013
    Posts:
    81
    I came across these examples and it is good. But click areas are rectanges for each char. So in this example I cant select "X" if it is not "at front" in ui sorting.


    2020-03-26_130834.png
     
  8. Stephan_B

    Stephan_B

    Unity Technologies

    Joined:
    Feb 26, 2017
    Posts:
    3,974
    The functions used to find the nearest character is contained in TMP_TextUtilities.cs file, you might be able to add by modifying one of those functions to check if two potential position finds more than one potential character and then add additional logic to determine which should be selected.

    Assuming you find some good logic here, this would be more efficient then adding several colliders per character.
     
  9. Sparkline

    Sparkline

    Joined:
    Feb 8, 2013
    Posts:
    81
    Thanks for fast reply. As I can understand it will work for several chars within one object. But as I mentioned i have separeted gameobjects for each char. And raycasting works according to sibling index. Are you sure you lead me to the right way (using FindNearestCharacter())?
     
  10. Stephan_B

    Stephan_B

    Unity Technologies

    Joined:
    Feb 26, 2017
    Posts:
    3,974
    There are several functions in the TMP_TextUtilities.cs file which are used in those examples to figure out what character, word, line, etc. intersect with a given position. Take a look at the scripts used in those examples to see how these functions are used.

    P.S. Pay close attention to the Camera setting where it may need to be null when in Screen Space Overlay for instance.
     
unityunity