UGUI学习笔记(七)自己实现圆形图片组件

一、通过Mask组件实现

第一种实现方式是通过UGUI原生的「Mask」遮罩组件。实现起来非常简单,首先创建一个Image对象,并挂载「Mask」组件。然后将Image的Sprite设置为事先准备好的圆形图片

然后再将这个Image对象设置为目标对象的父物体即可

但是这种方式有个问题,Mask组件会增加额外的Draw Call调用(Shader中的概念),也就会增加额外的性能消耗。可以通过Game窗口中的Stats界面查看Draw Call调用情况

二、手动实现

2.1 修改渲染模式

既然要实现一个圆形图片组件,那么肯定是基于原生的「Image」组件实现的。因此我们创建一个空物体,并挂载一个空的脚本。让脚本中的类继承Image类

public class CircleImage : Image
{
   
   
    protected override void OnPopulateMesh(VertexHelper toFill)
    {
   
   
	    // 清除顶点数据  
		toFill.Clear();
    }
}

当一个UI元素生成顶点数据时,会调用OnPopulateMesh(VertexHelper toFill)方法。它传入了一个VertexHelper类型的参数,其中记录了将图片渲染到屏幕上所需的顶点和三角形信息。我们要做的就是重写这个方法,并对参数中的顶点和三角形信息进行修改,以达成将图片渲染成圆形的目的。

接下来我们需要将uv贴图坐标与渲染到场景中的坐标的对应关系计算出来。一张图片对应的uv坐标如下图所示

它的四个坐标点在Unity中由一个四维变量进行存储。获取到这个变量,以及UI的宽高后,就可以计算出uv中心点、uv坐标到UI坐标的换算比率等信息

// 获取当前图片的外层uv  
var uv = overrideSprite != null ? DataUtility.GetOuterUV(overrideSprite) : Vector4.zero;  
  
var width = rectTransform.rect.width;  
var height = rectTransform.rect.height;  
var uvWidth = uv.z - uv.x;  
var uvHeight = uv.w - uv.y;

// 获取uv中心点  
Vector2 uvCenter = new Vector2(uvWidth * 0.5f, uvHeight * 0.5f);  
// 计算换算比率  
Vector2 convertRatio = new Vector2(uvWidth / width, uvHeight / height);
// 计算UI中心点  
Vector2 originPos = new Vector2((0.5f - rectTransform.pivot.x) * width, (0.5f - rectTransform.pivot.y) * height);
// 整个圆形的半径  
var radius = width * 0.5f;

这里需要注意一点,计算UI的中点时,要考虑到UI锚点变化的问题。如果将中点始终设为(0,0)的话,当锚点挪动,图案也会跟着一起挪动。因此当锚点不再是(0.5,0.5)时,就需要给中点坐标加一个偏移值,使它始终保持在UI的中心位置。

我们知道,屏幕上显示出来的图案实际上是由GPU渲染出来的。而GPU渲染时是以三角形面片为基本单位进行绘制。三角形的数量越多,绘制出来的圆形也就越精细。

因而我们需要定义出圆形由多少块三角面片组成,后续可以更改这个值来调整圆形的渲染精度。

// 圆形由多少块三角面片拼成
private int _segments = 100;

有了三角面片的数量,我们就可以求出每个三角形所对应的弧度

// 每个三角形的弧度  
var radian = (2 * Mathf.PI) / _segments;

准备工作完成,我们现在可以来创建圆心点了。UI的顶点信息在Unity中以UIVertex对象进行存储。我们可以设置它的颜色、位置、uv坐标等信息。创建完成后将其添加到顶点集合中。

// 创建圆心顶点  
UIVertex origin = new();  
origin.color = color;  
origin.position = originPos;  
origin.uv0 = new Vector2(uvCenter.x, uvCenter.y);  
toFill.AddVert(origin);

接下来需要计算位于圆周上的顶点坐标。有每个三角形对应的弧度、圆形的半径,计算起来也很简单。这里注意Mathf.Cos(x)Mathf.Sin(x)传入的参数是弧度,而不是角度

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值