Шейдер, который назначает разный цвет различным частям объекта в Unity - PullRequest
0 голосов
/ 10 октября 2019

У меня есть набор данных, которые имеют разные сегменты цвета, например,

  • 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

Обновление: текущий код и объяснение шейдера

В сети я нашел шейдер, который раскрасил полосу, разделив ее на две части -> Здоровье и повреждения. Затем я изменил этот код, добавив в него три раздела: Здоровье, Урон и Щит, чтобы приблизить меня к своему идеалу с накоплением штанг. У меня также есть сценарий 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". Чего мне не хватает?

1 Ответ

0 голосов
/ 11 октября 2019

Я потратил еще немного времени на чтение учебников, в частности, из учебника по шахматной доске из Unity: Примеры вершин / фрагментов Unity

stacked shader 33-33-34

stacked shader 20-40-40

Это то, что у меня сейчас есть, оно работает так, как я ожидаю:

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
  {
      Pass
      {
      CGPROGRAM
          #pragma vertex vert
          #pragma fragment frag
          #include "UnityCG.cginc"

          struct v2f
          {
              float4 vertex   : SV_POSITION;
              float2 uv        : TEXCOORD0;
          };

          fixed4 _LifeColor;
          half _LifePercent;

          fixed4 _DamagesColor;
          half _DamagesPercent;

          fixed4 _ShieldColor;
          half _ShieldPercent;

          v2f vert(float4 pos : POSITION, float2 uv : TEXCOORD0)
          {
            v2f o;
            o.vertex = UnityObjectToClipPos(pos);
            o.uv = uv * 100;
            return o;
          }

          fixed4 frag(v2f IN) : SV_Target
          {
              float2 c = IN.uv;
              fixed4 cout;

              if (c.y < _LifePercent){
                cout = _LifeColor;
              }
              else if (c.y > _LifePercent && c.y < _DamagesPercent + _LifePercent){
                cout = _DamagesColor;
              }
              else {
                cout = _ShieldColor;
              }
              return cout;

          }
      ENDCG
      }
  }

}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...