Unity ShaderLab新手宝典简单Shader:描边效果 + 相关基础知识

原理

当Shader中有多个Pass时,Pass会按照顺序执行,后执行的Pass绘制的图像会覆盖掉前面的Pass绘制的图像。
这个案例就是通过两层Pass实现,第一层Pass将模型的顶点位置沿法线方向膨胀一段距离,然后为膨胀的模型指定一个颜色,不需要与任何灯光交互。
第二层模型正常显示,本案例使用Surface Shader,并使用Standard Specular光照模型。
正常情况第一层膨胀起来的模型会将第二层模型笼罩,因此第二层模型无法通过深度测试,最终只会显示第一层的模型。为解决这个问题,需要让第二层模型通过深度测试。具体解决办法有如下两种:

  1. 更改第二层的深度值比较方法,但这样做会导致其它物体在深度测试时出现错误,所以排除此法。
  2. 关闭第一层的深度写入,这样深度缓存中没有第一层模型深度值,第二层模型自然就可以通过深度测试了。
    但使用第二种方法又会引发另一个问题,就是当物体关闭深度写入后,后面被遮挡的物体无法知道自己被遮挡,在绘制图像时会覆盖已经绘制好的第一层模型。为了避免这个问题,需要让该物体在所有不透明物体绘制完成后在进行绘制,所以更改Shader的渲染队列为Transparent,这样就不会被后面的物体覆盖了。
Shader "Samples/OutLine"
{
    Properties
    {
        [Header(Texture Group)]//[Header(name)]材质面板说明
        [Space(10)]//间距
        _Albedo("Albedo",2D) = "white"{}
        [NoScaleOffset]_Specular("Specular(RGB-A)",2D) = "black"{}//[NoScalleOffset]就是没有贴图缩放和位移设置
        [NoScaleOffset]_Normal("Normal",2D) = "bump"{}
        [NoScaleOffset]_AO("Ambient Occlusion",2D) = "white"{}
        [Header(OutLine Properties)]
        [Space(10)]
        _OutLineColor("OutLine Color",Color) = (1,0,1,1)
        _OutLineWidth("OutLine Width",Range(0,0.1)) = 0.01
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "Queue" = "Transparent"}
        
        //----------OutLine Layer----------

        Pass
        {
            ZWrite Off//ZWrite On/Off 表示设置是否写入深度缓存,默认为On

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            
            struct v2f
            {
                float4 vertex : SV_POSITION;
            };
            
            fixed4 _OutLineColor;
            fixed _OutLineWidth;

            v2f vert (appdata_base v)
            {
                v2f o;
                v.vertex.xyz += v.normal * _OutLineWidth;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return _OutLineColor;
            }
            ENDCG
        }

        //----------Regular Layer----------
        CGPROGRAM
        #pragma surface surf StandardSpecular fullforwardshadows//定义表面着色器的名称,通常使用surf,定义光照模型为StandardSpecular,fullforwardshadows指令使物体支持所有灯光类型的投影

        struct Input
        {
             float2 uv_Albedo;
        };

        sampler2D _Albedo;
        sampler2D _Specular;
        sampler2D _Normal;
        sampler2D _AO;

        void surf(Input IN, inout SurfaceOutputStandardSpecular o)
        {
            fixed4 c = tex2D(_Albedo, IN.uv_Albedo);
            o.Albedo = c.rgb;

            fixed4 specular = tex2D(_Specular, IN.uv_Albedo);
            o.Specular = specular.rgb;
            o.Smoothness = specular.a;

            o.Normal = UnpackNormal(tex2D(_Normal, IN.uv_Albedo));
            o.Occlusion = tex2D(_AO, IN.uv_Albedo);
        }
        ENDCG   
    }
}

我使用这个Shader遇到了一些问题:
1、在URP模板中使用了这个Shader的材质球除描边外呈粉紫色,但是没有报错。

可以设置的渲染状态

渲染状态

数值

作用

Cull

Cull Back/Front/Off

设置多边形的剔除方式,有背面剔除、正面剔除、不剔除,默认为back

ZTest

ZTest (Less/Greater/LEqual/GEqual/Equal/NotEqual/Always)

设置深度测试的对比方式,默认为LEqual

ZWrite

ZWrite On/Off

设置是否写入深度缓存,默认为On

Blend

Blend sourecBlendMode destBlendMode

设置渲染图像的混合方式

ColorMask

ColorMask RGB/A/0/或者R、G、B、A的任意组合

设置颜色通道的写入蒙版,默认蒙版为RGBA,当设置为0时,则无法写入任何颜色