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)); 
 | 
    } 
 | 
  
 | 
  
 | 
} 
 |