Unity3d Unity中的多层纹理着色器
我对着色器真的很陌生。我在不同的论坛上搜索了一个类似的问题,但没有一个能帮助我解决我所面临的问题 基本上,我必须做一个着色器,将6个纹理合并成一个。我有6层。每个层都是一个纹理,所有这些层都必须显示在彼此的顶部。每层纹理的大小相同 这是我目前的代码:Unity3d Unity中的多层纹理着色器,unity3d,shader,Unity3d,Shader,我对着色器真的很陌生。我在不同的论坛上搜索了一个类似的问题,但没有一个能帮助我解决我所面临的问题 基本上,我必须做一个着色器,将6个纹理合并成一个。我有6层。每个层都是一个纹理,所有这些层都必须显示在彼此的顶部。每层纹理的大小相同 这是我目前的代码: Shader "TileShaders/Chunk" { Properties { [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
Shader "TileShaders/Chunk"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_SecondLayer ("Second Layer", 2D) = "white" {}
_ThirdLayer ("Third Layer", 2D) = "white" {}
_FourthLayer ("Fourth Layer", 2D) = "white" {}
_FifthLayer ("Fifth Layer", 2D) = "white" {}
_SixthLayer ("Sixth Layer", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
[MaterialToggle] PixelSnap ("Pixel snap", 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;
float2 texcoord : TEXCOORD0;
};
fixed4 _Color;
v2f vert(appdata_t IN)
{
v2f OUT;
OUT.vertex = UnityObjectToClipPos(IN.vertex);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color * _Color;
#ifdef PIXELSNAP_ON
OUT.vertex = UnityPixelSnap (OUT.vertex);
#endif
return OUT;
}
sampler2D _MainTex;
sampler2D _AlphaTex;
float _AlphaSplitEnabled;
fixed4 SampleSpriteTexture (float2 uv)
{
fixed4 color = tex2D (_MainTex, uv);
#if UNITY_TEXTURE_ALPHASPLIT_ALLOWED
if (_AlphaSplitEnabled)
color.a = tex2D (_AlphaTex, uv).r;
#endif //UNITY_TEXTURE_ALPHASPLIT_ALLOWED
return color;
}
fixed4 frag(v2f IN) : SV_Target
{
fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
c.rgb *= c.a;
return c;
}
ENDCG
}
}
}
这是Sprites/Default unity着色器,我刚刚添加了以下几个变量,因为我知道我需要这些数据将其显示为一个纹理:
_SecondLayer ("Second Layer", 2D) = "white" {}
_ThirdLayer ("Third Layer", 2D) = "white" {}
_FourthLayer ("Fourth Layer", 2D) = "white" {}
_FifthLayer ("Fifth Layer", 2D) = "white" {}
_SixthLayer ("Sixth Layer", 2D) = "white" {}
我就这么做了。我真的不知道怎么开始。这是我第一次用着色器做一些事情
编辑
谢谢您的回复!
lerp()对我帮助很大,没有它,所有的图层都可以同时看到,看起来很奇怪
现在一切看起来都很好。但有一个小问题。只要所有层都包含纹理,它看起来就很棒。但是,如果只有一层指定了纹理,而其他层没有,则整个结果纹理为白色
下面是代码的外观:
fixed4 c = tex2D(_MainTex, IN.texcoord);
fixed4 c2 = tex2D(_SecondLayer, IN.texcoord);
fixed4 returnTexture = c;
returnTexture.rgba = lerp(c, c2, c2.a).rgba;
return returnTexture;
fixed4 c1 = tex2D(_MainTex, IN.texcoord);
fixed4 c2 = tex2D(_SecondLayer, IN.texcoord);
fixed4 c3 = tex2D(_ThirdLayer, IN.texcoord);
fixed4 c4 = tex2D(_FourthLayer, IN.texcoord);
fixed4 c5 = tex2D(_FifthLayer, IN.texcoord);
fixed4 c6 = tex2D(_SixthLayer, IN.texcoord);
fixed4 returnTexture1 = lerp(c1, c2, c2.a);
fixed4 returnTexture2 = lerp(c3, c4, c4.a);
fixed4 returnTexture3 = lerp(c5, c6, c6.a);
fixed4 returnAlmostFinalTexture = lerp(returnTexture1, returnTexture2, returnTexture2.a);
fixed4 returnFinalTexture = lerp(returnAlmostFinalTexture, returnTexture3, returnTexture3.a);
return returnFinalTexture;
为了避免这个问题,我考虑使用if语句来检查每个层上的纹理是否存在,但我听说如果可能的话,我应该随时避免。有没有更好的办法处理
编辑2
我不知道最终帮助我的答案是否仍然是visiblue,因为我最新的关于删除后的答案,但这里有一个来自:trojanfoe的解决方案
请编辑原始问题,而不是创建扩展问题的答案。不要使用if语句;相反,您可能希望使用着色器功能并使用#if HAVE_TEXTURE_2
等。这样unity将生成着色器的多个版本,每个版本都根据“打开”的纹理进行定制。此外,您不需要使用.rgba
开关,因为这是默认设置
编辑3
因此,我试图将所有这些层显示在彼此的顶部,但我对lerp()有一些问题
“returnAlmostFinalTexture”正常工作,但“returnFinalTexture”中断。
现在我有4个工作层,但我无法让所有6个层都工作。但是我很确定,如果我一共有8层的话,它就可以工作了
我可以用更简单的方法删除2个以上的纹理吗
编辑4
好吧,这是我的工作,这是它现在的样子:
fixed4 c = tex2D(_MainTex, IN.texcoord);
fixed4 c2 = tex2D(_SecondLayer, IN.texcoord);
fixed4 returnTexture = c;
returnTexture.rgba = lerp(c, c2, c2.a).rgba;
return returnTexture;
fixed4 c1 = tex2D(_MainTex, IN.texcoord);
fixed4 c2 = tex2D(_SecondLayer, IN.texcoord);
fixed4 c3 = tex2D(_ThirdLayer, IN.texcoord);
fixed4 c4 = tex2D(_FourthLayer, IN.texcoord);
fixed4 c5 = tex2D(_FifthLayer, IN.texcoord);
fixed4 c6 = tex2D(_SixthLayer, IN.texcoord);
fixed4 returnTexture1 = lerp(c1, c2, c2.a);
fixed4 returnTexture2 = lerp(c3, c4, c4.a);
fixed4 returnTexture3 = lerp(c5, c6, c6.a);
fixed4 returnAlmostFinalTexture = lerp(returnTexture1, returnTexture2, returnTexture2.a);
fixed4 returnFinalTexture = lerp(returnAlmostFinalTexture, returnTexture3, returnTexture3.a);
return returnFinalTexture;
这是我能做到的最好的方法吗?或者我可以以某种方式简化/优化所有这些纹理?您通常会将颜色值相乘以合并它们,因此在片段着色器中,您可以执行以下操作:
fixed4 c1 = tex2D(_MainTex, IN.texcoord);
fixed4 c2 = tex2D(_SecondLayer, IN.texcoord);
fixed4 c3 = tex2D(_ThirdLayer, IN.texcoord);
fixed4 c4 = tex2D(_FourthLayer, IN.texcoord);
fixed4 c5 = tex2D(_FifthLayer, IN.texcoord);
fixed4 c6 = tex2D(_SixthLayer, IN.texcoord);
return c1 * c2 * c3 * c4 * c5 * c6 * _Color;
如果要配置每个层对最终颜色的影响程度,可以使用lerp()
和每个纹理的标准化输入值
编辑:您已经扩展了您的问题,提到当纹理未指定给着色器输入时,这不起作用。我对此的回应是,在这里可以为每个可选纹理输入添加切换,然后使用
#如果有_texture_2
<代码>#endif。这样Unity将根据“打开”的纹理生成不同的着色器,这将比使用if(have_texture_2)
等更有效。谢谢,先生。但是我怎样才能去除两种以上的纹理呢?我编辑了我的问题,所以你可以看到我做了什么。@MichałLorenc你需要将LERP链接在一起。所以fixed4 color=lerp(_color,tex2D(_MainTex,IN.texcoord),_Influence1);颜色=lerp(颜色,tex2D(_SecondLayer,IN.texcoord),_Influence2)。。。;返回颜色代码>。