首页 > 解决方案 > 在 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
      }
  }

}

这是我修改之前的shader的来源: unity life bar shader

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

标签: unity3dshadervertex-shader

解决方案


我花了更多时间阅读教程,特别是来自统一的棋盘教程:统一顶点/片段示例

堆叠着色器 33-33-34

堆叠着色器 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
      }
  }

}


推荐阅读