【问题标题】:Multi layer texture shader in UnityUnity中的多层纹理着色器
【发布时间】:2020-03-13 05:45:14
【问题描述】:

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

基本上,我必须制作一个将 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 shader,我只是添加了这几个变量,因为我知道我需要这些数据来将其显示为一个纹理:

_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;

为了避免这个问题,我正在考虑 if 语句将检查每一层上的纹理是否存在,但我听说如果可能的话我应该随时避免它。有没有更好的处理方法?

编辑 2 由于我对帖子删除的最新回答,我不知道最终帮助我的答案是否仍然可见,但这是来自:trojanfoe 的解决方案

请编辑您的原始问题,而不是创建答案来扩展您的问题。不要使用 if 语句;相反,您可能想要使用着色器功能并使用#if HAVE_TEXTURE_2 等。这样统一将生成着色器的多个版本,每个版本都针对“打开”的纹理量身定制。此外,您不需要 .rgba swizzles,因为这是默认设置。

编辑 3

所以我尝试将所有这些层叠加显示,但 lerp() 存在一些问题。

        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 = c1;
        fixed4 returnTexture2 = c2;
        fixed4 returnTexture3 = c3;
        fixed4 returnTexture4 = c4;
        fixed4 returnTexture5 = c5;
        fixed4 returnTexture6 = c6;

        returnTexture1 = lerp(c1, c2, c2.a);
        returnTexture2 = lerp(c3, c4, c4.a);
        returnTexture3 = lerp(c5, c6, c6.a);

        fixed4 returnAlmostFinalTexture = lerp(returnTexture1, returnTexture2, returnTexture2.a);
        fixed4 returnFinalTexture = lerp(returnTexture2, returnTexture3, returnTexture3.a);

        return returnFinalTexture;

'returnAlmostFinalTexture' 可以正常工作,但 'returnFinalTexture' 会中断。 现在我有 4 个工作层,但我无法让所有 6 个工作层都工作。但我很确定如果我总共有 8 层,它就可以完成工作。

我可以更轻松地处理超过 2 个纹理吗?

编辑 4

好吧,我得到了这个工作,这就是现在的样子:

        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;

这是我能做到的最好方法吗?或者我可以以某种方式更轻松/更优化地处理所有这些纹理?

【问题讨论】:

    标签: unity3d shader


    【解决方案1】:

    您通常会乘以颜色值以合并它们,因此在片段着色器中您可以执行以下操作:

    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() 和每个纹理的标准化输入值。

    编辑:你已经扩展了你的问题,提到当纹理没有分配给着色器输入时这不起作用。我对此的回应是使用shader features,您可以在其中为每个可选纹理输入添加切换,然后使用#if HAVE_TEXTURE_2 ...#endif。这样,Unity 将根据“打开”的纹理生成不同的着色器,这将比使用 if (have_texture_2) 等更有效。

    【讨论】:

    • 谢谢先生。但是我怎样才能处理两个以上的纹理呢?我编辑了我的问题,所以你可以看到我做了什么。
    • @MichałLorenc 您需要将 lerps 链接在一起。所以fixed4 color = lerp(_Color, tex2D(_MainTex, IN.texcoord), _Influence1); color = lerp(color, tex2D(_SecondLayer, IN.texcoord), _Influence2); ...; return color;.
    猜你喜欢
    • 1970-01-01
    • 2021-10-16
    • 1970-01-01
    • 2023-02-08
    • 2020-09-06
    • 2013-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多