在游戏中经常会出现这样的效果,当角色跑到其他物体(如建筑,墙)背后的时候,被物体遮挡的部分会出现半透高亮效果(X-Ray效果),而没有被遮挡的部分依然正常显示,这种效果被称为遮挡半透效果。
1.0 实现原理
遮挡半透效果中包含了俩种显示效果,即半透高亮效果和正常显示效果,因此需要一个Shader中实现这俩种效果,并且需要在被遮挡和不被遮挡俩种不同的条件下分别执行对于的效果。
(1)被遮挡效果:被遮挡的部分并没有被剔除,而是显示为中间半透,边缘发亮效果,类似于菲涅尔效果。因此需要将这个Pass的深度测试比较方法设定为Greater,是被遮挡之后依然可以通过深度测试。
(2)未被遮挡效果:这一部分其实就是正常的Shader效果。
当物体没有被遮挡的时候,遮挡效果的Pass就不会通过深度测试,于是只会显示未被遮挡的正常效果;当物体被遮挡的时候,遮挡效果的Pass就会通过深度测试,而未被遮挡的正常效果则不会通过深度测试,因此不会覆盖已经绘制的遮挡效果。
2.0 实现逻辑
Shader代码如下:
Shader "Samples/X-Ray"
{
Properties
{
[Header(The Blocked Part)]
[Space(10)]
_Color ("X-Ray Color", Color) = (0,1,1,1)
_Width ("X-Ray Width", Range(1, 2)) = 1
_Brightness ("X-Ray Brightness",Range(0, 2)) = 1
[Header(The Normal Part)]
[Space(10)]
_Albedo("Albedo", 2D) = "white"{}
[NoScaleOffset]_Specular ("Specular (RGB-A)", 2D) = "black"{}
[NoScaleOffset]_Normal ("Nromal", 2D) = "bump"{}
[NoScaleOffset]_AO ("AO", 2D) = "white"{}
}
SubShader
{
// 本Shader属于不透明效果,因此将渲染类型设置为Opaque
// 遮挡半透明不需要显示后面的物体,因此将渲染队列设置为Geometry而不是Transparent
Tags{"RenderType" = "Opaque" "Queue" = "Geometry"}
//---------- 遮挡效果 ----------
Pass
{
// 深度测试比较方法设置为Greater,从而是物体即使被遮挡也会显示出来
ZTest Greater
// 为了不遮挡住后面的Pass,需要将深度写入关闭
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f
{
float4 vertexPos : SV_POSITION;
float3 viewDir : TEXCOORD0;
float3 worldNor : TEXCOORD1;
};
v2f vert(appdata_base v)
{
v2f o;
o.vertexPos = UnityObjectToClipPos(v.vertex);
// 获取世界空间视角方向
o.viewDir = normalize(WorldSpaceViewDir(v.vertex));
// 获取世界空间法线向量
o.worldNor = UnityObjectToWorldNormal(v.normal);
return o;
}
fixed4 _Color;
fixed _Width;
half _Brightness;
float4 frag(v2f i) : SV_Target
{
// 菲涅尔(Fresnel)算法
half NDotV = saturate( dot(i.worldNor, i.viewDir));
NDotV = pow(1 - NDotV, _Width) * _Brightness;
fixed4 color;
color.rgb = _Color.rgb;
color.a = NDotV;
return color;
}
ENDCG
}
//---------- 未被遮挡效果 ----------
CGPROGRAM
#pragma surface surf StandardSpecular
#pragma target 3.0
struct Input
{
float2 uv_Albedo;
};
sampler2D _Albedo;
sampler2D _Specular;
sampler2D _Normal;
sampler2D _AO;
void surf(Input IN, inout SurfaceOutputStandardSpecular o)
{
o.Albedo = tex2D(_Albedo, IN.uv_Albedo).rgb;
fixed4 specular = tex2D(_Specular, IN.uv_Albedo);
o.Specular = specular.rgb;
o.Smoothness = specular.a;
o.Normal = UnpackNormal(tex2D(_Normal, IN.uv_Albedo));
}
ENDCG
}
}
效果如图:

3.0 遮挡半透算法缺陷
该描边算法只适合顶点法线方向各异的模型(如球),而对于一些顶点法线方向比较一致的模型(如立方体),当相机朝向与该模型法线方向平行时,不会出现X-Ray效果。如图:


网友评论