Unity Version: 2020.3.13f1
TextMeshPro Version: 3.0.6
AssetBundle에 TMP_FontAsset을 포함하여 사용할 때 AssetBundle이 간헐적으로 수정되어 발생했던 문제.
최초 설치 시 필요한 리소스를 제외하고 나머지를 AssetBundle로 관리하여 업데이트를 진행할 수 있게 개발하던 중 AssetBundle이 업데이트가 필요한지, 동일한 파일인지 체크하기 위해 파일의 Hash 값을 비교하도록 구현하였는데 Font와 TMP_FontAsset를 포함한 AssetBundle이 간헐적으로 Hash 값이 변경되는 현상이 발생.
사용되는 Font의 개수가 여러 개여서 몇 MB 단위인 AssetBundle 이 간헐적으로 변경되어 업데이트되는 상황이 발생하면 안 되기 때문에 문제를 파악하기 위해 Font와 TMP_FontAsset 중 원인이 어느쪽인지 확인 진행.
확인 방법은 Font 와 TMP_FontAsset 을 별개의 AssetBundle로 만들고 테스트를 진행하여 Hash 값이 변하는 원인이 어느쪽인지 확인.
결과적으로 TMP_FontAsset이 원인이었으며 변경되는 내용은 TMP_FontAsset의 'Atlas Population Mode' 가 'Dynamic' 이어서 해당 TMP_FontAsset이 쓰이는 TMP 컴포넌트에서 텍스트가 사용될 때마다 TMP Atlas에 텍스트가 추가되어 변경되는 것이었다.
해결 방법은 개발 중 TMP_FontAsset의 Atlas가 동적으로 변경되어도 AssetBundle을 만들 때는 항상 Atlas가 동일한 상태가 되도록 만들면 해결될 문제였다.
아래의 스크립트를 이용해 Editor 상에서 Play & Edit 상태에 진입 시, AssetBundle & 프로그램 빌드 시 TMP_FontAsset 중 Dynamic 으로 설정되어 있는 것들의 Atlas를 초기화하도록 처리하여 항상 동일한 상태가 되도록 만들었다.
적용 시 주의점
1. 초기화 시 텍스트 Atlas 정보가 사라져서 씬의 TMP 들이 일시적으로 깨져보일 수 있음 ( TMP 오브젝트를 재활성화 하거나 씬에 다시 진입 시 해결 )
2. AssetBundle, 프로그램 빌드 등의 Editor 처리가 되면 Canvas의 Rebuild가 일어나면서 'OnRebuildRequested' 호출로 TMP 갱신이 됨. 이로 인한 처리를 갱신하기 위해 'PostProcess' , 'CompilationPipeline' Callback을 사용.
스크립트
#if UNITY_EDITOR
public class PostProcess
{
[PostProcessBuild(1)]
static void PostProcessBuild(BuildTarget buildTarget, string path)
{
EditorApplication.delayCall += () =>
{
EditorApplication.delayCall += () =>
{
EditorPlayModeState.ClearTMPFontAssetTable();
};
};
}
[PostProcessScene]
static void PostProcessScene()
{
if (!EditorApplication.isPlaying)
{
EditorApplication.delayCall += () =>
{
EditorPlayModeState.ClearTMPFontAssetTable();
};
}
}
}
[InitializeOnLoad]
[DefaultExecutionOrder(-100)]
public static class EditorPlayModeState
{
static EditorPlayModeState()
{
EditorApplication.playModeStateChanged += ClearTMPFontAssetTable;
CompilationPipeline.compilationStarted += (object) =>
{
ClearTMPFontAssetTable();
};
CompilationPipeline.compilationFinished += (object) =>
{
EditorApplication.delayCall += () =>
{
ClearTMPFontAssetTable();
};
};
}
private static void ClearTMPFontAssetTable(PlayModeStateChange playModeStateChange)
{
switch (playModeStateChange)
{
case PlayModeStateChange.EnteredPlayMode:
case PlayModeStateChange.EnteredEditMode:
string[] tmpFontAssetGUIDs = AssetDatabase.FindAssets("t:" + typeof(TMP_FontAsset));
foreach (string guid in tmpFontAssetGUIDs)
{
TMP_FontAsset fontAsset = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid), typeof(TMP_FontAsset)) as TMP_FontAsset;
if (fontAsset.atlasPopulationMode == AtlasPopulationMode.Dynamic)
{
fontAsset.ClearFontAssetData();
EditorUtility.SetDirty(fontAsset);
}
}
break;
}
if (playModeStateChange == PlayModeStateChange.EnteredEditMode)
{
EditorApplication.playModeStateChanged -= ClearTMPFontAssetTable;
}
AssetDatabase.Refresh();
}
public static void ClearTMPFontAssetTable()
{
ClearTMPFontAssetTable(PlayModeStateChange.EnteredEditMode);
}
}
#endif
'Unity Engine' 카테고리의 다른 글
Unity를 종료할 때 종료를 중지하고 확인창 띄우기 (3) | 2022.06.13 |
---|---|
Unity에서 Android Plugin을 활용해 APK 설치하기 (0) | 2022.02.28 |
ScriptableObject AssetBundle 참조 및 불러오기 실패 문제 (0) | 2021.03.17 |
UGUI Text Typing 스크립트 (Rich Text 중첩 지원) (0) | 2020.02.21 |
C# 람다(Lambda) : Button onClick을 반복문에서 동적 할당 시 지역 변수 참조 문제 (0) | 2019.10.10 |