unity基于shader的填充式进度条

简述

参考mask 实现一个基于shader,填充方式的进度条
mask源码地址: https://bitbucket.org/Unity-Technologies/ui/downloads/?tab=tags

效果如图,笔记&详情见注释
unity基于shader的填充式进度条_第1张图片

源码

shader
Shader "UI/CP3"
{
    Properties
    {
        [PerRendererData] _MainTex ("Texture", 2D) = "white" {}
        [PerRendererData] _Width ("Width", Float) = 0
        [PerRendererData] _Height ("Height", Float) = 0
        _Color("Tint", Color) = (1,1,1,1)
        _Progress ("Progress", Float) = 0
    }
    SubShader
    {
        Tags {
            "Queue"="Transparent" 
            "IgnoreProjector"="True" 
            "RenderType"="Transparent" 
            "PreviewType"="Plane"
            "CanUseSpriteAtlas"="True"
        }
        LOD 100

        Cull Off
        Lighting Off
        ZWrite Off
        ZTest [unity_GUIZTestMode]
        Blend SrcAlpha OneMinusSrcAlpha


        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 _Color;
            float _Progress;
            float _Width;
            float _Height;
            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);

                float px = (i.uv.x - 0.5) * _Width / _Height;
                float py = (i.uv.y - 0.5);
                float isPro = step(px * px + py * py, _Progress * _Progress);
                return (col * isPro) + (col * _Color * col.a * !isPro);
            }
            ENDCG
        }
    }
}

PointProgess组件及对应编辑器脚本

unity基于shader的填充式进度条_第2张图片

//PointProgess.cs
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Rendering;
using UnityEngine.UI;
using UnityEngine.Serialization;


namespace VMUI
{
    //添加到菜单
    [AddComponentMenu("UI/PointProgress", 14)]
    //总是执行
    [ExecuteAlways]
    //需要RectTransform组件
    [RequireComponent(typeof(RectTransform))]
    //不允许同时编辑
    [DisallowMultipleComponent]

    // ugui下的接口,用于更新ui
    public class PointProgress : UIBehaviour, ICanvasRaycastFilter, IMaterialModifier
    {

        private static List m_List = new List();

        [NonSerialized]
        private RectTransform m_RectTransform;
        public RectTransform rectTransform
        {
            get { return m_RectTransform ?? (m_RectTransform = GetComponent()); }
        }

        [NonSerialized]
        private Material m_Material;

        [SerializeField]
        private int m_Progess = 0;

        //每次改变进度值时,重新调用渲染绘制
        public int Progess
        {
            get{return m_Progess;}

            set
            {
                if(m_Progess == value)
                    return;

                m_Progess = value;
                if (graphic != null)
                    graphic.SetMaterialDirty();
            }
        }

        //Graphic 渲染组件 无则说明不支持ugui渲染 不可调用相关方法
        [NonSerialized]
        private Graphic m_Graphic;

        /// 
        /// The graphic associated with the Mask.
        /// 
        public Graphic graphic
        {
            get { return m_Graphic ?? (m_Graphic = GetComponent()); }
        }

        protected override void OnEnable()
        {
            base.OnEnable();
            if (graphic != null)
            {
                graphic.canvasRenderer.hasPopInstruction = true;
                graphic.SetMaterialDirty();
            }
        }

        protected override void OnDisable()
        {
            base.OnDisable();
            if (graphic != null)
            {
                graphic.SetMaterialDirty();
                graphic.canvasRenderer.hasPopInstruction = false;
                graphic.canvasRenderer.popMaterialCount = 0;
            }

            //释放HideFlags.DontSave标志的资源
            DestroyImmediate(m_Material);
            m_Material = null;
        }

//编辑器下的渲染相关回调
#if UNITY_EDITOR
        protected override void OnValidate()
        {
            base.OnValidate();

            if (!IsActive())
                return;

            if (graphic != null)
                graphic.SetMaterialDirty();
        }

#endif

        public virtual bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
        {
            if (!isActiveAndEnabled)
                return true;

            return RectTransformUtility.RectangleContainsScreenPoint(rectTransform, sp, eventCamera);
        }

        //使用SetMaterialDirty后 会调用到该接口获取渲染材质
        public virtual Material GetModifiedMaterial(Material baseMaterial)
        {
            //为每个物体创建材质,进度和颜色等 独立设置
            if(m_Material == null){
                //拷贝已有材质
                m_Material = new Material(baseMaterial);
                m_Material.name = m_Material.name + "(Copy)";

                //HideFlags.DontSave | HideFlags.NotEditable 
                //HideFlags 使用 | 合并标签
                //DontSave 资源需要DestroyImmediate释放,否则会一直存在内存中
                //NotEditable 不可在编辑器中编辑资源
                m_Material.hideFlags = HideFlags.DontSave;

                //选择完材质后 需要设定宽高 方便计算与中心点的距离 见相关shader
                m_Material.SetFloat("_Width", rectTransform.sizeDelta.x);
                m_Material.SetFloat("_Height", rectTransform.sizeDelta.y);
            }

            //设置单独材质的进度
            m_Material.SetFloat("_Progress", Progess / 100.0f);
            return m_Material;
        }
    }

}


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

//PointProgress类对应编辑器显示 PointProgressEditor.cs
namespace VMUI
{
    [CustomEditor(typeof(PointProgress), true)]
    [CanEditMultipleObjects]
    public class PointProgressEditor : Editor
    {
        SerializedProperty m_Progess;

        protected virtual void OnEnable()
        {
            m_Progess = serializedObject.FindProperty("m_Progess");
        }

        public override void OnInspectorGUI()
        {
            var graphic = (target as PointProgress).GetComponent();

            if (graphic && !graphic.IsActive())
                EditorGUILayout.HelpBox("Masking disabled due to Graphic component being disabled.", MessageType.Warning);

            serializedObject.Update();
            //进度条化 m_Progess
            EditorGUILayout.IntSlider (m_Progess, 0, 100, new GUIContent (""), new GUILayoutOption[1]{GUILayout.Width(300)});
            //更新serialized属性
            serializedObject.ApplyModifiedProperties();
        }
    }
}

ps

Graphic

Graphic是UGUI的核心组件,负责显示图像。它是一个抽象类,是MaskableGraphic(可遮罩图像)的基类(同样是抽象类),而后者是RawImage、Image和Text的基类。
https://blog.csdn.net/ecidevilin/article/details/52548747

你可能感兴趣的:(ui框架相关)