【Unity Shader】遮罩纹理

遮罩纹理实现

遮罩纹理(mask texture)是本章要介绍的最后一种纹理,它非常有用,在很多商业游戏中都可以见到它的身影。那么什么是遮罩呢?简单来讲,遮罩允许我们可以保护某些区域,使它们免于某些修改。例如,在之前的实现中,我们都是把高光反射应用到模型表面的所有地方,即所有的像素都使用同样大小的高光强度和高光指数。但有时,我们希望模型表面某些区域的反光强烈一些,而某些区域弱一些。为了得到更加细腻的效果,我们就可以使用一张遮罩纹理来控制光照。另一种常见的应用是在制作地形材质时需要混合多张图片,例如表现草地的纹理、表现石子的纹理、表现裸露土地的纹理等,使用遮置纹理可以控制如何混合这些纹理。使用遮罩纹理的流程一般是:通过采样得到遮罩纹理的纹素值,然后使用其中某个(或某几个)通道的值(例如 texel.r)来与某种表面属性进行相乘,这样,当该通道的值为0时,可以保护表面不受该属性的影响。总而言之,使用遮罩纹理可以让美术人员更加精准(像素级别)地控制模型表面的各种性质。
在这里插入图片描述

Shader "Custom/MaskTexture"
{
    Properties{
        _Color("Color Tint",Color)=(1,1,1,1)
        _MainTex("Main Tex",2D) = "while"{} //主纹理
        _BumpMap("Normal Tex",2D) = "while"{}//法线纹理
        _BumpScale("Bump Scale",Float) = 1
        _SpecularMask("Specular Mask",2D) = "while"{}//高光反射遮罩纹理
        _SpecularScale("Specular Scale",Float) = 1 //控制遮罩影响度系数
        _Specular("Specular",Color) = (1,1,1,1)
        _Gloss("Gloss",Range(8,256)) = 20 
    }

    SubShader{
        Pass{
            Tags{"LightMode" = "ForwardBase"}
            CGPROGRAM
                #pragma vertex vert 
                #pragma fragment frag
                #include "UnityCG.cginc"
                #include "Lighting.cginc"

                fixed4 _Color;
                sampler2D _MainTex;
                float4 _MainTex_ST;//贴图 xy 偏移值
                sampler2D _BumpMap;
                float _BumpScale;
                sampler2D _SpecularMask;
                float _SpecularScale;
                fixed4 _Specular;
                float _Gloss;

                struct a2v{
                    float4 vertex : POSITION;
                    float3 normal : NORMAL;
                    float4 tangent : TANGENT;
                    float4 texcoord : TEXCOORD0;
                };

                struct v2f{
                    float4 pos : SV_POSITION;
                    float2 uv : TEXCOORD0;
                    float3 lightDir : TEXCOORD2;
                    float3 viewDir : TEXCOORD3;
                };

                //在顶点着色器中,对光照和视角方向进行坐标空间转换,
                //把他们从模型空间转换到切线空间中,以便在片元着色器中
                //和法线进行光照运算
                v2f vert(a2v v){
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    o.uv.xy = v.texcoord.xy*_MainTex_ST.xy+_MainTex_ST.zw;
                    TANGENT_SPACE_ROTATION;//法线空间转换矩阵宏定义;
                    //将光照和视角方向由模型空间转换到世界空间再转换到切线空间
                    o.lightDir = mul(rotation,ObjSpaceLightDir(v.vertex)).xyz;
                    o.viewDir = mul(rotation,ObjSpaceViewDir(v.vertex)).xyz;
                    return o; 
                }

                //使用遮罩纹理的是片元着色器,使用它来控制模型表面的高光反射强度
                fixed4 frag(v2f i):SV_Target{
                    fixed3 tangentLightDir = normalize(i.lightDir);
                    fixed3 tangentViewDir = normalize(i.viewDir);
                    fixed3 tangentNormal = UnpackNormal(tex2D(_BumpMap,i.uv));
                    tangentNormal.xy*=_BumpScale;
                    //由于法线是单位矢量,因此z分量可以xy分量计算而得
                    tangentNormal.z = sqrt(1.0-saturate(dot(tangentNormal.xy,tangentNormal.xy)));
                    //计算反射率
                    fixed3 albedo = tex2D(_MainTex,i.uv).rgb*_Color;
                    //计算环境光
                    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*albedo;
                    //计算漫反射
                    fixed3 diffuse = _LightColor0.rgb*albedo*max(0,dot(tangentNormal,tangentLightDir));
                    //计算高光反射
                    fixed3 halfDir = normalize(tangentLightDir+tangentViewDir);
                    //得到遮罩值
                    fixed speculuarMask = tex2D(_SpecularMask,i.uv).r*_SpecularScale;
                    //计算带有遮罩的高光反射
                    fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(max(0,dot(tangentNormal,halfDir)),_Gloss)*speculuarMask;
                    return fixed4(ambient+diffuse+specular,1.0);
                }
                
            ENDCG
        }
    }
    Fallback "Specular"
}

其他遮罩纹理

在真实的游戏制作过程中,遮罩纹理已经不止限于保护某些区域使它们免于某些修改,而是可以存储任何我们希望逐像素控制的表面属性。通常,我们会充分利用一张纹理的 RGBA四个通道,用于存储不同的属性。例如,我们可以把高光反射的强度存储在R通道,把边缘光照的强度存储在G通道,把高光反射的指数部分存储在B 通道,最后把自发光强度存储在A通道在游戏《DOTA2》的开发中,开发人员为每个模型使用了4张纹理:一张用于定义模型颜色张用于定义表面法线,另外两张则都是遮罩纹理。这样,两张遮罩纹理提供了共种额外的表面属性,这使得游戏中的人物材质自由度很强,可以支持很多高级的模型属性。读者可以在他们的官网上找到关于《DOTA2》的更加详细的制作资料,包括游戏中的人物模型、纹理以及制作手册等。这是非常好的学习资料。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值