zoukankan      html  css  js  c++  java
  • 关于 UGUI 字体花屏或乱码。

      我们项目从某个时候开始ui突然开始出现字体花屏现象(unity 开发版本:5.3.6p6),而且很难必现却又时有发生,确实查找和解决起来并不太容易。

      关于这个问题,uwa官方给出了解释,http://blog.uwa4d.com/archives/techsharing_35.html, http://blog.uwa4d.com/search/%E5%AD%97%E4%BD%93/。可用的方案就是一开始把字体扩容到足够大,但对于常用汉字就有3000多个,再加上不同的大小和样式,不同的字体,内存占用光想一想就很可观,所以将此当做最保底的方案。Unity 官方应该是解决过这个问题,但是没有彻底。但是我更加高度怀疑的是:FontTexture 本身的生成和对应的 UV 信息并没有问题,而是字体使用的 UV 有问题(没有更新),uwa 提供的方案可能是针对的早期问题,也许现在问题是新引起的。

      后来又看到雨松MOMO的博客也有提到并给出了解决方案:http://www.xuanyusong.com/archives/4259,这个方法很好,在 FontTexture 重建时在其后的 LateUpdate 中刷新所有的 Text,这个方案也是我希望的方式,不会产生过多的浪费字体纹理。不过 GameObject.FindObjectsOfType<Text>() 这个调用我觉得对于 Text 过多的场景恐怕效率堪忧,翻阅了下 UI 的源码,发现其中有个类 UnityEngine.UI.FontUpdateTracker 就是专门用来更新 Text 相关字体信息的,但是接口都不是 public,但是可以反射调用就好,所以可以用此对 雨松MONO 的方案优化一下:

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    
    public class DynamicFontTextureRebuildTracker : MonoBehaviour
    {
        private class FontUpdateNode
        {
            private bool m_FontTextureRebuilt = false;
            private Font m_FontRebuilt = null;
    
            public FontUpdateNode(Font font)
            {
                m_FontRebuilt = font;
                Validate();
            }
    
            public void Validate()
            {
                if (null == m_FontRebuilt)
                {
                    m_FontTextureRebuilt = false;
    
                    Debug.LogWarning("You need a actual font to validate!");
                    return;
                }
    
                m_FontTextureRebuilt = true;
            }
    
            public void Invalidate()
            {
                m_FontTextureRebuilt = false;
            }
    
            public bool NeedUpdate
            {
                get { return m_FontTextureRebuilt && (null != m_FontRebuilt); }
            }
    
            public Font font
            {
                get { return m_FontRebuilt; }
            }
        }
    
        private System.Reflection.MethodInfo m_RebuildForFont = null;
        private List<FontUpdateNode> m_FontUpdateList = new List<FontUpdateNode>();
    
        private static DynamicFontTextureRebuildTracker m_Instance = null;
    
        void Awake()
        {
            if (null != m_Instance)
            {
                Debug.LogError("There is only one DynamicFontTextureRebuildTracker instance allowed!");
                Destroy(gameObject);
                return;
            }
    
            m_Instance = this;
        }
    
        // Use this for initialization
        void Start() 
        {
            Font.textureRebuilt += OnFontTextureRebuilt;
    
            System.Type fontUpdateTrackerType = typeof(UnityEngine.UI.FontUpdateTracker);
            m_RebuildForFont = fontUpdateTrackerType.GetMethod("RebuildForFont", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
            Debug.Log("Get RebuildForFont method is: " + m_RebuildForFont);
        }
        
        // Update is called once per frame
        void LateUpdate() 
        {
            if (null == m_RebuildForFont)
            {
                return;
            }
    
            for (int i = 0; i < m_FontUpdateList.Count; i++)
            {
                FontUpdateNode node = m_FontUpdateList[i];
                if (node.NeedUpdate)
                {
                    Font font = node.font;
                    m_RebuildForFont.Invoke(null, new object[] { font });
    
                    // Log rebuild.
                    Texture fontTexture = font.material.mainTexture;
                    Debug.Log(string.Format("Texture of dynamic font "{0}" is enlarged to {1}x{2}.", font.name, fontTexture.width, fontTexture.height));
    
                    node.Invalidate();
                }
            }
        }
    
        void OnDestroy()
        {
            Font.textureRebuilt -= OnFontTextureRebuilt;
        }
    
        private void OnFontTextureRebuilt(Font font)
        {
            bool findThisFont = false;
            for (int i = 0; i < m_FontUpdateList.Count; i++)
            {
                FontUpdateNode node = m_FontUpdateList[i];
                if (node.font == font)
                {
                    node.Validate();
                    findThisFont = true;
                    break;
                }
            }
    
            if (!findThisFont)
            {
                m_FontUpdateList.Add(new FontUpdateNode(font));
            }
        }
    
        //void OnGUI()
        //{
        //    if (GUI.Button(new Rect(30.0f, 50.0f, 200.0f, 50.0f), "Force Update Text"))
        //    {
        //        for (int i = 0; i < m_FontUpdateList.Count; i++)
        //        {
        //            Font font = m_FontUpdateList[i].font;
        //            m_RebuildForFont.Invoke(null, new object[] { font });
        //            Debug.Log(string.Format("Force rebuild text for font "{0}".", font.name));
        //        }
    
        //        Debug.Log("Force rebuild all text ok!");
        //    }
        //}
    }

      为了验证确实是 FontTexture 是 ok 的而乱码只是 Text 的 uv 不正确,可以将 OnGUI 的代码放开,将 LateUpdate 的代码注释,然后运行游戏,在出现字体乱码后点击 “Force Update Text” 按钮,如果文字乱码立即消失,就证实了上面的猜测仅仅是 Text UV 没有更新而已。经过在手机上实际测试出现乱码后立即点击按钮,文字均显示正常,也证实了这个问题。

      使用时在初始场景中新建一个空 GameObject,然后 DontDestroyOnLoad,再挂上 DynamicFontTextureRebuildTracker 脚本即可。后来游戏中(ios, android)就再也没有出现过字体花屏乱码等现象。

      最后附上该脚本下载地址:http://pan.baidu.com/s/1c1LPoJY


    2017-07-01 更新:

      最近我们项目的 Unity 版本一直稳定在 5.3.7p4,但是极少数情况下(甚至是某一小段时间内)依然偶尔出现了字体花屏,但是最近又没有了,不知道原因,有可能其它系统引起了问题。


    2017-07-06 更新:

      最近测试同学报告说,最近偶尔依然出现的字体花屏不像以前一进场景就花掉,而是出现了角色单位后就变化了,进一步缩小了范围,先记录下,后面有时间研究下。

  • 相关阅读:
    阿里云CDN缓存加速学习总结
    阿里云SLB学习总结
    zabbix3.2安装
    drf中的增删改查接口
    drf中二次封装Response
    drf常用模块
    Django—auth模块
    csrf跨站请求伪造与CBV装饰器
    Django—cookie与session
    Django—中间件(待更新)
  • 原文地址:https://www.cnblogs.com/yaukey/p/unity_ugui_font_texture_uv_wrong.html
Copyright © 2011-2022 走看看