在 Unity 中为对象的不同部分分配不同颜色的着色器

Shader that assigns a different color to different sections of an object in Unity

我有一组具有不同颜色段的数据,例如

我在 Unity 中创建了大小相对于单元总数的对象,例如

我想根据对象的分布为所有对象着色,例如

目标

我希望做的是实例化一个带有着色器的项目,该着色器适当地获取每种颜色的单元数和它的颜色段。

到目前为止我做了什么

我创建了 m 个较小的段对象,其中 m 是每个项目的段数。然后我适当地给这些片段对象上色,并将它们并排放置,这样它们看起来就像一个多色项目。

为什么我认为这很糟糕

这是一个可行的解决方案,但可能有数千个项目和数千个分段,我相信省去这一步会大大提高性能。

我对着色器没有任何经验,但这感觉应该是一个已经解决的问题,我不想重新发明轮子。也就是说,如果不存在针对我的问题的确切解决方案,那么实现某些类似功能的着色器代码也将是完美的。

示例照片

更新:当前着色器代码和说明

我在网上找到了一个着色器,它为条形着色,将其一分为二 -> 生命值和伤害。然后我将该代码修改为包含三个部分,即健康、伤害和护盾,以使我更接近理想的堆叠条形类型。我还有一个调用

的 C# 脚本
GetComponent<MeshRenderer>().material.SetFloat("_LifePercent", percent);
GetComponent<MeshRenderer>().material.SetFloat("_DamagesPercent", percent);
GetComponent<MeshRenderer>().material.SetFloat("_ShieldPercent", percent);

着色器

  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 life bar shader

应用了 material / 着色器的对象似乎只有 mainTex,任何地方都没有颜色。我也不完全理解我在 fixed4 "c" 上执行的操作。我错过了什么?

我花了更多时间阅读教程,特别是来自 unity 的棋盘教程:unity vertex/fragment examples

这就是我现在所拥有的,它的工作原理与我预期的差不多:

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
      }
  }

}