在 Unity 中为对象的不同部分分配不同颜色的着色器
Shader that assigns a different color to different sections of an object in Unity
我有一组具有不同颜色段的数据,例如
项目 1:[红色:3 个单位,蓝色:5 个单位,绿色:4 个单位,白色:5 个单位](总单位数 17)
项目 2:[红色:4 个单位,绿色:2 个单位,白色:2 个单位](总单位 8)
- 项目 N:...
我在 Unity 中创建了大小相对于单元总数的对象,例如
- 项目 1:---------------- (17)
- 项目 2:-------- (8)
我想根据对象的分布为所有对象着色,例如
- item1: rrr|bbbbb|gggg|wwwww
- item2: rrrr|gg|ww
目标
我希望做的是实例化一个带有着色器的项目,该着色器适当地获取每种颜色的单元数和它的颜色段。
到目前为止我做了什么
我创建了 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
}
}
}
我有一组具有不同颜色段的数据,例如
项目 1:[红色:3 个单位,蓝色:5 个单位,绿色:4 个单位,白色:5 个单位](总单位数 17)
项目 2:[红色:4 个单位,绿色:2 个单位,白色:2 个单位](总单位 8)
- 项目 N:...
我在 Unity 中创建了大小相对于单元总数的对象,例如
- 项目 1:---------------- (17)
- 项目 2:-------- (8)
我想根据对象的分布为所有对象着色,例如
- item1: rrr|bbbbb|gggg|wwwww
- item2: rrrr|gg|ww
目标
我希望做的是实例化一个带有着色器的项目,该着色器适当地获取每种颜色的单元数和它的颜色段。
到目前为止我做了什么
我创建了 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
}
}
}