Unity creates curve progress bar

Unity creates curve progress bar

  Hello everyone, my name is A Zhao.
  When using the Unity engine to make a progress bar, you sometimes encounter a problem. What should you do if the progress bar is not a simple horizontal, vertical or circular shape, but an arbitrary irregular shape? For example:
Insert image description here

1. Production method

1. Prepared materials

  The principle of this progress bar is very simple. We need a picture that changes grayscale along this path. This picture probably looks like this:
Insert image description here
Insert image description here

  I used the RGB channel as the grayscale here, and the Alpha channel as the display range. Combined together, a picture in Unity will look like this:
Insert image description here

  Of course, there are other ways to use pictures. For example, if we want to display some gradient colors or textures on the progress bar, we can use the RGB channel of the picture as a texture picture, and then the Alpha channel can be used as a grayscale change. After all, grayscale changes only use One channel is enough, there is no need to use three RGB channels.

2. Calculation process

Purpose:
1. Can be used on the UI
2. Use the image of the Image as input
3. Use the RGB channel of the color of the Image as the color of the progress bar
4. Use the A channel of the color of the Image as the progress control of the progress bar display
Insert image description here

  The calculation of color is very simple, just get the RGB of the vertex color directly. If you think the pure RGB color doesn’t look good, you can also make another colored picture for display.
  Next is the effect of masking the progress bar. Because here I directly used the grayscale gradient of the RGB color of the image, so I first took an RGB grayscale. If, as mentioned above, you want to make a patterned progress bar picture using RGB color, then you can actually use RGB color instead of RGB color for this progress. You can also use the Alpha channel of the picture as grayscale.
Insert image description hereInsert image description here

  No matter what, you get the grayscale value of an image, then enter a value you want to control the progress of, use this value and the grayscale value to do subtraction, and then use the Step function to control the display range. If you want a gradient effect at the transition point, you can use the SmoothStep function. Since grayscale gradients along the path, when the input value changes, the display range will change along the grayscale path.
  Finally, use the result of Step as the displayed Alpha value, combined with the RGB color to be displayed, to get the final display color and range of the progress bar.

3. Production of grayscale gradient map

  The difficulty of this method is not the writing of the shader, but the production of the materials.
  I used a 3D method to create this image. First, I created a patch and set its number of horizontal segments to 1000.
Insert image description here

  Then expand the UV, the leftmost u coordinate of the patch is 0, and the rightmost u coordinate is 1. Then make a gradient map from left to right. Assign the gradient map to the patch.
Insert image description here

  Finally, through path deformation, the patch is stretched along the path to obtain the shape.
Insert image description here

Finally, after rendering this model, the gradient grayscale image above is obtained.

  By doing this, you can barely get a uniformly distributed grayscale image, but it is not 100% accurate. If you want to get a grayscale image that completely matches the change in percentage, for example, draw a scale on the progress bar, and then enter a percentage, and the grayscale of the image just reaches that percentage, then you have to think of other ways to make this image.

3. Shader source code

Shader "azhao/CurveProgress"
{
    
    
	Properties
	{
    
    
		[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {
    
    }
		_Color ("Tint", Color) = (1,1,1,1)
		
		_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

		_ColorMask ("Color Mask", Float) = 15

		[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
		_min("min", Range( -1 , 1)) = 0
		_max("max", Range( 0 , 1)) = 1
		[HideInInspector] _texcoord( "", 2D ) = "white" {
    
    }

	}

	SubShader
	{
    
    
		LOD 0

		Tags {
    
     "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" "CanUseSpriteAtlas"="True" }
		
		Stencil
		{
    
    
			Ref [_Stencil]
			ReadMask [_StencilReadMask]
			WriteMask [_StencilWriteMask]
			CompFront [_StencilComp]
			PassFront [_StencilOp]
			FailFront Keep
			ZFailFront Keep
			CompBack Always
			PassBack Keep
			FailBack Keep
			ZFailBack Keep
		}


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

		
		Pass
		{
    
    
			Name "Default"
		CGPROGRAM
			
			#pragma vertex vert
			#pragma fragment frag
			#pragma target 3.0

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

			#pragma multi_compile __ UNITY_UI_CLIP_RECT
			#pragma multi_compile __ UNITY_UI_ALPHACLIP
			
			#define ASE_NEEDS_FRAG_COLOR

			
			struct appdata_t
			{
    
    
				float4 vertex   : POSITION;
				float4 color    : COLOR;
				float2 texcoord : TEXCOORD0;
				UNITY_VERTEX_INPUT_INSTANCE_ID
				
			};

			struct v2f
			{
    
    
				float4 vertex   : SV_POSITION;
				fixed4 color    : COLOR;
				half2 texcoord  : TEXCOORD0;
				float4 worldPosition : TEXCOORD1;
				UNITY_VERTEX_INPUT_INSTANCE_ID
				UNITY_VERTEX_OUTPUT_STEREO
				
			};
			
			uniform fixed4 _Color;
			uniform fixed4 _TextureSampleAdd;
			uniform float4 _ClipRect;
			uniform sampler2D _MainTex;
			uniform float4 _MainTex_ST;
			uniform float _min;
			uniform float _max;

			
			v2f vert( appdata_t IN  )
			{
    
    
				v2f OUT;
				UNITY_SETUP_INSTANCE_ID( IN );
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
				UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
				OUT.worldPosition = IN.vertex;
				
				
				OUT.worldPosition.xyz +=  float3( 0, 0, 0 ) ;
				OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);

				OUT.texcoord = IN.texcoord;
				
				OUT.color = IN.color * _Color;
				return OUT;
			}

			fixed4 frag(v2f IN  ) : SV_Target
			{
    
    
				float2 uv_MainTex = IN.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
				float4 tex2DNode1 = tex2D( _MainTex, uv_MainTex );
				float grayVal = Luminance(tex2DNode1.rgb);
				float remapVal = ( grayVal - ( 1.0 - (0.0 + (( IN.color.a + 0.01 ) - 0.0) * (( _max + 1.0 ) - 0.0) / (1.0 - 0.0)) ) );
				float smoothstepVal = smoothstep( _min , _max , remapVal);
				float4 color = (float4(IN.color.r , IN.color.g , IN.color.b , ( tex2DNode1.a * smoothstepVal )));
				
			
				#ifdef UNITY_UI_CLIP_RECT
                color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
                #endif
				
				#ifdef UNITY_UI_ALPHACLIP
				clip (color.a - 0.001);
				#endif

				return color;
			}
		ENDCG
		}
	}
	
	
	
}

Guess you like

Origin blog.csdn.net/liweizhao/article/details/133105955