블로그 이미지
Every unexpected event is a path to learning for you.

카테고리

분류 전체보기 (2737)
Unity3D (817)
Programming (474)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (228)
협업 (58)
3DS Max (3)
Game (12)
Utility (136)
Etc (96)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (53)
Android (14)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday
04-26 06:22

Unity 2021.3.14f1

NGUI 2022.06.08

 

NGUI의 UILabel에 있는 Dynamic Font 글자 사용시 가끔 글자가 깨졌다가 돌아오는 현상이 있어서 수정함.

 

UILabel에서 글자가 깨지는 이유는 Dynamic Font Texture 사이즈가 256x256을 기본으로 쓰다가,

텍스쳐 사이즈가 모자라면 512x512로 늘리는데 사이즈가 변경되는 시점에 잠시 글자가 깨졌다가 보이게 된다고 한다.

그래서 사이즈 변경할 필요 없게 사용하는 폰트의 글자를 모두 로드해 버리기로 했다.

(아래 첨부된 txt 파일의 글자를 로드하니 2048x2048이 나온다. 처음부터 로드하고 써버리기로 함.)

 

아래 [참조]링크의 소스를 참조해서 정리해서 아래와 같이 FontManager에 적용했다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FontManagerSGT : MonoSingleton<FontManagerSGT>
{
    public delegate void OnChangeFontDelegate(eLanguage _eLanguage);
    public static event OnChangeFontDelegate OnChangeFontEvent;

    public NGUIFont m_nguiFontMain_Dynamic;
    public Font m_fontMain_GO;  // Global
    public Font m_fontMain_JA;  // Japan

    private eLanguage m_eLanguage_Prev = eLanguage.None;
    private eLanguage m_eLanguage_Current = eLanguage.None;

    private string m_strReferenceTxt_GO = null;
    private string m_strReferenceTxt_JA = null;
    private Texture m_textureFontMainTexture = null;
    private TextAsset m_textReferenceTxt = null;


    void Start()
    {
        SetDontDestroy();
    }

    void OnEnable()
    {

    }

    void OnDisable()
    {

    }

    public void SetFont(eLanguage _eLanguage)
    {
        // 폰트매니저용 언어로 변경(JA 외는 GO(글로벌)로 변환)
        m_eLanguage_Current = GetLanguageForFont(_eLanguage);

        ChangeFont(m_eLanguage_Current);
        m_eLanguage_Prev = m_eLanguage_Current;
    }

    public eLanguage GetLanguageForFont(eLanguage _eLanguage)
    {
        switch (_eLanguage)
        {
            // Japan
            case eLanguage.JA:
                return eLanguage.JA;

            // Global(Less)
            default:
                return eLanguage.GO;
        }
    }

    void ChangeFont(eLanguage _eLanguage)
    {
        Debug.LogFormat("[eLanguage] [Prev] {0} [Current] {1}", m_eLanguage_Prev, _eLanguage);

        // 같은 폰트면 Pass
        if (m_eLanguage_Prev == _eLanguage)
            return;

        Debug.Assert(null != m_nguiFontMain_Dynamic);
        Debug.Assert(null != m_fontMain_GO);
        Debug.Assert(null != m_fontMain_JA);

        switch (_eLanguage)
        {
            // Japan
            case eLanguage.JA:
                {
                    m_nguiFontMain_Dynamic.dynamicFont = m_fontMain_JA;
                    FixBrokenWord_JA();
                }
                break;

            // Global(Less)
            default:
                {
                    m_nguiFontMain_Dynamic.dynamicFont = m_fontMain_GO;
                    FixBrokenWord_GO();
                }
                break;
        }

        OnChangeFontEvent?.Invoke(_eLanguage);
    }

    void FixBrokenWord_JA()
    {
        if (m_strReferenceTxt_JA == null)
        {
            m_textReferenceTxt = Resources.Load("ReferenceTxt/ja") as TextAsset;
            if (null != m_textReferenceTxt)
            {
                m_strReferenceTxt_JA = m_textReferenceTxt.ToString();
            }
        }

        if (null != m_strReferenceTxt_JA)
        {
            m_fontMain_JA.RequestCharactersInTexture(m_strReferenceTxt_JA);
            m_textureFontMainTexture = m_fontMain_JA.material.mainTexture; // Font 내부 텍스쳐
            Debug.LogWarning(string.Format("[m_strReferenceTxt_JA] texture : {0}x{1}", m_textureFontMainTexture.width, m_textureFontMainTexture.height)); // 텍스쳐 크기
        }
        else
        {
            Debug.LogWarning("m_strReferenceTxt_JA is null");
        }
    }

    void FixBrokenWord_GO()
    {
        if (m_strReferenceTxt_GO == null)
        {
            m_textReferenceTxt = Resources.Load("ReferenceTxt/go") as TextAsset;
            if (null != m_textReferenceTxt)
            {
                m_strReferenceTxt_GO = m_textReferenceTxt.ToString();
            }
        }

        if (null != m_strReferenceTxt_GO)
        {
            m_fontMain_GO.RequestCharactersInTexture(m_strReferenceTxt_GO);
            m_textureFontMainTexture = m_fontMain_GO.material.mainTexture; // Font 내부 텍스쳐
            Debug.LogWarning(string.Format("[m_fontMain_GO] texture : {0}x{1}", m_textureFontMainTexture.width, m_textureFontMainTexture.height)); // 텍스쳐 크기
        }
        else
        {
            Debug.LogWarning("m_strReferenceTxt_GO is null");
        }
    }
}

 

GO(Global)는 JA(일본어)를 제외한 모든 폰트를 합친 글로벌용 폰트이다.

일본어 한자가 중국어(번체)(대만)와 ASCII 코드가 겹치는 문제로 폰트 자체를 분리했다.

 

소스상에서 Resources.Load 하고 있는 go.txt와 ja.txt는 아래 올려둔다.

폰트를 2개로 분리해놔서 해당 폰트 사용 시, 맞는 txt를 로드하기 위해 Load 파일도 2개이다.

 

첨부된 파일은 폰트 병합 할 때 쓰는 참조용 데이터이기 때문에 모두 로드하면 폰트에 있는 모든 글자를 쓰게 되므로 이걸 로드해서 쓰게되면 더이상 텍스쳐가 커질일은 없을거라 예상된다.

 

 

[폰트 텍스쳐 확장을 위한 참조용 txt 파일]

go.txt
0.03MB
ja.txt
0.01MB

 

 

[참조] https://blueasa.tistory.com/2688

 

[펌] Unity 동적 글꼴 텍스트 깨짐 솔루션(Dynamic Font Broken)

Unity의 동적 글꼴을 사용하여 텍스트를 그릴 때 두 개의 UI 인터페이스가 열리면 그 뒤에 있는 텍스트가 깨집니다(완전히 엉망이 됨). 내가 사용하는 UI 플러그인은 Daikon Forge입니다. 라벨 업데이

blueasa.tistory.com

[참조2] https://blueasa.tistory.com/2664

 

[펌] NGUI - Dynamic Font 글자 깨짐? 사라짐? 현상

게임도중 핸드폰에서 Home 키를 눌러 배경화면으로 이동 후 Server와 끊기기를 기다리고 다시 Server와 리커넥팅 되도록 해서 팝업 떴는데.. Font가 깨졌다. 뭐지.. .... UILabel 에서 DynamicFont 가 이상한

blueasa.tistory.com

 

반응형
Posted by blueasa
, |

프로젝트는 NGUI를 사용하며 최근에 로딩 인터페이스의 프롬프트 텍스트가 깨지는 버그가 발생했습니다.


다음 기사를 참조했습니다.

http://blog.csdn.net/langresser_king/article/details/22095235

이 문제가 발생하는 이유를 먼저 이해합시다.



이해해야 할 것은 NGUI의 UILabel은 Unity에서 제공하는 글꼴을 글꼴의 입력으로 사용한다는 것입니다.

Unity는 글꼴 생성에 대해 매우 경제적이며 이는 정상적인 엔진이며 엔진은 이와 같아야 합니다.



(1) Loading 인터페이스의 UILabel에 세 단어 로딩을 표시하면 Unity가 이 세 단어의 텍스처를 생성하고 128x128의 FontTexture가 충분해야 합니다. 그런 다음 UILabel은 글꼴에 따라 각 단어의 그래픽을 가져옵니다.



(2) 그런 다음 다른 인터페이스를 열고 이 인터페이스에 많은 문자가 있을 때 128x128 FontTexture가 충분하지 않으면 Unity는 새 FontTexture를 생성하고 콜백을 발생시킵니다.

(3) 그런 다음 NGUI의 UILabel에서 이 콜백을 처리하고 모든 UILabel을 트래버스하고 UILabel의 모든 내용을 Font에 푸시하여 FontTexture에 대한 새 텍스트 그래픽을 생성합니다.

static BetterList<UILabel> mList = new BetterList<UILabel>();
protected override void OnInit ()
{
    base.OnInit();
    mList.Add(this);
    SetActiveFont(trueTypeFont);
}

 

//每次新建一个UILabel,都会读取UILabel上面的内容,在FontTexture上添加一块字体纹理。当FontTexture超过了原来的大小时,就会抛弃原来的FontTexture,用一个新的FontTexture,然后遍历所有的UILabel,往新的FontTexture上添加字体纹理。
static void OnFontTextureChanged ()
{
    for (int i = 0; i < mList.size; ++i)
    {
        UILabel lbl = mList[i];
 
        if (lbl != null)
        {
            Font fnt = lbl.trueTypeFont;
 
            if (fnt != null)
            {
                fnt.RequestCharactersInTexture(lbl.mText, lbl.mPrintedSize, lbl.mFontStyle);
            }
        }
    }
 
    //这段代码让UILabel重新读取UV 重新渲染,下一帧文字就是正常的了
    for (int i = 0; i < mList.size; ++i)
    {
        UILabel lbl = mList[i];
 
        if (lbl != null)
        {
            Font fnt = lbl.trueTypeFont;
 
            if (fnt != null)
            {
                lbl.RemoveFromPanel();
                lbl.CreatePanel();
            }
        }
    }
}


(4) 마지막으로 UILabel이 다시 렌더링됩니다.

깨진 글꼴은 (2)에서 나타납니다 UILabel이 이미 렌더링 중일 때 Unity는 새 FontTexture를 생성하므로 현재 프레임에 표시되는 그래픽에 문제가 있을 것입니다.

해결책은 게임의 모든 캐릭터를 포함하여 처음에 글꼴에 충분한 텍스트를 제공하여 향후 게임을 푸시할 필요가 없고 FontTexture를 영원히 사용할 수 있도록 하는 것입니다.

UILabel에 기능 추가

    private static void DynamicFontBrokenFix(Font fnt)
    {
        if(fnt==null)
        {
            return;
        }
 
        if(fnt.characterInfo.Length<500)
        {
            string tmpStr = Resources.Load<TextAsset>("DynamicFontBrokenFix").text;
            fnt.RequestCharactersInTexture(tmpStr, 32);
        }
    }


그런 다음 글꼴을 설정할 때 호출

protected void SetActiveFont (Font fnt)
{
    if (mActiveTTF != fnt)
    {
        if (mActiveTTF != null)
        {
            int usage;
 
            if (mFontUsage.TryGetValue(mActiveTTF, out usage))
            {
                usage = Mathf.Max(0, --usage);
 
                if (usage == 0)
                {
                    mActiveTTF.textureRebuildCallback = null;
                    mFontUsage.Remove(mActiveTTF);
                }
                else
                {
                    mFontUsage[mActiveTTF] = usage;
                }
            }
			else
            {
            	mActiveTTF.textureRebuildCallback = null;
            }
		}
 
		mActiveTTF = fnt;
        DynamicFontBrokenFix(mActiveTTF);
 
		if (mActiveTTF != null)
		{
			int usage = 0;
 
			// Font hasn't been used yet? Register a change delegate callback
			if (!mFontUsage.TryGetValue(mActiveTTF, out usage))
				mActiveTTF.textureRebuildCallback = OnFontTextureChanged;
#if UNITY_FLASH
			mFontUsage[mActiveTTF] = usage + 1;
#else
			mFontUsage[mActiveTTF] = ++usage;
#endif
		}
	}
}


DynamicFontBrokenFix는 게임의 모든 문자를 저장하는 텍스트입니다.
http://blog.csdn.net/huutu http://www.liveslives.com에서 전송됨

FontTexture가 여러 번 생성되는 것을 방지하기 위한 최적화 지점이기도 합니다.

 

[출처] https://blog.csdn.net/huutu/article/details/61923191

 

NGUI UILabel 文字破碎__Captain的博客-CSDN博客

项目使用NGUI,最近碰到 Loading界面的提示文字破碎的Bug。 参考了以下文章 http://blog.csdn.net/langresser_king/article/details/22095235 转自http://blog.csdn.net/huutu http://www.liveslives.com 下面先来了解一下为什么会

blog.csdn.net

 

반응형
Posted by blueasa
, |

Unity의 동적 글꼴을 사용하여 텍스트를 그릴 때 두 개의 UI 인터페이스가 열리면 그 뒤에 있는 텍스트가 깨집니다(완전히 엉망이 됨). 내가 사용하는 UI 플러그인은 Daikon Forge입니다. 라벨 업데이트 메커니즘으로 인해 최종 성능이 깨진 텍스트 표시보다 나쁠 수 있습니다. 텍스트 컨트롤이 계속 새로 고쳐지고 열릴 새 인터페이스가 표시되지 않을 가능성이 큽니다.

         이것은 근본적으로 Unity의 동적 글꼴 구현이 충분히 똑똑하지 않다는 사실 때문입니다. 이론적으로 NGUI에도 이러한 문제가 있습니다. 동적 글꼴을 사용하고 많은 텍스트를 렌더링하는 한.

         NGUI와 Daikon Forge는 동적 글꼴인 텍스트를 그릴 때 내부적으로 Unity의 글꼴을 사용합니다. RequestCharactersInTexture 함수를 사용하여 글꼴에 텍스트 정보 업데이트를 요청한 다음 GetCharacterInfo를 사용하여 렌더링할 텍스트 정보를 가져옵니다. GetCharacterInfo를 호출할 때 RequestCharactersInTexture를 통해 모든 텍스트가 요청되었는지 확인하십시오.

         요청 시점에 Font 내부에 유지되는 텍스처가 충분하지 않으면 textureRebuildCallback의 콜백이 트리거되어 Font를 사용하는 외부 객체에 내부 텍스처가 업데이트되었고 외부 객체를 새로 고쳐야 함을 알립니다.

        Unity 글꼴의 기본 텍스처 크기는 256x256이며 순수 영어 글꼴의 경우에는 충분합니다. 하지만 한자나 일본어 같은 동양글꼴은 전혀 부족하다. 앞에서 언급한 두 플러그인은 텍스트를 그릴 때 단락을 요청하는 데 사용되며, Unity의 새로 고침 콜백이 트리거되면 모든 텍스트 컨트롤이 새로 고쳐집니다. 이렇게 하면 글꼴이 쉽게 깨질 수 있습니다. 정상적인 상황에서는 한 번에 많은 텍스트를 요청하지 않으며 사용된 텍스처는 256x256을 초과하지 않으며 Unity는 텍스처 크기를 자동으로 확장하지 않습니다. 그리고 콜백 함수에서 글꼴을 다시 새로 고칠 때 텍스처가 충분하지 않아 다른 새로 고침 콜백을 트리거하기 쉽습니다. 따라서 중단되고 지속적으로 새로 고쳐지는 상황을 표시하기 위해 텍스트 컨트롤이 전송됩니다.

        문제의 원인을 알면 해결책이 나옵니다. 충분한 텍스트를 요청하는 한 Unity는 내부적으로 텍스처 크기를 자동으로 확장하므로 지속적인 새로 고침 상황을 피할 수 있습니다. 한자 2000자 텍스트를 준비했는데, 텍스트 정보 요청 후 내부 텍스쳐를 기본적으로 게임에 충분한 크기인 1024x1024 크기로 확장했습니다. 어느 날 이것이 충분하지 않다고 생각되면 한자를 더 준비하고 질감을 2048x1024로 확장하십시오.

 

static string chineseTxt = null;
public UnityEngine.Font baseFont;

public void FixBrokenWord()
{
    if (chineseTxt == null) 
    {
        TextAsset txt = Resources.Load("config/chinese") as TextAsset;
        chineseTxt = txt.ToString();
    }

    baseFont.RequestCharactersInTexture(chineseTxt);
    Texture texture = baseFont.material.mainTexture; // Font的内部纹理
    Debug.Log(string.Format("texture:{0} {1}", texture.width, texture.height)); // 纹理大小
}


그 중 baseFont는 NGUI나 Daikon Forge의 텍스트 렌더링 컨트롤에 사용되는 UnityEngine.Font입니다.baseFont를 초기화할 때 FixBrokenWord 함수를 호출합니다(한 번만 호출하면 됨). 일반적으로 사용되는 한자 목록이 포함된 텍스트를 읽은 다음(인터넷에서 일반적으로 사용되는 한자 목록에서 복사하기만 하면 됨) 이 텍스트의 정보를 요청하면 내부 텍스처가 자동으로 확장됩니다.

 

[출처] https://blog.csdn.net/e295166319/article/details/54861275

 

Unity动态字体文字破碎的解决方法(Dynamic Font Broken)_起个名字真的好难啊的博客-CSDN博客

 使用Unity的动态字体绘制文字的时候,打开两个ui界面的时候,后面的文字会显示破碎(完全乱掉)。我使用的ui插件是Daikon Forge,由于其label的更新机制问题,最终表现的结果可能比一个文本显

blog.csdn.net

 

반응형
Posted by blueasa
, |