【《Unity 2018 Shaders and Effects Cookbook》提炼总结】(四)打包和混合纹理

        纹理不仅可以存储数据的负载,而且可以存储向我们通常认为的那样的像素颜色,也可以存储像我们通常认为的那样的像素颜色。也可以存储x和y方向以及RGBA通道中的多组像素。我们实际上可以将多个图像打包成单个RGBA纹理,并通过从Shader代码始终提取每个组件,将每个R,G,B和A组件用作单独的纹理。

         将单个灰度图片打包成单个RGBA纹理的结果可以在以下屏幕截图中看到。

        这有什么作用呢,那么,就应用程序占用的实际内存而言,纹理是应用程序的很大一部分。因此为了减少应用程序的大小,我们可以查看我们在Shader中使用的所有图像,看看我们是否可以将这些纹理合并成单个纹理。使用其中包含多个图像的文件比单独的文件需要更少的draw calls和更少的开销。我们也可以使用这个概念将不规则的纹理(即那些不受正方形的纹理)组成一个单独的纹理,以占用比它们自己的完整纹理更少的空间。

        任何灰度纹理都可以打包到另一个纹理的RGBA通道之一中。

        使用这些打包纹理的一个示例是,当您想要将一组纹理混合到一个表面上时,在地形类型shader中最常见到这种情况,在这种情况下,我们需要使用某种控件纹理或打包纹理很好地混合到另一个纹理中。

        a.创建一个shader命名为TextureBlending。

        b.创建一个Material命名为TextureBlendingMat。(命名约定完全取决于你的shader和材质文件,但为了方便后序使用,我们应该尽量使它们井井有条。)

        c.我们需要汇集四个我们想混合在一起的纹理图片。它们可以是任何东西,但是对于一个漂亮的地形shader,你会想要草,泥土,岩石泥土和岩石纹理。我们可以使用非常复杂的混合纹理在地形网格上创建非常逼真的 地形纹理分布,如下屏幕截图所示。

        d.最后,我们还需要一个灰度图像打包的集合。这将为我们提供四种混合纹理,我们可以用它来指导颜色纹理如何放置在对象表面上。

          e.我们需要在我们的属性块里添加一些属性,我们需要五个sampler2D 对象或纹理和两个Color属性。并且移走我们不需要的属性。

    Properties {
        _MainTint ("Diffuse Tint",Color) = (1,1,1,1)
        _ColorA("Terrain Color A",Color) = (1,1,1,1)
        _ColorB("Terrain Color B",Color) = (1,1,1,1)
        _RTexture("Red Channel Texture",2D) = "" {}
        _GTexture("Green Channel Texture",2D) = "" {}
        _BTexture("Blue Channel Texture",2D) = "" {}
        _ATesture("Alpha Channel Texture",2D) = "" {}
        _BlendTex("Blend Texture",2D) = ""{}
    }

         h.然后我们需要在Subshader{}部分创建连接属性块的变量。

    CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Lambert

        // Use shader model 3.5 target, to support enough textures
        #pragma target 3.5

        float4 _MainTex;
        float4 _ColorA;
        float4 _ColorB;
        sampler2D _RTexture;
        sampler2D _GTexture;
        sampler2D _BTexture;
        sampler2D _BlendTex;
        sampler2D _ATexture;

 由于shader内部的纹理数目,我们需要将shader模型的目标级别版本更新为3.5。有关更多Unity模型等级的知识,可到:

https://docs.unity3d.com/Manual/SL-ShaderCompileTargets.html 

          i.所以,现在我们有了纹理属性,我们将它们传递给SubShader{}函数,为了允许用户在每个纹理的基础上更改平铺率,我们需要修改我们的Input结构。这将允许我们在每个纹理上使用平铺和偏移参数。

          struct Input {
            float2 uv_RTexture;
            float2 uv_GTexture;
            float2 uv_BTexture;
            float2 uv_BlendTex;
            float2 uv_ATexture;
        };

          j.在surf()函数中,获取纹理信息并将其存储在自己的变量中,以便我们以干净,易于理解的方式处理数据。

            //Get the pixel data from the blend texture
            //we need a float 4 here because the texture will return R,G,B and A or X,Y,Z,和W
            float4 blendData = tex2D(_BlendTex, IN.uv_BlendTex);
            //Get the data from the textures we want to Blend
            float4 rTexData = tex2D(_RTexture, IN.uv_RTexture);
            float4 gTexData = tex2D(_GTexture, IN.uv_GTexture);
            float4 bTexData = tex2D(_BTexture, IN.uv_BTexture);
            float4 aTexData = tex2D(_ATexture, IN.uv_ATexture);

         注意:由于我们使用了Lambert,在surf函数中所以我们将使用SurfaceOutput 来代替SurfaceOutputStandard

        k.让我们使用lerp()函数将每个纹理混合在一起,它需要三个参数,lerp(value :a,value :b,和blend:c)。函数接受两个纹理,并将它们和最后一个参数中给出的float值混合:

         //No we need to construct a new RGBA value and all the different blended texture back together 
            float4 finalColor;
            finalColor = lerp(rTexData, gTexData, blendData.g);
            finalColor = lerp(finalColor, bTexData, blendData.b);
            finalColor = lerp(finalColor, aTexData, blendData.a);
            finalColor.a = 1.0;

        l.最后,我们将混合纹理乘以颜色色调值并使用红色通道确定两种不同地形色调颜色的位置,然后保存脚本回到场景。    

       l.通过使用不同的纹理和地形着色来创建一些外观极佳的地形,可以进一步实现这种效果。在以下屏幕截图中可以看到将四个地形纹理混合在一起并创建地形着色技术的结果。

    

它是怎么运行的

       这可能看起来像几行代码,但混合背后的概念实际上非常简单。要使该技术起作用,我们必须使用CgFX标准库中的内置lerp()函数。此函数允许我们使用参数3作为混合量来选择参数1和参数2之间的值

      因此,例如,如果我们想要找到介于1和2之间的中间值,我们可以将值0.5作为第三个参数提供给lerp()函数,它将返回值1.5。这对于我们的混合需求非常有效,因为RGBA纹理中单个通道的值是单个浮点值,通常在0到1的范围内。在着色器中,我们只需从混合纹理中选取一个通道并使用它驱动每个像素的lerp()函数中拾取的颜色。例如,我们采用草纹理和灰土纹理,使用混合纹理中的红色通道,并将其提供给lerp()函数。这将为我们提供表面上每个像素的正确混合颜色结果。使用lerp()函数时所发生情况的更直观的表示如下图所示:    

        shader代码只使用混合纹理的四个通道和所有颜色纹理来创建最终的混合纹理。然后,最终纹理成为我们可以与漫反射光照相乘的颜色。

以上均基于Unity2018.1.0f源码可见我的GitHub:https://github.com/xiaoshuivv/ShadersUnity2018.1.0f

猜你喜欢

转载自blog.csdn.net/qq_39218906/article/details/86708215
今日推荐