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)。

UGUI内核大探究(九)Image与RawImage相关推荐

  1. UGUI内核大探究(十二)Slider

    Slider是UGUI的一个组件,使用它可以实现滑动条,算是一个比较常用的组件,它与ScrollBar(参考UGUI内核大探究(十一)ScrollRect与ScrollBar)有些类似,但又不太相同. ...

  2. UGUI内核大探究(八)MaskableGraphic

    MaskableGraphic是UGUI的核心组件,它继承自Graphic.MaskableGraphic是一个抽象类,它的派生类有RawImage.Image.Text.顾名思义,MaskableG ...

  3. UGUI内核大探究(十六)InputField

    InputField是UGUI的重要组件,可以提供文本输入功能,是与用户交互的一个重要手段.我们可以在编辑器里,为OnValueChanged和OnEndEdit两个事件添加监听,这样就可以获得用户输 ...

  4. UGUI内核大探究(十八)Raycaster

    射线其实是属于事件系统,它在EventSystem/Raycasters目录下,有BaseRaycaster.PhysicsRaycaster和Physics2DRaycaster三个类,命名空间也是 ...

  5. UGUI内核大探究(十三)Dropdown

    Dropdown(下拉框)可谓是UGUI的集大成者,在Unity Editor里新建一个Dropdown,会随之附赠Text(Label对象).Image(Arrow对象).ScrollRect(Te ...

  6. UGUI内核大探究(二)执行事件

    UGUI内核大探究(一)EventSystem我们探究了事件系统,其中我们讲到EventSystem可以通过ExecuteEvents这个类来执行事件,那么事件是如何执行的呢?这里涉及到了两个文件Ev ...

  7. UGUI内核大探究(十一)ScrollRect与ScrollBar

    当我们在Unity Editor里创建一个Scroll View的时候含有ScrollRect的对象,它下面还有三个子对象,两个含有ScrollBar组件的子对象是作为滚动条,一个Viewport用于 ...

  8. UGUI内核大探究(一)EventSystem

    2019独角兽企业重金招聘Python工程师标准>>> UGUI是Unity3D官方推出的UI系统,为了更好的使用UGUI,我们就需要去了解它. UGUI代码开源,我们可以从bitb ...

  9. C语言之字符串探究(九):空格去除——trim系列

    相关博文:C++之char和string字符串类探究 相关博文:C语言之数组探究(一):定义.大小.初始化.访问和三要素 相关博文:C语言之字符串探究(一):字符串与字符数组 相关博文:C语言之字符串 ...

最新文章

  1. Opencv实战 | 用摄像头自动化跟踪特定颜色物体
  2. java中什么是递归_java中什么是递归
  3. matlab treeview,treeview控件
  4. Quartz简单实例
  5. 1、绪论初识机器学习
  6. 网站的iphone版快开发完了
  7. shell遍历文件夹
  8. Android NDK引用预编译的动态链接库
  9. 加密Spring加载的Properties文件
  10. 毕业后拉开距离的真正原因!
  11. Aerospike 使用场景
  12. 数据通信与计算机网络有哪些协议,​数据传输协议都有哪些?五种常用网络协议...
  13. 基于R语言地理探测器包(GD)空间异质性与驱动力分析
  14. linux——alsa中多个声卡设备时打开某一指定声卡的PCM设备
  15. hihoCoder 1498 Diligent Robots
  16. php处理抢购类功能的高并发请求,php处理抢购类
  17. 电脑数据怎么迁移?6种旧电脑数据传输到新电脑方法分享
  18. 4月11号软件资讯更新合集......
  19. UVC系列5-编写Android jni代码实现控制PTZ
  20. Redis常用的五种数据类型

热门文章

  1. DateUtils 工具类:获取指定月份第一天时间,最后一天时间
  2. Edge主页被360篡改的解决办法
  3. IE和谷歌浏览器主页被篡改的修复
  4. 收购Beat Game,Facebook离“VR游戏社交王国”梦还有多远?
  5. mysql bulkupdate_django_bulk_update源码分析
  6. 对于nth-child()的理解
  7. 视频怎么制作虚化边框背景的效果?
  8. HDU6057 Kanade‘s convolution
  9. openai的gym baseline spiningup 深度强化学习环境安装 手撸gym环境demo
  10. 弹出页面代码及相关解释