当前位置:   article > 正文

UGUI中实现多边形网格显示图形_texturepacker导出tpsheet

texturepacker导出tpsheet

UGUI中实现多边形网格显示图形

在使用UGUI Image组件显示不规则图片、镂空图片时,Image总是会创建一个四边形网格来显示图形,渲染过程中,GPU需要对完全透明的区域进行计算,这不利于性能的优化,一个解决办法是采用多边形网格显示图形,来减少这种不必要的消耗。

下面是Image组件和多边形显示组件的网格对比
网格对比


下面是Image和多边形的Overdraw对比
overdraw对比

整个方案的实现过程包括以下几个步骤:

  1. 生成图集,这里推荐使用 Texture Packer,这里要求导出 tpsheet 格式。
  2. 导入图集、生成多边形,这里需要从AssetStore下载TexturePackerImporter(已经包含的项目中)。到导入插件之后,将 tpsheet 文件和图集一起导入项目中,导入之后TexturePackerImporter会自动将图集转换成带多边形的Sprite。
  3. 使用UIPolyImage组件替换 Image 组件。(该组件目前只支持 Simple 模式)

如果需要根据图形做射线检测,在 UIPolyImage/Image 组件上添加PolyRaycastFilter 组件。因为该组件需要读取贴图的像素,所以需要将贴图的 readAndWrite 属性勾选。

示例项目:这里

多边形Image组件

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

namespace UnityEngine.UI
{
    public class UIPolyImage : Image
    {
        protected override void OnPopulateMesh(VertexHelper vh)
        {
            if (overrideSprite == null)
            {
                base.OnPopulateMesh(vh);
                return;
            }

            switch (type)
            {
                case Type.Simple:
                case Type.Filled:
                case Type.Sliced:
                case Type.Tiled:
                    GenerateSimpleSprite(vh, preserveAspect);
                    break;
            }
        }

        void GenerateSimpleSprite(VertexHelper vh, bool lPreserveAspect)
        {
            Vector4 v = GetDrawingDimensions(lPreserveAspect);
            var color32 = color;

            float width = v.z - v.x;
            float height = v.w - v.y;

            //将sprite.pivot进行归一化
            Vector2 spritePivot = new Vector2(sprite.pivot.x / sprite.rect.width, sprite.pivot.y / sprite.rect.height);
            Vector2 pivotOffset = Vector2.Scale(spritePivot - rectTransform.pivot, new Vector2(width, height));

            Vector3 scale = new Vector3(1, 1, 1);
            scale.x = width / sprite.bounds.size.x;
            scale.y = height / sprite.bounds.size.y;
            Matrix4x4 trsMT = Matrix4x4.TRS(pivotOffset, Quaternion.identity, scale);

            vh.Clear();
            for (int i = 0; i < sprite.vertices.Length; i++)
            {
                vh.AddVert(trsMT.MultiplyPoint3x4(sprite.vertices[i]), color32, sprite.uv[i]);
            }

            for (int i = 0; i < sprite.triangles.Length; i += 3)
            {
                vh.AddTriangle(sprite.triangles[i], sprite.triangles[i + 1], sprite.triangles[i + 2]);
            }
        }

        public Rect GetDrawingRect()
        {
            Vector4 v = GetDrawingDimensions(preserveAspect);
            return Rect.MinMaxRect(v.x, v.y, v.z, v.w);
        }

        /// Image's dimensions used for drawing. X = left, Y = bottom, Z = right, W = top.
        private Vector4 GetDrawingDimensions(bool shouldPreserveAspect)
        {
            var padding = overrideSprite == null ? Vector4.zero : UnityEngine.Sprites.DataUtility.GetPadding(overrideSprite);
            var size = overrideSprite == null ? Vector2.zero : new Vector2(overrideSprite.rect.width, overrideSprite.rect.height);

            Rect r = GetPixelAdjustedRect();
            // Debug.Log(string.Format("r:{2}, size:{0}, padding:{1}", size, padding, r));

            int spriteW = Mathf.RoundToInt(size.x);
            int spriteH = Mathf.RoundToInt(size.y);

            var v = new Vector4(
                    padding.x / spriteW,
                    padding.y / spriteH,
                    (spriteW - padding.z) / spriteW,
                    (spriteH - padding.w) / spriteH);

            if (shouldPreserveAspect && size.sqrMagnitude > 0.0f)
            {
                var spriteRatio = size.x / size.y;
                var rectRatio = r.width / r.height;

                if (spriteRatio > rectRatio)
                {
                    var oldHeight = r.height;
                    r.height = r.width * (1.0f / spriteRatio);
                    r.y += (oldHeight - r.height) * rectTransform.pivot.y;
                }
                else
                {
                    var oldWidth = r.width;
                    r.width = r.height * spriteRatio;
                    r.x += (oldWidth - r.width) * rectTransform.pivot.x;
                }
            }

            v = new Vector4(
                    r.x + r.width * v.x,
                    r.y + r.height * v.y,
                    r.x + r.width * v.z,
                    r.y + r.height * v.w
                    );

            return v;
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110

射线检测过滤组件

这里实现方式是通过获取像素的 Alpha 值来进行判断的,所以一个明显的缺点就是需要将贴图的 readable 设置为true。当然还有一些其他的方法也可以实现功能,比如设置多边形碰撞、多边形检测等等,后续如果有机会的话,会补充其他的方法。

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

namespace UnityEngine.UI
{
    /// <summary>
    /// 用于检测不规则图形的射线检测方法,由于需要进行多边形的射线检测,
    /// 效率相对较低,所以,确认自己必须进行不规则射线检测时,才使用
    /// 该组件。
    /// </summary>
    [RequireComponent(typeof(UIPolyImage))]
    public class PolyRaycastFilter : MonoBehaviour, ICanvasRaycastFilter
    {
        private UIPolyImage image
        {
            get
            {
                if (m_Image == null)
                    m_Image = GetComponent<UIPolyImage>();
                return m_Image;
            }
        }

        private RectTransform rectTransform
        {
            get
            {
                if (m_RectTransform == null)
                    m_RectTransform = GetComponent<RectTransform>();
                return m_RectTransform;
            }
        }

        private UIPolyImage m_Image;
        private RectTransform m_RectTransform;

        public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
        {
            if (image.sprite == null)
                return false;

            //首先转换到本地坐标系中,方便下面的计算
            Vector2 localP = rectTransform.InverseTransformPoint(sp);

            Rect pixelRect = image.GetDrawingRect();
            if (!pixelRect.Contains(localP, false))
                return false;

            Vector2 delta = localP - pixelRect.min;
            Vector2 normalizedDelta = new Vector2(delta.x / pixelRect.width, delta.y / pixelRect.height);
            int x = Mathf.CeilToInt(normalizedDelta.x * image.sprite.rect.width+image.sprite.rect.xMin);
            int y = Mathf.CeilToInt(normalizedDelta.y * image.sprite.rect.height+image.sprite.rect.yMin);

            Color pixel = image.sprite.texture.GetPixel(x, y);

            return !Mathf.Approximately(pixel.a, 0f);
        }
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/木道寻08/article/detail/881903
推荐阅读
相关标签
  

闽ICP备14008679号