using UnityEngine;
|
using UnityEngine.UI;
|
using System.Collections.Generic;
|
|
|
/// <summary>
|
/// UGUI描边
|
/// </summary>
|
public class OutlineEx : BaseMeshEffect
|
{
|
[Header("新shader描边")]
|
public Color m_OutlineColor= new Color(0, 0, 0, 0.5f);// Color.black;
|
public Color OutlineColor
|
{
|
get { return m_OutlineColor; }
|
set
|
{
|
m_OutlineColor = value;
|
this._Refresh();
|
}
|
}
|
|
QualityTextColType m_ColorType = QualityTextColType.None;
|
public QualityTextColType colorType
|
{
|
get { return m_ColorType; }
|
set
|
{
|
if (m_ColorType != value)
|
{
|
m_ColorType = value;
|
OutlineColor = UIHelper.GetUIOutlineColor(value);
|
}
|
}
|
}
|
|
|
[Range(0, 30)]
|
//默认10,不同的颜色(包括调整alpha)视觉上描边粗细有差异,故shader里乘以0.2适应不同情况
|
public int OutlineWidth = 10;
|
|
private static List<UIVertex> m_VetexList = new List<UIVertex>();
|
|
protected override void Start()
|
{
|
base.Start();
|
|
if (base.graphic)
|
{
|
if (base.graphic.material == null || base.graphic.material.shader.name != "TSF Shaders/UI/OutlineEx")
|
{
|
// #if UNITY_EDITOR
|
|
var texMaterial = ResManager.Instance.LoadAsset<Material>("Materials", "OutlineMat");
|
if (texMaterial != null)
|
{
|
base.graphic.material = texMaterial;
|
}
|
else
|
{
|
Debug.LogError("没有找到材质OutlineMat.mat");
|
}
|
// #else
|
// var shader = Shader.Find("TSF Shaders/UI/OutlineEx");
|
// base.graphic.material = new Material(shader);
|
// #endif
|
}
|
|
if (base.graphic.canvas)
|
{
|
var v1 = base.graphic.canvas.additionalShaderChannels;
|
var v2 = AdditionalCanvasShaderChannels.TexCoord1;
|
if ((v1 & v2) != v2)
|
{
|
base.graphic.canvas.additionalShaderChannels |= v2;
|
}
|
v2 = AdditionalCanvasShaderChannels.TexCoord2;
|
if ((v1 & v2) != v2)
|
{
|
base.graphic.canvas.additionalShaderChannels |= v2;
|
}
|
v2 = AdditionalCanvasShaderChannels.TexCoord3;
|
if ((v1 & v2) != v2)
|
{
|
base.graphic.canvas.additionalShaderChannels |= v2;
|
}
|
v2 = AdditionalCanvasShaderChannels.Tangent;
|
if ((v1 & v2) != v2)
|
{
|
base.graphic.canvas.additionalShaderChannels |= v2;
|
}
|
v2 = AdditionalCanvasShaderChannels.Normal;
|
if ((v1 & v2) != v2)
|
{
|
base.graphic.canvas.additionalShaderChannels |= v2;
|
}
|
}
|
this._Refresh();
|
}
|
}
|
|
#if UNITY_EDITOR
|
protected override void OnValidate()
|
{
|
base.OnValidate();
|
|
if (base.graphic.material != null)
|
{
|
if (base.graphic.material.shader.name != "TSF Shaders/UI/OutlineEx")
|
{
|
var texMaterial = ResManager.Instance.LoadAsset<Material>("Materials", "OutlineMat");
|
if (texMaterial != null)
|
{
|
base.graphic.material = texMaterial;
|
}
|
else
|
{
|
Debug.LogError("没有找到材质OutlineMat.mat");
|
}
|
//var shader = Shader.Find("TSF Shaders/UI/OutlineEx");
|
//base.graphic.material = new Material(shader);
|
}
|
this._Refresh();
|
}
|
}
|
#endif
|
|
|
private void _Refresh()
|
{
|
/*if (base.graphic.material.GetInt("_OutlineWidth") != this.OutlineWidth || base.graphic.material.GetColor("_OutlineColor") != this.OutlineColor)
|
{
|
base.graphic.material.SetColor("_OutlineColor", this.OutlineColor);
|
base.graphic.material.SetInt("_OutlineWidth", this.OutlineWidth);
|
}*/
|
base.graphic.SetVerticesDirty();
|
}
|
|
|
public override void ModifyMesh(VertexHelper vh)
|
{
|
vh.GetUIVertexStream(m_VetexList);
|
|
this._ProcessVertices();
|
|
vh.Clear();
|
vh.AddUIVertexTriangleStream(m_VetexList);
|
}
|
|
|
private void _ProcessVertices()
|
{
|
for (int i = 0, count = m_VetexList.Count - 3; i <= count; i += 3)
|
{
|
var v1 = m_VetexList[i];
|
var v2 = m_VetexList[i + 1];
|
var v3 = m_VetexList[i + 2];
|
// 计算原顶点坐标中心点
|
//
|
var minX = _Min(v1.position.x, v2.position.x, v3.position.x);
|
var minY = _Min(v1.position.y, v2.position.y, v3.position.y);
|
var maxX = _Max(v1.position.x, v2.position.x, v3.position.x);
|
var maxY = _Max(v1.position.y, v2.position.y, v3.position.y);
|
var posCenter = new Vector2(minX + maxX, minY + maxY) * 0.5f;
|
// 计算原始顶点坐标和UV的方向
|
//
|
Vector2 triX, triY, uvX, uvY;
|
Vector2 pos1 = v1.position;
|
Vector2 pos2 = v2.position;
|
Vector2 pos3 = v3.position;
|
if (Mathf.Abs(Vector2.Dot((pos2 - pos1).normalized, Vector2.right))
|
> Mathf.Abs(Vector2.Dot((pos3 - pos2).normalized, Vector2.right)))
|
{
|
triX = pos2 - pos1;
|
triY = pos3 - pos2;
|
uvX = v2.uv0 - v1.uv0;
|
uvY = v3.uv0 - v2.uv0;
|
}
|
else
|
{
|
triX = pos3 - pos2;
|
triY = pos2 - pos1;
|
uvX = v3.uv0 - v2.uv0;
|
uvY = v2.uv0 - v1.uv0;
|
}
|
// 计算原始UV框
|
var uvMin = _Min(v1.uv0, v2.uv0, v3.uv0);
|
var uvMax = _Max(v1.uv0, v2.uv0, v3.uv0);
|
//OutlineColor 和 OutlineWidth 也传入,避免出现不同的材质球
|
var col_rg = new Vector2(OutlineColor.r, OutlineColor.g); //描边颜色 用uv3 和 tangent的 zw传递
|
var col_ba = new Vector4(0,0,OutlineColor.b, OutlineColor.a);
|
var normal = new Vector3(0, 0, OutlineWidth); //描边的宽度 用normal的z传递
|
|
// 为每个顶点设置新的Position和UV,并传入原始UV框
|
v1 = _SetNewPosAndUV(v1, this.OutlineWidth, posCenter, triX, triY, uvX, uvY, uvMin, uvMax);
|
v1.uv3 = col_rg;
|
v1.tangent = col_ba;
|
v1.normal = normal;
|
v2 = _SetNewPosAndUV(v2, this.OutlineWidth, posCenter, triX, triY, uvX, uvY, uvMin, uvMax);
|
v2.uv3 = col_rg;
|
v2.tangent = col_ba;
|
v2.normal = normal;
|
v3 = _SetNewPosAndUV(v3, this.OutlineWidth, posCenter, triX, triY, uvX, uvY, uvMin, uvMax);
|
v3.uv3 = col_rg;
|
v3.tangent = col_ba;
|
v3.normal = normal;
|
|
|
// 应用设置后的UIVertex
|
//
|
m_VetexList[i] = v1;
|
m_VetexList[i + 1] = v2;
|
m_VetexList[i + 2] = v3;
|
}
|
}
|
|
|
private static UIVertex _SetNewPosAndUV(UIVertex pVertex, int pOutLineWidth,
|
Vector2 pPosCenter,
|
Vector2 pTriangleX, Vector2 pTriangleY,
|
Vector2 pUVX, Vector2 pUVY,
|
Vector2 pUVOriginMin, Vector2 pUVOriginMax)
|
{
|
// Position
|
var pos = pVertex.position;
|
var posXOffset = pos.x > pPosCenter.x ? pOutLineWidth : -pOutLineWidth;
|
var posYOffset = pos.y > pPosCenter.y ? pOutLineWidth : -pOutLineWidth;
|
pos.x += posXOffset;
|
pos.y += posYOffset;
|
pVertex.position = pos;
|
// UV
|
var uv = pVertex.uv0;
|
|
|
uv += new Vector4((pUVX / pTriangleX.magnitude * posXOffset * (Vector2.Dot(pTriangleX, Vector2.right) > 0 ? 1 : -1)).x, (pUVX / pTriangleX.magnitude * posXOffset * (Vector2.Dot(pTriangleX, Vector2.right) > 0 ? 1 : -1)).y, 0, 0);
|
uv += new Vector4((pUVY / pTriangleY.magnitude * posYOffset * (Vector2.Dot(pTriangleY, Vector2.up) > 0 ? 1 : -1)).x, (pUVY / pTriangleY.magnitude * posYOffset * (Vector2.Dot(pTriangleY, Vector2.up) > 0 ? 1 : -1)).y, 0, 0);
|
|
pVertex.uv0 = uv;
|
|
pVertex.uv1 = pUVOriginMin; //uv1 uv2 可用 tangent normal 在缩放情况 会有问题
|
pVertex.uv2 = pUVOriginMax;
|
|
return pVertex;
|
}
|
|
|
private static float _Min(float pA, float pB, float pC)
|
{
|
return Mathf.Min(Mathf.Min(pA, pB), pC);
|
}
|
|
|
private static float _Max(float pA, float pB, float pC)
|
{
|
return Mathf.Max(Mathf.Max(pA, pB), pC);
|
}
|
|
|
private static Vector2 _Min(Vector2 pA, Vector2 pB, Vector2 pC)
|
{
|
return new Vector2(_Min(pA.x, pB.x, pC.x), _Min(pA.y, pB.y, pC.y));
|
}
|
|
|
private static Vector2 _Max(Vector2 pA, Vector2 pB, Vector2 pC)
|
{
|
return new Vector2(_Max(pA.x, pB.x, pC.x), _Max(pA.y, pB.y, pC.y));
|
}
|
|
|
}
|