[Unity] UGUI拓展 - 实现Image的镜像

作者: _Walker__ | 来源:发表于2018-05-05 10:51 被阅读33次

    参考:Unity3D UGUI优化:制作镜像图片(1)

    效果预览 (左侧从上到下依次是Horizontal、Vertical、Quater的效果)

    1、序

      这两天美术在整理UI资源,主要目的是降低内存,大概做的事有:

    • 删除废弃的资源
    • 重新划分图集(把小图集合并到大图集中)
    • 压缩大Icon:降低分辨率、对称资源砍半
        图片镜像就是为对称资源砍半提供的支持,更多的益处可以直接去看参考文章,里面写的很好了。我的实现方法和参考文章有很大差别,我主要希望能取得更好的性能,为此牺牲了一些代码量和表现效果。
    参考文章实现 我的实现 勾选Preserve Aspect (上图是参考方案,下图是我的,虽然都不对但毕竟上面的好看Orz...)

    2、记

      参考方案使用vh.GetUIVertexStream(output)来获取顶点列表,它返回的顶点就已经是存在冗余的了,一个普通的Image其列表长度是6。也就是说,列表里每3个元素为一组,它们代表一个三角面。简单测试后发现,经过GetUIVertexStream() -> AddUIVertexTriangleStream()这个处理后,即使图像没有发生显示上的变化,顶点数也会增加。
      为了规避顶点增加的问题,我只是用了最简单的两个接口VertexHelper.AddVert(UIVertex v)VertexHelper.AddTriangle(int idx0, int idx1, int idx2),这可以保证产生的顶点数最少,因为相邻三角面的两个顶点是共用的。这个方案的弊端是没有普适的逻辑来创建三角面(或者有什么算法能做到,只是我不知道),因此只能人肉排顶点编号。对于目前只有几个三角面的情况,工作量和代码量都还在可接受范围内。

    三角的面的顶点顺序,要遵循左手定则:

    拇指朝向屏幕外,其余四指弯曲的方向,就是顶点的顺序

    3、码

    using UnityEngine;
    using UnityEngine.UI;
    
    /// <summary>
    /// 对UI图形进行镜像处理
    /// Image - Sample顶点顺序
    /// ------
    /// |1 /2|
    /// |0/ 3|
    /// ------
    /// </summary>
    [RequireComponent(typeof(Image))]
    public class UIImageMirror: BaseMeshEffect
    {
        public enum MirrorDir
        {
            Horizontal, // 水平镜像
            Vertical,   // 垂直镜像
            Quater,     // 四方镜像(先水平,后垂直)
        }
    
        protected const int AxisX = 0;
        protected const int AxisY = 1;
    
        [SerializeField]
        private MirrorDir _direction;
    
        public override void ModifyMesh(VertexHelper vh)
        {
            if (!IsActive()) return;
    
            Image img = graphic as Image;
            if (null == img) return;
    
            if (img.type == Image.Type.Simple)
            {
                _SimpleMirror(vh);
            }
        }
    
    
        #region ========= Image.Type.Simple模式 =========
    
        private void _SimpleMirror(VertexHelper vh)
        {
            Rect rect = graphic.GetPixelAdjustedRect();
            ShrinkVert(vh, rect);
    
            Vector2 doubleCenter = rect.center * 2;
            switch (_direction)
            {
                case MirrorDir.Horizontal:
                    SimpleMirrorHor(vh, doubleCenter.x);
                    break;
    
                case MirrorDir.Vertical:
                    SimpleMirrorVer(vh, doubleCenter.y);
                    break;
    
                case MirrorDir.Quater:
                    SimpleMirrorQuat(vh, doubleCenter);
                    break;
            }
        }
    
        /// <summary>
        /// Simple模式的水平镜像
        /// 顶点布局:
        /// -----------
        /// |1 /2| \ 5|
        /// |0/ 3|  \4|
        /// -----------
        /// </summary>
        protected void SimpleMirrorHor(VertexHelper vh, float doubleX)
        {
            AddMirrorVert(vh, 0, AxisX, doubleX);  // 顶点4
            AddMirrorVert(vh, 1, AxisX, doubleX);  // 顶点5
    
            vh.AddTriangle(2, 4, 3);
            vh.AddTriangle(2, 5, 4);
        }
    
        /// <summary>
        /// Simple模式的垂直镜像
        /// 顶点布局:
        /// ------
        /// |4\ 5|
        /// |  \ |
        /// ------
        /// |1 /2|
        /// |0/ 3|
        /// ------
        /// </summary>
        protected void SimpleMirrorVer(VertexHelper vh, float doubleY)
        {
            AddMirrorVert(vh, 0, AxisY, doubleY);  // 顶点4
            AddMirrorVert(vh, 3, AxisY, doubleY);  // 顶点5
    
            vh.AddTriangle(2, 1, 4);
            vh.AddTriangle(2, 4, 5);
        }
    
        /// <summary>
        /// Simple模式的四方镜像
        /// 顶点布局:
        /// -----------
        /// |6 /7| \ 8|
        /// | /  |  \ |
        /// -----------
        /// |1 /2| \ 5|
        /// |0/ 3|  \4|
        /// -----------
        /// </summary>
        protected void SimpleMirrorQuat(VertexHelper vh, Vector2 doubleCenter)
        {
            // 水平
            AddMirrorVert(vh, 0, AxisX, doubleCenter.x);   // 顶点4
            AddMirrorVert(vh, 1, AxisX, doubleCenter.x);   // 顶点5
            vh.AddTriangle(2, 4, 3);
            vh.AddTriangle(2, 5, 4);
    
            // 垂直
            AddMirrorVert(vh, 0, AxisY, doubleCenter.y);   // 顶点6
            AddMirrorVert(vh, 3, AxisY, doubleCenter.y);   // 顶点7
            AddMirrorVert(vh, 4, AxisY, doubleCenter.y);   // 顶点8
            vh.AddTriangle(7, 1, 6);
            vh.AddTriangle(7, 2, 1);
            vh.AddTriangle(7, 5, 2);
            vh.AddTriangle(7, 8, 5);
        }
    
        #endregion
    
    
        /// <summary>
        /// 添加单个镜像顶点
        /// </summary>
        /// <param name="vh"></param>
        /// <param name="srcVertIdx">镜像源顶点的索引值</param>
        /// <param name="axis">轴向:0-X轴;1-Y轴</param>
        /// <param name="doubleCenter">Rect.center轴向分量的两倍值</param>
        protected static void AddMirrorVert(VertexHelper vh, int srcVertIdx, int axis, float doubleCenter)
        {
            UIVertex vert = UIVertex.simpleVert;
            vh.PopulateUIVertex(ref vert, srcVertIdx);
            Vector3 pos = vert.position;
            pos[axis] = doubleCenter - pos[axis];
            vert.position = pos;
            vh.AddVert(vert);
        }
    
        /// <summary>
        /// 收缩顶点坐标
        /// 根据镜像类型,将原始顶点坐标向“起始点(左/下)”收缩
        /// </summary>
        protected void ShrinkVert(VertexHelper vh, Rect rect)
        {
            int count = vh.currentVertCount;
    
            UIVertex vert = UIVertex.simpleVert;
            for (int i = 0; i < count; ++i)
            {
                vh.PopulateUIVertex(ref vert, i);
                Vector3 pos = vert.position;
                if (MirrorDir.Horizontal == _direction || MirrorDir.Quater == _direction)
                {
                    pos.x = (rect.x + pos.x) * 0.5f;
                }
                if (MirrorDir.Vertical == _direction || MirrorDir.Quater == _direction)
                {
                    pos.y = (rect.y + pos.y) * 0.5f;
                }
                vert.position = pos;
                vh.SetUIVertex(vert, i);
            }
        }
    
    
        #region ======设置Image的原尺寸======
    
        private RectTransform _rectTrans;
        public RectTransform RectTrans
        {
            get
            {
                if (null == _rectTrans)
                {
                    _rectTrans = GetComponent<RectTransform>();
                }
                return _rectTrans;
            }
        }
    
        public void SetNativeSize()
        {
            Image img = graphic as Image;
            if (null == img) return;
    
            Sprite sprite = img.overrideSprite;
            if(null == sprite) return;
    
            float w = sprite.rect.width / img.pixelsPerUnit;
            float h = sprite.rect.height / img.pixelsPerUnit;
            RectTrans.anchorMax = RectTrans.anchorMin;
            switch (_direction)
            {
                case MirrorDir.Horizontal:
                    RectTrans.sizeDelta = new Vector2(w * 2, h);
                    break;
                case MirrorDir.Vertical:
                    RectTrans.sizeDelta = new Vector2(w, h * 2);
                    break;
                case MirrorDir.Quater:
                    RectTrans.sizeDelta = new Vector2(w * 2, h * 2);
                    break;
            }
    
            img.SetVerticesDirty();
        }
    
        #endregion
    }
    
    

    相关文章

      网友评论

        本文标题:[Unity] UGUI拓展 - 实现Image的镜像

        本文链接:https://www.haomeiwen.com/subject/aksjrftx.html