Unity实现自定义图集(四)
以下内容是根据Unity 2020.1.0f1版本进行编写的
在之前的篇章中已经把自定义图集在编辑器上的使用,以及运行时所需的信息都准备好了,接下来就是魔改UGUI的Image组件,使其能够像Image那样运行时如果引用的资源有打自定义图集,则加载对应自定义图集的Texture。
1、思路
如图,想要模仿Image组件是怎么判断一个资源是否从有打图集的,先直接在Image组件上搜SpriteAtlas,发现只能搜出如上图这几个结果。
看起来应该是有一个SpriteAtlas的管理类,在Image初始化的时候注册了一个RebuildImage的事件,每当资源变动/运行游戏等情况时,就会执行这个RebuildImage的方法,方法调用时会传入一个SpriteAtlas的参数,SpriteAtlas类中有个CanBindTo的方法,看来这个应该就是判断资源是否有打图集的方法了。
再点进去看发现是外部方法,于是打开反编译软件看看有没有具体的代码
反编译软件里显示代码是写到了C++的内部文件,这样就看不到具体的实现过程了。但是我们可以自己实现一个类似的。
我们可以在自定义图集中多保存一份图集内全部资源的guid对应路径的字典(去掉之前的guid列表),然后在自定义的Image组件中保存一份当前引用资源的guid,当在某一个图集中找到自定义Image组件中的guid时,则认为该Image组件引用的资源已经打了自定义图集。
接下来就是如何在运行时把有自定义图集的自定义Image组件中的Texture换成自定义图集的Texture,并将其uv设对。
这里先实现编辑器的自定义图集Texture加载。
在前面的文章中就已经准备好了自定义图集的Texture,并且会在每次Unity启动前更新,那么编辑器下运行时只需要把存放在Library文件夹的Texture读取出来就可以了
读取出来后,自定义图集MyAtlas中已经保存有对应资源的uv信息了,这时候看Image代码(如图),发现传进去的uv是一个0~1的值。因此自定义图集保存时还需要多保存width和height两个值。
注意;这里不直接将保存的uv信息从int改成float后double,一是不希望保存太多小数,二是考虑到width和height值可能会有被其它地方用到的时候。
数据都准备好了,这时候还有一个问题,Image组件中,如果在上图的GenerateSimpleSprite方法中将原有的设置顶点信息和uv的代码去掉,增加判断当前Image资源是否已打自定义图集,并且加载图集的Texture并设置为材质球的Texture,会发现运行时资源是无法知道其guid的,甚至路径也不知道。
获取guid或者资源路径的代码一般使用的是AssetDataBase类,但是这个类是编辑器类,不能打包后在其它设备使用,打包时也会报错。看了一下Image的代码,猜测是Unity内部有自己的一套资源管理系统,能在运行时获取资源的信息,但是没有开放接口。
于是直接使用简单的办法,在自定义的Image组件上加一个guid变量,并且在对应的Editor类中对于每次Image引用的资源有变动,就刷新一次其引用资源的guid即可。
2、实现
首先需要去掉项目原来的UGUI插件,并从Unity官方下载UGUI源码,并将源码复制到项目中。(我这里复制的是魔改UGUI代码工程里的源码)
然后新建一个MyImage类,复制Image的代码,并按上面的思路修改
增加guid属性和纹理图属性,用于保存当前引用的资源guid和运行时资源对应图集的纹理图
接下来应该改动mainTexture,当获取mainTexture时,如果当前引用的资源存在自定义图集,那么应该直接返回自定义图集的图。
但是mainTexture没有set方法,只有get方法,因此先需要在其基础类Graphic类中将mainTexture虚拟属性增加一个空的set方法。然后再在MyImage中的get方法判断是否存在自定义图集的纹理图,若存在则直接返回,否则就按原来的代码执行。set方法也比较简单,就是把值赋给新增的m_MainTexture属性就行。
protected void SpriteGUI(){EditorGUI.BeginChangeCheck();EditorGUILayout.PropertyField(m_Sprite, m_SpriteContent);if (EditorGUI.EndChangeCheck()){var newSprite = m_Sprite.objectReferenceValue as Sprite;if (newSprite){MyImage.Type oldType = (MyImage.Type)m_Type.enumValueIndex;if (newSprite.border.SqrMagnitude() > 0){m_Type.enumValueIndex = (int)MyImage.Type.Sliced;}else if (oldType == MyImage.Type.Sliced){m_Type.enumValueIndex = (int)MyImage.Type.Simple;}//自定义改动MyImage myImage = target as MyImage;if(myImage.sprite){string path = AssetDatabase.GetAssetPath(newSprite);string guid = AssetDatabase.AssetPathToGUID(path);m_guid.stringValue = guid;Debug.Log("image editor set guid: " + guid);}else{m_guid.stringValue = "";}EditorUtility.SetDirty(myImage);}(serializedObject.targetObject as MyImage).DisableSpriteOptimizations();}
在Editor文件夹下新建MyImageEditor脚本,复制ImageEditor代码,增加每次资源变动获取资源的guid并赋值到MyImage类的guid属性上。(自定义改动部分)
接着在MyAtlas类实现一个类似SpriteAtlas的CanBindTo方法。用于判断资源是否存在自定义图集。这里仅实现了在编辑器模式下的图集纹理加载,即加载保存到Library文件夹下的纹理图。
同理,在自定义图集管理类中也需要加一个CanBindTo方法,用于全局调用。
最后是改一下生成VertexHelper的方法,对应有4个方法,分别对应Image Type中的simple、sliced、tiled、filled模式。其中,平铺图tiled模式,如果将平铺图资源打进图集,可能会导致顶点数大大增加,因此一般不会把平铺图打图集,此外平铺图的生成比较麻烦,所以这里的改动忽略了平铺图生成VertexHelper的方法(即使用tiled平铺图不会合批)。
代码如下:
Simple模式:
private void GenerateSimpleSprite(VertexHelper vh, bool lPreserveAspect){Vector4 drawingDimensions = GetDrawingDimensions(lPreserveAspect);Vector4 vector = (activeSprite != null) ? DataUtility.GetOuterUV(activeSprite) : Vector4.zero;Color color = this.color;vh.Clear();//vh.AddVert(new Vector3(drawingDimensions.x, drawingDimensions.y), color, new Vector2(vector.x, vector.y));//vh.AddVert(new Vector3(drawingDimensions.x, drawingDimensions.w), color, new Vector2(vector.x, vector.w));//vh.AddVert(new Vector3(drawingDimensions.z, drawingDimensions.w), color, new Vector2(vector.z, vector.w));//vh.AddVert(new Vector3(drawingDimensions.z, drawingDimensions.y), color, new Vector2(vector.z, vector.y));//自定义改动if(Application.isPlaying){MyAtlas atlas = MyAtlasManager.CanBindTo(this);Debug.LogError("atlas: " + atlas);if (atlas){Texture2D texture2D = atlas.GetTexture(OnSetMainTexture);RectInfo rectInfo = atlas.GetRectInfo(guid);if (texture2D && rectInfo != null){mainTexture = texture2D;int textureWidth = atlas.GetWidth();int textureHeight = atlas.GetHeight();float x = (float)(rectInfo.x + vector.x * rectInfo.width) / textureWidth;float y = (float)(rectInfo.y + vector.y * rectInfo.height) / textureHeight;float z = (float)(rectInfo.x+ vector.z * rectInfo.width) / textureWidth;float w = (float)(rectInfo.y+ vector.w * rectInfo.height) / textureHeight;vector = new Vector4(x, y, z, w);}}else{mainTexture = null;}}vh.AddVert(new Vector3(drawingDimensions.x, drawingDimensions.y), color, new Vector2(vector.x, vector.y));vh.AddVert(new Vector3(drawingDimensions.x, drawingDimensions.w), color, new Vector2(vector.x, vector.w));vh.AddVert(new Vector3(drawingDimensions.z, drawingDimensions.w), color, new Vector2(vector.z, vector.w));vh.AddVert(new Vector3(drawingDimensions.z, drawingDimensions.y), color, new Vector2(vector.z, vector.y));vh.AddTriangle(0,
相关文章:

Unity实现自定义图集(四)
以下内容是根据Unity 2020.1.0f1版本进行编写的 在之前的篇章中已经把自定义图集在编辑器上的使用,以及运行时所需的信息都准备好了,接下来就是魔改UGUI的Image组件,使其能够像Image那样运行时如果引用的资源有打自定义图集,则加载对应自定义图集的Texture。 1、思路 …...

k8s-pod的管理及优化设置
Pod是Kubernetes(k8s)中最小的资源管理组件,也是最小化运行容器化应用的资源对象。以下是对Pod的详细介绍: 一、Pod的基本概念 定义:Pod是Kubernetes中可以创建和管理的最小单元,是资源对象模型中由用户创…...

软件测试面试题大全
什么是软件测试? 答案:软件测试是一系列活动,旨在评估软件产品的质量,并验证它是否满足规定的需求。它包括执行程序或系统以识别任何缺陷、问题或错误,并确保软件产品符合用户期望。 软件测试的目的是什么?…...

SQL第16课挑战题
1. 美国各州的缩写应始终用大写。更新所有美国地址,包括供应商状态(Vendors表中的vend_state)和顾客状态(customers表中的cust_state),使它们均为大写。 2. 第15课挑战题1要求将自己添加到customers表中,现在删除自己,…...

Python3 爬虫 中间人爬虫
中间人(Man-in-the-Middle,MITM)攻击是指攻击者与通信的两端分别创建独立的联系,并交换其所收到的数据,使通信的两端认为其正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。在中…...

Leetcode 50. Pow ( x , n ) 快速幂、取模 C++实现
问题:Leetcode 50. Pow ( x , n ) 实现 pow(x, n) ,即计算 x 的整数 n 次幂函数。 算法: 具体实现流程如下: 代码: class Solution { public:double myPow(double x, int N) {double ans 1;long long n N;if (n <…...

Java SE vs Java EE 与 JVM vs JDK vs JRE
Java SE(Java Platform,Standard Edition): Java 平台标准版,Java 编程语言的基础,它包含了支持 Java 应用程序开发和运行的核心类库以及虚拟机等核心组件。Java SE 可以用于构建桌面应用程序或简单的服务器应用程序。…...

Linux YUM设置仓库优先级
1.安装yum-plugin-priorities优先级插件 yum install yum-plugin-priorities -y 2.设置仓库优先级 vim /etc/yum.repos.d/local.repo [local] namecentos7.5 baseurlfile:///mnt enable1 gpgcheck0 priority1 注释: priority1 #数字越小代表优先级越高ÿ…...

做一个不断更新的链接库
做一个不断更新的链接库 anaconda anaconda官方镜像源 anaconda清华镜像源 社区 CSDN CSDN-华为开发者空间 python开发库 股票爬虫 - akshare...

Ping32企业加密软件:保护数据安全
在数字化时代,数据安全已成为每个企业不可忽视的重要课题。无论是客户信息、财务报表,还是商业机密,数据的安全性直接关系到企业的声誉与运营。为了应对不断变化的安全威胁,选择一款可靠的企业加密软件尤为重要。在这里࿰…...

【Java】异常的处理-方式【主线学习笔记】
文章目录 前言1、处理概述2、Java异常处理机制(方式)方式一(抓抛模型):try-catch-finally方式二:throws 异常类型总结 前言 Java是一门功能强大且广泛应用的编程语言,具有跨平台性和高效的执行…...

React modal暴露ref简洁使用
父组件使用 import { useRef } from react import { FormModal } from ./modalconst IndexRoute () > {const formRef useRef<any>()const openModal (row?: any) > {const params {title: row?.id ? 【${row.name}】编辑 : 创建,isView: false,row,api: r…...

小米路由器ax1500+DDNS+公网IP+花生壳实现远程访问
有远程办公的需求,以及一些其他东西。 为什么写? ax1500路由器好像没搜到相关信息。以及其中有一点坑。 前置 公网ip Xiaomi路由器 AX1500 MiWiFi 稳定版 1.0.54 实现流程 花生壳申请壳域名https://console.hsk.oray.com/ 这里需要为域名实名认证 …...

毕设分享 大数据用户画像分析系统(源码分享)
文章目录 0 前言2 用户画像分析概述2.1 用户画像构建的相关技术2.2 标签体系2.3 标签优先级 3 实站 - 百货商场用户画像描述与价值分析3.1 数据格式3.2 数据预处理3.3 会员年龄构成3.4 订单占比 消费画像3.5 季度偏好画像3.6 会员用户画像与特征3.6.1 构建会员用户业务特征标签…...

使用 Redis 实现分布式锁:原理、实现与优化
在分布式系统中,分布式锁是确保多个进程或线程在同一时间内对共享资源进行互斥访问的重要机制。Redis 作为一个高性能的内存数据库,提供了多种实现分布式锁的方式。本文将详细介绍如何使用 Redis 实现分布式锁,包括基本原理、实现方法、示例代…...

Android常用C++特性之std::make_pair
声明:本文内容生成自ChatGPT,目的是为方便大家了解学习作为引用到作者的其他文章中。 std::make_pair 是 C 标准库中的一个函数模板,用于创建一个 std::pair 对象。std::pair 是一种可以存储两个不同类型值的简单数据结构,类似于二…...

Kafka-参数详解
一、上下文 从《Kafka-初识》中可以看到运行kafka-console-producer和 kafka-console-consumer来生产和消费数据时会打印很多参数,这些参数给我们应对多种场景提供了遍历,除了producer和consumer的提供了参数外,Kafka服务器集群中的broker也…...

Docker Overlay2 空间优化
目录 分析优化数据路径规划日志大小限制overlay2 大小限制清理冗余数据 总结 分析 overlay2 目录占用磁盘空间较大的原因通常与 Docker 容器和镜像的存储机制以及它们的长期累积相关,其实我之前在 Docker 原理那里已经提到过了。 通常时以下几种原因导致ÿ…...

第 3 章:使用 Vue 脚手架
1. 初始化脚手架 1.1 说明 Vue 脚手架是 Vue 官方提供的标准化开发工具(开发平台)。最新的版本是 5.x。文档: https://cli.vuejs.org/zh/ 1.2 具体步骤 第一步(仅第一次执行):全局安装vue/cli。 npm install -g vu…...

Spring 循环依赖详解:问题分析与三级缓存解决方案
在Spring框架中,循环依赖(Circular Dependency)是指多个Bean相互依赖,形成一个循环引用。例如,Bean A依赖于Bean B,而Bean B又依赖于Bean A。这种情况在Bean创建时可能导致Spring容器无法正常完成初始化&am…...

爬虫prc技术----小红书爬取解决xs
知识星球:知识星球 | 深度连接铁杆粉丝,运营高品质社群,知识变现的工具知识星球是创作者连接铁杆粉丝,实现知识变现的工具。任何从事创作或艺术的人,例如艺术家、工匠、教师、学术研究、科普等,只要能获得一…...

uni-app之旅-day06-加入购物车
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言8.0 创建 cart 分支8.1 配置 vuex8.2 创建购物车的 store 模块8.3 在商品详情页中使用 Store 中的数据8.4 实现加入购物车的功能8.5 动态统计购物车中商品的总数…...

【Kubernetes】常见面试题汇总(五十六)
目录 123. pod 创建失败? 124. kube-flannel-ds-amd64-ndsf7 插件 pod 的 status 为 Init:0/1 ? 特别说明: 题目 1-68 属于【Kubernetes】的常规概念题,即 “ 汇总(一)~(二十二&#x…...

LabVIEW激光诱导击穿光谱识别与分析系统
LabVIEW激光诱导击穿光谱(LIBS)分析系统利用高能量脉冲激光产生高温等离子体,通过分析等离子体发出的光谱来定性分析样品中的元素种类。该系统的开发集成了软件与硬件的设计,实现了自动识别和定性分析功能,适用于环境监…...

Redis的基础篇
Redis的基础篇 1.在CentOs7上安装Redis(最好不要在windows上装,版本少) 1.安装gcc --> yum install gcc tcl(可能会报错,重新安装yum就行了) 2.下载redis --> 最好是6.2上的版本 3.解压redis --> tar -zxvf redis-6.2.…...

java和python哪个好
Java和Python各有优缺点,适合不同的应用场景,具体看你需要在哪种情况下使用编程语言。以下是Java和Python的一些对比,帮助你决定哪种更适合你的需求: 性能 Java:编译型语言,编译成字节码运行在Java虚拟机&…...

Electron + ts + vue3 + vite
正常搭建脚手架:npm create vitelatest 项目名称 安装electron的相关依赖:注:安装时终端url要项目名那一层 安装npm install electron -D安装打包工具:npm install electron-builder -D开发工具:npm install electron-…...

《大规模语言模型从理论到实践》第一轮学习--分布式训练
基础知识 5分钟看懂电脑硬件配置 - 知乎 (zhihu.com) 显存 定义:显存是显卡上的专用高速缓存,用于存储图形处理器(GPU)在处理图像和视频数据时所需的临时数据。 功能:显存的主要作用是提供GPU快速访问的数据存储&a…...

多模态智能
研究背景: 深度学习从1.0的端到端走向2.0的预训练,通过大规模预训练来记忆多模态数据中共性知识,增强对下游任务的学习能力。 深度学习1.0:特定任务有标注训练数据->随机初始化训练->最终模型 深度学习2.0:大规…...

【机器学习(十三)】机器学习回归案例之股票价格预测分析—Sentosa_DSML社区版
文章目录 一、背景描述二、Python代码和Sentosa_DSML社区版算法实现对比(一) 数据读入(二) 特征工程(三) 样本分区(四) 模型训练和评估(五) 模型可视化 三、总结 一、背景描述 股票价格是一种不稳定的时间序列,受多种因素的影响。影响股市的外部因素很多,主要有经济因素、政治因…...