Unity利用MaskableGraphic类画自定义UI图形,并且对顶点设置UV坐标,然后用贴图映射效果

目的

文章解决的目的

1、起初目的是因为XChart的3D图表没有提供美化3D环形圆柱饼图的效果;

目标效果和当下的效果

2、下面是我们UI设计的效果。
在这里插入图片描述
3、这是默认画出的效果
在这里插入图片描述
4、目前达到的效果
在这里插入图片描述
在这里插入图片描述

分析

UIShader来实现

1、搜索了很多效果实现方案,其中知乎作者的UIShader效果中找到了一个扫光效果
https://zhuanlan.zhihu.com/p/399478677

2、但是经过测试,扫光效果对XChart生成的Mesh并没有影响,于是我想到了先用贴图叠加的方式写Shader

// Properties
_Tex("Tex", 2D) = "white" {}//叠加颜色

//Pass
sampler2D _Tex;//自己的
float4 _Tex_ST;

//Vert //这是把新贴图的UV映射到UI上
OUT.texcoord[0] = IN.texcoord;
//OUT.texcoord[0] = TRANSFORM_TEX(IN.texcoord, _MainTex);
OUT.texcoord[1] = TRANSFORM_TEX(IN.texcoord.xy, _Tex);

//frag
half4 color = tex2D(_MainTex,IN.texcoord[0]) * IN.color * _Color;//这是原来UI的
fixed4 col = tex2D(_Tex, IN.texcoord[1]);//它的问题在于没有UV
color.rgb*=col.rgb*_Factor;//额外图片叠加
color.a*=(0.1+col.a);//确保遇到透明的部位不是绝对透明
return color;

最终问题所在

3、经过测试发现是因为XChart利用继承MaskableGraphic 重写OnPopulateMesh实现图形绘制时候吧所有UV都设置到了一个点Vector.zero,导致贴图无法顺利叠加。
4、下图分析如何设置顶点UV坐标地址
在这里插入图片描述

实施

抄了一遍XChart的实现绘制代码

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

[RequireComponent(typeof(CanvasRenderer))]//MaskableGraphic必须依赖CanvasRenderer
public class MyPainter : MaskableGraphic
{

    protected override void OnPopulateMesh(VertexHelper vh)
    {
        vh.Clear();
        var currentVertCount = vh.currentVertCount;
        int count = 250;
        Vector3 center = new Vector3(0, -80, 0);
        float hig = 30;
        float startAngle = 0;
        float endAngle = 356;
        var diff = (endAngle - startAngle) / count;
        float inw = 200;
        float inh = 130;
        float outw = 240;
        float outh = 156;
        var isLeft = false;
        Color startSideColor = new Color(0, 1, 0, 1);
        Color endSideColor = new Color(0, 0,1, 1);
        Color sideColor = new Color(1, 0, 0, 1);
        Color color_w = new Color(1, 1, 1, 1);
        var index = 1;
        Debug.Log(string.Format("count:{0} ,center{1} ,hig {2} diff{3} inw{4} inh{5}  outw{6} outh{7} ",
                             count, center, hig, diff, inw, inh, outw, outh));
        for (int i = 0; i <= count; i++)
        {
            var angle = startAngle + i * diff;
            var rad = (360 - angle) * Mathf.Deg2Rad;
            var sin = Mathf.Sin(rad);
            var cos = Mathf.Cos(rad);
            var ix = center.x + inw * cos;
            var iy = center.y + inh * sin;
            var ox = center.x + outw * cos;
            var oy = center.y + outh * sin;
            var ipb = new Vector3(ix, iy);
            var ipt = new Vector2(ix, iy + hig);
            var opb = new Vector3(ox, oy);
            var opt = new Vector2(ox, oy + hig);
            isLeft = opb.x < center.x;
            if (i == 0)
            {
                //slice.topPolygons.Add(ipt);
                //slice.topPolygons.Add(opt);
                //slice.sidePolygons.Add(opb);
                //slice.sidePolygons.Add(opt);
                vh.AddVert(ipb, Color.red, Vector2.zero); //0
                vh.AddVert(ipt, Color.blue, Vector2.zero); // 1
                vh.AddVert(opb, Color.green, Vector2.zero); // 2
                vh.AddVert(opt, Color.yellow, Vector2.zero); // 3
            }
            vh.AddVert(ipb, color_w, new Vector2(i,190)); //4  //圆环上部内壁下方  //0  blue
            vh.AddVert(ipt, color_w, new Vector2(i, 250)); //5 //圆环上部内壁上方  //0  yellow
            vh.AddVert(ipt, color_w, new Vector2(i, 0)); //6 //圆环 整个上面内环  //1

            vh.AddVert(opb, color_w, new Vector2(i, 75)); //7 圆环 外壁下环   //2   red
            vh.AddVert(opt, color_w, new Vector2(i, 135)); //8//圆环 外壁上环  //2  green
            vh.AddVert(opt, color_w, new Vector2(i, 60)); //9  //圆环 整个上面外环 //1
            index = currentVertCount + (i * 6) + 4;
            if (i == 0)
            {
                if (isLeft &&true /*startSide*/)
                {
                    //slice.startOrEndPolygons.Add(ipb);
                    //slice.startOrEndPolygons.Add(ipt);
                    //slice.startOrEndPolygons.Add(opt);
                    //slice.startOrEndPolygons.Add(opb);
                    vh.AddTriangle(currentVertCount, currentVertCount + 1, currentVertCount + 3); // startSide: 0 1 3
                    vh.AddTriangle(currentVertCount, currentVertCount + 3, currentVertCount + 2); //startSide: 1 5 6
                }
            }
            else
            {
                //inside
                if (angle >= 180 && angle <= 360)
                {
                    vh.AddTriangle(index, index + 1, index - 5); // inside: 10 11 5
                    vh.AddTriangle(index, index - 5, index - 6); // inside: 10 5 4
                }
                //top
                vh.AddTriangle(index - 4, index - 1, index + 2); // top: 6 9 12
                vh.AddTriangle(index + 2, index - 1, index + 5); // top: 12 9 15
                                                                 // //outside
                if (angle >= 0 && angle <= 180)
                {
                    vh.AddTriangle(index + 3, index + 4, index - 2); // outside: 13 14 8
                    vh.AddTriangle(index + 3, index - 2, index - 3); // outside: 13 8 7
                }
            }
            if (i == count)
            {
                //slice.topPolygons.Add(opt);
                //slice.topPolygons.Add(ipt);
                //slice.sidePolygons.Add(opt);
                //slice.sidePolygons.Add(opb);
                if (!isLeft &&true /*endSide*/)
                {
                    //slice.startOrEndPolygons.Add(ipb);
                    //slice.startOrEndPolygons.Add(ipt);
                    //slice.startOrEndPolygons.Add(opt);
                    //slice.startOrEndPolygons.Add(opb);
                    vh.AddVert(ipb, endSideColor, Vector2.zero); //22            //截面积 左下角
                    vh.AddVert(ipt, endSideColor, Vector2.zero); //23            //截面积 左上角
                    vh.AddVert(opb, endSideColor, Vector2.zero); //24            //截面积 右下角
                    vh.AddVert(opt, endSideColor, Vector2.zero); //25                    //截面积 右上角
                    vh.AddTriangle(index + 6, index + 7, index + 9); // endSide: 22 23 25  //一个三角形顺时针画
                    vh.AddTriangle(index + 6, index + 9, index + 8); // endSide: 22 25 24 //都是顺时针画  好像是优先画和之前画的相邻的边
                }
            }
        }

    }
}

Shader源代码

Shader "UGUI/UIShaderTexAdd"
{
	Properties
	{
		[PerRendererData] _MainTex("MainTex", 2D) = "white" {}
				 _Color("Tint", Color) = (1,1,1,1)

		[Header(Stencil)]
		_StencilComp("Stencil Comparison", Float) = 8
		_Stencil("Stencil ID", Float) = 0
		_StencilOp("Stencil Operation", Float) = 0
		_StencilWriteMask("Stencil Write Mask", Float) = 255
		_StencilReadMask("Stencil Read Mask", Float) = 255
		_Factor("_Factor",Float)=1
		
		
		_Width("宽度",float)=1// 6 7 消融和扫光都用
		[HDR]_Brightness("扫光颜色",Color)=(1,1,1,1) //扫光用
		_Softness("柔和度",float)=1//扫光用
		_Gloss("光泽度",float)=1//扫光用
		_Rotation("旋转度",float)=15//扫光用
		
		
		_Tex("Tex", 2D) = "white" {}//叠加颜色
		_ColorMask("Color Mask", Float) = 15  //_ColorMask:设置颜色通道写入遮罩。写入 ColorMask 0 可关闭对所有颜色通道的渲染。
				[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip("Use Alpha Clip", Float) = 0  //_UseUIAlphaClip是否用clip来进行不显示 。[Toggle(UNITY_UI_ALPHACLIP)], 如果Toggle是true , 则自动#define UNITY_UI_ALPHACLIP ,可以用#ifdef进行预处理。
	}

		SubShader
		{
			Tags
			{
				"Queue" = "Transparent"
				"IgnoreProjector" = "True"
				"RenderType" = "Transparent"
				"PreviewType" = "Plane"
				"CanUseSpriteAtlas" = "True"
			}

			Stencil
			{
				Ref[_Stencil] //_Stencil 模板测试相关属性,Unity会自动修改参数,UI可以使用模板测试进行不显示。
				Comp[_StencilComp]
				Pass[_StencilOp]
				ReadMask[_StencilReadMask]
				WriteMask[_StencilWriteMask]
			}
				Cull Off   //关闭剔除
			Lighting Off
			ZWrite Off  //关闭深度写人
			ZTest[unity_GUIZTestMode]
			Blend SrcAlpha OneMinusSrcAlpha
			ColorMask[_ColorMask]

			Pass
			{
				CGPROGRAM
				#pragma vertex vert
				#pragma fragment frag

				#pragma multi_compile __ UNITY_UI_ALPHACLIP

				#include "UnityCG.cginc"
				#include "UnityUI.cginc"

				struct appdata_t
				{
					float4 vertex   : POSITION;
									float4 color    : COLOR;
					float2 texcoord : TEXCOORD0;
					UNITY_VERTEX_INPUT_INSTANCE_ID
				};
					struct v2f
				{
					float4 vertex   : SV_POSITION;
					float4 color    : COLOR;
					half2 texcoord[2]  : TEXCOORD0;
					UNITY_VERTEX_OUTPUT_STEREO
				};

				sampler2D _MainTex;
				float4 _MainTex_TexelSize;
							float4 _Color;
				float _Factor;

				float _Width;//消融 扫光
				float4 _Brightness;//扫光用
				float _Softness;//扫光
				float _Gloss;//扫光用
				float _Rotation;//扫光用
			
				sampler2D _Tex;//自己的
				float4 _Tex_ST;
				
				v2f vert(appdata_t IN)
				{
					v2f OUT;
					UNITY_SETUP_INSTANCE_ID(IN);
					UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);

					OUT.vertex = UnityObjectToClipPos(IN.vertex);
							
								OUT.color = IN.color;
					OUT.texcoord[0] = IN.texcoord;
					//OUT.texcoord[0] = TRANSFORM_TEX(IN.texcoord, _MainTex);
                    OUT.texcoord[1] = TRANSFORM_TEX(IN.texcoord.xy, _Tex);
					return OUT;
				}

				//=================UV旋转算法
				float2x2 Rotation(half Angle)
		       {
		            Angle=UNITY_PI/180*Angle;
		            half cosAngle = cos(Angle);
		            half sinAngle = sin(Angle);
		            float2x2 rot = float2x2(cosAngle,-sinAngle,sinAngle,cosAngle);
		            return rot;
		        }
			
				fixed4 frag(v2f IN) : SV_Target
				{
					half4 color = tex2D(_MainTex,IN.texcoord[0]) * IN.color * _Color;

					fixed4 col = tex2D(_Tex, IN.texcoord[1]);//它的问题在于没有UV
					//=========================================================


					//=================7 扫描光  可以用贴图或代码得到扫光线,叠加在纹理贴图上,用_Factor控制扫光位置。

					float2 shinyUv=mul(Rotation(_Rotation),IN.texcoord[0]-0.5);

					fixed nomalizedPos = shinyUv.x;
					half location = _Factor * 2 - 0.5;
					half normalized = 1 - saturate(abs((nomalizedPos - location) / _Width));
					half shinePower = smoothstep(0, _Softness, normalized);
					half3 reflectColor = lerp(fixed3(1,1,1), color.rgb * 7, _Gloss);
					color.rgb += color.a * (shinePower / 2) * _Brightness * reflectColor*_Color;
					//=========================================================
					
					color.rgb*=col.rgb*_Factor;//额外图片叠加
					color.a*=(0.1+col.a);

					//更多  https://zhuanlan.zhihu.com/p/399478677
					return color;
				}
			ENDCG
			}
		}
}
 //加入颜色叠加
 fixed4 ifFlag= step(color,fixed4(0.5,0.5,0.5,0.5));//叠加
 fixed4 C=ifFlag*color*blCol*2+(1-ifFlag)*(1-(1-color)*(1-blCol)*2);//叠加
 return C;

在这里插入图片描述

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

歌德之殇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值