字體顏色漸變
我們先看看二顏色漸變效果:
二顏色漸變效果
我們看看三顏色漸變效果:
三顏色漸變效果
左面Scene場景是網(wǎng)格狀態(tài)叨吮。
通過Scene場景我們可以看見,我們需要向中間插入兩個點,做個頂點過渡。
頂點部署應(yīng)該是這樣的:
* TL--------TR
* | |
* | |
* CL--------CR
* | |
* | |
* BL--------BR
首先我們要知道孵稽,顯示文本有個文本區(qū)域,而這個區(qū)域的坐標是基于局部坐標十偶,所以我們要先轉(zhuǎn)出到屏幕坐標肛冶,然后再換算。
準備的變量和枚舉:
public enum GradientType
{
TowColor = 0,
ThreeColor,
}
[SerializeField] private GradientType m_GradientType = GradientType.TowColor;
[SerializeField] private Color32 m_TopColor = Color.white;
[SerializeField] private Color32 m_MiddleColor = Color.white;
[SerializeField] private Color32 m_BottomColor = Color.black;
[Range(0f, 1f)] [SerializeField] private float m_ColorOffset = 0.5f;
[SerializeField] private Camera m_UICamera;
private List<UIVertex> iVertices = new List<UIVertex>();
核心換算代碼:
vh.GetUIVertexStream(iVertices);
vh.Clear();
for (int i = 0; i < iVertices.Count; i += 6)
{
UIVertex TL = iVertices[i + 0];
UIVertex TR = iVertices[i + 1];
UIVertex CR = iVertices[i + 2];
UIVertex CL = iVertices[i + 4];
UIVertex BL = iVertices[i + 4];
UIVertex BR = iVertices[i + 2];
Vector2 uvTL = iVertices[i + 0].uv0;
Vector2 uvTR = iVertices[i + 1].uv0;
Vector2 uvBR = iVertices[i + 2].uv0;
Vector2 uvBL = iVertices[i + 4].uv0;
Vector3 TR_World_Pos = this.transform.TransformPoint(TR.position);
Vector3 BR_World_Pos = this.transform.TransformPoint(BR.position);
Vector3 TR_Screen_Pos = TR_World_Pos;
Vector3 BR_Screen_Pos = BR_World_Pos;
if (this.m_UICamera != null)
{
TR_Screen_Pos = this.m_UICamera.WorldToScreenPoint(TR_World_Pos);
BR_Screen_Pos = this.m_UICamera.WorldToScreenPoint(BR_World_Pos);
}
float yHeight = (TR_Screen_Pos.y - BR_Screen_Pos.y) * this.m_ColorOffset;
Vector2 C_Screen_Pos = new Vector2(TR_Screen_Pos.x, TR_Screen_Pos.y - yHeight);
if (this.m_UICamera != null)
{
C_Screen_Pos = this.m_UICamera.ScreenToWorldPoint(C_Screen_Pos);
}
CR.position = this.transform.InverseTransformPoint(C_Screen_Pos);
CL.position.y = CR.position.y;
CR.uv0.y = CR.uv0.y * this.m_ColorOffset;
CL.uv0.y = CL.uv0.y * this.m_ColorOffset;
TL.color = this.m_TopColor;
TR.color = this.m_TopColor;
CR.color = this.m_MiddleColor;
CL.color = this.m_MiddleColor;
BL.color = this.m_BottomColor;
BR.color = this.m_BottomColor;
vh.AddVert(TL);
vh.AddVert(TR);
vh.AddVert(CR);
vh.AddVert(CL);
vh.AddVert(BL);
vh.AddVert(BR);
}
上面的代碼意思就是先清理原始數(shù)據(jù)扯键,然后把坐標轉(zhuǎn)到屏幕坐標系上,需要經(jīng)過兩步 局部坐標 => 世界坐標 => 屏幕坐標珊肃,然后給y做某個點上距離縮放:
屏幕坐標計算
float yHeight = (TR_Screen_Pos.y - BR_Screen_Pos.y) * this.m_ColorOffset;
在這個距離做個縮放荣刑,TR_Screen_Pos.y - yHeight
計算出來差值,就是我們需要的中點高度伦乔。(CR\CL的高度是一樣的厉亏,計算一次即可,X值保留默認烈和。)
接下來添加三角面:
for (int i = 0; i < vh.currentVertCount; i += 6)
{
if (this.m_GradientType == GradientType.ThreeColor)
{
vh.AddTriangle(i + 0, i + 1, i + 2);
vh.AddTriangle(i + 2, i + 3, i + 0);
vh.AddTriangle(i + 3, i + 2, i + 5);
vh.AddTriangle(i + 5, i + 4, i + 3);
}
else
{
vh.AddTriangle(i + 0, i + 1, i + 5);
vh.AddTriangle(i + 0, i + 5, i + 4);
}
}
大致就是這些爱只。
補充,上面版本有些bug招刹,核心算法做個優(yōu)化:
/*
* TL--------TR
* | |
* | |
* CL--------CR
* | |
* | |
* BL--------BR
* **/
for (int i = 0; i < count; i++)
{
UIVertex vertex = UIVertex.simpleVert;
vh.PopulateUIVertex(ref vertex, i);
this.iVertices.Add(vertex);
}
vh.Clear();
for (int i = 0; i < this.iVertices.Count; i += 4)
{
UIVertex TL = this.GeneralUIVertex(this.iVertices[i + 0]);
UIVertex TR = this.GeneralUIVertex(this.iVertices[i + 1]);
UIVertex BR = this.GeneralUIVertex(this.iVertices[i + 2]);
UIVertex BL = this.GeneralUIVertex(this.iVertices[i + 3]);
TL.color = this.m_TopColor;
TR.color = this.m_TopColor;
BL.color = this.m_BottomColor;
BR.color = this.m_BottomColor;
vh.AddVert(TL);
vh.AddVert(TR);
if (this.m_GradientType == GradientType.ThreeColor)
{
UIVertex CR = this.GeneralUIVertex(this.iVertices[i + 2]);
UIVertex CL = this.GeneralUIVertex(this.iVertices[i + 3]);
CR.position = (TR.position + BR.position) * this.m_ColorOffset;
CL.position = (TL.position + BL.position) * this.m_ColorOffset;
CR.uv0 = (TR.uv0 + BR.uv0) * this.m_ColorOffset;
CL.uv0 = (TL.uv0 + BL.uv0) * this.m_ColorOffset;
CR.color = this.m_MiddleColor;
CL.color = this.m_MiddleColor;
vh.AddVert(CR);
vh.AddVert(CL);
}
vh.AddVert(BR);
vh.AddVert(BL);
}
int step = 4;
if (this.m_GradientType == GradientType.ThreeColor)
{
step = 6;
}
for (int i = 0; i < vh.currentVertCount; i += step)
{
if (this.m_GradientType == GradientType.ThreeColor)
{
vh.AddTriangle(i + 0, i + 1, i + 2);
vh.AddTriangle(i + 2, i + 3, i + 0);
vh.AddTriangle(i + 3, i + 2, i + 4);
vh.AddTriangle(i + 4, i + 5, i + 3);
}
else
{
vh.AddTriangle(i + 0, i + 1, i + 2);
vh.AddTriangle(i + 2, i + 3, i + 0);
}
}
private UIVertex GeneralUIVertex(UIVertex vertex)
{
UIVertex result = UIVertex.simpleVert;
result.normal = new Vector3(vertex.normal.x, vertex.normal.y, vertex.normal.z);
result.position = new Vector3(vertex.position.x, vertex.position.y, vertex.position.z);
result.tangent = new Vector4(vertex.tangent.x, vertex.tangent.y, vertex.tangent.z, vertex.tangent.w);
result.uv0 = new Vector2(vertex.uv0.x, vertex.uv0.y);
result.uv1 = new Vector2(vertex.uv1.x, vertex.uv1.y);
return result;
}
最終代碼:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using System;
public enum GradientType
{
TowColor = 0,
ThreeColor,
}
/// <summary>
/// 漸變字體
/// </summary>
public class Gradient : BaseMeshEffect
{
[SerializeField] private GradientType m_GradientType = GradientType.TowColor;
[SerializeField] private Color32 m_TopColor = Color.white;
[SerializeField] private Color32 m_MiddleColor = Color.white;
[SerializeField] private Color32 m_BottomColor = Color.black;
[Range(0f, 1f)] [SerializeField] private float m_ColorOffset = 0.5f;
[SerializeField] private Camera m_UICamera;
private List<UIVertex> iVertices = new List<UIVertex>();
public override void ModifyMesh(VertexHelper vh)
{
this.iVertices.Clear();
if (!IsActive())
{
return;
}
var count = vh.currentVertCount;
if (count == 0)
return;
/*
* TL--------TR
* | |
* | |
* CL--------CR
* | |
* | |
* BL--------BR
* **/
for (int i = 0; i < count; i++)
{
UIVertex vertex = UIVertex.simpleVert;
vh.PopulateUIVertex(ref vertex, i);
this.iVertices.Add(vertex);
}
vh.Clear();
for (int i = 0; i < this.iVertices.Count; i += 4)
{
UIVertex TL = this.GeneralUIVertex(this.iVertices[i + 0]);
UIVertex TR = this.GeneralUIVertex(this.iVertices[i + 1]);
UIVertex BR = this.GeneralUIVertex(this.iVertices[i + 2]);
UIVertex BL = this.GeneralUIVertex(this.iVertices[i + 3]);
TL.color = this.m_TopColor;
TR.color = this.m_TopColor;
BL.color = this.m_BottomColor;
BR.color = this.m_BottomColor;
vh.AddVert(TL);
vh.AddVert(TR);
if (this.m_GradientType == GradientType.ThreeColor)
{
UIVertex CR = this.GeneralUIVertex(this.iVertices[i + 2]);
UIVertex CL = this.GeneralUIVertex(this.iVertices[i + 3]);
CR.position = (TR.position + BR.position) * this.m_ColorOffset;
CL.position = (TL.position + BL.position) * this.m_ColorOffset;
CR.uv0 = (TR.uv0 + BR.uv0) * this.m_ColorOffset;
CL.uv0 = (TL.uv0 + BL.uv0) * this.m_ColorOffset;
CR.color = this.m_MiddleColor;
CL.color = this.m_MiddleColor;
vh.AddVert(CR);
vh.AddVert(CL);
}
vh.AddVert(BR);
vh.AddVert(BL);
}
int step = 4;
if (this.m_GradientType == GradientType.ThreeColor)
{
step = 6;
}
for (int i = 0; i < vh.currentVertCount; i += step)
{
if (this.m_GradientType == GradientType.ThreeColor)
{
vh.AddTriangle(i + 0, i + 1, i + 2);
vh.AddTriangle(i + 2, i + 3, i + 0);
vh.AddTriangle(i + 3, i + 2, i + 4);
vh.AddTriangle(i + 4, i + 5, i + 3);
}
else
{
vh.AddTriangle(i + 0, i + 1, i + 2);
vh.AddTriangle(i + 2, i + 3, i + 0);
}
}
}
private UIVertex GeneralUIVertex(UIVertex vertex)
{
UIVertex result = UIVertex.simpleVert;
result.normal = new Vector3(vertex.normal.x, vertex.normal.y, vertex.normal.z);
result.position = new Vector3(vertex.position.x, vertex.position.y, vertex.position.z);
result.tangent = new Vector4(vertex.tangent.x, vertex.tangent.y, vertex.tangent.z, vertex.tangent.w);
result.uv0 = new Vector2(vertex.uv0.x, vertex.uv0.y);
result.uv1 = new Vector2(vertex.uv1.x, vertex.uv1.y);
return result;
}
}