Unity镂空图像做法

news/2024/9/22 19:59:48/

问题和解决方案

现在要完成一个需求,即镂空中间部分的image,外围image可以定义颜色并可选屏蔽点击,而中间的image需要透明且可以穿透,必须不能屏蔽点击。

由此拆分成了两个问题:

1.定义外围image颜色,内部image不绘制

2.外围image可选raycast target,内围image不受raycast target标志位影响。

由此可继承Graphic和ICanvasRaycastFilter来分别实现这个目标。

OnPopulateMesh

继承graphic脚本后重写Graphic.OnPopulateMesh函数,可以在里面去完成重绘操作。与其说不绘制中间的这部分范围,不如说只绘制外面的范围。用VertexHelper.AddTriangle即可完成简单的三角形绘制工作,由此可以根据外image顶点和内image顶点来完成八个三角形的构建绘制工作,如下示意图所示:

因此代码如下所示:

protected override void OnPopulateMesh(VertexHelper vh)
{if (innerTrans == null){base.OnPopulateMesh(vh);return;}vh.Clear();UIVertex vertex = UIVertex.simpleVert;vertex.color = color;//0 outer左下角vertex.position = new Vector3(outerLeftBottom.x, outerLeftBottom.y);vh.AddVert(vertex);//1 outer左上角vertex.position = new Vector3(outerLeftBottom.x, outerRightTop.y);vh.AddVert(vertex);//2 outer右上角vertex.position = new Vector3(outerRightTop.x, outerRightTop.y);vh.AddVert(vertex);//3 outer右下角vertex.position = new Vector3(outerRightTop.x, outerLeftBottom.y);vh.AddVert(vertex);//4 inner左下角vertex.position = new Vector3(innerLeftBottom.x, innerLeftBottom.y);vh.AddVert(vertex);//5 inner左上角vertex.position = new Vector3(innerLeftBottom.x, innerLeftTop.y);vh.AddVert(vertex);//6 inner右上角vertex.position = new Vector3(innerLeftTop.x, innerLeftTop.y);vh.AddVert(vertex);//7 inner右下角vertex.position = new Vector3(innerLeftTop.x, innerLeftBottom.y);vh.AddVert(vertex);//绘制三角形vh.AddTriangle(0, 1, 4);vh.AddTriangle(1, 4, 5);vh.AddTriangle(1, 5, 2);vh.AddTriangle(2, 5, 6);vh.AddTriangle(2, 6, 3);vh.AddTriangle(6, 3, 7);vh.AddTriangle(4, 7, 3);vh.AddTriangle(0, 4, 3);
}

IsRaycastLocationValid

继承ICanvasRaycastFilter接口,重写内置的IsRaycastLocationValid即可:

return innerTrans == null || !RectTransformUtility.RectangleContainsScreenPoint(innerTrans, sp, eventCamera);

整体代码:

public class HollowOutMask : Graphic, ICanvasRaycastFilter
{[Header("镂空区域")]public RectTransform innerTrans;RectTransform outerTrans;//背景区域Vector3 innerLeftTop = Vector3.zero;//镂空区域的右上角坐标Vector3 innerLeftBottom = Vector3.zero;//镂空区域的左下角坐标Vector2 outerRightTop = Vector2.zero;//背景区域的右上角坐标Vector2 outerLeftBottom = Vector2.zero;//背景区域的左下角坐标protected override void Awake(){base.Awake();outerTrans = GetComponent<RectTransform>();}protected override void OnPopulateMesh(VertexHelper vh){if (innerTrans == null){base.OnPopulateMesh(vh);return;}vh.Clear();UIVertex vertex = UIVertex.simpleVert;vertex.color = color;//0 outer左下角vertex.position = new Vector3(outerLeftBottom.x, outerLeftBottom.y);vh.AddVert(vertex);//1 outer左上角vertex.position = new Vector3(outerLeftBottom.x, outerRightTop.y);vh.AddVert(vertex);//2 outer右上角vertex.position = new Vector3(outerRightTop.x, outerRightTop.y);vh.AddVert(vertex);//3 outer右下角vertex.position = new Vector3(outerRightTop.x, outerLeftBottom.y);vh.AddVert(vertex);//4 inner左下角vertex.position = new Vector3(innerLeftBottom.x, innerLeftBottom.y);vh.AddVert(vertex);//5 inner左上角vertex.position = new Vector3(innerLeftBottom.x, innerLeftTop.y);vh.AddVert(vertex);//6 inner右上角vertex.position = new Vector3(innerLeftTop.x, innerLeftTop.y);vh.AddVert(vertex);//7 inner右下角vertex.position = new Vector3(innerLeftTop.x, innerLeftBottom.y);vh.AddVert(vertex);//绘制三角形vh.AddTriangle(0, 1, 4);vh.AddTriangle(1, 4, 5);vh.AddTriangle(1, 5, 2);vh.AddTriangle(2, 5, 6);vh.AddTriangle(2, 6, 3);vh.AddTriangle(6, 3, 7);vh.AddTriangle(4, 7, 3);vh.AddTriangle(0, 4, 3);}/// <summary>/// 过滤掉射线检测/// </summary>public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera){return innerTrans == null || !RectTransformUtility.RectangleContainsScreenPoint(innerTrans, sp, eventCamera);}private bool NeedUpdateBounds(){if (innerTrans == null){return false;}Bounds bounds = RectTransformUtility.CalculateRelativeRectTransformBounds(outerTrans, innerTrans);if (innerLeftTop == bounds.max&& innerLeftBottom == bounds.min&& outerRightTop == outerTrans.rect.max&& outerLeftBottom == outerTrans.rect.min){return false;}return true;}private void UpdateBounds(){if (innerTrans == null){return;}Bounds bounds = RectTransformUtility.CalculateRelativeRectTransformBounds(outerTrans, innerTrans);innerLeftTop = bounds.max;innerLeftBottom = bounds.min;outerRightTop = outerTrans.rect.max;outerLeftBottom = outerTrans.rect.min;}private void Update(){if(NeedUpdateBounds()){UpdateBounds();SetAllDirty();}}
}

注意我们需要赋值一个innerImage transform给这个graphic脚本,作为内image大小和位置控制;而外image则调整挂载这个graphic脚本本身的transform即可。


http://www.ppmy.cn/news/1444918.html

相关文章

第13天 String,正则表达式,String 支持正则表达式,object,JavaBean

String 字符串.charAt(索引值):获取字符串中索引处的字符 char[] chars 字符串.tocharArray(); : 将字符串转换为字符数组 String s new String(字符数组名,起始索引&#xff0c;截取字符串总共的长度) &#xff1a;截取一部分字符数组转化为字符串 String s new String(字…

小米金融守护消费权益,共筑金融和谐新篇章

随着金融市场的日益成熟&#xff0c;金融消费者的权益保护问题逐渐受到广泛关注。作为金融服务体系中的重要一环&#xff0c;保护消费者权益不仅是金融机构的基本职责&#xff0c;更是其长远发展的基石。小米金融聚焦于金融消费者权益保护&#xff0c;通过梳理典型案例&#xf…

idea常用知识点随记

idea常用知识点随记 1. 打开idea隐藏的commit窗口2. idea中拉取Git分支代码3. idea提示代码报错&#xff0c;项目编译没有报错4. idea中实体类自动生成序列号5. idea隐藏当前分支未commit代码6. idea拉取新建分支的方法 1. 打开idea隐藏的commit窗口 idea左上角File→Settings…

微服务使用SockJs+Stomp实现Websocket 前后端实例 | Vuex形式断开重连、跨域等等问题踩坑(二)

大家好&#xff0c;我是程序员大猩猩。 上次我们实践了&#xff0c;Java后端如何完成SockJSStomp的配置实现。 微服务使用SockJsStomp实现Websocket 前后端实例 | Vuex形式断开重连、跨域等等问题踩坑&#xff08;一&#xff09; 那么今天我们做一下web vue端的是如何来实现…

web server apache tomcat11-28-Windows Service

前言 整理这个官方翻译的系列&#xff0c;原因是网上大部分的 tomcat 版本比较旧&#xff0c;此版本为 v11 最新的版本。 开源项目 从零手写实现 tomcat minicat 别称【嗅虎】心有猛虎&#xff0c;轻嗅蔷薇。 系列文章 web server apache tomcat11-01-官方文档入门介绍 web…

为什么centos官方版不支持arm架构?

为什么centos官方版不支持arm架构&#xff1f; 1、资源限制&#xff1a;CentOS是由社区维护的开源操作系统&#xff0c;其开发和维护需要大量的人力和物力资源。由于ARM架构的设备相对较少&#xff0c;社区资源有限&#xff0c;因此官方版CentOS选择集中精力在x86架构上进行开发…

数据的定义及其分类

1&#xff09;、数据&#xff1a;任何以电子或者其他方式对信息的记录 2&#xff09;、重要数据&#xff1a;特定领域、特定群体、特定区域或者达到一定精度和规模的、一旦被篡改或者泄露、损毁&#xff0c;可能直接危害国家安全、经济运行、社会稳定、公共健康和安全的数据&a…

上海亚商投顾:沪指创年内新高 房地产板块掀涨停潮

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 三大指数昨日继续反弹&#xff0c;沪指盘中涨超1%&#xff0c;重返3100点上方&#xff0c;深成指涨超2%&#…