欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 文化 > 【Unity编辑器扩展】SpriteAltas资源一键转换为TMP_SpriteAsset或Sprite图集

【Unity编辑器扩展】SpriteAltas资源一键转换为TMP_SpriteAsset或Sprite图集

2024/10/24 11:18:56 来源:https://blog.csdn.net/final5788/article/details/141818775  浏览:    关键词:【Unity编辑器扩展】SpriteAltas资源一键转换为TMP_SpriteAsset或Sprite图集

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

 博文工具源码见GF_X自动化游戏开发框架:GitHub - sunsvip/GF_X: Unity GameFramework + HybridCLR,Includes several automated editor extension tools, an efficient automated development workflow.(大量自动化编辑器扩展工具, 高效的自动化开发工作流)

 前面博文中介绍过把Sprite图集转换为艺术字的工具,但是通过Unity的Sprite Editor自动划分子Sprite的Rect会有偏差,就需要手动调整Rect,用户体验很差。如果能支持SpriteAtlas,就可以直接把艺术字碎图打成SpriteAtlas,这样就能更好的划分Sprite Rect。

而Text Mesh Pro创建TMP_SpriteAsset资源也很鸡肋(如下图),自己的SpriteAtlas图集功能不用,非要依赖第三方Texture Packer图集。

为了解决上述痛点,需要实现两个编辑器扩展功能:

1. 把SpriteAtlas资源直接转换为TMP_SpriteAsset;

2. 把SpriteAtlas资源转换为普通的Sprite图集(Sprite Multiple);

功能实现:

首先通过右键Create->2D->Sprite Atlas创建一个SpriteAtlas资源,然后把碎图拖到SpriteAtlas中:

一,SpriteAtlas转换为TMP_SpriteAsset:

 首先看看TMP_SpriteAsset需要哪些信息:

①. 需要一张图集Texture2D和一个材质;

②. Sprite Character Table,也就是图片映射的字符Unicode、name。TextMeshPro输入字符的Unicode在Sprite Character Table中存在时就会显示对应的Sprite。 而name的作用就是可以通过服富文本标签显示name对应的Sprite:<sprite="sprite_name">

③. Sprite Glyph Table, 也就是Sprite在图集Texture2D中的像素rect区域。

1. SpriteAtlas资源转Texture2D: 

首先要把SpriteAtlas资源生成为一张贴图给TMP_SpriteAsset的材质使用,从SpriteAtlas的Inspector面板可以看到Pack Preview按钮就可以生成图集贴图,所以Unity内部应该是提供了现成接口的。

 通过Unity开源代码就可以快速查到UnityEditor.U2D.SpriteAtlasExtensions有个非公开的静态扩展方法GetPreviewTextures,返回值为Texture2D[],即SpriteAltas每个子图集作为一张Texture。

用法:

var getPreviewFunc = typeof(UnityEditor.U2D.SpriteAtlasExtensions).GetMethod("GetPreviewTextures", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
Texture2D[] previews = getPreviewFunc.Invoke(null, new object[] { atlas }) as Texture2D[];

 但是这里有个问题,通过SpriteAtlasExtensions.GetPreviewTextures拿到的都是压缩过的贴图,并且贴图数据是在一片不可读内存上,不能直接使用EncodeToPNG解码保存为png文件。所以我们需要通过Graphics接口把贴图复制出来:

var atlasTex2d = previews[0];
RenderTexture rt = new RenderTexture(atlasTex2d.width, atlasTex2d.height, 0);
Graphics.Blit(atlasTex2d, rt);
RenderTexture.active = rt;Texture2D readableAtlasTex = new Texture2D(rt.width, rt.height);
readableAtlasTex.alphaIsTransparency = true;
readableAtlasTex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
readableAtlasTex.Apply();
RenderTexture.active = null;

2. 解析SpriteAltas的碎图并映射到TMP_SpriteAsset的spriteGlyphTable:

Sprite[] sprites = new Sprite[atlas.spriteCount];
atlas.GetSprites(sprites);
TMP_SpriteAsset spriteAsset;
if (File.Exists(tmpSpriteAssetName))
{spriteAsset = AssetDatabase.LoadAssetAtPath<TMP_SpriteAsset>(tmpSpriteAssetName);
}
else
{spriteAsset = ScriptableObject.CreateInstance<TMP_SpriteAsset>();AssetDatabase.CreateAsset(spriteAsset, tmpSpriteAssetName);
}
spriteAsset.spriteSheet = AssetDatabase.LoadAssetAtPath<Texture2D>(textureFileName);
spriteAsset.spriteCharacterTable.Clear();
spriteAsset.spriteGlyphTable.Clear();
if (spriteAsset.material == null)
{Material material = new Material(Shader.Find("TextMeshPro/Sprite"));material.mainTexture = spriteAsset.spriteSheet;AssetDatabase.AddObjectToAsset(material, spriteAsset);AssetDatabase.SaveAssetIfDirty(spriteAsset);spriteAsset.material = material;
}for (int i = 0; i < sprites.Length; i++)
{var sp = sprites[i];var spUVRect = sp.textureRect;var glyph = new TMP_SpriteGlyph((uint)i, new UnityEngine.TextCore.GlyphMetrics(spUVRect.width, spUVRect.height, 0, spUVRect.height, spUVRect.width),new UnityEngine.TextCore.GlyphRect(spUVRect), 1, 0);spriteAsset.spriteGlyphTable.Add(glyph);var spChar = new TMP_SpriteCharacter(0xFFFE, glyph);spChar.name = sp.name;spriteAsset.spriteCharacterTable.Add(spChar);
}
AssetDatabase.SaveAssetIfDirty(spriteAsset);

 SpriteAltas一键转换为TMP_SpriteAsset功能预览:

二, SpriteAltas转换为Sprite Multiple:

也就是通过程序一键把SpriteAltas转换为图集贴图,并自动分割好碎图区域,如下图:

 而我们的艺术字生成工具正好依赖这种分割好的图集,也就间接实现了对碎图的支持,不用依赖Texture Packer等三方图集工具;

功能实现:

前面已经示例了SpriteAltas转为Texture,剩下只需要把Texture类型改成Sprite,Sprite Mode改为Multiple,然后把SpriteAltas碎图Rect映射过来即可:

1. 获取SpriteAtlas所有碎图的Rect信息:

static SpriteRect[] GetSpriteRects(SpriteAtlas atlas)
{if (atlas == null || atlas.spriteCount == 0) return null;Sprite[] sprites = new Sprite[atlas.spriteCount];atlas.GetSprites(sprites);SpriteRect[] spriteRects = new SpriteRect[sprites.Length];var spNameTrim = "(Clone)".ToCharArray();for (int i = 0; i < sprites.Length; i++){var sp = sprites[i];spriteRects[i] = new SpriteRect(){name = sp.name.Trim(spNameTrim),rect = sp.textureRect};}return spriteRects;
}

2. 根据碎图的Rect信息自动划分:

TextureImporter texImporter = TextureImporter.GetAtPath(textureFileName) as TextureImporter;
var factory = new SpriteDataProviderFactories();
factory.Init();
var dataProvider = factory.GetSpriteEditorDataProviderFromObject(texImporter);
dataProvider.InitSpriteEditorDataProvider();
dataProvider.SetSpriteRects(GetSpriteRects(atlas));
dataProvider.Apply();
texImporter.SaveAndReimport();

 SpriteAltas一键转为Sprite Multiple功能预览:

源码获取:GF_X/Assets/AAAGame/ScriptsBuiltin/Editor/Common/RightClickMemus/RightClickMenuExtension.SpriteAtlasTools.cs at master · sunsvip/GF_X · GitHub 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com