( 1)在Unity中新建一个场景。在本书资源中,该场景名为Scene_7_4。在Unity 5.2中,默认情况下场景将包含一个摄像机和一个平行光,并且使用了内置的天空盒子。在Window -> Lighting -> Skybox中去掉场景中的天空盒子。

点击 window-rendering-lighting,点击 environment,点击 skybox material

(2)新建一个材质。在本书资源中,该材质名为MaskTextureMat。

(3)新建一个Unity Shader。在本书资源中,该Unity Shader名为Chapter7-MaskTexture。把新的Unity Shader赋给第2步中创建的材质。

(4)在场景中创建一个胶囊体,并把第2步中的材质赋给该胶囊体。

(5)保存场景。
打开新建的Chapter7-MaskTexture,删除所有已有代码,并进行如下修改:

(1)首先,我们需要为这个Shader起一个名字:

(2)我们需要在Properties语义块中声明更多的变量来控制高光反射:

(3)然后,我们在SubShader语义块中定义了一个Pass语义块,并在Pass的第一行指明了该Pass的光照模式:

(4)然后,我们使用CGPROGRAM和ENDCG来包围住CG代码片,以定义最重要的顶点着色器和片元着色器代码。我们使用#pragma指令来告诉Unity,我们定义的顶点着色器和片元着色器叫什么名字。在本例中,它们的名字分别是vert和frag:

(5)为了使用Unity内置的一些变量,如_LightColor0,还需要包含进Unity的内置文件Lighting.cginc:

(6)随后,我们需要定义和Properties中各个属性类型相匹配的变量:

(7)定义顶点着色器的输入和输出结构体:

(8)在顶点着色器中,我们对光照方向和视角方向进行了坐标空间的变换,把它们从模型空间变换到了切线空间中,以便在片元着色器中和法线进行光照运算:

(9)使用遮罩纹理的地方是片元着色器。我们使用它来控制模型表面的高光反射强度:

(10)最后,我们为该Unity Shader设置了合适的Fallback:

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Custom/Chapter7-MaskTexture"
{
    Properties {
        _Color  ("Color  Tint",  Color)  =  (1,1,1,1)
        _MainTex  ("Main  Tex",  2D)  =  "white"  {}
        _BumpMap  ("Normal  Map",  2D)  =  "bump"  {} //normal map 法线纹理
        _BumpScale("Bump  Scale",  Float)  =  1.0 //凹凸强度
        _SpecularMask  ("Specular  Mask",  2D)  =  "white"  {} //_SpecularMask即是我们需要使用的高光反射遮罩纹理
        _SpecularScale  ("Specular  Scale",  Float)  =  1.0 //_SpecularScale则是用于控制遮罩影响度的系数
        _Specular  ("Specular",  Color)  =  (1,  1,  1,  1)
        _Gloss  ("Gloss",  Range(8.0,  256))  =  20
    }

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

            fixed4  _Color;
            sampler2D  _MainTex;
            float4  _MainTex_ST; //为主纹理_MainTex、法线纹理_BumpMap和遮罩纹理_SpecularMask定义了它们共同使用的纹理属性变量_MainTex_ST。这意味着,在材质面板中修改主纹理的平铺系数和偏移系数会同时影响3个纹理的采样。使用这种方式可以让我们节省需要存储的纹理坐标数目,如果我们为每一个纹理都使用一个单独的属性变量TextureName_ST,那么随着使用的纹理数目的增加,我们会迅速占满顶点着色器中可以使用的插值寄存器。而很多时候,我们不需要对纹理进行平铺和位移操作,或者很多纹理可以使用同一种平铺和位移操作,此时我们就可以对这些纹理使用同一个变换后的纹理坐标进行采样。
            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;
                float4  uv  :  TEXCOORD0;
                float3  lightDir:  TEXCOORD1;
                float3  viewDir  :  TEXCOORD2;
            };

            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;
                tangentNormal.z  =  sqrt(1.0  -  saturate(dot(tangentNormal.xy,  tangentNormal.xy)));
                fixed3 albedo  =  tex2D(_MainTex,  i.uv).rgb  *  _Color.rgb;
                fixed3 ambient  =  UNITY_LIGHTMODEL_AMBIENT.xyz  *  albedo;
                fixed3 diffuse  =  _LightColor0.rgb * albedo * max(0, dot(tangentNormal, tangentLightDir));
                fixed3 halfDir  =  normalize(tangentLightDir  +  tangentViewDir);

                //  Get  the  mask  value
                fixed  specularMask  =  tex2D(_SpecularMask,  i.uv).r  *  _SpecularScale; //在这里我们选择使用r分量来计算掩码值,掩码值和_SpecularScale相乘,一起来控制高光反射的强度。
                //  Compute  specular  term  with  the  specular  mask
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(tangentNormal,halfDir)),  _Gloss) * specularMask;
                return  fixed4(ambient  +  diffuse  +  specular,  1.0);
            }
            ENDCG
        }
    }
    Fallback "Specular"


}

下载这个纹理

https://github.com/candycat1992/Unity_Shaders_Book/blob/master/Assets/Textures/Chapter7/Road_Diffuse.tga

贴给对应的 mat

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐