У меня есть набор данных, которые имеют разные сегменты цвета, например,
item1: [красный: 3 единицы, синий: 5 единиц, зеленый: 4 единицы, белый: 5 единиц] (всего 17 единиц)
item2: [красный: 4 единицы, зеленый: 2 единицы, белый: 2 единицы] (всего 8 единиц)
- itemN: ...
Я создал объекты в Unity, которые имеют размер относительно общего количества единиц, например
- item1: ----------------- (17)
- item2: -------- (8)
Я бы хотел покрасить все объектыв зависимости от дистрибутива, например:
- item1: rrr | bbbbb | gggg | wwwww
- item2: rrrr | gg | ww
Цель
То, что я надеюсь сделать, - это создать экземпляр одного элемента с шейдером, который берет количество единиц каждого цвета и соответствующие сегменты цветов.
Что я сделал до сих пор
Я создал m меньших объектов-сегментов, где m - количество сегментов на элемент. Затем я соответствующим образом окрашиваю эти сегментированные объекты и помещаю их рядом друг с другом, чтобы они выглядели как один разноцветный предмет.
Почему я считаю, что это плохо
Это рабочее решение, но могут быть тысячи элементов с тысячами сегментов, и я считаю, что это значительно повысит производительность, чтобы сократить этот шаг.
У меня нет опыта работы с шейдерами, но кажется, что это уже решенная проблема, и я не хочу изобретать велосипед. Тем не менее, если точного решения моей проблемы не существует, шейдерный код, который выполняет некоторые аналогичные функции, также будет идеальным.
Пример фото
![stacked bar graph](https://i.stack.imgur.com/36yl3.png)
Обновление: текущий код и объяснение шейдера
В сети я нашел шейдер, который раскрасил полосу, разделив ее на две части -> Здоровье и повреждения. Затем я изменил этот код, добавив в него три раздела: Здоровье, Урон и Щит, чтобы приблизить меня к своему идеалу с накоплением штанг. У меня также есть сценарий C #, который вызывает
GetComponent<MeshRenderer>().material.SetFloat("_LifePercent", percent);
GetComponent<MeshRenderer>().material.SetFloat("_DamagesPercent", percent);
GetComponent<MeshRenderer>().material.SetFloat("_ShieldPercent", percent);
Shader
Shader "Sprites/HealthBar"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
[Header(Life)]_LifeColor ("Main Color", Color) = (0.2,1,0.2,1)
_LifePercent ("Life Percent", Float) = 1
[Header(Damages)]_DamagesColor ("Damages color", Color) = (1,1,0,1)
_DamagesPercent ("Damages Percent", Float) = 0
[Header(Shield)]_ShieldColor ("Shield color", Color) = (.2, .2, 1, 0)
_ShieldPercent ("Shield Percent", Float) = 0
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
Cull Off
Lighting Off
ZWrite Off
Blend One OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile _ PIXELSNAP_ON
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
half2 texcoord : TEXCOORD0;
};
fixed4 _LifeColor;
half _LifePercent;
fixed4 _DamagesColor;
half _DamagesPercent;
fixed4 _ShieldColor;
half _ShieldPercent;
v2f vert(appdata_t IN)
{
v2f OUT;
OUT.vertex = UnityObjectToClipPos(IN.vertex);
OUT.texcoord = IN.texcoord;
return OUT;
}
sampler2D _MainTex;
fixed4 frag(v2f IN) : SV_Target
{
fixed4 c = tex2D(_MainTex, IN.texcoord);
if ( IN.texcoord.x > _LifePercent + _DamagesPercent + _ShieldPercent )
{
c.a = 0;
}
else if ( IN.texcoord.x < _LifePercent )
{
c *= _LifeColor;
}
else if ( IN.texcoord.x < _LifePercent + _ShieldPercent && IN.texcoord.x > _LifePercent )
{
c *= _ShieldColor;
}
// if we weren't in the previous two segments we're now in the damages segment
else
{
c *= _DamagesColor;
}
c.rgb *= c.a;
return c;
}
ENDCG
}
}
}
Вот источник шейдера до того, как я его изменил: unity lifebar shader
Кажется, что объект с примененным материалом / шейдером имеет mainTex, нигде не окрашенный. Я также не до конца понимаю операции, которые выполняю на фиксированном "c". Чего мне не хватает?