广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >Unity实现圆形Image组件
  • 794
分享到

Unity实现圆形Image组件

2024-04-02 19:04:59 794人浏览 泡泡鱼
摘要

本文实例为大家分享了Unity实现圆形Image组件的具体代码,供大家参考,具体内容如下 一、前言 游戏里很多图片都是以圆形展示的,例如头像、技能图标等,一般做法是使用Image组件

本文实例为大家分享了Unity实现圆形Image组件的具体代码,供大家参考,具体内容如下

一、前言

游戏里很多图片都是以圆形展示的,例如头像、技能图标等,一般做法是使用Image组件+Mask组件实现,但是Mask组件会影响效率(增加额外的drawcall)所以不建议大量使用

UGUI的Mask实现原理:利用GPU的模版缓冲

Mask组件会赋给父级和子级UI一个特殊的材质,这个材质会给Image的每个像素点进行标记并放在一个称为Stencil Buffer的缓存内,父级每个像素点的标记设置为1,子级UI进行渲染的时候会去检查这个Stencil Buffer内的标记是否为1,如果为1则进行渲染,否则不渲染

二、实现自己的圆形组件

像Image,RawImage这些组件都是继承自自MsakGraphics类,MsakGraphics类继承自Graphic类,Graphic类中有个OnPopulateMesh方法用于绘制图形,UGUI的Image组件实现原理是重写了OnPopulateMesh方法并绘制了一个矩形,所以按照这个思路我们可以重写OnPopulateMesh方法直接绘制一个圆形
——获取图片的长宽、uv等信息

——OnPopulateMesh:当UI元素生成顶点数据时会调用OnPopulateMesh(VertexHelper vh)函数,我们只需要将原先的矩形顶点数据清除,改写入圆形顶点数据,这样渲染出来的自然是圆形图片

——不规则UI元素的响应区域判定
UI组件的响应区域判定是通过实现IcanvasRaycastFilter接口中的IsRaycastLocationValid函数,它的返回值是一个bool值,返回true则视为可以响应,例如Image组件,它判定了两个条件:当前屏幕坐标是否在当前图片矩形区域内和当前屏幕坐标的图片区域透明度是否大于alphaHitTestMinimumThreshold参数
我们想实现精确的点击判断,可以代码动态将alphaHitTestMinimumThreshold参数设置为0.1,这样就实现了只有在透明度大于0.1的像素点才视为响应,但它要求图片的Read/Write Enabled必须开启,这就导致了图片占用了两份内存,所以不建议使用
对于像素级的点击判定,有一种算法可以实现:Ray-Crossing算法
此算法适用于所有图形,实现思路是从指定点向任意方向发出一条水平射线,与图形相交,如果交点是奇数个,则点在图形内,如果交点是偶数个,则点在图形外

using UnityEngine;
using UnityEngine.Sprites;
using UnityEngine.UI;
using System.Collections.Generic;
 
/// <summary>
/// 圆形Image组件
/// </summary>
[AddComponentMenu("LFramework/UI/CircleImage", 11)]
public class CircleImage : MaskableGraphic, ICanvasRaycastFilter
{
    /// <summary>
    /// 渲染类型
    /// </summary>
    public enum RenderType
    {
        Simple,
        Filled,
    }
 
    /// <summary>
    /// 填充类型
    /// </summary>
    public enum FilledType
    {
        Radial360,
    }
 
    /// <summary>
    /// 绘制起始点(填充类型-360度)
    /// </summary>
    public enum Origin360
    {
        Right,
        Top,
        Left,
        Bottom,
    }
 
    //Sprite图片
    [SerializeField]
    Sprite m_Sprite;
    public Sprite Sprite
    {
        get { return m_Sprite; }
    }
 
    //贴图
    public override Texture mainTexture
    {
        get
        {
            if (m_Sprite == null)
            {
                if (material != null && material.mainTexture != null)
                {
                    return material.mainTexture;
                }
                return s_WhiteTexture;
            }
 
            return m_Sprite.texture;
        }
    }
 
    //渲染类型
    [SerializeField]
    RenderType m_RenderType;
 
    //填充类型
    [SerializeField]
    FilledType m_FilledType;
 
    //绘制起始点(填充类型-360度)
    [SerializeField]
    Origin360 m_Origin360;
 
    //是否为顺时针绘制
    [SerializeField]
    bool m_Clockwise;
 
    //填充度
    [SerializeField]
    [Range(0, 1)]
    float m_FillAmount;
 
    //多少个三角面组成
    [SerializeField]
    int segements = 100;
 
    List<Vector3> vertexCache = new List<Vector3>();
 
    protected override void OnPopulateMesh(VertexHelper vh)
    {
        vh.Clear();
        vertexCache.Clear();
 
        switch (m_RenderType)
        {
            case RenderType.Simple:
                GenerateSimpleSprite(vh);
                break;
            case RenderType.Filled:
                GenerateFilledSprite(vh);
                break;
        }
    }
 
    void GenerateSimpleSprite(VertexHelper vh)
    {
        Vector4 uv = m_Sprite == null
            ? Vector4.zero
            : DataUtility.GetOuterUV(m_Sprite);
        float uvWidth = uv.z - uv.x;
        float uvHeight = uv.w - uv.y;
        float width = rectTransfORM.rect.width;
        float height = rectTransform.rect.height;
        float dia = width > height ? width : height;
        float r = dia * 0.5f;
        Vector2 uvCenter = new Vector2((uv.x + uv.z) * 0.5f, (uv.y + uv.w) * 0.5f);
        Vector3 posCenter = new Vector2((0.5f - rectTransform.pivot.x) * width, (0.5f - rectTransform.pivot.y) * height);
        float uvScaleX = uvWidth / width;
        float uvScaleY = uvHeight / height;
        float deltaRad = 2 * Mathf.PI / segements;
 
        float curRad = 0;
        int vertexCount = segements + 1;
        vh.AddVert(posCenter, color, uvCenter);
        for (int i = 0; i < vertexCount - 1; i++)
        {
            UIVertex vertex = new UIVertex();
            Vector3 posOffset = new Vector3(r * Mathf.Cos(curRad), r * Mathf.Sin(curRad));
            vertex.position = posCenter + posOffset;
            vertex.color = color;
            vertex.uv0 = new Vector2(uvCenter.x + posOffset.x * uvScaleX, uvCenter.y + posOffset.y * uvScaleY);
            vh.AddVert(vertex);
            vertexCache.Add(vertex.position);
 
            curRad += deltaRad;
        }
 
        for (int i = 0; i < vertexCount - 2; i++)
        {
            vh.AddTriangle(0, i + 1, i + 2);
        }
        vh.AddTriangle(0, segements, 1);
    }
 
    void GenerateFilledSprite(VertexHelper vh)
    {
        Vector4 uv = m_Sprite == null
            ? Vector4.zero
            : DataUtility.GetOuterUV(m_Sprite);
        float uvWidth = uv.z - uv.x;
        float uvHeight = uv.w - uv.y;
        float width = rectTransform.rect.width;
        float height = rectTransform.rect.height;
        float dia = width > height ? width : height;
        float r = dia * 0.5f;
        Vector2 uvCenter = new Vector2((uv.x + uv.z) * 0.5f, (uv.y + uv.w) * 0.5f);
        Vector3 posCenter = new Vector2((0.5f - rectTransform.pivot.x) * width, (0.5f - rectTransform.pivot.y) * height);
        float uvScaleX = uvWidth / width;
        float uvScaleY = uvHeight / height;
        float deltaRad = 2 * Mathf.PI / segements;
 
        switch (m_FilledType)
        {
            case FilledType.Radial360:
                float quarterRad = 2 * Mathf.PI * 0.25f;
                float curRad = quarterRad * (int)m_Origin360;
                int vertexCount = m_FillAmount == 1
                    ? segements + 1
                    : Mathf.RoundToInt(segements * m_FillAmount) + 2;
                vh.AddVert(posCenter, color, uvCenter);
                for (int i = 0; i < vertexCount - 1; i++)
                {
                    UIVertex vertex = new UIVertex();
                    Vector3 posOffset = new Vector3(r * Mathf.Cos(curRad), r * Mathf.Sin(curRad));
                    vertex.position = posCenter + posOffset;
                    vertex.color = color;
                    vertex.uv0 = new Vector2(uvCenter.x + posOffset.x * uvScaleX, uvCenter.y + posOffset.y * uvScaleY);
                    vh.AddVert(vertex);
                    vertexCache.Add(vertex.position);
 
                    curRad += m_Clockwise ? -deltaRad : deltaRad;
                }
 
                for (int i = 0; i < vertexCount - 2; i++)
                {
                    vh.AddTriangle(0, i + 1, i + 2);
                }
                if (m_FillAmount == 1)
                {
                    vh.AddTriangle(0, segements, 1);
                }
                break;
        }
    }
 
    public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
    {
        Vector2 localPos;
        int crossPointCount;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, sp, eventCamera, out localPos);
        RayCrossing(localPos, out crossPointCount);
        return crossPointCount % 2 != 0;
    }
 
    public void RayCrossing(Vector2 localPos, out int crossPointCount)
    {
        crossPointCount = 0;
        for (int i = 0; i < vertexCache.Count; i++)
        {
            Vector3 p1 = vertexCache[i];
            Vector3 p2 = vertexCache[(i + 1) % vertexCache.Count];
 
            if (p1.y == p2.y) continue;
            if (localPos.y <= Mathf.Min(p1.y, p2.y)) continue;
            if (localPos.y >= Mathf.Max(p1.y, p2.y)) continue;
            float crossX = (localPos.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x;
            if (crossX >= localPos.x)
            {
                crossPointCount++;
            }
        }
    }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。

--结束END--

本文标题: Unity实现圆形Image组件

本文链接: https://www.lsjlt.com/news/161874.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Unity实现圆形Image组件
    本文实例为大家分享了Unity实现圆形Image组件的具体代码,供大家参考,具体内容如下 一、前言 游戏里很多图片都是以圆形展示的,例如头像、技能图标等,一般做法是使用Image组件...
    99+
    2022-11-12
  • Unity如何实现圆形Image组件
    本文小编为大家详细介绍“Unity如何实现圆形Image组件”,内容详细,步骤清晰,细节处理妥当,希望这篇“Unity如何实现圆形Image组件”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。一、前言游戏里很多图片...
    99+
    2023-06-26
  • Android圆形控件实现画圆效果
    本文实例为大家分享了Android圆形控件实现画圆效果的具体代码,供大家参考,具体内容如下 实现圆形控件 实现如下 package com.example.demo.util;...
    99+
    2022-11-12
  • Android实现圆角矩形和圆形ImageView的方式
    Android中实现圆角矩形和圆形有很多种方式,其中最常见的方法有ImageLoader设置Option和自定义View。 1.ImageLoader加载图片 publi...
    99+
    2022-06-06
    Android
  • Android自定义控件之圆形/圆角的实现代码
    一、问题在哪里? 问题来源于app开发中一个很常见的场景——用户头像要展示成圆的:  二、怎么搞? 机智的我,第一想法就是,切一张中间圆形透明、四周与底色相同、尺寸...
    99+
    2022-06-06
    Android
  • Android自定义view实现圆形与半圆形菜单
    前不久看到鸿洋大大的圆形菜单,就想开始模仿,因为实在是太酷了,然后自己根据别人(zw哥)给我讲的一些思路、一些分析,就开始改造自己的圆形菜单了。 文章结构:1.功能介绍以及展示...
    99+
    2022-06-06
    菜单 view Android
  • 怎么在Android中使用圆形控件实现画圆效果
    这篇文章给大家介绍怎么在Android中使用圆形控件实现画圆效果,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。package com.example.demo.util;import android...
    99+
    2023-06-15
  • 基于Cesium实现绘制圆形,正方形,多边形,椭圆图形标注
    目录官方案例绘制矩形绘制多边形绘制椭圆绘制圆形绘制立方体绘制椭圆柱体绘制多边柱体绘制圆柱体立体串串好难形容 又平面又立体的板板“回”字绘制立方体,扭转一定角度...
    99+
    2022-11-13
  • Unity 实现删除missing脚本组件
    通过Resources.FindObjectsOfTypeAll查找所有GameObject,然后通过.hideFlags == HideFlags.None判断是否为存在于Hier...
    99+
    2022-11-12
  • Android自定义Drawable实现圆形和圆角
    本文实例为大家分享了自定义Drawable实现圆形和圆角的具体代码,供大家参考,具体内容如下圆形package com.customview.widget;import android.graphics.Bitmap;import andr...
    99+
    2023-05-30
    android drawable 圆形
  • Android自定义view实现圆形、圆角和椭圆图片(BitmapShader图形渲染)
    一、前言 Android实现圆角矩形,圆形或者椭圆等图形,一般主要是个自定义View加上使用Xfermode实现的。实现圆角图片的方法其实不少,常见的就是利用Xfermode,...
    99+
    2022-06-06
    view 图片 椭圆 Android
  • Android自定义控件实现圆形进度条
    项目中常用到的圆形进度条有好多个,从网上搜到的自定义进度条多是封装的比较好的代码,但是不利于初学者,现在本博客就教给大家如何一步步实现自定义进度条的效果: 先看效果如图… ...
    99+
    2022-06-06
    进度条 Android
  • Android基于Fresco实现圆角和圆形图片
    Fresco是FaceBook开源的Android平台图片加载库,可以从网络,从本地文件系统,本地资源加载图片 Fresco本身已经实现了圆角以及圆形图片的功能。 <!--圆形...
    99+
    2022-11-13
  • HTML5怎么实现圆角矩形
    今天小编给大家分享一下HTML5怎么实现圆角矩形的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下...
    99+
    2022-10-19
  • javascript实现canvas圆形橡皮擦
    在前端开发中,canvas是一个非常重要的技术,它可以让我们绘制各种图形,实现一些非常炫酷的效果。在很多情况下,我们需要实现一个橡皮擦功能,让用户可以擦除canvas上的一些元素,比如涂鸦、图片等。本文将介绍如何使用javascript实现...
    99+
    2023-05-17
  • Java实现圆形碰撞检测
    本文实例为大家分享了Java实现圆形碰撞检测的具体代码,供大家参考,具体内容如下 圆形碰撞图如下: 核心思路是:判断两个圆心之间的距离是否小于两个圆的半径之和。 实现代码如下: ...
    99+
    2022-11-12
  • Android实现圆形图片效果
    本文实例为大家分享了Android实现圆形图片效果的具体代码,供大家参考,具体内容如下 创建RoundPicture.java文件 在src/main/java/XX包下新建Ro...
    99+
    2022-11-12
  • Android View实现圆形进度条
    本文实例为大家分享了Android View实现圆形进度条的具体代码,供大家参考,具体内容如下 主要涉及到下面几个方法: // 画圆 canvas.drawCircle // 画...
    99+
    2022-11-12
  • vue3+ts实现树形组件(菜单组件)
    目录前言全局注册组件组件的实现树形组件的基本结构:完善组件(添加点击事件,过渡效果)✌️✌️添加过渡总结:前言 之前在使用element-plus的使用,使用el-menu组件,并且...
    99+
    2023-05-18
    vue3 ts 树形组件 vue3 ts菜单组件
  • Unity UI组件ScrollRect实现无限滚动条
    在游戏开发中经常遇到滚动显示的数据,特别是商店商品 排行榜 .......等数据很多,每一条数据去加载一个UI来显示显然对内存浪费很大,这种情况处理一般就是用几个显示条可滚动循环显示...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作