UGUI内核大探究(九)Image与RawImage

2023-11-14

Image组件是UGUI里最常用的组件(可能没有之一),我们知道其实还有一个RawImage组件。那么二者的区别是什么呢?之前的文章UGUI内核大探究(八)MaskableGraphic中我们提到过,二者(连同Text)都继承自MaskableGraphic。但是同为图片组件,Image的代码有接近一千行之多,而RawImage却只有120行。

RawImage顾名思义,未加工的生肉图片,RawImage只为我们提供了修改UV的方法,除此之外都是继承自MaskableGraphic的方法。是一个清纯不做作的组件。

而Image提供了四种ImageType:Simple(普通)、Sliced(切割)、Tiled(平铺)、Filled(填充),而且它还是布局元素(ILayoutElement),可以被各种布局组(ILayoutGroup)所包含,将它和其他布局元素进行布局。

所以假如我们要在UI上添加图片的时候,不妨考虑一下你到底需要的是轻量级的RawImage还是功能丰富的Image。

按照惯例,附上UGUI源码下载地址

那么既然RawImage代码只有120行,那本文就先介绍RawImage。

最重要的一个方法:

        protected override void OnPopulateMesh(VertexHelper vh)
        {
            Texture tex = mainTexture;
            vh.Clear();
            if (tex != null)
            {
                var r = GetPixelAdjustedRect();
                var v = new Vector4(r.x, r.y, r.x + r.width, r.y + r.height);

                {
                    var color32 = color;
                    vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(m_UVRect.xMin, m_UVRect.yMin));
                    vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(m_UVRect.xMin, m_UVRect.yMax));
                    vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(m_UVRect.xMax, m_UVRect.yMax));
                    vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(m_UVRect.xMax, m_UVRect.yMin));

                    vh.AddTriangle(0, 1, 2);
                    vh.AddTriangle(2, 3, 0);
                }
            }
        }

OnPopulateMesh实在Graphic中被调用的(祥参UGUI内核大探究(七)Graphic),它为CanvasRenderer的Mesh提供了顶点、顶点颜色、UV和三角形信息(关于Mesh可以参考Unity3D Mesh小课堂)。关于UV,可以参考Unity3D Mesh小课堂(二)为三角形添加纹理,这里不做赘述,只是简单演示一下:

我们为一个圆形的生肉图片,设置UV矩形,x=0.5,w=0.5,这样我们就看到了一个被压扁的半圆:


如果把四个值x,y,w,h都改成0.5,我们就可以看到一个四分之一圆:


我们点击Set Native Size按钮,就可以看到,四分之一圆变小了(宽高各减少一半)。那么我们就引入下一个比较重要的方法:

        public override void SetNativeSize()
        {
            Texture tex = mainTexture;
            if (tex != null)
            {
                int w = Mathf.RoundToInt(tex.width * uvRect.width);
                int h = Mathf.RoundToInt(tex.height * uvRect.height);
                rectTransform.anchorMax = rectTransform.anchorMin;
                rectTransform.sizeDelta = new Vector2(w, h);
            }
        }

很好理解,不再赘述。


分析完轻量级的RawImage,我们便要分析近1000行代码的Image了。

还是先看OnPopulateMesh

        protected override void OnPopulateMesh(VertexHelper toFill)
        {
            if (overrideSprite == null)
            {
                base.OnPopulateMesh(toFill);
                return;
            }

            switch (type)
            {
                case Type.Simple:
                    GenerateSimpleSprite(toFill, m_PreserveAspect);
                    break;
                case Type.Sliced:
                    GenerateSlicedSprite(toFill);
                    break;
                case Type.Tiled:
                    GenerateTiledSprite(toFill);
                    break;
                case Type.Filled:
                    GenerateFilledSprite(toFill, m_PreserveAspect);
                    break;
            }
        }
这里根据图片设置的不同类型,要生成不同的顶点、顶点颜色、UV和三角形信息,所以分成了四个方法各自计算。

GenerateSimpleSprite方法是最简单的,与RawImage类似,只不过会根据精灵(sprite)的间隙(padding)和RectTransform的尺寸再计算一下顶点,并根据精灵的外侧UV信息(GetOuterUV)来设置UV。

GenerateSlicedSprite会生成36个uv点,如下图:


九宫格里每一个格子对应四个uv点。

uv点就36个,顶点也就有36个:


同样每个格子对应四个顶点(大致画一下格子)。

由此我们就可以看出实际上是中心区域被拉大了(四角部分不变,上下部分拉宽,左右部分拉长)。

我们取消Fill Center的时候会看到:


这是因为这种情况下中心格子的顶点、uv等信息都没有。

GenerateTiledSprite方法如果sprite有边界,那么便会生成跟GenerateSlicedSprite一样的结果(不知道为什么会有这样的设定,虽然貌似很合理,但是体验却不怎么好,而且我也搞不明白为什么要写两份相同功能的代码),如果没有边界,那么就会出现下面这种结果:


因为GenerateTiledSprite会计算该区域里可以放下多少个精灵单元(横纵分别向上取整),假设为格子数N,便会有4N个顶点,如果一个小格子可以完整的放下一个精灵单元,uv值便是x从0到1y从0到1的完整纹理坐标。而如果只能放下一部分,那边根据百分比计算uv值。

GenerateFilledSprite是最长的一个方法,因为它还区分了不同的填充方法(Horizontal,Vertical,Radial 90,Radial 180,Radial 360)。

但是分析起来却没那么复杂,Horizontal和Vertical很简单,只需要根据Fill Origin和Fill Amount设置矩形的顶点和UV值。而Radial系列方法不过是根据几何方法,来计算出顶点和UV值。(有兴趣的可以详细研究一下)


除了MaskableGraphic,Image还继承了ISerializationCallbackReceiver, ILayoutElement, ICanvasRaycastFilter三个接口。

ISerializationCallbackReceiver需要实现OnBeforeSerialize(序列化之前)和OnAfterDeserialize(发序列化之后)两个方法。我们知道UnityEditor会把我们设置的参数保存在Scene或者Prefab里面,这就是序列化,加载或运行的时候,需要从Scene或者Prefab读出来,这就是反序列化。

Image的OnBeforeSerialize是个空方法,OnAfterDeserialize里则是矫正了Fill Origin和Fill Amount为有效值。

ILayoutElement是布局元素,需要实现一些属性(Property),用于调节尺寸时做参考。具体细节,后续文章介绍Layout的时候再详细介绍。

最后还有一个ICanvasRaycastFilter,它是UnityEngine命名空间下的接口。它在Graphic中被调用,用于筛选出被射线照射到的图像。需要实现接口IsRaycastLocationValid。

Image的IsRaycastLocationValid接口将输入点转化为Image的内部点,然后在转换为Sprite纹理上的内部点,然后判断该点上的alpha值是否大于等于m_EventAlphaThreshold。这个值对应于可读写的属性eventAlphaThreshold。我们可以外部修改这个值,例如改成0.5f,那么点击到alpha小于0.5f的像素点就无法接收事件(参考UGUI内核大探究(一)EventSystem)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

UGUI内核大探究(九)Image与RawImage 的相关文章

  • 如何使用 Misc.imread 将图像分割为红色、绿色和蓝色通道

    我正在尝试将图像切片为 RGB 但在绘制这些图像时遇到问题 我使用此函数从某个文件夹获取所有图像 def get images path image type image list for filename in glob glob pat
  • 减少1000张图片的HTTP请求?

    我知道这个问题可能听起来有点疯狂 但我想也许有人会想出一个聪明的主意 假设您在一个 HTML 页面上有 1000 个缩略图 图像大小约为5 10 kb 有没有办法在单个请求中加载所有图像 以某种方式将所有图像压缩到一个文件中 或者您对该主题
  • 如何更改焦点/按下时图像按钮的色调

    我有一个ImageButton在我的应用程序中 当按钮打开时我需要更改图像的色调pressed focused 我有ImageButton设置为获取其src来自 XML 文件 如下所示
  • java设置图像的分辨率和打印尺寸

    我编写了一个程序 生成一个 BufferedImage 以显示在屏幕上 然后打印 图像的一部分包括 1 像素宽的网格线 即 一行为1个像素 行与行之间大约有10个像素 由于屏幕分辨率的原因 图像显示得比这大得多 每行有几个像素 我想将其绘制
  • Tkinter:无法识别图像文件中的数据[重复]

    这个问题在这里已经有答案了 我有以下问题 我使用外部应用程序生成 GIF 文件 对我来说 GIF 看起来不错 我可以毫无问题地打开它们 然而 使用 photo PhotoImage file screenshot file self pre
  • Javascript图像编辑插件

    在哪里可以找到 Javascript 或 jQuery 图像编辑器插件 用户可以单击图像进行编辑 并且该插件允许他们进行裁剪 调整大小 旋转 翻转等 Pixastic http pixastic com lib 不再活跃 和CamanJS
  • 如何在java中通过socket发送Image数据类型

    我真的很困惑如何通过套接字发送图像数据类型 请帮我 我已经搜索了如何将 Image 数据类型转换为 char 但结果是 0 Use ImageIO http docs oracle com javase 1 4 2 docs api jav
  • 在python中将二维数组转换为彩色图像

    我有这样的二维整数列表 list1 1 30 50 21 45 9 97 321 100 接下来我将把它转换为 numpy 数组 myarr np asarray list1 接下来我将使用 PIL 将其转换为图像 如下所示 img Ima
  • 仅获取图像中的外部轮廓

    我有这段代码 可以在图像中绘制轮廓 但我只需要外部轮廓 import cv2 import numpy as np camino C Users Usuario Documents Deteccion de Objetos 123 jpg
  • 如何将图像转换为 UIImage?

    如何转换 SwiftUIImage to a UIImage let image Image systemName circle fill let UIImage image as UIImage 没有直接的方法将 Image 转换为 UI
  • 使用无图像按钮有哪些优点?

    讨论关于这个答案 https stackoverflow com questions 520640 how can i use googles new imageless button how could i reverse enginee
  • WPF 中按钮的启用和禁用状态的不同图像

    我想根据按钮的状态更改下面代码中按钮的图像 即使用不同的图像来启用和禁用状态
  • 左对齐图像和居中文本在 div 内的同一级别?

    HTML br div class UpperTitle img src align left CableSolve Web Dashboard Version 0 1 1 div br CSS UpperTitle text align
  • JavaFX:将像素写入 PixelWriter 的最快方法

    我正在寻找最快的方式来写入像素javafx scene image Image 写信给BufferedImage的后备数组要快得多 至少在我制作的测试图像上 只花了大约 20 毫秒BufferedImage WritableImage另一方
  • createImage(int width, int height) 的问题

    我有以下代码 作为游戏的一部分每 10 毫秒运行一次 private void gameRender if dbImage null createImage returns null if GraphicsEnvironment isHea
  • PIL - 需要抖动,但限制调色板会导致问题

    我是 Python 新手 正在尝试使用 PIL 来执行 Arduino 项目所需的解析任务 这个问题涉及到Image convert 方法以及调色板 抖动等选项 我有一些硬件能够一次仅显示 16 种颜色的图像 但它们可以指定为 RGB 三元
  • 在 android 中使用 MediaStore.ACTION_IMAGE_CAPTURE 意图捕获图像

    我正在使用 MediaStore ACTION IMAGE CAPTURE 意图捕获图像 它在大多数设备上运行良好 但它无法按预期在某些最新的 Android 设备中正常工作 我的目的是使用相机捕获图像并将其发送到服务器 但不将该图像存储在
  • Java .drawImage:如何“取消绘制”或删除图像?

    我需要在程序运行时不断在不同位置重绘某个图像 因此 我设置了一个 while 循环 该循环应该在屏幕上移动图像 但它只是一遍又一遍地重新绘制图像 我究竟做错了什么 有没有办法在将旧图像绘制到新位置之前删除旧图像 JFrame frame b
  • 保存为 HDF5 的图像未着色

    我目前正在开发一个将文本文件和 jpg 图像转换为 HDF5 格式的程序 用HDFView 3 0打开 似乎图像仅以灰度保存 hdf h5py File Sample h5 img Image open Image jpg data np
  • 如何垂直对齐div内的图像

    如何在包含的内容中对齐图像div Example 在我的示例中 我需要将 img in the div with class frame div class frame style height 25px img src http jsfi

随机推荐

  • input 上传文件 判断重名限制文件个数

    原生文件上传 accept快捷上传 xls xlsx格式 文件上传表单的提交方式必须是 post 编码类型必须为 enctype multipart form data 上传多个文件属性 multiple
  • Mac Idea使用技巧

    1 IDEA自动生成serialVersionUID Inspections gt serialzable class without serialVersionUID 勾上 在实现了Serializable接口的类上使用alt enter
  • xzp 线刷 android 10,索尼Xperia XZ刷机教程_Sony XZ强刷官方FTF系统包

    在这里来说一下有关索尼Xperia XZ的强刷教程了 这个强刷教程主要就是针对官方的FTF格式的强刷包来操作的 因为之前看到有机友把官方的rom强刷包下载下来之后不知道如何刷入 所以在这里整理了一下详细的强刷教程供大家参考一下了 这个也不复
  • Property or method “scope“ is not defined

    VUE报错 Property or method scope is not defined 是因为缺失了 slot scope scope 造成组件认为 scope 未定义 加上去就行
  • 内网离线安装 Visual Studio 2022 及插件

    一 互联网环境下使用命令行创建本地缓存 首先下载小型引导程序文件 然后使用命令行创建本地缓存 缓存创建后 可使用它来安装 Visual Studio 一 下载 Visual Studio 引导程序 1 通过互联网电脑下载最新当前频道版本的
  • 对偶上升实例-MATLAB代码

    一 本文概述 本文给出对偶上升法 dual ascent 求解凸优化问题最优解的代码实例 如果您觉得对您有帮助 请点个赞 加个收藏 谢谢 二 简单实例 本文以下述实例为例 撰写对偶上升法的迭代步骤 并给出最终可运行的MATLAB代码 以便大
  • Yolov5配置傻瓜教程

    软硬件环境 Win10 anaconda python3 7 gtx 1660ti cuda 10 1 pytorch 1 7 YOLOv5 介绍 2020年6月25日 Ultralytics发布了YOLOV5 的第一个正式版本 其性能与Y
  • #超级系统详细#搭建深度学习环境(python3.8+cuda10.2+tensorflow2.3)

    写在前面 1 搭建环境前最重要的是先清楚各个版本之间的配对情况 官网版本匹配信息 tensorflow与python https tensorflow google cn install source windows 大致如下 cuda9
  • 【python】将自定义常用的一些函数封装成可以直接调用的模块方法

    将常用一些的函数封装成可以直接调用的模块方法 1 背景 2 具体步骤 3 扩展 1 背景 在实际的操作过程中 经常会用到一个功能 如果每次编写代码的时候都进行重新编写或者打开已经编写好的函数进行复制粘贴 这样就显得很麻烦 有没有什么方法可以
  • Different Subsets For All Tuples (经典,贪心考虑一个子序列是否出现在原序列中)

    https codeforces com problemset problem 660 E include
  • 基础算法题 —— 说反话-加强版(字符串截取)

    说反话 加强版 给定一句英语 要求你编写程序 将句中所有单词的顺序颠倒输出 输入格式 测试输入包含一个测试用例 在一行内给出总长度不超过500 000的字符串 字符串由若干单词和若干空格组成 其中单词是由英文字母 大小写有区分 组成的字符串
  • 摄像头分辨率与码流对照表

    https support dahuatech com tools onlineTools
  • 【进制转换】二进制,十进制,八进制,16进制

    1 二进制与十进制相互转换 二进制转为十进制 0000 0110转换为10进制 二进制里面没有 个位 十位 百位 只能通过从左到右或者从右到左第几位来描述 从右往左开始 第一位是0 进制的基数是2 那么就是0 20 第二位是1 就是1 21
  • 如何实现数据可视化分析?有这个解决方案就够了

    在这个数据呈爆炸式增长的时代 每天都有海量数据在产生 如何通过简单的方式实现业务上的分析 计算 交互 并最终呈现出可视化的分析结果 帮助业务人员更好地理解数据的价值 将数据变现 是当前众多企业都需要面对的问题 想要直观准确地从不同领域中的数
  • XGBOOST算法Python实现(保姆级)

    摘要 XGBoost算法 eXtreme Gradient Boosting 在目前的Kaggle 数学建模和大数据应用等竞赛中非常流行 本文将会从XGBOOST算法原理 Python实现 敏感性分析和实际应用进行详细说明 目录 0 绪论
  • sqlite3加密支持

    sqlite3加密支持 sqlite3免费版并不支持加密 不过留有接口 有不少开源的加密实现 不过有的需要使用openssl配置略显繁琐 不过使用wxsqlite比较方便 wxSqlite3 wxSqlite3是wxWidgets的扩展组件
  • 声笔飞码超字模式效率分析

    声笔飞码超字模式效率分析 2 keys 672 items 405280396 00 times covering 72 48 2 keys 672 items 405280396 00 times covering 72 48 3 key
  • SVM(2)从原始问题到对偶问题的转换

    S VM的水真是太深了 只能一点一点的解决了 今天这篇博客简单讲解SVM的目标函数从原始问题到对偶问题的转换 在这里再给大家一个大牛的博客链接 http blog pluskid org p 685 1 转化对偶问题 上篇博客中我们得到的目
  • 计算机无法访问指定设备路径或文件怎么回事,window无法访问指定设备 路径或文件是怎么回事...

    近日许多用户在咨询小编说自己的电脑在打开某些程序的时候 就出现提示window无法访问指定设备 路径或文件 从而导致程序的无法正常运行 许多用户对此也都不知该从而下手 非常烦恼 那么window无法访问指定设备 路径或文件怎么解决呢 下面小
  • UGUI内核大探究(九)Image与RawImage

    Image组件是UGUI里最常用的组件 可能没有之一 我们知道其实还有一个RawImage组件 那么二者的区别是什么呢 之前的文章UGUI内核大探究 八 MaskableGraphic中我们提到过 二者 连同Text 都继承自Maskabl