UGUI使用教程(十五)Shadow与Outline

发表于2018-01-27
评论0 4k浏览
本篇文章主要给大家介绍的是Shadow和Outline的原理和使用,想在Unity3D里为一个图片或者文字添加阴影效果,只需要在该对象上在添加一个Shadow组件。Shadow通过为图像或者文字的Mesh添加顶点来实现阴影效果,而Outline是在对象四角上各添加了一个Shadow。由此我们可以得知,Outline的(额外)消耗是Shadow的四倍,所以还是需要谨慎使用。

按照惯例,附上UGUI源码下载地址

Outline继承自Shadow,Shadow继承自BaseMeshEffect,BaseMeshEffect继承自UIBehaviour和IMeshModifier。

UGUI使用教程(七)Graphic》中提到过,Graphic在生成完Mesh数据之后,会查找对象上IMeshModifier类型的组件,调用它们的ModifyMesh方法,之后再正式生成Mesh。

BaseMeshEffect是一个抽象类,而ModifyMesh是一个抽象方法(以Mesh为参数的ModifyMesh方法是过期的不再讨论),具体在其子类里实现。它的OnEnable、OnDisable和OnDidApplyAnimationProperties(当应用动画属性后),会调用graphic属性的SetVerticesDirty方法(设置顶点数据为脏的,重建图像时重新生成顶点数据)。graphic是一个只读属性,获取的是本对象的Graphic组件(Image、RawImage或Text)。

Shadow的ModifyMesh方法:
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);  
} 
获取VertexHelper(暂存顶点数据,用于辅助生成Mesh)里的顶点数据output。然后根据effectColor和effectDistance调整顶点。ApplyShadow会将顶点数乘以2,然后调用ApplyShadowZeroAlloc方法。遍历output的顶点,根据顶点生成一个新的顶点vt,添加到顶点列表里,并将vt的位置加上偏移量,并设置颜色。最后将output重新添加到VertexHelper里面(AddUIVertexTriangleStream会自行生成三角形)。

Outline的ModifyMesh方法:
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);  
    vh.Clear();  
    vh.AddUIVertexTriangleStream(verts);  
    ListPool<UIVertex>.Release(verts);  
}  

Outline将顶点数乘以了5,并在四角上各添加了一组(阴影)顶点。

补充:
除了Shadow和Outline以外,UGUI还内置了一个效果PositionAsUV1。
代码十分简单:
public class PositionAsUV1 : BaseMeshEffect  
{  
    protected PositionAsUV1()  
    {}  
    public override void ModifyMesh(VertexHelper vh)  
    {  
        UIVertex vert = new UIVertex();  
        for (int i = 0; i < vh.currentVertCount; i++)  
        {  
            vh.PopulateUIVertex(ref vert, i);  
            vert.uv1 =  new Vector2(vert.position.x, vert.position.y);  
            vh.SetUIVertex(vert, i);  
        }  
    }  
}  

就是根据坐标点设置uv1坐标(法线贴图坐标),为图片或者文字添加法线贴图效果。
原理我们知道了,那么效果是怎么样的呢?

导入一张贴图:

导入设置Texture Type为Normal map(法线贴图)。

我们新建一个Material,设置shader为UI/Unlit/Detail。将刚刚导入的法线贴图设置为Detail(RGB)。

在场景里新建一个Image,为它设置Material。我们会发现图片的颜色变深了一点,但是除此之外并没有变化。

接着为这个Image对象添加PositionAsUV1组件。如图:

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引