<aside> 💡 TextMesy Pro를 사용할 경우, 언어별로 머티리얼들 구축해야 하기 때문에 이를 자동화시킴
</aside>
예시 이미지
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using TMPro;
/*
------------------------------------------------------------------------------------------------------------
작성 : (woody)
설명 : TMP 메인 폰트의 머티리얼 리스트를 기준으로, 각 언어별 TMP 폰트들을 대상으로 동일한 머티리얼 리스트를 생성합니다.
주의 : 메인 폰트가 변경될 경우, 'mainFontName' 변수를 변경해줘야 합니다.
주의 : 만약 "Font & Materials" 의 Root 경로가 변경될 경우, 'fontFolderPath' 변수를 변경해줘야 합니다.
주의 : TMP 폰트의 Atlas Population Mode -> static 이어야 정상 작동합니다. (Dinamic 불가)
------------------------------------------------------------------------------------------------------------
*/
public class TextMeshProMaterialGenerator : MonoBehaviour
{
[MenuItem("UI Utility/TextMeshPro Material Generator")]
static void TmpMatGen()
{
TMP_FontAsset[] fonts = Resources.LoadAll<TMP_FontAsset>("Font & Materials"); // "Font & Materials" 폴더내 전체 TMP 폰트
Material[] materials = Resources.LoadAll<Material>("Font & Materials"); // "Font & Materials" 폴더내 전체 머티리얼
Texture2D[] atlases = Resources.LoadAll<Texture2D>("Font & Materials"); // "Font & Materials" 폴더내 전체 아틀라스
List<Material> oneMobile_materials = new List<Material>(); // ONE Mobile 머티리얼 리스트
List<Material> core_materials = new List<Material>(); // 각 폰트의 코어 머티리얼 리스트
string mainFontName = "ONE Mobile POP SDF"; // ONE Mobile TMP 폰트명 : (**메인폰트 변경시 이 부분을 바꿔줌)
string fontFolderPath = "Assets/Asset Game/Graphics/Resources/Font & Materials/";
try
{
AssetDatabase.StartAssetEditing(); // 데이터베이스 편집 시작
foreach (Material material in materials)
{
// OneMobile 폰트의 머티리얼만 추출
if (material.name.Contains(mainFontName) && !material.name.EndsWith("Material"))
{
oneMobile_materials.Add(material);
Debug.Log("Main Material: " + material.name);
// 폰트 자체에 포함된 머티리얼은 패스
}
else if (material.name.EndsWith("Material"))
{
core_materials.Add(material);
Debug.Log("EndsWidth Material: " + material.name);
// ONE Mobile 관련 머티리얼이 아니라면 모두 제거
}
else
{
string path = AssetDatabase.GetAssetPath(material);
AssetDatabase.DeleteAsset(path);
Debug.Log("Deleted Material: " + material.name);
}
}
}
finally
{
AssetDatabase.StopAssetEditing(); // 데이터베이스 편집 종료
}
// 메인 폰트를 제외한 나머지 폰트들에 대해 적용
foreach (TMP_FontAsset font in fonts)
{
if (font.name != mainFontName)
{
foreach (Material oneMobile_material in oneMobile_materials)
{
Material clonedMaterial = new Material(oneMobile_material); // OneMobile 머티리얼 복제
clonedMaterial.name = oneMobile_material.name.Replace(mainFontName, font.name); // 복제한 머티리얼의 이름 변경: mainFontName -> font.name으로
foreach (Texture2D atlas in atlases) { // 아틀라스 교체 로직
foreach (Material core_material in core_materials)
{
// 폰트 머티리얼의 속성값을 복제된 머티리얼에 모두 적용
if (atlas.name.Contains(font.name) && core_material.name.Contains(font.name))
{
clonedMaterial.SetTexture("_MainTex", atlas);
clonedMaterial.SetFloat("_GradientScale", core_material.GetFloat("_GradientScale"));
clonedMaterial.SetFloat("_TextureWidth", core_material.GetFloat("_TextureWidth"));
clonedMaterial.SetFloat("_TextureHeight", core_material.GetFloat("_TextureHeight"));
clonedMaterial.SetFloat("_ScaleX", core_material.GetFloat("_ScaleX"));
clonedMaterial.SetFloat("_ScaleY", core_material.GetFloat("_ScaleY"));
clonedMaterial.SetFloat("_Sharpness", core_material.GetFloat("_Sharpness"));
clonedMaterial.SetFloat("_PerspectiveFilter", core_material.GetFloat("_PerspectiveFilter"));
clonedMaterial.SetFloat("_VertexOffsetX", core_material.GetFloat("_VertexOffsetX"));
clonedMaterial.SetFloat("_VertexOffsetY", core_material.GetFloat("_VertexOffsetY"));
clonedMaterial.SetVector("_ClipRect", core_material.GetVector("_ClipRect"));
clonedMaterial.SetFloat("_MaskSoftnessX", core_material.GetFloat("_MaskSoftnessX"));
clonedMaterial.SetFloat("_MaskSoftnessY", core_material.GetFloat("_MaskSoftnessY"));
clonedMaterial.SetFloat("_CullMode", core_material.GetFloat("_CullMode"));
break;
}
}
}
// 복제한 머티리얼을 프로젝트에 저장
string path = fontFolderPath + clonedMaterial.name + ".mat";
AssetDatabase.CreateAsset(clonedMaterial, path);
Debug.Log("Created Material: " + clonedMaterial.name + " for Font: " + font.name);
}
}
}
}
}