[UnityShaderCookbook 读书笔记] [04] 多层纹理

5 篇文章 0 订阅
4 篇文章 0 订阅

多层纹理


有时我们会需要给同一表面施加多层不同的纹理,这一情况在地形中常常出现,例如一个地形上同时会有泥土,岩石,草,花等不同纹理,此时,针对每一层纹理,我们都需要mask来表示该层纹理在地形上的分布。

如果给每一层纹理都附加一张mask图片,即使我们每张mask使用的都是灰度图,多张图片对系统依然是一个负担。在此,我们可以把每张灰度图作为一个通道,由此一张有4个通道(R,G,B,A)的图片就可以存储4张不同的mask。

每通道存储一个mask原理图解
这里写图片描述

下图为我们预期使用的4张不同的纹理
这里写图片描述

下图为我们的mask纹理,图示为各个通道的内容
这里写图片描述

我们需要先在属性段里添加5个2D贴图,分别为4张纹理以及1张mask纹理

Properties
{
    _RTexture ("Red Channel Texture", 2D) = ""{}
    _GTexture ("Green Channel Texture", 2D) = ""{}
    _BTexture ("Blue Channel Texture", 2D) = ""{}
    _ATexture ("Alpha Channel Texture", 2D) = ""{}
    _MaskTexture ("Mask Texture", 2D) = ""{}
}

在SubShader块内的 CGPROGRAM 内再次声明这5个变量,
#pragma surface surf Lambert 后添加

sampler2D _RTexture;
sampler2D _GTexture;
sampler2D _BTexture;
sampler2D _ATexture;
sampler2D _MaskTexture;

再修改 surface 函数,在其中分别使用mask纹理的 R,G,B,A 通道来控制4张贴图。

将 surface 函数修改为

void surf (Input IN, inout SurfaceOutput o) {
    float4 rTexData = tex2D(_RTexture, IN.uv_MaskTexture);
    float4 gTexData = tex2D(_GTexture, IN.uv_MaskTexture);
    float4 bTexData = tex2D(_BTexture, IN.uv_MaskTexture);
    float4 aTexData = tex2D(_ATexture, IN.uv_MaskTexture);
    float4 maskData = tex2D(_MaskTexture, IN.uv_MaskTexture);

    float4 finalColor;
    finalColor = lerp(float4(1,1,1,1), rTexData, maskData.r);
    finalColor = lerp(finalColor, gTexData, maskData.g);
    finalColor = lerp(finalColor, bTexData, maskData.b);
    finalColor = lerp(finalColor, aTexData, maskData.a);
    finalColor.a = 1.0;
    finalColor = saturate(finalColor);

    o.Albedo = finalColor.rgb;
    o.Alpha = finalColor.a;
}

最终实现的效果为
这里写图片描述

最终的多层纹理 Shader 为

Shader "HineNotes/CookbookCh_02/rgbaMask" {
     Properties {
          _RTexture ("Red Channel Texture", 2D) = ""{}
          _GTexture ("Green Channel Texture", 2D) = ""{}
          _BTexture ("Blue Channel Texture", 2D) = ""{}
          _ATexture ("Alpha Channel Texture", 2D) = ""{}
          _MaskTexture ("Mask Texture", 2D) = ""{}
     }
     SubShader {
          Tags { "RenderType"="Opaque" }
          LOD 200

          CGPROGRAM
          #pragma surface surf Lambert

          sampler2D _RTexture;
          sampler2D _GTexture;
          sampler2D _BTexture;
          sampler2D _ATexture;
          sampler2D _MaskTexture;

          struct Input {
               float2 uv_MaskTexture;
          };

          void surf (Input IN, inout SurfaceOutput o) {
               float4 rTexData = tex2D(_RTexture, IN.uv_MaskTexture);
               float4 gTexData = tex2D(_GTexture, IN.uv_MaskTexture);
               float4 bTexData = tex2D(_BTexture, IN.uv_MaskTexture);
               float4 aTexData = tex2D(_ATexture, IN.uv_MaskTexture);
               float4 maskData = tex2D(_MaskTexture, IN.uv_MaskTexture);

               float4 finalColor;
               finalColor = lerp(float4(1,1,1,1), rTexData, maskData.r);
               finalColor = lerp(finalColor, gTexData, maskData.g);
               finalColor = lerp(finalColor, bTexData, maskData.b);
               finalColor = lerp(finalColor, aTexData, maskData.a);
               finalColor.a = 1.0;
               finalColor = saturate(finalColor);

               o.Albedo = finalColor.rgb;
               o.Alpha = finalColor.a;
          }
          ENDCG
     }
     FallBack "Diffuse"
}

在上面的 surf 函数中,我们用到了CGFX 标准库 中的内建函数 lerp()

函数描述
lerp(a,b,f)线性插值计算: ( 1 - f ) * a + b * f
其中,a和b为相同类型的向量,或标量。f可以为标量,或与a、b类型匹配的向量

lerp函数的作用,即是在 a 与 b 之间利用 f 进行线性插值。举例来说,当 f = 0 时,插值结果为 a, f = 1 时, 插值结果为 b。

下图为 lerp() 函数的作用图解
这里写图片描述

在 shader 代码当中,我们首先将 R 贴图与白色利用 R mask 线性插值,再将其结果利用 B mask 与 B 贴图线性插值,如此反复对每个贴图与原先的结果进行线性插值,最终就得到了混合后的结果。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值