Unity3d Unity中的多层纹理着色器

Unity3d Unity中的多层纹理着色器,unity3d,shader,Unity3d,Shader,我对着色器真的很陌生。我在不同的论坛上搜索了一个类似的问题,但没有一个能帮助我解决我所面临的问题 基本上,我必须做一个着色器,将6个纹理合并成一个。我有6层。每个层都是一个纹理,所有这些层都必须显示在彼此的顶部。每层纹理的大小相同 这是我目前的代码: Shader "TileShaders/Chunk" { Properties { [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}

我对着色器真的很陌生。我在不同的论坛上搜索了一个类似的问题,但没有一个能帮助我解决我所面临的问题

基本上,我必须做一个着色器,将6个纹理合并成一个。我有6层。每个层都是一个纹理,所有这些层都必须显示在彼此的顶部。每层纹理的大小相同

这是我目前的代码:

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)。。。;返回颜色