【Unity实战篇 】 | Unity实现UGUI颜色渐变,支持透明渐变

news2024/11/25 1:55:58

请添加图片描述

      • 前言
  • 【Unity实战篇 】 | Unity实现UGUI颜色渐变,支持透明渐变
    • 一、双层颜色渐变
      • 1.1 组件属性面板
      • 1.2 效果及代码
    • 二、多层颜色渐变
      • 2.1 组件属性面板
      • 2.2 效果及代码
  • 总结

请添加图片描述


前言

  • 在Unity中UGUI的实现图片和文字颜色渐变效果是一个很常见的需求。
  • 下面就来看一下颜色渐变效果是怎样实现的吧。

【Unity实战篇 】 | Unity实现UGUI颜色渐变,支持透明渐变

效果展示
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述

一、双层颜色渐变

双层颜色渐变 是游戏中用到的比较多的效果,实现方式也比较简单,下面看下效果和实现方式。

1.1 组件属性面板

在这里插入图片描述

属性说明
Direction方向
Color1颜色1
Color2颜色2
range偏移量
isFlip是否翻转

通过配置参数可以调节渐变的颜色、偏移量和翻转效果。


1.2 效果及代码

在这里插入图片描述

完整代码如下:

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Gradient : BaseMeshEffect
{
    public enum DirectionType
    {
        Horizontal,
        Vertical,
    }

    [SerializeField]
    private DirectionType m_Direction = DirectionType.Vertical;
    [SerializeField]
    public Color32 m_Color1 = Color.white;
    [SerializeField]
    public Color32 m_Color2 = Color.white;

    [SerializeField]
    private float m_Range = 0f;
    [SerializeField]
    private bool m_Flip = false;

    public override void ModifyMesh(VertexHelper vh)
    {
        if (!IsActive() || vh.currentVertCount <= 0)
        {
            return;
        }

        int count = vh.currentVertCount;
        List<UIVertex> vertices = new List<UIVertex>();
        for (int i = 0; i < count; i++)
        {
            UIVertex uIVertex = new UIVertex();
            vh.PopulateUIVertex(ref uIVertex, i);
            vertices.Add(uIVertex);
        }
        switch (m_Direction)
        {
            case DirectionType.Horizontal:
                DrawHorizontal(vh, vertices, count);
                break;
            case DirectionType.Vertical:
                DrawVertical(vh, vertices, count);
                break;
            default:
                break;
        }
    }

    private void DrawVertical(VertexHelper vh, List<UIVertex> vertices, int count)
    {
        float topY = vertices[0].position.y;
        float bottomY = vertices[0].position.y;
        for (int i = 0; i < count; i++)
        {
            float y = vertices[i].position.y;
            if (y > topY)
            {
                topY = y;
            }
            else if (y < bottomY)
            {
                bottomY = y;
            }
        }

        float height = topY - bottomY;
        for (int i = 0; i < count; i++)
        {
            UIVertex vertex = vertices[i];
            Color32 color = Color.white;
            if (m_Flip)
            {
                color = Color32.Lerp(m_Color2, m_Color1, 1 - (vertex.position.y - bottomY) / height * (1f - m_Range));
            }
            else
            {
                color = Color32.Lerp(m_Color2, m_Color1, (vertex.position.y - bottomY) / height * (1f - m_Range));
            }
            vertex.color = color;
            vh.SetUIVertex(vertex, i);
        }
    }
    private void DrawHorizontal(VertexHelper vh, List<UIVertex> vertices, int count)
    {
        float topX = vertices[0].position.x;
        float bottomX = vertices[0].position.x;
        for (int i = 0; i < count; i++)
        {
            float y = vertices[i].position.x;
            if (y > topX)
            {
                topX = y;
            }
            else if (y < bottomX)
            {
                bottomX = y;
            }
        }

        float height = topX - bottomX;
        for (int i = 0; i < count; i++)
        {
            UIVertex vertex = vertices[i];
            Color32 color = Color.white;
            if (m_Flip)
            {
                color = Color32.Lerp(m_Color1, m_Color2, 1 - (vertex.position.x - bottomX) / height * (1f - m_Range));
            }
            else
            {
                color = Color32.Lerp(m_Color1, m_Color2, (vertex.position.x - bottomX) / height * (1f - m_Range));
            }
            vertex.color = color;
            vh.SetUIVertex(vertex, i);
        }
    }
}

使用ModifyMesh()方法(通常在实现IMeshModifier接口时被重写,这个接口允许开发者自定义UI元素在渲染时的外观)进行网格修改。

比如垂直渐变时,找到图形的顶部和底部顶点并计算出高度差,然后计算出所有顶点位置的颜色值,并根据设置好的颜色进行赋值即可完成颜色渐变效果。


二、多层颜色渐变

在有些情况下双层渐变可能满足不了需求,需要用到多层颜色渐变的效果。

2.1 组件属性面板

在这里插入图片描述

属性说明
Direction方向
ColorArray颜色数组
Flip是否翻转

2.2 效果及代码

在这里插入图片描述

完整代码如下:

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Gradients : BaseMeshEffect
{
    /// <summary>
    /// 渐变方向
    /// </summary>
    public enum DirectionType
    {
        Horizontal,
        Vertical,
    }

    [SerializeField]
    private DirectionType direction = DirectionType.Horizontal;
    [SerializeField]
    private Color32[] m_ColorArray = new Color32[2] { Color.black, Color.white };

    [SerializeField]
    private bool m_Flip = false;

    //每一个文字的顶点数
    int m_VertexCountPer = 6;
    //顶点缓存
    List<UIVertex> m_VertexCache = new List<UIVertex>();
    //绘制使用的顶点列表
    List<UIVertex> m_VertexList = new List<UIVertex>();

    public override void ModifyMesh(VertexHelper vh)
    {
        if (!IsActive() || m_ColorArray.Length < 2) { return; }

        vh.GetUIVertexStream(m_VertexCache);

        if (m_VertexCache.Count == 0) { return; }

        switch (direction)
        {
            case DirectionType.Horizontal:
                ApplyGradient_Horizontal(m_VertexCache, m_ColorArray.Length);
                break;
            case DirectionType.Vertical:
                ApplyGradient_Vertical(m_VertexCache, m_ColorArray.Length);
                break;
            default:
                break;
        }

        vh.Clear();
        vh.AddUIVertexTriangleStream(m_VertexList);
        m_VertexCache.Clear();
        m_VertexList.Clear();
    }

    void ApplyGradient_Horizontal(List<UIVertex> vertexCache, int colorCount)
    {
        for (int n = 0; n < m_VertexCache.Count / 6; n++)
        {
            UIVertex lastVertexLT = new UIVertex();
            UIVertex lastVertexLB = new UIVertex();
            UIVertex lastVertexRT = new UIVertex();
            UIVertex lastVertexRB = new UIVertex();
            for (int i = 0; i < colorCount - 1; i++)
            {
                UIVertex vertexRT;
                UIVertex vertexLT;
                UIVertex vertexRB;
                UIVertex vertexLB;

                //翻转
                if (m_Flip)
                {
                    //右上角和右下角
                    if (i == 0)
                    {
                        vertexRT = CalcVertex(vertexCache[n * m_VertexCountPer + 1], m_ColorArray[i]);
                        vertexRB = CalcVertex(vertexCache[n * m_VertexCountPer + 2], m_ColorArray[i]);
                    }
                    else
                    {
                        vertexRT = lastVertexLT;
                        vertexRB = lastVertexLB;
                    }

                    //左上角和左下角
                    if (i == colorCount - 2)
                    {
                        vertexLT = CalcVertex(vertexCache[n * m_VertexCountPer + 0], m_ColorArray[i + 1]);
                        vertexLB = CalcVertex(vertexCache[n * m_VertexCountPer + 4], m_ColorArray[i + 1]);
                    }
                    else
                    {
                        vertexLT = CalcVertex(vertexCache[n * m_VertexCountPer + 0], vertexCache[n * m_VertexCountPer + 1],
                            (colorCount - i - 2) * 1f / (colorCount - 1), m_ColorArray[i + 1]);
                        vertexLB = CalcVertex(vertexCache[n * m_VertexCountPer + 4], vertexCache[n * m_VertexCountPer + 2],
                            (colorCount - i - 2) * 1f / (colorCount - 1), m_ColorArray[i + 1]);
                    }

                    lastVertexLT = vertexLT;
                    lastVertexLB = vertexLB;
                }
                else
                {
                    //左上角和左下角
                    if (i == 0)
                    {
                        vertexLT = CalcVertex(vertexCache[n * m_VertexCountPer + 0], m_ColorArray[i]);
                        vertexLB = CalcVertex(vertexCache[n * m_VertexCountPer + 4], m_ColorArray[i]);
                    }
                    else
                    {
                        vertexLT = lastVertexRT;
                        vertexLB = lastVertexRB;
                    }

                    //右上角和右下角
                    if (i == colorCount - 2)
                    {
                        vertexRT = CalcVertex(vertexCache[n * m_VertexCountPer + 1], m_ColorArray[i + 1]);
                        vertexRB = CalcVertex(vertexCache[n * m_VertexCountPer + 2], m_ColorArray[i + 1]);
                    }
                    else
                    {
                        vertexRT = CalcVertex(vertexCache[n * m_VertexCountPer + 1], vertexCache[n * m_VertexCountPer + 0],
                            (colorCount - i - 2) * 1f / (colorCount - 1), m_ColorArray[i + 1]);
                        vertexRB = CalcVertex(vertexCache[n * m_VertexCountPer + 2], vertexCache[n * m_VertexCountPer + 4],
                            (colorCount - i - 2) * 1f / (colorCount - 1), m_ColorArray[i + 1]);
                    }

                    lastVertexRT = vertexRT;
                    lastVertexRB = vertexRB;
                }

                m_VertexList.Add(vertexLT);
                m_VertexList.Add(vertexRT);
                m_VertexList.Add(vertexRB);
                m_VertexList.Add(vertexRB);
                m_VertexList.Add(vertexLB);
                m_VertexList.Add(vertexLT);
            }
        }
    }

    void ApplyGradient_Vertical(List<UIVertex> vertexCache, int colorCount)
    {
        for (int n = 0; n < m_VertexCache.Count / 6; n++)
        {
            UIVertex lastVertexLT = new UIVertex();
            UIVertex lastVertexRT = new UIVertex();
            UIVertex lastVertexLB = new UIVertex();
            UIVertex lastVertexRB = new UIVertex();

            for (int i = 0; i < colorCount - 1; i++)
            {
                UIVertex vertexRT;
                UIVertex vertexLT;
                UIVertex vertexRB;
                UIVertex vertexLB;

                //翻转
                if (m_Flip)
                {
                    //左下角和右下角
                    if (i == 0)
                    {
                        vertexLB = CalcVertex(vertexCache[n * m_VertexCountPer + 4], m_ColorArray[i]);
                        vertexRB = CalcVertex(vertexCache[n * m_VertexCountPer + 2], m_ColorArray[i]);
                    }
                    else
                    {
                        vertexLB = lastVertexLT;
                        vertexRB = lastVertexRT;
                    }

                    //左上角和右上角
                    if (i == colorCount - 2)
                    {
                        vertexLT = CalcVertex(vertexCache[n * m_VertexCountPer + 0], m_ColorArray[i + 1]);
                        vertexRT = CalcVertex(vertexCache[n * m_VertexCountPer + 1], m_ColorArray[i + 1]);
                    }
                    else
                    {
                        vertexLT = CalcVertex(vertexCache[n * m_VertexCountPer + 0], vertexCache[n * m_VertexCountPer + 4],
                            (colorCount - i - 2) * 1f / (colorCount - 1), m_ColorArray[i + 1]);
                        vertexRT = CalcVertex(vertexCache[n * m_VertexCountPer + 1], vertexCache[n * m_VertexCountPer + 2],
                            (colorCount - i - 2) * 1f / (colorCount - 1), m_ColorArray[i + 1]);
                    }
                    lastVertexLT = vertexLT;
                    lastVertexRT = vertexRT;
                }
                else
                {
                    //左上角和右上角
                    if (i == 0)
                    {
                        vertexLT = CalcVertex(vertexCache[n * m_VertexCountPer + 0], m_ColorArray[i]);
                        vertexRT = CalcVertex(vertexCache[n * m_VertexCountPer + 1], m_ColorArray[i]);
                    }
                    else
                    {
                        vertexLT = lastVertexLB;
                        vertexRT = lastVertexRB;
                    }

                    //左下角和右下角
                    if (i == colorCount - 2)
                    {

                        vertexLB = CalcVertex(vertexCache[n * m_VertexCountPer + 4], m_ColorArray[i + 1]);
                        vertexRB = CalcVertex(vertexCache[n * m_VertexCountPer + 2], m_ColorArray[i + 1]);
                    }
                    else
                    {
                        vertexLB = CalcVertex(vertexCache[n * m_VertexCountPer + 4], vertexCache[n * m_VertexCountPer + 0],
                            (colorCount - i - 2) * 1f / (colorCount - 1), m_ColorArray[i + 1]);
                        vertexRB = CalcVertex(vertexCache[n * m_VertexCountPer + 2], vertexCache[n * m_VertexCountPer + 1],
                            (colorCount - i - 2) * 1f / (colorCount - 1), m_ColorArray[i + 1]);
                    }
                    lastVertexLB = vertexLB;
                    lastVertexRB = vertexRB;
                }

                m_VertexList.Add(vertexLT);
                m_VertexList.Add(vertexRT);
                m_VertexList.Add(vertexRB);
                m_VertexList.Add(vertexRB);
                m_VertexList.Add(vertexLB);
                m_VertexList.Add(vertexLT);
            }
        }
    }

    /// <summary>
    /// 计算顶点数据(只计算颜色)
    /// </summary>
    UIVertex CalcVertex(UIVertex vertex, Color32 color)
    {
        vertex.color = color;
        return vertex;
    }

    /// <summary>
    /// 计算顶点数据
    /// </summary>
    UIVertex CalcVertex(UIVertex vertexA, UIVertex vertexB, float ratio, Color32 color)
    {
        UIVertex vertexTemp = new UIVertex();
        vertexTemp.position = (vertexB.position - vertexA.position) * ratio + vertexA.position;
        vertexTemp.color = color;
        vertexTemp.normal = (vertexB.normal - vertexA.normal) * ratio + vertexA.normal;
        vertexTemp.tangent = (vertexB.tangent - vertexA.tangent) * ratio + vertexA.tangent;
        vertexTemp.uv0 = (vertexB.uv0 - vertexA.uv0) * ratio + vertexA.uv0;
        vertexTemp.uv1 = (vertexB.uv1 - vertexA.uv1) * ratio + vertexA.uv1;
        return vertexTemp;
    }
}

使用时将该渐变脚本挂载到Image或者Text组件上,然后配置自己所需的参数即可。


总结

  • 本文提供了两种UGUI颜色渐变的方法,可以满足多数使用情景。
  • 如果有更好的解决方案,也可以在评论区指出一起分享学习!

  • 🎬 博客主页:https://xiaoy.blog.csdn.net

  • 🎥 本文由 呆呆敲代码的小Y 原创 🙉

  • 🎄 学习专栏推荐:Unity系统学习专栏

  • 🌲 游戏制作专栏推荐:游戏制作

  • 🌲Unity实战100例专栏推荐:Unity 实战100例 教程

  • 🏅 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!

  • 📆 未来很长,值得我们全力奔赴更美好的生活✨

  • ------------------❤️分割线❤️-------------------------

请添加图片描述请添加图片描述请添加图片描述

请添加图片描述

资料白嫖,技术互助

学习路线指引(点击解锁)知识定位人群定位
🧡 Unity系统学习专栏 🧡入门级本专栏从Unity入门开始学习,快速达到Unity的入门水平
💛 Unity实战类项目 💛进阶级计划制作Unity的 100个实战案例!助你进入Unity世界,争取做最全的Unity原创博客大全。
❤️ 游戏制作专栏 ❤️ 难度偏高分享学习一些Unity成品的游戏Demo和其他语言的小游戏!
💚 游戏爱好者万人社区💚 互助/吹水数万人游戏爱好者社区,聊天互助,白嫖奖品
💙 Unity100个实用技能💙 Unity查漏补缺针对一些Unity中经常用到的一些小知识和技能进行学习介绍,核心目的就是让我们能够快速学习Unity的知识以达到查漏补缺

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1797538.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【微前端实战总结篇】

微前端现有的落地方案可以分为三类&#xff0c;自组织模式、基座模式以及模块加载模式。 一、为什么需要微前端? 这里我们通过3W(what,why,how)的方式来讲解什么是微前端&#xff1a; 1.What?什么是微前端? 微前端就是将不同的功能按照不同的维度拆分成多个子应用。通过主应…

面向AI应用开发实战分享 - 基础篇

“前端转AI&#xff0c;第一讲来了” 引言 如果你是一名前端开发&#xff0c;同时又对AI开发很感兴趣&#xff0c;那么恭喜你&#xff0c;机会来了。 如果不是也没关系&#xff0c;同样能帮大家了解AI应用的开发思路。 本文将带大家从面向AI开发的基础知识开始&#xff0c;再…

1、旋转在三维空间中的表现形式

有4种表达方式&#xff1a;旋转矩阵SO(3)、四元数、旋转向量和欧拉角。 一、旋转矩阵SO(3) 定义&#xff1a;旋转矩阵是一个33的正交矩阵&#xff0c;且行列式为1。表示&#xff1a;可逆矩阵&#xff0c;逆矩阵和转置矩阵相同&#xff0c;表示相反的旋转。优点&#xff1a;可…

卫星通信频段有哪些

卫星通信使用到的频段涵盖L, S, C, Ku, Ka等&#xff0c;而最常用的频段是C(4~8GHz)和Ku(12~18GHz)频段&#xff0c;而Ka(27-40GHz)频段是后起之秀。目前地球赤道上空有限的地球同步卫星轨位几乎已被各国占满&#xff0c;C和Ku频段内的频率资源被大量使用&#xff0c;而Ka频段的…

1347:【例4-8】格子游戏

【解题思路】 该题为判断无向图是否有环。可以使用并查集来完成。学习并查集时&#xff0c;每个元素都由一个整数来表示。而该问题中每个元素是一个坐标点&#xff0c;由(x, y)两个整数构成。 将二维坐标变为一个整数,通过一个公式将二维坐标换算为一个整数&…

弘君资本:20家退市!港交所迎“新”扫“旧”

港交所行政总裁陈翊庭周三到会彭博亚洲财富峰会时表明&#xff0c;对研制开支大的企业和许多科技企业来说&#xff0c;香港商场仍是具备招引力的上市渠道&#xff0c;上市规矩18C章可满足特专科技企业需求。 值得一提的是&#xff0c;首家特专科技新股晶泰科技已于6月4日正式进…

抖音小红书淘宝拼多多商家订单对接ERP|获取电商平台订单信息(商家授权)

custom-自定义API操作 支持抖音拼多多淘宝小红书 公共参数 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,item_…

恢复误删和格式化的文件的利器

一、简介 1、一款由Piriform开发的免费文件恢复工具,它能够帮助用户恢复那些不小心从电脑上删除的文件,包括从回收站清空的文件,以及因用户错误操作而从存储设备中删除的图片、音乐、文档等多种格式的文件。Recuva支持对硬盘、闪存卡、U盘等多种存储介质进行扫描与恢复,并且…

AI魔法相机:实时3D重建与场景魔法化

一、产品概述 AI魔法相机是一款创新的硬件产品,它结合了AI技术和3D重建扫描技术,能够实时捕捉并重建3D场景和物理世界。用户只需通过简单的点击操作,即可捕捉现实物体或环境,并将其无缝融合到任何场景中,创造出全新的想象现实。 二、核心功能 实时捕捉:一键式操作,迅速…

Redis限流方案

限流简介 限流算法在分布式领域是一个经常被提起的话题&#xff0c;当系统的处理能力有限时&#xff0c;如何阻止计划外的请求继续对系统施压&#xff0c;是一个需要重视的问题。 除了控制流量&#xff0c;限流还有一个应用目的是用于控制用户行为&#xff0c;避免垃圾请求&a…

java版spring cloud 知识付费平台的功能模块与子模块划分

随着互联网技术的飞速发展&#xff0c;知识付费平台已经成为了我国在线教育领域的一颗新星。这些平台以用户需求为出发点&#xff0c;围绕高质量的内容打造&#xff0c;利用互联网技术为用户提供了一个便捷、高效的学习环境。它们汇聚了丰富的专业知识&#xff0c;覆盖了职业技…

Pulsar 社区周报 | No.2024-05-30 | BIGO 百页小册《Apache Pulsar 调优指南》

“ 各位热爱 Pulsar 的小伙伴们&#xff0c;Pulsar 社区周报更新啦&#xff01;这里将记录 Pulsar 社区每周的重要更新&#xff0c;每周发布。 ” BIGO 百页小册《Apache Pulsar 调优指南》 Hi&#xff0c;Apache Pulsar 社区的小伙伴们&#xff0c;社区 2024 上半年度的有奖问…

STM8单片机变频器设计

变频调速技术是现代电力传动技术的重要发展方向,而作为变频调速系统的核心—变频器的性能也越来越成为调速性能优劣的决定因素,除了变频器本身制造工艺的“先天”条件外,对变频器采用什么样的控制方式也是非常重要的。随着电力电子技术、微电子技术、计算机网络等高新技术的…

springboot 医院预约挂号app-计算机毕业设计源码65042

摘 要 随着互联网时代的到来&#xff0c;同时计算机网络技术高速发展&#xff0c;网络管理运用也变得越来越广泛。因此&#xff0c;建立一个B/S结构的医院预约挂号系统&#xff0c;会使&#xff1b;医院预约挂号系统的管理工作系统化、规范化&#xff0c;也会提高平台形象&…

el-date-picker的结束日期的时分秒为0:0:0时修改成23:59:59

<el-date-pickerv-model"taskTime"type"datetimerange"range-separator"-"start-placeholder"开始时间"end-placeholder"结束时间"change"handleTimeChange" /> js <script setup lang"ts"&…

XR和Steam VR项目合并问题

最近有一个项目是用Steam VR开发的&#xff0c;里面部分场景是用VRTK框架做的&#xff0c;还有一部分是用SteamVR SDK自带的Player预制直接开发的。 这样本身没有问题&#xff0c;因为最终都是通过SteamVR SDK处理的&#xff0c;VRTK也管理好了SteamVR的逻辑&#xff0c;并且支…

java:一个简单的WebFlux的例子

【pom.xml】 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId><version>2.3.12.RELEASE</version> </dependency> <dependency><groupId>org.spr…

从传统工厂到数字化工厂,从这几方面着手

信息技术与制造技术的结合&#xff0c;产生了新的生产实现模式&#xff0c;是制造业迈向智能化的重要标志。实践应用表明&#xff0c;数字化工厂可以缩短制造周期&#xff0c;优化生产流程&#xff0c;提高协同工作能力&#xff0c;降低成本。 从传统工厂到数字化工厂的转型是一…

.NET集成DeveloperSharp操作Redis缓存

&#x1f3c6;作者&#xff1a;科技、互联网行业优质创作者 &#x1f3c6;专注领域&#xff1a;.Net技术、软件架构、人工智能、数字化转型、DeveloperSharp、微服务、工业互联网、智能制造 &#x1f3c6;欢迎关注我&#xff08;Net数字智慧化基地&#xff09;&#xff0c;里面…

优思学院|一文看懂新版FMEA与FMEA的七大步骤

FMEA的起源 FMEA最早起源于20世纪40年代的美国军工行业。当时&#xff0c;美国军方为了提高武器系统的可靠性和安全性&#xff0c;开始使用FMEA来识别和评估潜在的故障模式及其影响。1949年&#xff0c;美国军方发布了《军用程序手册》&#xff08;Military Procedures Handbo…