【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 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/53058.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【时间盒子】-【3.新建项目】创建元服务工程,选择默认模板Empty Ability

一、新建项目 1、打开DevEco Studio >>文件>>新建>>新建项目&#xff0c;选择元服务 Atomic Service>>默认模板Empty Ability。 2、设置元服务的工程名称、Bundle name等&#xff0c;模型选Stage&#xff0c;语言是ArkTS&#xff0c;支持的设备类型只…

Web安全:SQL注入实战测试.(扫描 + 测试)

Web安全&#xff1a;SQL注入实战测试. SQL注入就是 有些恶意用户在提交查询请求的过程中 将SQL语句插入到请求内容中&#xff0c;同时程序的本身对用户输入的内容过于相信&#xff0c;没有对用户插入的SQL语句进行任何的过滤&#xff0c;从而直接被SQL语句直接被服务端执行&am…

【Python】3.基础语法(3)函数

文章目录 1.函数2.语法格式3.函数参数4. 函数返回值5. 变量作用域6.函数执行过程7. 链式调用8.嵌套调用9. 函数递归10. 参数默认值11. 关键字参数 1.函数 编程中的函数, 是一段 可以被重复使用的代码片段。 代码示例: 求数列的和, 不使用函数 # 1. 求 1 - 100 的和 sum 0 f…

“立创EDA专业版”笔记

目录 二、立创EDA专业版 2.0 整体功能 2.0.1 快捷键 2.1 右侧功能栏 2.1.1 过滤 2.2 PCB设计 2.2.1 切换亮度 2.2.2 偏移 2.2.3 单位切换 2.2.4 检查DRC 2.2.5 重新铺铜 2.2.6 布线 2.2.7 锁定 2.2.8 “过滤”设置锁定 2.3 上方菜单栏 2.3.1 保存文件 2.4 元件…

安卓(Android)平台上的MVVM架构:关键知识点、优劣分析及实践示例

​ 一、安卓MVVM架构核心知识点 1.1、架构组成 1.1.1、Model层 承载业务逻辑与数据实体&#xff0c;独立于UI并与ViewModel进行交互&#xff0c;实现数据获取与处理功能。 1.1.2、View层 负责用户界面展示&#xff0c;借助Android XML布局文件及Activity/Fragment等组件&a…

Java学习第六天

Java进阶知识面向对象 static&#xff1a;是静态的意思&#xff0c;可以修饰成员变量&#xff0c;表示该成员变量在内存中只存储一份&#xff0c;可以被共享访问。 静态成员变量&#xff08;有static修饰&#xff0c;属于类&#xff0c;内存中加载一次&#xff09;&#xff1a…

网络安全-安全渗透简介和安全渗透环境准备

文章目录 前言1. 安全渗透简介1.1 什么是安全渗透&#xff1f;1.2 安全渗透所需的工具1.3 渗透测试流程 2. 使用 Kali Linux 进行安全渗透2.1 下载ISO镜像2.2 下载VMware Workstaion软件2.3 Kali Linux简介2.4 准备Kali Linux环境2.5 Kali Linux初始配置2.6 VIM鼠标右键无法粘贴…

从汇编层看64位程序运行——likely提示编译器的优化案例和底层实现分析

大纲 代码分析with_attributes::powno_attributes::pow分析 我们在《Modern C——使用分支预测优化代码性能》一文中介绍了likely提示编译器进行编译优化&#xff0c;但是我们又讲了最终优化不是对分支顺序的调换&#xff0c;那么它到底做了什么样的优化&#xff0c;让整体性能…

Temu、Shein半托管vs全托管?养号测评怎么整?

2024年&#xff0c;跨境电商的市场风向又变了&#xff01;1月4日&#xff0c;阿里旗下的速卖通推出半托管模式&#xff0c;通过免佣金和现金补贴吸引卖家&#xff1b;同月&#xff0c;拼多多的Temu也在美国上线了半托管服务&#xff0c;TikTok Shop和SHEIN紧随其后。这给才流行…

Vue学习笔记 二

4、Vue基础扩展 4.1 插槽 组件的最大特性就是复用性,而用好插槽能大大提高组件的可复用能力在Vue中插槽是很重要的存在,通过插槽,我们可以把父组件中指定的DOM作用到子组件的任意位置,后面我们坐项目用到的组件库比如element-ui,vant-ui都频繁用到的插槽,Vue的插槽主要有…

MySQL:简述多版本并发控制MVCC

一、MVCC的概念 1、MVCC 数据库并发场景有三种&#xff0c;分别为&#xff1a; &#xff08;1&#xff09;读读&#xff1a;不存在任何问题&#xff0c;也不需要并发控制。 &#xff08;2&#xff09;读写&#xff1a;有线程安全问题&#xff0c;可能会造成事务隔离性问题&am…

最新!yolov10+deepsort的目标跟踪实现

目录 yolov10介绍——实时端到端物体检测 概述 主要功能 型号 性能 方法 一致的双重任务分配&#xff0c;实现无 NMS 培训 效率-精度驱动的整体模型设计 提高效率 精度提升 实验和结果 比较 deepsort介绍&#xff1a; yolov10结合deepsort实现目标跟踪 效果展示…

.NET周刊【9月第1期 2024-09-01】

国内文章 【音视频通话】使用asp.net core 8vue3 实现高效音视频通话 https://www.cnblogs.com/1996-Chinese-Chen/p/18384394 该文章描述了使用SRS实现音视频通话和共享桌面的经验。从最初使用nginx的RTMP到研究SRS和ZLMediaKit的过程&#xff0c;再到最终实现功能的详细步…

TF | SD 卡出现无法删除的文件,乱码文件该如何处理 macOS

TF | SD 卡出现无法删除的文件&#xff0c;乱码文件该如何处理 macOS 一、问题描述 最近手头有张用在 Miyoo 掌机上的游戏 TF 卡&#xff0c;在macOS 系统下在回收站中出现了几个特殊文件名的文件&#xff0c;始终无法删除。 二、试着解决 我试过了网上的所有方法都无法删除…

RuoYi-Cloud 部署与配置 [CentOS7]

静态IP设置 # 修改网卡配置文件 vim /etc/sysconfig/network-scripts/ifcfg-ens33# 修改文件内容 TYPEEthernet PROXY_METHODnone BROWSER_ONLYno BOOTPROTOstatic IPADDR192.168.18.130 NETMASK255.255.255.0 GATEWAY192.168.18.2 DEFROUTEyes IPV4_FAILURE_FATALno IPV6INIT…

Electron桌面应用与文件路径处理:从Git、SourceTree到TortoiseGit的安装与配置

更多内容前往个人网站&#xff1a;孔乙己大叔 在开发Electron桌面应用程序时&#xff0c;正确处理文件路径是一个至关重要的环节。特别是当涉及到需要调用外部程序&#xff08;如Git、SourceTree或TortoiseGit&#xff09;时&#xff0c;确保这些程序安装在正确的位置&#xff…

@Tanstack/vue-query 的使用介绍

Tanstack/vue-query 的使用介绍 前言 在今年的vue conf 会议上&#xff0c;提到了vue-query这个库&#xff0c;这里对它的基本使用做一个介绍。 会议资料地址&#xff1a; https://vueconf.cn/ Tanstack-query的前身是react-query&#xff0c;是一个本地的服务端状态管理的库…

3.6 逻辑运算

&#x1f393; 微机原理考点专栏&#xff08;通篇免费&#xff09; 欢迎来到我的微机原理专栏&#xff01;我将帮助你在最短时间内掌握微机原理的核心内容&#xff0c;为你的考研或期末考试保驾护航。 为什么选择我的视频&#xff1f; 全程考点讲解&#xff1a;每一节视频都…

wpf prism 《3》 弹窗 IOC

传统的弹窗 这种耦合度高 new 窗体() . Show(); new 窗体() . ShowDialog(); 利用Prism 自动的 IOC 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 》》否…

【C语言】十六进制、二进制、字节、位、指针、数组

【C语言】十六进制、二进制、字节、位 文章目录 [TOC](文章目录) 前言一、十六进制、二进制、字节、位二、变量、指针、指针变量三、数组与指针四、指针自加运算五、二维数组与指针六、指向指针的指针七、指针变量作为函数形参八、函数指针九、函数指针数组十、参考文献总结 前…