ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

基于TextMeshPro实现打印机效果

2022-02-08 23:33:50  阅读:255  来源: 互联网

标签:TMP 打印机 基于 网格 TextMeshPro characterInfo textInfo meshInfo verticeIndex


目标

屏幕上逐字显示文本的打印机效果,使用的显示文本控件为TextMeshPro和TextMeshProUGUI,动态效果如下
在这里插入图片描述

实现方式

基本思路

一种最简单的想法就是,将文本拆分,依次传入给TextMesh组件。但这种方式需要产生多个substring,给后续GC带来压力,且每次对text赋值就需要重新计算文字的网格位置。既然原字符串显示的时候已经计算过了网格,那么就可以考虑利用这份网格数据,依次输出给renderer来实现字符依次显示。

具体实现

如图,每个字符都由4个顶点组成构成,只要想办法控制绘制顶点的数量,就能控制显示文字的长度。
在这里插入图片描述

在TextMeshPro中,要显示的文字和网格信息都存储在textInfo这个变量中,变量的类型为TMP_TextInfo。TMP_TextInfo类型中,meshInfo缓存了文字网格数据,可以修改该变量中的内容,之后调用UpdateVertexData方法,即可将网格数据传递给相应的Renderer中。所以要做的就是在合适的时机修改meshInfo中的数值,主要实现代码如下

    IEnumerator PlayPrinterEffect(TMPro.TMP_Text textComponent, float speed)
    {
        if (textComponent == null)
        {
            Debug.LogError("Input component is null!!!");
            yield break;
        }
        if (speed <= 0)
        {
            Debug.LogError("Input speed should be larger than 0!!!");
            speed = 1;
        }

        TMPro.TMP_TextInfo textInfo = textComponent.textInfo;

        // 开始播放打印机效果,首先清空所有文字网格
        for (int i = 0; i < textInfo.materialCount; ++i)
        {
            textInfo.meshInfo[i].Clear();
        }
        textComponent.UpdateVertexData(TMPro.TMP_VertexDataUpdateFlags.Vertices);

        float timer = 0;
        float duration = 1 / speed;
        for (int i = 0; i < textInfo.characterCount; ++i)
        {
            while (timer < duration)
            {
                yield return null;
                timer += Time.deltaTime;
            }

            timer -= duration;

            TMPro.TMP_CharacterInfo characterInfo = textInfo.characterInfo[i];

            int materialIndex = characterInfo.materialReferenceIndex;
            int verticeIndex = characterInfo.vertexIndex;
            if(characterInfo.elementType == TMPro.TMP_TextElementType.Sprite)
            {
                verticeIndex = characterInfo.spriteIndex;
            }
            if (characterInfo.isVisible)
            {
                textInfo.meshInfo[materialIndex].vertices[0 + verticeIndex] = characterInfo.vertex_BL.position;
                textInfo.meshInfo[materialIndex].vertices[1 + verticeIndex] = characterInfo.vertex_TL.position;
                textInfo.meshInfo[materialIndex].vertices[2 + verticeIndex] = characterInfo.vertex_TR.position;
                textInfo.meshInfo[materialIndex].vertices[3 + verticeIndex] = characterInfo.vertex_BR.position;
                textComponent.UpdateVertexData(TMPro.TMP_VertexDataUpdateFlags.Vertices);
            }

        }
    }

每次TextMesh属性改变的时候,都会对显示文字重新计算位置,每个字符的显示信息通过结构体TMP_CharacterInfo来保存。因此在清除所有网格数据后,定时从该结构体中获取网格数据重新构建网格,来得到每个字符依次显示的动画效果。

注意点

在改变text后立即调用上述方法无法正常播放动效,因为尚未执行文字网格的重新计算,获得的characterInfo仍然是改变text之前的数据。可通过调用TextMesh的ForceMeshUpdate方法强制进行网格更新,在进行动效的播放。

优势

1、不用重新生成多个子字符串,也不会触发TextMesh对文字网格重新计算,减少多个string的GC和网格计算的消耗
2、可以轻松处理富文本,因为富文本携带的信息已经被转化为characterInfo中的数据存储好了

缺陷

1、对于fontStyle设置了下划线,删除线等效果暂时无法在动效中复现(目前暂未找到下划线和删除线的网格生成方式)
2、GeometrySorting设置为Reverse时,动效显示将出问题。(GeometrySorting的值影响网格数据的顶点排序,Reverse为反向保存的,即顶点数组从最后一个字符开始保存顶点坐标。目前还未研究清楚这种方式有何作用,暂时没想到合适的处理方式)

参考资料

TextMeshPro源码。源码可在本地的unity的packages文件夹下找到,下面是我本地保存的位置
C:\Users\Administrator\AppData\Local\Unity\cache\packages\packages.unity.com\com.unity.textmeshpro@3.0.0-preview.1

标签:TMP,打印机,基于,网格,TextMeshPro,characterInfo,textInfo,meshInfo,verticeIndex
来源: https://blog.csdn.net/whr12/article/details/122831938

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有