zoukankan      html  css  js  c++  java
  • (七)自定义Graphic

    1.前言

    基于CanvasRenderer实现一个自定义(破产版)的graphic。以往自定义ui形式时,可以新建脚本继承Graphic,通过重写虚方法来实现一些特殊功能。此文则从CanvasRenderer的层面,实现一个Graphic。实现时采用的方法则是SetMesh、SetMaterial以及SetMaterial等方法。完整代码在文末。

    2.实现Graphic

    2.1 设置网格

    网格为ui的平面mesh,可以参考uimesh。由于我们需要网格随着RectTransform的变化而更改,所以此处给出两个网格的实现,一个是固定网格,一个是动态更改网格。生成mesh后通过canvasRender.SetMesh(UIMesh);设置网格。

    2.1.1 固定网格

    如下代码网格是固定大小:

        public Mesh UIMesh
        {
            get
            {
                if (mesh && useLastMesh)
                    return mesh;
    
                mesh = new Mesh();
                VertexHelper vh = new VertexHelper();
    
                var r = GetPixelAdjustedRect();
                var v = new Vector4(r.x, r.y, r.x + r.width, r.y + r.height);
    
                vh.AddVert(new Vector3(-50, -50), Color.white, new Vector2(0, 0));
                vh.AddVert(new Vector3(50, -50), Color.red, new Vector2(1, 0));
                vh.AddVert(new Vector3(50, 50), Color.red, new Vector2(1, 1));
                vh.AddVert(new Vector3(-50, 50), Color.white, new Vector2(0, 1));
    
                vh.AddTriangle(0, 1, 2);
                vh.AddTriangle(0, 2, 3);
    
                vh.FillMesh(mesh);
    
                return mesh;
            }
        }
    

    2.1.2 动态网格

    网格根据rect的大小动态更改。通过GetPixelAdjustedRect来获取rect的大小,然后根据获取到的大小数据生成网格。

        public Mesh UIMesh
        {
            get
            {
                if (mesh && useLastMesh)
                    return mesh;
    
                mesh = new Mesh();
                VertexHelper vh = new VertexHelper();
    
                var r = GetPixelAdjustedRect();
                var v = new Vector4(r.x, r.y, r.x + r.width, r.y + r.height);
    
                //vh.AddVert(new Vector3(-50, -50), Color.white, new Vector2(0, 0));
                //vh.AddVert(new Vector3(50, -50), Color.red, new Vector2(1, 0));
                //vh.AddVert(new Vector3(50, 50), Color.red, new Vector2(1, 1));
                //vh.AddVert(new Vector3(-50, 50), Color.white, new Vector2(0, 1));
    
                //vh.AddTriangle(0, 1, 2);
                //vh.AddTriangle(0, 2, 3);
    
                vh.Clear();
                vh.AddVert(new Vector3(v.x, v.y), Color.white, new Vector2(0f, 0f));
                vh.AddVert(new Vector3(v.x, v.w), Color.white, new Vector2(0f, 1f));
                vh.AddVert(new Vector3(v.z, v.w), Color.white, new Vector2(1f, 1f));
                vh.AddVert(new Vector3(v.z, v.y), Color.white, new Vector2(1f, 0f));
    
                vh.AddTriangle(0, 1, 2);
                vh.AddTriangle(2, 3, 0);
    
                vh.FillMesh(mesh);
    
                return mesh;
            }
        }
    

    2.2 材质

    在unity中新建Material,然后将此材质shader选为UI/Default。然后将此材质设置给CanvasRenderer,并设置Texture。如下:

            canvasRender.materialCount = 1;
            canvasRender.SetMesh(UIMesh);
            canvasRender.SetMaterial(material, 0);
            canvasRender.SetTexture(mainTexture);
    

    2.3 设置Rect剔除

    RectMaskD的剔除作用是通过CanvasRenderer的EnableRectCliping实现的,入口参数为Rect类型变量。但是主意一点,此Rect的值是Canvas下的坐标,因为此方法定义的是本UI图像在Canvas的剔除位置,至于剔除子物体是由ui的逻辑控制的。如下:

        private void EnableRectClip(Rect rect)
        {
            canvasRender.EnableRectClipping(rect);
        }
    

    2.4 启动位置

    可以在start里生成ui也可在update中,如果当ui内容变化(比如贴图或者大小等),则需要标记此变化,在下一帧去更改。原Graphic的做法是在Canvas.willRenderCanvases中进行的,如下:

    void Start ()
        {
            SetCanvasRenderer();
    
            Canvas.willRenderCanvases += WillRenderCanvas;
        }
    
        void WillRenderCanvas()
        {
            if (!useLastMesh)
            {
                SetCanvasRenderer();
                useLastMesh = true;
            }
        }
    

    3.完整代码

    如下是整个破产版Graphic的完整代码:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class CustomGraphic : MonoBehaviour
    {
        public Texture mainTexture;
        public CanvasRenderer canvasRender;
        public Material material;
        public Canvas canvas;
        public RectTransform rectTransform;
    
        public bool enableClip = true;
    
        private Mesh mesh;
        private bool useLastMesh = true;
    
        public Mesh UIMesh
        {
            get
            {
                if (mesh && useLastMesh)
                    return mesh;
    
                mesh = new Mesh();
                VertexHelper vh = new VertexHelper();
    
                var r = GetPixelAdjustedRect();
                var v = new Vector4(r.x, r.y, r.x + r.width, r.y + r.height);
    
                //vh.AddVert(new Vector3(-50, -50), Color.white, new Vector2(0, 0));
                //vh.AddVert(new Vector3(50, -50), Color.red, new Vector2(1, 0));
                //vh.AddVert(new Vector3(50, 50), Color.red, new Vector2(1, 1));
                //vh.AddVert(new Vector3(-50, 50), Color.white, new Vector2(0, 1));
    
                //vh.AddTriangle(0, 1, 2);
                //vh.AddTriangle(0, 2, 3);
    
                vh.Clear();
                vh.AddVert(new Vector3(v.x, v.y), Color.white, new Vector2(0f, 0f));
                vh.AddVert(new Vector3(v.x, v.w), Color.white, new Vector2(0f, 1f));
                vh.AddVert(new Vector3(v.z, v.w), Color.white, new Vector2(1f, 1f));
                vh.AddVert(new Vector3(v.z, v.y), Color.white, new Vector2(1f, 0f));
    
                vh.AddTriangle(0, 1, 2);
                vh.AddTriangle(2, 3, 0);
    
                vh.FillMesh(mesh);
    
                return mesh;
            }
        }
    
        private void SetCanvasRenderer()
        {
            if(enableClip)
            EnableRectClip(new Rect(-150, -150, 300, 300));
    
            canvasRender.materialCount = 1;
            canvasRender.SetMesh(UIMesh);
            canvasRender.SetMaterial(material, 0);
            canvasRender.SetTexture(mainTexture);
        }
    
        private void EnableRectClip(Rect rect)
        {
            canvasRender.EnableRectClipping(rect);
        }
    
    	void Start ()
        {
            SetCanvasRenderer();
    
            Canvas.willRenderCanvases += WillRenderCanvas;
        }
    
        void WillRenderCanvas()
        {
            if (!useLastMesh)
            {
                SetCanvasRenderer();
                useLastMesh = true;
            }
        }
    
        private void OnRectTransformDimensionsChange()
        {
            useLastMesh = false;
        }
    
        private Rect GetPixelAdjustedRect()
        {
            if (!canvas || canvas.renderMode == RenderMode.WorldSpace || canvas.scaleFactor == 0.0f || !canvas.pixelPerfect)
                return rectTransform.rect;
            else
                return RectTransformUtility.PixelAdjustRect(rectTransform, canvas);
        }
    }
    
    

    4.结语

    由于原UGUI为了更自动化也为了功能的全面性,添加了很多逻辑功能,其中大部分动能用到了GetComponents方法(以及类似方法),所以都对设备产生了比较多的消耗。

  • 相关阅读:
    (三)openwrt主Makefile解析
    (二)我的Makefile学习冲动&&编译过程概述
    openwrt修改flash大小
    (一)openwrt源码目录概述
    git_sop 脚本使用说明
    Openwrt LuCI模块练习详细步骤
    openwrt简单ipk生成及Makefile解释
    oracle中比较两表表结构差异和数据差异的方法
    C#泛型集合之Dictionary<k, v>使用技巧
    SQL语句添加,删除主键
  • 原文地址:https://www.cnblogs.com/llstart-new0201/p/12678243.html
Copyright © 2011-2022 走看看