184 lines
6.5 KiB
C#
184 lines
6.5 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using XLua.Cast;
|
|
|
|
|
|
[RequireComponent(typeof(Text))]
|
|
public class UIOutlineEffect : BaseMeshEffect
|
|
{
|
|
[SerializeField]
|
|
private Color outlineColor = Color.black;
|
|
|
|
public Color OutlineColor
|
|
{
|
|
get { return outlineColor; }
|
|
set { outlineColor = value; }
|
|
}
|
|
|
|
[Range(0, 5)]
|
|
public int OutlineWidth = 0;
|
|
private List<UIVertex> cacheVertexList = new List<UIVertex>();
|
|
|
|
protected override void Awake()
|
|
{
|
|
base.Awake();
|
|
if (base.graphic)
|
|
{
|
|
if (base.graphic.canvas)
|
|
{
|
|
var shaderChannelOrigin = base.graphic.canvas.additionalShaderChannels;
|
|
var needChannel = AdditionalCanvasShaderChannels.TexCoord1;
|
|
if ((shaderChannelOrigin & needChannel) != needChannel)
|
|
{
|
|
base.graphic.canvas.additionalShaderChannels |= needChannel;
|
|
}
|
|
needChannel = AdditionalCanvasShaderChannels.TexCoord2;
|
|
if ((shaderChannelOrigin & needChannel) != needChannel)
|
|
{
|
|
base.graphic.canvas.additionalShaderChannels |= needChannel;
|
|
}
|
|
|
|
needChannel = AdditionalCanvasShaderChannels.TexCoord3;
|
|
if ((shaderChannelOrigin & needChannel) != needChannel)
|
|
{
|
|
base.graphic.canvas.additionalShaderChannels |= needChannel;
|
|
}
|
|
|
|
needChannel = AdditionalCanvasShaderChannels.Tangent;
|
|
if ((shaderChannelOrigin & needChannel) != needChannel)
|
|
{
|
|
base.graphic.canvas.additionalShaderChannels |= needChannel;
|
|
}
|
|
|
|
needChannel = AdditionalCanvasShaderChannels.Normal;
|
|
if ((shaderChannelOrigin & needChannel) != needChannel)
|
|
{
|
|
base.graphic.canvas.additionalShaderChannels |= needChannel;
|
|
}
|
|
}
|
|
base.graphic.SetVerticesDirty();
|
|
}
|
|
}
|
|
|
|
public override void ModifyMesh(VertexHelper vh)
|
|
{
|
|
vh.GetUIVertexStream(cacheVertexList);
|
|
vh.Clear();
|
|
ProcessVertexs();
|
|
vh.AddUIVertexTriangleStream(cacheVertexList);
|
|
}
|
|
|
|
//扩充顶点 并将计算信息缓存在顶点不需要但可以传递的参数中
|
|
private void ProcessVertexs()
|
|
{
|
|
var total = cacheVertexList.Count;
|
|
for (var i = 0; i < total; i += 3)
|
|
{
|
|
var v1 = cacheVertexList[i];
|
|
var v2 = cacheVertexList[i + 1];
|
|
var v3 = cacheVertexList[i + 2];
|
|
//计算原顶点中心点
|
|
var minX = Min(v1.position.x, v2.position.x, v3.position.x);
|
|
var maxX = Max(v1.position.x, v2.position.x, v3.position.x);
|
|
var minY = Min(v1.position.y, v2.position.y, v3.position.y);
|
|
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 vPos1 = v1.position;
|
|
Vector2 vPos2 = v2.position;
|
|
Vector2 vPos3 = v3.position;
|
|
//点乘计算哪两个顶点为三角形最x最大offset y最大offset
|
|
if (Mathf.Abs(Vector2.Dot((vPos2 - vPos1).normalized, Vector2.right)) >
|
|
Mathf.Abs(Vector2.Dot((vPos3 - vPos2).normalized, Vector2.right)))
|
|
{
|
|
triX = vPos2 - vPos1;
|
|
triY = vPos3 - vPos2;
|
|
uvX = v2.uv0 - v1.uv0;
|
|
uvY = v3.uv0 - v2.uv0;
|
|
}
|
|
else
|
|
{
|
|
triX = vPos3 - vPos2;
|
|
triY = vPos2 - vPos1;
|
|
uvX = v3.uv0 - v2.uv0;
|
|
uvY = v2.uv0 - v1.uv0;
|
|
}
|
|
|
|
//uv框
|
|
var uvOriginMin = Min(v1.uv0, v2.uv0, v3.uv0);
|
|
var uvOriginMax = Max(v1.uv0, v2.uv0, v3.uv0);
|
|
var color_rg = new Vector2(outlineColor.r, outlineColor.g);
|
|
var color_ba = new Vector4(0 ,0 , outlineColor.b, outlineColor.a);
|
|
var normal = new Vector3(0, 0, OutlineWidth);
|
|
|
|
v1 = SetNewPosAndUV(v1, OutlineWidth, posCenter, triX, triY, uvX, uvY, uvOriginMin, uvOriginMax);
|
|
v1.uv3 = color_rg;
|
|
v1.tangent = color_ba;
|
|
v1.normal = normal;
|
|
v2 = SetNewPosAndUV(v2, OutlineWidth, posCenter, triX, triY, uvX, uvY, uvOriginMin, uvOriginMax);
|
|
v2.uv3 = color_rg;
|
|
v2.tangent = color_ba;
|
|
v2.normal = normal;
|
|
v3 = SetNewPosAndUV(v3, OutlineWidth, posCenter, triX, triY, uvX, uvY, uvOriginMin, uvOriginMax);
|
|
v3.uv3 = color_rg;
|
|
v3.tangent = color_ba;
|
|
v3.normal = normal;
|
|
|
|
cacheVertexList[i] = v1;
|
|
cacheVertexList[i + 1] = v2;
|
|
cacheVertexList[i + 2] = v3;
|
|
|
|
}
|
|
}
|
|
|
|
private UIVertex SetNewPosAndUV(UIVertex vertex, int outlineWidth,
|
|
Vector2 vertexsCenter,
|
|
Vector2 triangleXMax, Vector2 triangleYMax,
|
|
Vector2 uvX, Vector2 uvY,
|
|
Vector2 uvOriginMin, Vector2 uvOriginMax)
|
|
{
|
|
//顶点位置扩充
|
|
var pos = vertex.position;
|
|
var posXOffset = pos.x > vertexsCenter.x ? outlineWidth : -outlineWidth;
|
|
var posYOffset = pos.y > vertexsCenter.y ? outlineWidth : -outlineWidth;
|
|
pos.x += posXOffset;
|
|
pos.y += posYOffset;
|
|
|
|
vertex.position = pos;
|
|
//uv 最后 * uvx方向纠正
|
|
var uv = vertex.uv0;
|
|
uv += (Vector4)uvX / triangleXMax.magnitude * posXOffset * (Vector2.Dot(triangleXMax, Vector2.right) > 0 ? 1 : -1);
|
|
uv += (Vector4)uvY / triangleYMax.magnitude * posYOffset * (Vector2.Dot(triangleYMax, Vector2.up) > 0 ? 1 : -1);
|
|
|
|
vertex.uv0 = uv;
|
|
vertex.uv1 = uvOriginMin;
|
|
vertex.uv2 = uvOriginMax;
|
|
return vertex;
|
|
}
|
|
|
|
private static float Min(float a, float b, float c)
|
|
{
|
|
return Mathf.Min(Mathf.Min(a, b), c);
|
|
}
|
|
|
|
private static float Max(float a, float b, float c)
|
|
{
|
|
return Mathf.Max(Mathf.Max(a, b), c);
|
|
}
|
|
|
|
private static Vector2 Min(Vector2 a, Vector2 b, Vector2 c)
|
|
{
|
|
return new Vector2(Min(a.x, b.x, c.x), Min(a.y, b.y, c.y));
|
|
}
|
|
|
|
private static Vector2 Max(Vector2 a, Vector2 b, Vector2 c)
|
|
{
|
|
return new Vector2(Max(a.x, b.x, c.x), Max(a.y, b.y, c.y));
|
|
}
|
|
}
|