- 前言
- 【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的知识以达到查漏补缺 |