Reputation: 61
I have a set of data that has different segments of color e.g.
item1: [red: 3 units, blue: 5 units, green: 4 units, white: 5 units] (total units 17)
item2: [red: 4 units, green: 2 units, white: 2 units] (total units 8)
I've created objects in Unity that have a size relative to the total number of units e.g.
I would like to color all the objects based on the distribution they have e.g.
What I hope to do is instantiate one item with a shader on it that takes the number of units of each color and colors segments of it appropriately.
I've created m smaller segment-objects, where m is the number of segments per item. I then color these segment-objects appropriately and place them next to each other so they look like one multi-colored item.
This is a working solution, but there can be thousands of items with thousands of segments and I believe it would vastly increase performance to cut this step out.
I don't have any experience with shaders, but this feels like it should be an already solved problem and I don't want to reinvent the wheel. That said, if an exact solution to my problem doesn't exist, shader code that achieves some similar functionality would be also be perfect.
I found a shader online that colored a bar, splitting it in two -> Health and Damages. I then modified that code to have three sections, Health, Damages and Shield to get me closer to my stacked bar type ideal. I also have a C# script that calls
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
}
}
}
Here's the source of the shader before I modified it: unity life bar shader
The object with the material / shader applied just seems to have the mainTex, with no color anywhere. I also don't fully understand the operations I'm performing on the fixed4 "c". What am I missing?
Upvotes: 1
Views: 5711
Reputation: 61
I spent some more time reading tutorials, specifically from the checkerboard tutorial from unity: unity vertex/fragment examples
This is what I've got now, it's working pretty much how I expect it to:
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
}
}
}
Upvotes: 2