UGUI Graphic Four (Text)

        Text is a very commonly used component in UGUI, which can display text based on strings. But in fact, there is not a lot of Text code, because most of the logic is implemented in TextGenerator, and TextGenerator is a class under the UnityEngine namespace. Uh (⊙o⊙)... Well, let's be optimistic, at least we don't need to worry about the underlying details anymore.
        Although the implementation of TextGenerator is officially hidden by Unity, we can use TextMesh to get a glimpse of it.

Create a new 3D Text, as shown in the figure:

        We see that it draws a rectangular frame (two triangles) for each subtitle. From this, we can guess that TextGenerator creates four vertices and two triangles based on the size and offset of each word in the font file, and according to the font Set the uv coordinates for the location of each word in the file.

        This is the Populate method of TextGenerator, which is called in the OnPopulateMesh method of Text.

 protected override void OnPopulateMesh(VertexHelper toFill)
        {
            if (font == null)
                return;
 
            // We don't care if we the font Texture changes while we are doing our Update.
            // The end result of cachedTextGenerator will be valid for this instance.
            // Otherwise we can get issues like Case 619238.
            m_DisableFontTextureRebuiltCallback = true;
 
            Vector2 extents = rectTransform.rect.size;
 
            var settings = GetGenerationSettings(extents);
            cachedTextGenerator.Populate(text, settings);
 
            Rect inputRect = rectTransform.rect;
 
            // get the text alignment anchor point for the text in local space
            Vector2 textAnchorPivot = GetTextAnchorPivot(m_FontData.alignment);
            Vector2 refPoint = Vector2.zero;
            refPoint.x = (textAnchorPivot.x == 1 ? inputRect.xMax : inputRect.xMin);
            refPoint.y = (textAnchorPivot.y == 0 ? inputRect.yMin : inputRect.yMax);
 
            // Determine fraction of pixel to offset text mesh.
            Vector2 roundingOffset = PixelAdjustPoint(refPoint) - refPoint;
 
            // Apply the offset to the vertices
            IList<UIVertex> verts = cachedTextGenerator.verts;
            float unitsPerPixel = 1 / pixelsPerUnit;
            //Last 4 verts are always a new line...
            int vertCount = verts.Count - 4;
 
            toFill.Clear();
            if (roundingOffset != Vector2.zero)
            {
                for (int i = 0; i < vertCount; ++i)
                {
                    int tempVertsIndex = i & 3;
                    m_TempVerts[tempVertsIndex] = verts[i];
                    m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
                    m_TempVerts[tempVertsIndex].position.x += roundingOffset.x;
                    m_TempVerts[tempVertsIndex].position.y += roundingOffset.y;
                    if (tempVertsIndex == 3)
                        toFill.AddUIVertexQuad(m_TempVerts);
                }
            }
            else
            {
                for (int i = 0; i < vertCount; ++i)
                {
                    int tempVertsIndex = i & 3;
                    m_TempVerts[tempVertsIndex] = verts[i];
                    m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
                    if (tempVertsIndex == 3)
                        toFill.AddUIVertexQuad(m_TempVerts);
                }
            }
            m_DisableFontTextureRebuiltCallback = false;
        }

        Text inherits from MaskableGraphic, which inherits from Graphic. Graphic's OnPopulateMesh method is rewritten in Text and is called (UpdateGeometry method) when rebuilding the image.
In the OnPopulateMesh method, a TextGenerationSettings is generated based on the user's settings, and then the Populate method of TextGenerator is called to generate the mesh's vertices, vertex colors, triangles, and UV coordinates. Then get the textAnchorPivot (text anchor axis) based on alignment, and calculate the offset (for example, left alignment requires space on the left side). Finally, traverse the TextGenerator's vertex array, divide their positions by pixelsPerUnit (pixels per unit) and add the offset (if any), and fill the result into toFill (VertexHelper type, Graphic uses it to create Mesh) .

        In addition, when OnDisable, OnEnable (see Untiy3D component tips (1) OnEnabled and OnDisabled for calling timing) or when the font is modified, the UntrackText and TrackText methods of FontUpdateTracker will be called. FontUpdateTracker is a static class that maintains a variable m_Tracked of type Dictionary<Font, List<Text>>. In TrackText, Text is added to the List, and if the Dictionary was empty before, UntrackText will move the Text out of the List. FontUpdateTracker will listen to the textureRebuilt event of the Font static class and call back RebuildForFont. The RebuildForFont method will find the List<Text> based on the incoming font, and then call the FontTextureChanged method of each Text (UpdateGeometry updates the geometry, recalculates the Mesh, or SetAllDirty to rebuild the layout, vertices and materials).

        By the way, I would like to add some code about FontData. As a configuration class, FontData itself has nothing to say, but it inherits the ISerializationCallbackReceiver interface, which needs to implement the OnBeforeSerialize and OnAfterDeserialize methods. These are two interesting methods (although not thread-safe and need to be used with care) that are called before serialization and after deserialization respectively. FontData's OnAfterDeserialize limits m_FontSize, m_MinSize and m_MaxSize to between 0 and 300 after deserialization.

Guess you like

Origin blog.csdn.net/ttod/article/details/135016325