Unity UGUI 文字描边与渐变

13 篇文章 0 订阅

文字描边

OutLine

默认顶点数为16

将描边距离分别设置x=100,y=50,使用OutLine8 与禁用OutLine8 对比,如下图,顶点数(Verts)相差100
在这里插入图片描述

一个字=一张图=2个三角面=6个顶点(vertex)包括2个共用顶点

使用Text,一个文字对应4个顶点,其中2个顶点共用

使用OutLine8,相当于在Text文本后面多绘制了8个文本,此时顶点数=2*6*9=108

Outline8 Code

using System.Collections.Generic;
using UGUIExtentions;

namespace UnityEngine.UI
{
	/// <summary>
	/// Adds an outline to a graphic using IVertexModifier.
	/// </summary>
	public class Outline8 : BaseMeshEffect
	{
		[SerializeField]
		private Color m_EffectColor = new Color(0f, 0f, 0f, 1f);

		[SerializeField]
		private Vector2 m_EffectDistance = new Vector2(1f, -1f);

		[SerializeField]
		private bool m_UseGraphicAlpha = true;

		private const float kMaxEffectDistance = 600f;

		protected Outline8()
		{ }

		
#if UNITY_EDITOR
        protected override void OnValidate()
        {
            effectDistance = m_EffectDistance;
            base.OnValidate();
        }

#endif
        /// <summary>
        /// Color for the effect
        /// </summary>
        public Color effectColor
        {
            get { return m_EffectColor; }
            set
            {
                m_EffectColor = value;
                if (graphic != null)
                    graphic.SetVerticesDirty();
            }
        }

        /// <summary>
        /// How far is the shadow from the graphic.
        /// </summary>
        public Vector2 effectDistance
        {
            get { return m_EffectDistance; }
            set
            {
	            Mathf.Clamp(value.x, -kMaxEffectDistance, kMaxEffectDistance);
	            Mathf.Clamp(value.y, -kMaxEffectDistance, kMaxEffectDistance);

                if (m_EffectDistance == value)
                    return;

                m_EffectDistance = value;

                if (graphic != null)
                    graphic.SetVerticesDirty();
            }
        }

        /// <summary>
        /// Should the shadow inherit the alpha from the graphic?
        /// </summary>
        public bool useGraphicAlpha
        {
            get { return m_UseGraphicAlpha; }
            set
            {
                m_UseGraphicAlpha = value;
                if (graphic != null)
                    graphic.SetVerticesDirty();
            }
        }
		
        // 添加4个角的顶点
		public override void ModifyMesh(VertexHelper vh)
		{
			if (!IsActive())
				return;

			var verts = ListPool<UIVertex>.Get();
			vh.GetUIVertexStream(verts);

			var neededCpacity = verts.Count * 5;
			if (verts.Capacity < neededCpacity)
				verts.Capacity = neededCpacity;

            // 顶点部分 开始
			var start = 0;
			var end = verts.Count;
			ApplyShadowZeroAlloc(verts, effectColor, start, verts.Count, effectDistance.x, effectDistance.y);

			start = end;
			end = verts.Count;
			ApplyShadowZeroAlloc(verts, effectColor, start, verts.Count, effectDistance.x, -effectDistance.y);

			start = end;
			end = verts.Count;
			ApplyShadowZeroAlloc(verts, effectColor, start, verts.Count, -effectDistance.x, effectDistance.y);

			start = end;
			end = verts.Count;
			ApplyShadowZeroAlloc(verts, effectColor, start, verts.Count, -effectDistance.x, -effectDistance.y);

			start = end;
			end = verts.Count;
			ApplyShadowZeroAlloc(verts, effectColor, start, verts.Count, effectDistance.x, 0);

			start = end;
			end = verts.Count;
			ApplyShadowZeroAlloc(verts, effectColor, start, verts.Count, -effectDistance.x, 0);

			start = end;
			end = verts.Count;
			ApplyShadowZeroAlloc(verts, effectColor, start, verts.Count, 0, effectDistance.y);

			start = end;
			end = verts.Count;
			ApplyShadowZeroAlloc(verts, effectColor, start, verts.Count, 0, -effectDistance.y);
            // 顶点部分 结束

            // 顶点部分 优化写法 
            // 参考 https://github.com/n-yoda/unity-vertex-effects
            /*var original = verts.Count;
			var count = 0;
			for (int x = -1; x <= 1; x++)
			{
				for (int y = -1; y <= 1; y++)
				{
					if (!(x == 0 && y == 0))
					{
						var next = count + original;
						ApplyShadowZeroAlloc(verts, effectColor, count, next, effectDistance.x * x, effectDistance.y * y);
						count = next;
					}
				}
			}*/

			vh.Clear();
			vh.AddUIVertexTriangleStream(verts);
			ListPool<UIVertex>.Release(verts);
		}

		protected void ApplyShadowZeroAlloc(List<UIVertex> verts, Color32 color, int start, int end, float x, float y)
		{
			UIVertex vt;

			var neededCapacity = verts.Count + end - start;
			if (verts.Capacity < neededCapacity)
				verts.Capacity = neededCapacity;

			for (int i = start; i < end; ++i)
			{
				vt = verts[i];
				verts.Add(vt);

				Vector3 v = vt.position;
				v.x += x;
				v.y += y;
				vt.position = v;
				var newColor = color;
				if (m_UseGraphicAlpha)
					newColor.a = (byte)((newColor.a * verts[i].color.a) / 255);
				vt.color = newColor;
				verts[i] = vt;
			}
		}
	}
}

Text扩展

创建OutlineText继承Text,重写OnPopulateMesh,在内部进行描边

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class OutLineText : Text {

	public bool m_OutLine=true;
	public Color m_OutLineColor=Color.black;
	public float m_OutLineOffsetX=0f;
	public float m_OutLineOffsetY=0f;
	protected override void OnPopulateMesh(VertexHelper toFill)
	{
		//这里是直接复制的UGUI的Text生成定点的代码
			Vector2 extent=rectTransform.rect.size;
			var settings= GetGenerationSettings(extent);
			cachedTextGenerator.Populate(this.text, settings);
			Rect inputRect = rectTransform.rect;
        	// get the text alignment anchor point for the text in local space
        	Vector2 textAnchorPivot = GetTextAnchorPivot(alignment);
        	Vector2 refPoint = Vector2.zero;
        	refPoint.x = Mathf.Lerp(inputRect.xMin, inputRect.xMax, textAnchorPivot.x);
        	refPoint.y = Mathf.Lerp(inputRect.yMin, inputRect.yMax, textAnchorPivot.y);

        	// Determine fraction of pixel to offset text mesh.
        	Vector2 roundingOffset = PixelAdjustPoint(refPoint) - refPoint;

        	// Apply the offset to the vertices
        	IList<UIVertex> verts = cachedTextGenerator.verts;
        	float unitsPerPixel = 1 / pixelsPerUnit;
        	//Last 4 verts are always a new line...
        	int vertCount = verts.Count - 4;
			toFill.Clear();
			UIVertex[] rVertex=new UIVertex[4];
        	if (roundingOffset != Vector2.zero)
        	{
            	for (int i = 0; i < vertCount; ++i)
            	{
                	int tempVertsIndex = i & 3;
                	rVertex[tempVertsIndex] = verts[i];
                	rVertex[tempVertsIndex].position *= unitsPerPixel;
                	rVertex[tempVertsIndex].position.x += roundingOffset.x;
                	rVertex[tempVertsIndex].position.y += roundingOffset.y;
                	if (tempVertsIndex == 3)
                    	toFill.AddUIVertexQuad(rVertex);
            	}
        	}
			else
			{
				for (int i = 0; i < verts.Count-4; i++)
				{
					int tempVertsIndex = i & 3;
                    rVertex[tempVertsIndex] = verts[i];
                    rVertex[tempVertsIndex].position.x += roundingOffset.x;
                    rVertex[tempVertsIndex].position.y += roundingOffset.y;
                    rVertex[tempVertsIndex].position *= unitsPerPixel;
                    rVertex[tempVertsIndex].uv1 = Vector2.zero;
                    if (m_OutLine && tempVertsIndex == 3)
                    {
						ApplyShadowZeroAlloc(ref rVertex, m_OutLineColor, m_OutLineOffsetX, m_OutLineOffsetY, toFill);
                        ApplyShadowZeroAlloc(ref  rVertex, m_OutLineColor, m_OutLineOffsetX, -m_OutLineOffsetY, toFill);
                        ApplyShadowZeroAlloc(ref  rVertex, m_OutLineColor, -m_OutLineOffsetX, m_OutLineOffsetY, toFill);
                        ApplyShadowZeroAlloc(ref rVertex, m_OutLineColor, -m_OutLineOffsetX, -m_OutLineOffsetY, toFill);
                        toFill.AddUIVertexQuad(rVertex);
                    }
				}
			}
	}
	private void ApplyShadowZeroAlloc(ref UIVertex[] rVertex, Color rEffectColor, float rEffectDistanceX, float rEffectDistanceY, VertexHelper rHelper)
    {
        for (int i = 0; i < rVertex.Length; i++)
        {
            Vector3 rPosition = rVertex[i].position;
            rPosition.x += rEffectDistanceX;
            rPosition.y += rEffectDistanceY;
            rVertex[i].position = rPosition;
            rVertex[i].color = rEffectColor;
        }
        rHelper.AddUIVertexQuad(rVertex);
        for (int i = 0; i < rVertex.Length; i++)
        {
            Vector3 rPosition = rVertex[i].position;
            rPosition.x -= rEffectDistanceX;
            rPosition.y -= rEffectDistanceY;
            rVertex[i].color = color;
            rVertex[i].position = rPosition;
        }
    }
}


Shader优化

OutlineEx.shader

Shader "TSF Shaders/UI/OutlineEx"
{
   Properties
   {
      _MainTex("Main Texture", 2D) = "white" {}
      _Color("Tint", Color) = (1, 1, 1, 1)
      // 描边颜色和宽度    
      _OutlineColor("Outline Color", Color) = (1, 1, 1, 1)
      _OutlineWidth("Outline Width", Int) = 1

      _StencilComp("Stencil Comparison", Float) = 8
      _Stencil("Stencil ID", Float) = 0
      _StencilOp("Stencil Operation", Float) = 0
      _StencilWriteMask("Stencil Write Mask", Float) = 255
      _StencilReadMask("Stencil Read Mask", Float) = 255

      _ColorMask("Color Mask", Float) = 15

      [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip("Use Alpha Clip", Float) = 0
   }

      SubShader
      {
         Tags
         {
            "Queue" = "Transparent"
            "IgnoreProjector" = "True"
            "RenderType" = "Transparent"
            "PreviewType" = "Plane"
            "CanUseSpriteAtlas" = "True"
         }

         Stencil
         {
            Ref[_Stencil]
            Comp[_StencilComp]
            Pass[_StencilOp]
            ReadMask[_StencilReadMask]
            WriteMask[_StencilWriteMask]
         }

         Cull Off
         Lighting Off
         ZWrite Off
         ZTest[unity_GUIZTestMode]
         Blend SrcAlpha OneMinusSrcAlpha
         ColorMask[_ColorMask]

         Pass
         {
            Name "OUTLINE"

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            sampler2D _MainTex;
            fixed4 _Color;
            fixed4 _TextureSampleAdd;
            float4 _MainTex_TexelSize;

            float4 _OutlineColor;
            int _OutlineWidth;

            struct appdata
            {
               float4 vertex : POSITION;
               float2 texcoord : TEXCOORD0;
               float2 texcoord1 : TEXCOORD1;
               float2 texcoord2 : TEXCOORD2;
               fixed4 color : COLOR;
            };

            struct v2f
            {
               float4 vertex : SV_POSITION;
               float2 texcoord : TEXCOORD0;
               float2 uvOriginXY : TEXCOORD1;
               float2 uvOriginZW : TEXCOORD2;
               fixed4 color : COLOR;
            };

            v2f vert(appdata IN)
            {
               v2f o;

               o.vertex = UnityObjectToClipPos(IN.vertex);
               o.texcoord = IN.texcoord;
               o.uvOriginXY = IN.texcoord1;
               o.uvOriginZW = IN.texcoord2;
               o.color = IN.color * _Color;

               return o;
            }

            // 检查点是否在给定矩形内
            fixed IsInRect(float2 pPos, float4 pClipRect)
            {
               // step函数a>b返回0,否则返回1
               pPos = step(pClipRect.xy, pPos) * step(pPos, pClipRect.zw);
               return pPos.x * pPos.y;
            }

            // 根据圆的参数方程计算采样坐标,使用alpha值进行颜色混合
            fixed SampleAlpha(int pIndex, v2f IN)
            {
               const fixed sinArray[12] = { 0, 0.5, 0.866, 1, 0.866, 0.5, 0, -0.5, -0.866, -1, -0.866, -0.5 };
               const fixed cosArray[12] = { 1, 0.866, 0.5, 0, -0.5, -0.866, -1, -0.866, -0.5, 0, 0.5, 0.866 };
               float2 pos = IN.texcoord + _MainTex_TexelSize.xy * float2(cosArray[pIndex], sinArray[pIndex]) * _OutlineWidth;
               return IsInRect(pos, float4(IN.uvOriginXY, IN.uvOriginZW)) * (tex2D(_MainTex, pos) + _TextureSampleAdd).w * _OutlineColor.w;
            }

            fixed4 frag(v2f IN) : SV_Target
            {
               fixed4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
               if (_OutlineWidth > 0)
               {
                  color.w *= IsInRect(IN.texcoord, float4(IN.uvOriginXY, IN.uvOriginZW));
                  half4 val = half4(_OutlineColor.x, _OutlineColor.y, _OutlineColor.z, 0);

                  val.w += SampleAlpha(0, IN);
                  val.w += SampleAlpha(1, IN);
                  val.w += SampleAlpha(2, IN);
                  val.w += SampleAlpha(3, IN);
                  val.w += SampleAlpha(4, IN);
                  val.w += SampleAlpha(5, IN);
                  val.w += SampleAlpha(6, IN);
                  val.w += SampleAlpha(7, IN);
                  val.w += SampleAlpha(8, IN);
                  val.w += SampleAlpha(9, IN);
                  val.w += SampleAlpha(10, IN);
                  val.w += SampleAlpha(11, IN);

                  val.w = clamp(val.w, 0, 1);
                  color = (val * (1.0 - color.a)) + (color * color.a);
                  color.a = saturate(color.a);
                  color.a *= IN.color.a;
               }
               return color;
            }
            ENDCG
         }
      }
}

OutlineEx.cs

//————————————————————————————————————————————
//  OutlineEx.cs
//
//  Created by Chiyu Ren on 2018/9/12 23:03:51
//————————————————————————————————————————————
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;


namespace TooSimpleFramework.UI
{
    /// <summary>
    /// UGUI描边
    /// </summary>
    public class Outline : BaseMeshEffect
    {
        public Color OutlineColor = Color.white;
        [Range(0, 6)]
        public int OutlineWidth = 0;
        public Shader OutlineShader;

        private static List<UIVertex> m_VetexList = new List<UIVertex>();


        protected override void Start()
        {
            base.Start();

            var shader = OutlineShader != null ? OutlineShader : Shader.Find("TSF Shaders/UI/OutlineEx");
            
            base.graphic.material = new Material(shader);

            // 修改additionalShaderChannels属性,将uv1和uv2传入shader
            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;
            }

            this._Refresh();
        }


#if UNITY_EDITOR
        protected override void OnValidate()
        {
            base.OnValidate();

            if (base.graphic.material != null)
            {
                this._Refresh();
            }
        }
#endif


        private void _Refresh()
        {
            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);
                var uvOrigin = new Vector4(uvMin.x, uvMin.y, uvMax.x, uvMax.y);
                
                // 为每个顶点设置新的Position和UV,并传入原始UV框
                v1 = _SetNewPosAndUV(v1, this.OutlineWidth, posCenter, triX, triY, uvX, uvY, uvOrigin);
                v2 = _SetNewPosAndUV(v2, this.OutlineWidth, posCenter, triX, triY, uvX, uvY, uvOrigin);
                v3 = _SetNewPosAndUV(v3, this.OutlineWidth, posCenter, triX, triY, uvX, uvY, uvOrigin);
                
                // 应用设置后的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,
            Vector4 pUVOrigin)
        {
            // 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 += pUVX / pTriangleX.magnitude * posXOffset * (Vector2.Dot(pTriangleX, Vector2.right) > 0 ? 1 : -1);
            uv += pUVY / pTriangleY.magnitude * posYOffset * (Vector2.Dot(pTriangleY, Vector2.up) > 0 ? 1 : -1);
            pVertex.uv0 = uv;
            
            // 原始UV框
            pVertex.uv1 = new Vector2(pUVOrigin.x, pUVOrigin.y);
            pVertex.uv2 = new Vector2(pUVOrigin.z, pUVOrigin.w);

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

文字渐变

Gradient.cs 由上到下渐变

// 渐变效果

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;


[AddComponentMenu("UI/Effects/Gradient", 13)]
public class Gradient : BaseMeshEffect
{
    [SerializeField] private Color32 m_TopColor = Color.white;
    [SerializeField] private Color32 m_BottomColor = Color.black;

    public Color32 topColor
    {
        get { return m_TopColor; }
        set { m_TopColor = value; }
    }

    public Color32 bottomColor
    {
        get { return m_BottomColor; }
        set { m_BottomColor = value; }
    }

    public override void ModifyMesh(VertexHelper vh)
    {
        if (!this.IsActive())
            return;

        List<UIVertex> vertexList = new List<UIVertex>();
        vh.GetUIVertexStream(vertexList);
        ModifyVertices(vertexList);

        vh.Clear();
        vh.AddUIVertexTriangleStream(vertexList);
    }

    public void ModifyVertices(List<UIVertex> vertexList)
    {
        if (!IsActive() || vertexList.Count <= 0)
        {
            return;
        }

        for (int i = 0; i < vertexList.Count;)
        {
            float bottomY = vertexList[i].position.y;
            float topY = bottomY;
            float dis = 1f;
            for (int k = 1; k < 6; k++)
            {
                float y = vertexList[k + i].position.y;
                if (y > topY)
                {
                    topY = y;
                }
                else if (y < bottomY)
                {
                    bottomY = y;
                }
            }

            dis = topY - bottomY;
            for (int k = 0; k < 6; k++)
            {
                UIVertex vertText = vertexList[k + i];
                vertText.color = Color32.Lerp(m_BottomColor, m_TopColor, (vertText.position.y - bottomY) / dis);
                vertexList[k + i] = vertText;
            }

            i += 6;
        }
    }
}

TextGradient.cs 支持横向,纵向,左上至右下,左下至右上渐变

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;


[RequireComponent(typeof(Text))]
public class TextGradient : BaseMeshEffect
{
    public enum GradientDirection { Horizontal, Vertical,LeftUpToRightDown,LeftDownToRightUp }

    [SerializeField]  //定义序列化属性,一会的Editor中需要通过定义的这个属性找到该字段
    public Color32 topColor = Color.white;//顶部颜色
    [SerializeField]
    public Color32 bottomColor = Color.black;//底部颜色
    [SerializeField]
    public GradientDirection gradientDirection;//渐变方向
    [SerializeField]
    public bool useEffect = false;//是否使用阴影
    [SerializeField]
    public Color effectColor = new Color(0f, 0f, 0f, 0.5f);//阴影颜色
    [SerializeField]
    public Vector2 effectDistance = new Vector2(1f, -1f);//阴影偏移

    private const int DefautlVertexNumPerFont = 6;//顶点数

    List<UIVertex> vertexBuffers = new List<UIVertex>();
    public Mesh mesh = null;


    /// <summary>
    /// 给顶点着色
    /// </summary>
    /// <param name="vertexList"></param>
    /// <param name="index"></param>
    /// <param name="color"></param>
    private void ModifyVertexColor(List<UIVertex> vertexList, int index, Color color)
    {
        UIVertex temp = vertexList[index];
        temp.color = color;
        vertexList[index] = temp;
    }
    //修改网格时调用
    public override void ModifyMesh(VertexHelper vh)
    {
        if (!IsActive())
        {
            return;
        }
        vh.GetUIVertexStream(vertexBuffers);//获取顶点
        Debug.Log(vertexBuffers.Count);

        //在Inspector中显示网格
        if (mesh == null)
        {
            mesh = new Mesh();
        }
        vh.FillMesh(mesh);


        int count = vertexBuffers.Count;
        if (count > 0)
        {
            /**给顶点着色( 这里需要明白顶点的顺序 )            
            *   5-0 ---- 1
            *    | \    |
            *    |  \   |
            *    |   \  |
            *    |    \ |
            *    4-----3-2
            **/
            for (int i = 0; i < count; i += DefautlVertexNumPerFont)
            {
                //分别设置每个顶点的颜色
                switch (gradientDirection)
                {
                    case GradientDirection.Horizontal:
                        ModifyVertexColor(vertexBuffers, i, topColor);
                        ModifyVertexColor(vertexBuffers, i + 1, topColor);
                        ModifyVertexColor(vertexBuffers, i + 2, bottomColor);
                        ModifyVertexColor(vertexBuffers, i + 3, bottomColor);
                        ModifyVertexColor(vertexBuffers, i + 4, bottomColor);
                        ModifyVertexColor(vertexBuffers, i + 5, topColor);
                        break;
                    case GradientDirection.Vertical:
                        ModifyVertexColor(vertexBuffers, i, topColor);
                        ModifyVertexColor(vertexBuffers, i + 1, bottomColor);
                        ModifyVertexColor(vertexBuffers, i + 2, bottomColor);
                        ModifyVertexColor(vertexBuffers, i + 3, bottomColor);
                        ModifyVertexColor(vertexBuffers, i + 4, topColor);
                        ModifyVertexColor(vertexBuffers, i + 5, topColor);
                        break;
                    case GradientDirection.LeftUpToRightDown:
                        ModifyVertexColor(vertexBuffers, i, topColor);
                        ModifyVertexColor(vertexBuffers, i + 1, bottomColor);
                        ModifyVertexColor(vertexBuffers, i + 2, topColor);
                        ModifyVertexColor(vertexBuffers, i + 3, topColor);
                        ModifyVertexColor(vertexBuffers, i + 4, bottomColor);
                        ModifyVertexColor(vertexBuffers, i + 5, topColor);
                        break;
                    case GradientDirection.LeftDownToRightUp:
                        ModifyVertexColor(vertexBuffers, i, bottomColor);
                        ModifyVertexColor(vertexBuffers, i + 1, topColor);
                        ModifyVertexColor(vertexBuffers, i + 2, bottomColor);
                        ModifyVertexColor(vertexBuffers, i + 3, bottomColor);
                        ModifyVertexColor(vertexBuffers, i + 4, topColor);
                        ModifyVertexColor(vertexBuffers, i + 5, bottomColor);
                        break;
                    default:
                        break;
                }                
            }
        }

        if (useEffect)//是否使用阴影(如果不需要阴影功能可以这部分代码删掉)
        {
            //扩充一倍的顶点容量
            var neededCapacity = vertexBuffers.Count * 2;
            if (vertexBuffers.Capacity < neededCapacity)
                vertexBuffers.Capacity = neededCapacity;

            for (int i = 0, cnt = vertexBuffers.Count; i < cnt; ++i)
            {
                var vt = vertexBuffers[i];
                vertexBuffers.Add(vt);

                Vector3 v = vt.position;
                v.x += effectDistance.x;
                v.y += effectDistance.y;
                vt.position = v;
                vt.color = effectColor;
                vertexBuffers[i] = vt;
            }
        }
        vh.Clear();
        //这个方法向VertexHelper中批量增加三角形顶点数据,参数的长度必须是三的倍数
        vh.AddUIVertexTriangleStream(vertexBuffers);
    }

   /// <summary>
   /// 在Scene中显示顶点
   /// </summary>
    void OnDrawGizmos()
    {
        Gizmos.color = Color.red;//设置颜色
        for (int i = 0; i < vertexBuffers.Count; i++)
        {
            //把mesh顶点转为世界坐标
            Vector3 targetPosition = transform.TransformPoint(vertexBuffers[i].position);
            Gizmos.DrawSphere(targetPosition, 5f);
        }
    }
}

参考资料

Beautiful Text Outline for Unity UI

UGUI Text组件扩展描边

基于Shader实现的UGUI描边解决方案

Unity实用功能之UGUI的Text实现颜色渐变详解(二)

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity UGUIUnity游戏开发中常用的用户界面实现方法。UGUIUnity自带的用户界面系统,可以通过创建UI元素来构建游戏的界面。在Unity中,UGUI可通过创建Button、Text、Image等UI组件来实现交互和展示。 在UGUI中,通常选择ISO模型进行2D平面开发。通过锁定界面可以防止镜头发生偏移,确保界面的稳定性。 添加Button点击事件的方法如下: 1. 在Hierarchy面板中创建一个空物体GameObject。 2. 在Project面板中创建一个新的C#脚本,命名为OnClickButton,并将该脚本添加到GameObject上。 3. 双击OnClickButton脚本,在打开的脚本编辑器中输入相应的代码。该代码的作用是在点击按钮后输出"You click the button."和若干次"Yes"。 4. 在Click方法中使用print函数输出相关信息,并通过循环打印"Yes"特定次数。 5. 完成脚本的编写后,将脚本保存并返回Unity编辑器界面。 以上是关于Unity UGUI的简要介绍和Button点击事件的添加方法。希望对你有所帮助!<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [超详细的Unity UGUI教学](https://blog.csdn.net/qq_37701948/article/details/106682377)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值