Unity создает кривую индикатор выполнения
Привет всем, меня зовут А Чжао.
При использовании движка Unity для создания индикатора выполнения иногда возникает проблема: что делать, если индикатор выполнения представляет собой не простую горизонтальную, вертикальную или круглую форму, а произвольную неправильную форму? Например:
1. Способ производства
1. Подготовленные материалы
Принцип работы этого индикатора выполнения очень прост: нам нужна картинка, которая по этому пути меняет оттенки серого. Вероятно, эта картина выглядит так:
Здесь я использовал канал RGB в качестве шкалы серого и канал Alpha в качестве диапазона отображения. В совокупности картинка в Unity будет выглядеть так:
Конечно, есть и другие способы использования изображений. Например, если мы хотим отобразить некоторые градиентные цвета или текстуры на индикаторе выполнения, мы можем использовать канал RGB изображения в качестве изображения текстуры, а затем можно использовать альфа-канал. используется как изменение оттенков серого.В конце концов, изменения оттенков серого используют только один канал, нет необходимости использовать три канала RGB.
2. Процесс расчета
Цель:
1. Может использоваться в пользовательском интерфейсе.
2. Использовать изображение изображения в качестве входных данных
. 3. Использовать канал RGB цвета изображения в качестве цвета индикатора выполнения.
4. Использовать канал A цвета изображения. Изображение в качестве элемента управления прогрессом отображения индикатора выполнения
Вычисление цвета очень простое: просто получите RGB цвета вершины напрямую. Если вы считаете, что чистый цвет RGB выглядит не очень хорошо, вы также можете создать для отображения другое цветное изображение.
Далее идет эффект маскировки индикатора выполнения. Поскольку здесь я напрямую использовал градиент оттенков серого цвета RGB изображения, поэтому сначала я взял оттенки серого RGB. Если, как упоминалось выше, вы хотите создать узорчатое изображение индикатора выполнения с использованием цвета RGB, то для этого процесса вы можете использовать цвет RGB вместо цвета RGB. Вы также можете использовать альфа-канал изображения в оттенках серого.
Несмотря ни на что, вы получаете значение оттенков серого изображения, затем вводите значение, ход которого хотите контролировать, используете это значение и значение оттенков серого для вычитания, а затем используете функцию «Шаг» для управления диапазоном отображения. Если вам нужен эффект градиента в точке перехода, вы можете использовать функцию SmoothStep. Поскольку оттенки серого градиенты вдоль пути, при изменении входного значения диапазон отображения будет меняться вдоль пути оттенков серого.
Наконец, используйте результат Step в качестве отображаемого значения Alpha в сочетании с отображаемым цветом RGB, чтобы получить окончательный цвет отображения и диапазон индикатора выполнения.
3. Создание карты градиентов в оттенках серого.
Сложность этого метода заключается не в написании шейдера, а в изготовлении материалов.
Для создания этого изображения я использовал 3D-метод: сначала я создал патч и установил количество его горизонтальных сегментов равным 1000.
Затем разверните UV, самая левая координата u патча равна 0, а самая правая координата u равна 1. Затем создайте карту градиента слева направо. Назначьте карту градиента патчу.
Наконец, за счет деформации пути заплатка растягивается вдоль пути, чтобы получить форму.
Наконец, после рендеринга этой модели получается изображение с градиентом в оттенках серого, приведенное выше.
Сделав это, вы вряд ли сможете получить равномерно распределенное изображение в оттенках серого, но оно не будет точным на 100%. Если вы хотите получить изображение в оттенках серого, которое полностью соответствует изменению в процентах, например, нарисуйте шкалу на индикаторе выполнения, а затем введите процент, а оттенки серого изображения как раз достигают этого процента, тогда вам придется подумать о другие способы сделать это изображение.
3. Исходный код шейдера
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
}
}
}