首先准备两个Shader,第一个用于产生Stencil,第二个用于产生模型对外挤出的渲染,同时,挤出渲染过程中利用第一个shader产生的Stencil将内部留空,这样就产生了Outline勾边效果。
这两个Shader在前面已经有了,为了方便查看这里再贴出来一下。
首先是用于产生Stencil的Shader:
Shader "Unlit/PureStencil"
{
Properties
{
[IntRange]_StencilID("Stencil ID", Range(0,255)) = 1
}
SubShader
{
Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "Queue" = "Geometry"}
Pass
{
Blend Zero One
ZWrite Off
Stencil
{
Ref [_StencilID]
Comp Always
Pass Replace
Fail Keep
}
}
}
}
其次是用于产生挤出的Shader:
Shader "Unlit/PureExtrude"
{
Properties
{
_OutlineColor("Outline Color",Color) = (1,0.5,0,0.5)
_Outline("Outline",Range(0,1)) = 0.1
}
SubShader
{
Tags { "RenderType" = "Transparent" "RenderPipeline" = "UniversalPipeline"}
Pass
{
Cull Off
ZTest LEqual
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Atributes
{
float4 posOS : POSITION;
float3 norOS : NORMAL;
};
struct Varyings
{
float4 posCS : SV_POSITION;
};
CBUFFER_START(UnityPerMaterial)
real4 _OutlineColor;
real _Outline;
CBUFFER_END
Varyings vert(Atributes v)
{
Varyings o = (Varyings)0;
o.posCS = TransformObjectToHClip(v.posOS.xyz);
float3 vNormal = normalize(mul((float3x3)UNITY_MATRIX_IT_MV, v.norOS));
float2 projPos = normalize(mul((float2x2)UNITY_MATRIX_P,vNormal.xy));
o.posCS.xy += projPos * _Outline * 0.1;
return o;
}
real4 frag(Varyings i) : SV_Target
{
return _OutlineColor;
}
ENDHLSL
}
}
}
有了这两个Shader之后,再在Unity中添加一个Outline层,目的是希望进入Outline层的物体才显示Outline效果。
然后在URP的Render Feature中添加两个Render Objects,参数如下图。
第一个Render Objects命名为Stencil,是用来产生蒙版的,第二个命名为Outline,用于产生挤出的像素。
第一个的Event参数选择了不透明渲染之后,第二个的Event选择了在Skybox渲染之前,这样就保证了第二个肯定可以使用第一个产生的Stencil。
两者的Layer Mask都使用了Outline,这个嘛,是当然了,呵呵。
第一个的覆盖材质使用了名字叫Stencil的材质,当然了这个材质使用了前面的Stencil这个Shader,同时这个材质的_StencilID设置为了一个大于0的数字,比如1;第二个的覆盖材质使用了名字叫Outline的材质,同理,这个材质使用了前面的Outline这个Shader。
两者的Depth都进行了勾选,而且Depth Test都设置为Always,这样保证了将来Outline的效果是覆盖在所有物体之上的,当然也不是说一定要这么干,这个根据情况调整吧,一般来说第一个选择Always是有必要的,第二个选择Less似乎也不错(如果更变态一点儿,再添加第三个Render Objects,也是用类似Outline的材质,然后选择Greater,用于产生一个不同效果的被遮挡部分的勾边,这样被遮挡和不被遮挡的部分就产生了不同的勾边,呵呵)。还有就是Depth Write不要勾选,由于这个例子里面是最后渲染的两个物体,其实Depth Write怎么设置都无所谓了。
第一个的Stencil不需要勾选,第二个的Stencil需要勾选,同时Value设置为0,Compare Function设置为Equal,这样蒙版所在的位置的像素都无法被渲染了,只有挤出多余的部分能够被渲染出来。