签到领奖

[younglee] Unity GUI(uGUI)扩展实例:文本竖直三色渐变

  [复制链接]
查看: 5289|回复: 18
排名
1015
昨日变化
2
发表于 2016-12-23 12:21:20 | 显示全部楼层 |阅读模式
本帖最后由 younglee 于 2016-12-23 12:32 编辑

大家知道uGUI中的Text组件默认是单色显示的,而通过一些简单的扩展,我们是可以让它支持渐变色的,比如如下效果:


在正式开始之前,再来回顾下相关内容。在图形渲染阶段,像素点的颜色默认是根据顶点颜色插值得来的;另外在前面的文章中我们介绍过,uGUI会默认为每个元素生成两个三角形用于渲染(也就是说uGUI的元素形状都是矩形的);对于Text,每个字符都由(6个顶点组成的)两个三角形来渲染的。

那么根据上面的原则,我们可以很直观地想到,如果可以改变Text的顶点颜色,是不是就能创造渐变效果呢?事实上,这正是uGUI提供给我们的扩展手段之一。

来看下今天的主角:BaseMeshEffect。
BaseMeshEffect
class in UnityEngine.UI/Inherits from:EventSystems.UIBehaviour
Implements interfaces:IMeshModifier

Description
Base class for effects that modify the generated Mesh.

这个类是提供给我们用于修改uGUI生成的网格数据,以自定义ui效果的。使用方式也很简单,首先我们自定义一个类来继承它,然后重写它的虚方法:
[C#] 纯文本查看 复制代码
public override void ModifyMesh(VertexHelper vh);

其中VertexHelper是用于辅助网格修改的类,通过它提供的接口,可以很方便地操作ui网格数据。

这个方法会在每次网格更新时调用,我们可以在这里修改网格数据,即可达到想要的效果。根据上面的思路,一个简单的竖直双色渐变代码:

[C#] 纯文本查看 复制代码
[RequireComponent(typeof(Text))]
public class TextVerticalGradientColor : BaseMeshEffect
{
    public Color colorTop = Color.white;
    public Color colorBottom = Color.black;

    protected TextVerticalGradientColor()
    {

    }

    private static void setColor(List<UIVertex> verts, int index, Color32 c)
    {
        UIVertex vertex = verts[index];
        vertex.color = c;
        verts[index] = vertex;
    }

    private void ModifyVertices(List<UIVertex> verts)
    {
        for (int i = 0; i < verts.Count; i += 6)
        {
            setColor(verts, i + 0, colorTop);
            setColor(verts, i + 1, colorTop);
            setColor(verts, i + 2, colorBottom);
            setColor(verts, i + 3, colorBottom);

            setColor(verts, i + 4, colorBottom);
            setColor(verts, i + 5, colorTop);
        }
    }

    #region implemented abstract members of BaseMeshEffect

    public override void ModifyMesh(VertexHelper vh)
    {
        if(!this.IsActive())
        {
            return;
        }
        List<UIVertex> verts = new List<UIVertex>(vh.currentVertCount);
        vh.GetUIVertexStream(verts);

        ModifyVertices(verts);

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

    #endregion
}


整段代码中,我们所做的只是遍历每个顶点,修改它的颜色。将这个脚本添加到Text上,即可看到效果。

当然,直到目前为止,我们只是实现了双色渐变,而如果要实现三色(甚至更多)渐变呢?由于uGUI默认为每个字符生成顶部和底部的6个顶点,单纯靠修改顶点颜色似乎是达不到这个目标的。

如果你仔细阅读并理解了上面的思路,应该不难想到,我们是不是可以通过在字符中间插入顶点的方式来实现三色渐变呢?


不如我们动手来试一下吧。根据上面的图片分析,我们需要把每个字符的顶点由默认的

【tl(左上)、tr(右上)、br(右下)、br、bl(左下)、tl】 改为

【tl、tr、cr(右中)、cr、cl(左中)、tl、cl、cr、br、br、bl、cl】, 并把三角形由默认的

【tl->tr->br, br->bl->tl】改为

【tl->tr->cr, cr->cl->tl, cl->cr->br, br->bl->cl】, 核心代码如下:

[C#] 纯文本查看 复制代码
for (int i = 0; i < verts.Count; i += step) {        //6 point
        var tl = multiplyColor(verts[i+0], colorTop);
        var tr = multiplyColor (verts [i+1], colorTop);
        var bl = multiplyColor (verts [i+4], colorBottom);
        var br = multiplyColor (verts [i + 3], colorBottom);
        var cl = calcCenterVertex(verts[i+0], verts [i+4]);
        var cr = calcCenterVertex (verts [i+1], verts [i+2]);

        vh.AddVert (tl);
        vh.AddVert (tr);
        vh.AddVert (cr);
        vh.AddVert (cr);
        vh.AddVert (cl);
        vh.AddVert (tl);

        vh.AddVert (cl);
        vh.AddVert (cr);
        vh.AddVert (br);
        vh.AddVert (br);
        vh.AddVert (bl);
        vh.AddVert (cl);
}

for (int i = 0; i < vh.currentVertCount; i += 12) {
        vh.AddTriangle (i + 0, i + 1, i + 2);
        vh.AddTriangle (i + 3, i + 4, i + 5);
        vh.AddTriangle (i + 6, i + 7, i + 8);
        vh.AddTriangle (i + 9, i + 10, i + 11);
}


修改完成后切回Unity,可以发现一切都如预期的顺利,三色渐变效果已经正常实现,来看下此时的网格:


可以发现,这种效果比默认的Text多生成了一倍的顶点和三角形(也就是每个字符变为12个顶点和4个三角形)。

按照这种思路,诸如水平渐变、径向渐变之类的效果也是不难实现的。通过这次的尝试,我们也能发现uGUI的扩展性也是挺好的。

附完整代码(在Unity 5.3 测试通过):

[C#] 纯文本查看 复制代码
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.UI;

namespace UI.Extension
{
    [AddComponentMenu ("UI/Effects/Text Vertical Gradient Color")]
    [RequireComponent(typeof(Text))]
    public class TextVerticalGradientColor : BaseMeshEffect
    {
        public Color colorTop = Color.white;
        public Color colorCenter = Color.grey;
        public Color colorBottom = Color.black;

        public bool MultiplyTextColor = false;

        protected TextVerticalGradientColor()
        {

        }

        public static Color32 Multiply(Color32 a, Color32 b)
        {
            a.r = (byte)((a.r * b.r) >> 8);
            a.g = (byte)((a.g * b.g) >> 8);
            a.b = (byte)((a.b * b.b) >> 8);
            a.a = (byte)((a.a * b.a) >> 8);
            return a;
        }

        private void ModifyVertices(VertexHelper vh)
        {
            List<UIVertex> verts = new List<UIVertex>(vh.currentVertCount);
            vh.GetUIVertexStream(verts);
            vh.Clear();

            int step = 6;

            for (int i = 0; i < verts.Count; i += step) {
                //6 point
                var tl = multiplyColor(verts[i+0], colorTop);
                var tr = multiplyColor (verts [i+1], colorTop);
                var bl = multiplyColor (verts [i+4], colorBottom);
                var br = multiplyColor (verts [i + 3], colorBottom);
                var cl = calcCenterVertex(verts[i+0], verts [i+4]);
                var cr = calcCenterVertex (verts [i+1], verts [i+2]);

                vh.AddVert (tl);
                vh.AddVert (tr);
                vh.AddVert (cr);
                vh.AddVert (cr);
                vh.AddVert (cl);
                vh.AddVert (tl);

                vh.AddVert (cl);
                vh.AddVert (cr);
                vh.AddVert (br);
                vh.AddVert (br);
                vh.AddVert (bl);
                vh.AddVert (cl);
            }

            for (int i = 0; i < vh.currentVertCount; i += 12) {
                vh.AddTriangle (i + 0, i + 1, i + 2);
                vh.AddTriangle (i + 3, i + 4, i + 5);
                vh.AddTriangle (i + 6, i + 7, i + 8);
                vh.AddTriangle (i + 9, i + 10, i + 11);
            }
        }

        private UIVertex multiplyColor(UIVertex vertex, Color color)
        {
            if (MultiplyTextColor)
                vertex.color = Multiply (vertex.color, color);
            else
                vertex.color = color;
            return vertex;
        }

        private UIVertex calcCenterVertex(UIVertex top, UIVertex bottom)
        {
            UIVertex center;
            center.normal = (top.normal + bottom.normal) / 2;
            center.position = (top.position + bottom.position) / 2;
            center.tangent = (top.tangent + bottom.tangent) / 2;
            center.uv0 = (top.uv0 + bottom.uv0) / 2;
            center.uv1 = (top.uv1 + bottom.uv1) / 2;

            if (MultiplyTextColor) {
                //multiply color
                var color = Color.Lerp(top.color, bottom.color, 0.5f);
                center.color = Multiply (color, colorCenter);
            } else {
                center.color = colorCenter;
            }

            return center;
        }

        #region implemented abstract members of BaseMeshEffect

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


            ModifyVertices(vh);
        }

        #endregion
    }
}








免费评分

参与人数 2泰斗币 +100 收起 理由
里斯 + 50 赞一个!
洞悉 + 50 赞一个!

查看全部评分

+1
1787°C
18
  • 星空1989
  • kx88
  • xideer
  • 里斯
  • jingfengji
过: 他们
3江湖小虾
223/500
排名
67
昨日变化
1
发表于 2016-12-23 13:10:07 | 显示全部楼层
看了LZ的帖子,我只想说一句很好很强大!
3江湖小虾
292/500
排名
35
昨日变化
发表于 2016-12-28 10:30:38 | 显示全部楼层
为了泰斗币,拼了。
[发帖际遇]: kx88 你天天对暗恋妹纸三笑留情,这是 1 泰斗币以表彰你的吊丝精神. 幸运榜 / 衰神榜
排名
1015
昨日变化
2
发表于 2016-12-28 11:41:39 | 显示全部楼层
泰斗那么大,我想来看看。
5武林高手
1394/2000
排名
179
昨日变化
发表于 2016-12-28 14:00:48 | 显示全部楼层
膜拜神贴,后面的请保持队形~
[发帖际遇]: 里斯 拉灯想跟你学用unity做航母,这是 6 泰斗币当学费了. 幸运榜 / 衰神榜
2武林新丁
118/200
排名
285
昨日变化
2
发表于 2016-12-28 23:26:53 | 显示全部楼层
之前也写过这种双色渐变色,不过还没试过添加顶点,受教了
2武林新丁
185/200
排名
229
昨日变化
发表于 2016-12-29 16:56:47 | 显示全部楼层
为了泰斗币,拼了。{:5_124:}
2武林新丁
138/200
排名
229
昨日变化
4
发表于 2016-12-30 09:52:09 | 显示全部楼层
这个是真的强 从来不知道还有这种东西
排名
1415
昨日变化
4
发表于 2016-12-30 11:03:06 | 显示全部楼层
为了泰斗币,拼了。

免费评分

参与人数 1泰斗币 +50 收起 理由
里斯 + 50 赞一个,这是公开课奖励

查看全部评分

排名
458
昨日变化
5
发表于 2017-1-3 10:10:44 | 显示全部楼层
厉害了,不过目前还看不太懂,想完全懂还得学着色器吧?
排名
1015
昨日变化
2
 楼主| 发表于 2017-1-3 11:25:38 | 显示全部楼层
winter_wang 发表于 2017-1-3 10:10
厉害了,不过目前还看不太懂,想完全懂还得学着色器吧?

不用,这个并没有用到着色器的东西~
2武林新丁
168/200
排名
272
昨日变化
2
发表于 2017-1-4 09:31:56 | 显示全部楼层
看了LZ的帖子,我只想说一句很好很强大!
排名
575
昨日变化
1
发表于 2017-1-9 09:38:22 | 显示全部楼层
。。。强!  无敌!!!
2武林新丁
116/200
排名
417
昨日变化
5
发表于 2017-1-13 15:03:43 | 显示全部楼层
非常有用,谢谢分享。
3江湖小虾
278/500
排名
186
昨日变化
发表于 2017-1-20 16:44:52 | 显示全部楼层
膜拜神贴,后面的请保持队形~
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /3 下一条

在线客服(工作时间:9:00-22:00)
010-82609395
泰斗社区公众号

Copyright   ©2015-2016  【泰斗社区】-专注互联网游戏和应用的开发者平台  Powered by©Discuz!  技术支持:迪恩网络     ( 沪ICP备14023207号-9 )