先介绍两种方法

  1. 基于法线方向与视角夹角是否垂直或位于边缘
  2. 两个 Pass, 一个 Pass 将模型边缘向外扩散一定距离,另一个 Pass 正常渲染

# 扩散外边界方式

这种方式只能扩散外边界 (比如内部纹理的描边就不行了), 而且规则模型的限制也很大

# 效果

# 代码

Shader “Custome/Outline”
{
Properties
{
[Header(Texture Group)]
[Space(10)]
_Albedo(“Albedo”,2D) = “white” {}
[NoScaleOffset]_Specular(“Specular (RGB-A)”,2D) = “black” {}
[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

        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

    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
    
}

}