OutLine源码解析 -- 为什么要尽量避免使用OutLine

相信很多人在刚入职Unity的时候都被告诫过尽量避免使用OutLine,只知道它很费性能,但是很多人并不知道它为什么很费性能。今天通过源码来探索一下。

首先看一下OutLine.cs里的源码

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

    var verts = ListPool<UIVertex>.Get();//这里的列表使用了对象池,减少消耗
    vh.GetUIVertexStream(verts);

    //这里直接把顶点容量扩大到了5倍
    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);

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

我们在 var neededCpacity = verts.Count * 5;这一句中就可以发现,直接把顶点容量扩大到5倍,也就是比之前增加了4倍。

我们发现它调用了4次 ApplyShadowZeroAlloc 方法,这个方法在Shadow.cs里面,因为OutLine继承了Shadow。接下来看一下ApplyShadowZeroAlloc方法的具体内容。

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

ApplyShadowZeroAlloc这里面就是去复制顶点添加到原来的顶点列表,然后给复制的来的顶点去设置偏移和颜色。

由此可见,使用了OutLine后就相当于直接多出4倍的顶点,所以要尽量避免使用。

然后我就想,如果用两倍的顶点,一倍顶点去放大一圈,一倍顶点去缩小一圈,能不能也实现对应的效果。然后我就写了一个新的OutLine组件。

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

public class OutLineNew : Shadow
{
    private const int VERTEX_GROUP_NUM = 6;
    private enum EDirection
    {
        LeftTop,
        RightTop,
        LeftBottom,
        RightBottom,
    }
    protected OutLineNew()
    { }
    private void SetVertexPos( List<UIVertex> vertexs ,int index ,bool isBig , EDirection dir )
    {
        UIVertex vertex = vertexs[index];
        Vector3 pos = vertex.position;
        int parm = isBig ? 1 : -1;
        switch (dir)
        {
            case EDirection.LeftTop:
                pos.x -= effectDistance.x * parm;
                pos.y += effectDistance.y * parm;
                break;
            case EDirection.RightTop:
                pos.x += effectDistance.x * parm;
                pos.y += effectDistance.y * parm;
                break;
            case EDirection.LeftBottom:
                pos.x -= effectDistance.x * parm;
                pos.y -= effectDistance.y * parm;
                break;
            case EDirection.RightBottom:
                pos.x += effectDistance.x * parm;
                pos.y -= effectDistance.y * parm;
                break;
            default:
                break;
        }
        vertex.position = pos;
        vertexs[index] = vertex;
    }
    public override void ModifyMesh(VertexHelper vh)
    {
        if (!IsActive())
            return;

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

        //把顶点容量扩大到原来的3倍
        var neededCpacity = verts.Count * 3;
        if (verts.Capacity < neededCpacity)
            verts.Capacity = neededCpacity;
        int cnt = verts.Count;

        //给顶点设置阴影颜色
        for (int i = 0; i < cnt; i++)
        {
            var vt = verts[i];
            verts.Add(vt);
            vt.color = effectColor;
            verts[i] = vt;
        }
        for (int i = cnt; i < cnt*2; i++)
        {
            var vt = verts[i];
            verts.Add(vt);
            vt.color = effectColor;
            verts[i] = vt;
        }

        //给顶点设置偏移。(一个文字是有4个顶点,组成两个三角面,但是组成两个三角面时,有两个顶点会重复)

        //先给一倍的顶点去放大一圈
        for (int i = 0; i < cnt; i+= VERTEX_GROUP_NUM)
        {
            SetVertexPos(verts,i, true , EDirection.LeftTop);
            SetVertexPos(verts, i+1, true, EDirection.RightTop);
            SetVertexPos(verts, i+2, true, EDirection.RightBottom);
            SetVertexPos(verts, i+3, true, EDirection.RightBottom);
            SetVertexPos(verts, i+4, true, EDirection.LeftBottom);
            SetVertexPos(verts, i+5, true, EDirection.LeftTop);
        }

        //再给一倍的顶点去缩小一圈
        for (int i = cnt; i < cnt*2; i += VERTEX_GROUP_NUM)
        {
            SetVertexPos(verts, i, false, EDirection.LeftTop);
            SetVertexPos(verts, i + 1, false, EDirection.RightTop);
            SetVertexPos(verts, i + 2, false, EDirection.RightBottom);
            SetVertexPos(verts, i + 3, false, EDirection.RightBottom);
            SetVertexPos(verts, i + 4, false, EDirection.LeftBottom);
            SetVertexPos(verts, i + 5, false, EDirection.LeftTop);
        }
        vh.Clear();
        vh.AddUIVertexTriangleStream(verts);
        ListPool<UIVertex>.Release(verts);
    }
}

对比一下效果

~~~~~果然效果差多了呀~~

 

顺便再说一下Shadow这个组件吧。看完了OutLine,Shadow就不难理解了。先上源码:

protected void ApplyShadow(List<UIVertex> verts, Color32 color, int start, int end, float x, float y)
{
    ApplyShadowZeroAlloc(verts, color, start, end, x, y);
}
public override void ModifyMesh(VertexHelper vh)
{
    if (!IsActive())
        return;

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

    ApplyShadow(output, effectColor, 0, output.Count, effectDistance.x, effectDistance.y);
    vh.Clear();
    vh.AddUIVertexTriangleStream(output);
    ListPool<UIVertex>.Release(output);
}

它就是调用了一次ApplyShadowZeroAlloc,多生成了一倍的顶点。

 

总结一下就是,OutLine会额外生成4倍的顶点,Shadow会额外生成1倍的顶点。

好了今天就到这吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值