当前位置:   article > 正文

【Unity编辑器扩展】艺术字/自定义图片字体/TextMeshPro艺术字生成工具_unity 艺术字

unity 艺术字

自动化游戏框架工具集——艺术字生成工具 支持TextMeshPro/uGUI Text

 

艺术字在游戏中很常用,由于普通字体样式过于平淡,制作花里胡哨的文字图片作为游戏字体使用,这就是艺术字。

不依赖第三方工具,仅使用Unity自带的Custom Font + 一张艺术字图集就能实现这个功能,但是为了便于使用,还需要依赖自动化工具,自动化把字符映射到图片纹理坐标,一键生成字体文件。

当然,工具也必须支持生成TextMeshPro的TM_FontAsset;

工具使用效果:

 字符对齐图片:

 艺术字使用效果:

Unity自定义字体参数面板如下:

 其中Character Rects数组是每个字符所在贴图的uv坐标系下的映射Rect:

Index:字符的Ascii码偏移值;字符真实ASCII码 = Ascii Start Offset + Index;这里建议把ASCII码起始值(Ascii Start Offset)设为0,把Index直接设置为字符的ASCII码。

Vert:字符的宽高信息, Y为高度的一半是为了垂直方向居中;

工具功能设计:

0. 首先,制作字符集图片,在Unity中用Sprite Editor进行自动Sprite碎图分割;

1. 拖拽添加字符图集;

2. 设置字符文件或直接在输入框输入字符,两处字符将自动合并去重;

3. 支持设置字体大小;自定义字体无法通过Text组件动态修改字体大小,因此需要为不同字号生成单独的字体文件,但材质和贴图共用,只消耗一个DC;

4.支持字符与图集对照预览;

5. 点击生成,一键创建字体文件和对应材质;

代码实现:

代码实现非常简单,主要就是读取Sprite中的子图Rect信息,然后转换到字体所需的UV坐标系Rect等;

使用Unity 2022新版Sprite编辑器API读取碎图信息:

  1. var texFact = new SpriteDataProviderFactories();
  2. texFact.Init();
  3. var texDataProvider = texFact.GetSpriteEditorDataProviderFromObject(texture2d);
  4. texDataProvider.InitSpriteEditorDataProvider();
  5. var spriteRects = texDataProvider.GetSpriteRects();

生成字体文件的Character Rects:

  1. private bool ParseCharsInfo(char[] chars, out CharacterInfo[] charInfoArr, out Texture2D charsTexture)
  2. {
  3. charInfoArr = null;
  4. charsTexture = null;
  5. if (chars == null || chars.Length < 1)
  6. {
  7. return false;
  8. }
  9. charsTexture = OwnerEditor.SelectObjectList[0] as Texture2D;
  10. var texSize = new Vector2Int(charsTexture.width, charsTexture.height);
  11. var texFact = new SpriteDataProviderFactories();
  12. texFact.Init();
  13. var texDataProvider = texFact.GetSpriteEditorDataProviderFromObject(charsTexture);
  14. texDataProvider.InitSpriteEditorDataProvider();
  15. var spRects = texDataProvider.GetSpriteRects();
  16. int count = Mathf.Min(chars.Length, spRects.Length);
  17. charInfoArr = new CharacterInfo[count];
  18. for (int i = 0; i < count; i++)
  19. {
  20. var spRect = spRects[i].rect;
  21. var uvMin = spRect.min / texSize;
  22. var uvMax = spRect.max / texSize;
  23. float fontHeight = m_FontSize;
  24. float fontScale = m_FontSize / spRect.height;
  25. charInfoArr[i] = new CharacterInfo
  26. {
  27. index = chars[i],
  28. uvBottomLeft = uvMin,
  29. uvBottomRight = new Vector2(uvMax.x, uvMin.y),
  30. uvTopLeft = new Vector2(uvMin.x, uvMax.y),
  31. uvTopRight = uvMax,
  32. minX = 0,
  33. minY = -(int)(fontHeight * 0.5f),//居中偏移量
  34. advance = (int)(spRect.width * fontScale),
  35. glyphWidth = (int)(spRect.width * fontScale),
  36. glyphHeight = (int)fontHeight,
  37. };
  38. }
  39. return true;
  40. }

生成字体文件:

  1. string outputDir = EditorUtility.SaveFolderPanel("保存到", Application.dataPath, null);
  2. if (!string.IsNullOrWhiteSpace(outputDir) && Directory.Exists(outputDir))
  3. {
  4. outputDir = Path.Combine("Assets", Path.GetRelativePath(Application.dataPath, outputDir));
  5. string outputFont = Path.Combine(outputDir, $"{charsTexture.name}_{m_FontSize}.fontsettings");
  6. Font newFont;
  7. if (!File.Exists(outputFont))
  8. {
  9. newFont = new Font(charsTexture.name);
  10. AssetDatabase.CreateAsset(newFont, outputFont);
  11. }
  12. newFont = AssetDatabase.LoadAssetAtPath<Font>(outputFont);
  13. string outputFontMat = Path.Combine(outputDir, $"{charsTexture.name}.mat");
  14. if (!File.Exists(outputFontMat))
  15. {
  16. var tempFontMat = new Material(Shader.Find("UI/Default Font"));
  17. AssetDatabase.CreateAsset(tempFontMat, outputFontMat);
  18. }
  19. var fontMat = AssetDatabase.LoadAssetAtPath<Material>(outputFontMat);
  20. fontMat.shader = Shader.Find("UI/Default Font");
  21. fontMat.SetTexture("_MainTex", charsTexture);
  22. EditorUtility.SetDirty(fontMat);
  23. AssetDatabase.SaveAssetIfDirty(fontMat);
  24. newFont.material = fontMat;
  25. newFont.characterInfo = charInfoArr;
  26. EditorUtility.SetDirty(newFont);
  27. AssetDatabase.SaveAssetIfDirty(newFont);
  28. Selection.activeInstanceID = newFont.GetInstanceID();
  29. }

生成TextMeshPro艺术字:

 上述步骤中已经将文字图片图集解析为CharacterInfo,那么我们只需要稍加转换,把CharacterInfo转换为TextMeshPro的Glyph, 也就是字符与图集的uv映射关系:

  1. private UnityEngine.TextCore.Glyph CharacterInfo2Glyph(int i, CharacterInfo charInfo, int atlasWidth, int atlasHeight)
  2. {
  3. var glyph = new UnityEngine.TextCore.Glyph((uint)i, new UnityEngine.TextCore.GlyphMetrics(charInfo.glyphWidth, charInfo.glyphHeight, 0, charInfo.glyphHeight, charInfo.glyphWidth),
  4. new UnityEngine.TextCore.GlyphRect((int)(charInfo.uvBottomLeft.x * atlasWidth), (int)(charInfo.uvBottomLeft.y * atlasHeight), charInfo.glyphWidth, charInfo.glyphHeight));
  5. return glyph;
  6. }

然后动态创建一个TM_FontAsset并自动映射字符和图像:

  1. private void GenerateTextMeshProFont(CharacterInfo[] charInfoArr, Texture2D charsTexture, string outputFont)
  2. {
  3. var maxHeight = charInfoArr[0].size;
  4. var fontAsset = TMP_FontAsset.CreateFontAsset(m_TMPBaseFont, maxHeight, 0, UnityEngine.TextCore.LowLevel.GlyphRenderMode.SMOOTH, charsTexture.width, charsTexture.height, AtlasPopulationMode.Static, false);
  5. AssetDatabase.CreateAsset(fontAsset, outputFont);
  6. var tmpMat = new Material(Shader.Find("TextMeshPro/Bitmap Custom Atlas"));
  7. var charsAtlas = UnityEngine.Object.Instantiate<Texture2D>(charsTexture);
  8. charsAtlas.alphaIsTransparency = true;
  9. var fileName = Path.GetFileNameWithoutExtension(outputFont);
  10. tmpMat.name = Utility.Text.Format("{0}_mat", fileName);
  11. tmpMat.mainTexture = charsAtlas;
  12. charsAtlas.name = Utility.Text.Format("{0}_tex", fileName);
  13. fontAsset.atlas = charsAtlas;
  14. fontAsset.material = tmpMat;
  15. fontAsset.atlasTextures = new Texture2D[] { charsAtlas };
  16. fontAsset.characterTable.Clear();
  17. fontAsset.glyphTable.Clear();
  18. for (int i = 0; i < charInfoArr.Length; i++)
  19. {
  20. var charInfo = charInfoArr[i];
  21. var glyph = CharacterInfo2Glyph(i, charInfo, charsAtlas.width, charsAtlas.height);
  22. fontAsset.characterTable.Add(new TMP_Character((uint)charInfo.index, glyph));
  23. fontAsset.glyphTable.Add(glyph);
  24. }
  25. var faceInfo = fontAsset.faceInfo;
  26. faceInfo.familyName = fileName;
  27. faceInfo.lineHeight = faceInfo.ascentLine = maxHeight;
  28. faceInfo.baseline = faceInfo.descentLine = 0;
  29. fontAsset.faceInfo = faceInfo;
  30. var fontSettings = fontAsset.creationSettings;
  31. fontSettings.referencedFontAssetGUID = null;
  32. fontSettings.sourceFontFileGUID = null;
  33. fontSettings.sourceFontFileName = null;
  34. AssetDatabase.AddObjectToAsset(charsAtlas, fontAsset);
  35. AssetDatabase.AddObjectToAsset(tmpMat, fontAsset);
  36. EditorUtility.SetDirty(fontAsset);
  37. AssetDatabase.SaveAssetIfDirty(fontAsset);
  38. Selection.activeInstanceID = fontAsset.GetInstanceID();
  39. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/922903
推荐阅读
相关标签
  

闽ICP备14008679号