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

来源:互联网 发布:开淘宝步骤 编辑:程序博客网 时间:2024/05/14 17:30

多层纹理


有时我们会需要给同一表面施加多层不同的纹理,这一情况在地形中常常出现,例如一个地形上同时会有泥土,岩石,草,花等不同纹理,此时,针对每一层纹理,我们都需要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 贴图线性插值,如此反复对每个贴图与原先的结果进行线性插值,最终就得到了混合后的结果。

1 0
原创粉丝点击