描边就是做出物体边缘的线条,通俗讲就是在边缘加上边框,一般是为了把物体和背景区分出来,便于识别。
王者荣耀设置面板有角色描边开关,如果是低端机器开启会卡,为什么?
实现方式一
一个pass 所有顶点沿着法线方向扩展一个标量_OutLinePower,绘制纯色_OutLineColor ,另一个pass绘制完整模型
Shader "S_Game_Hero/OutLine"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_OutLinePower("factor",Range(0,0.1)) = 0.01
_OutLineColor("outline color",Color) = (0,0,0,1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
//绘制一个方向就够了
Cull Front
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 vertex : SV_POSITION;
};
float _OutLinePower;
half4 _OutLineColor;
v2f vert (appdata v)
{
v2f o;
//法线方向扩张
float3 offset = v.normal * _OutLinePower;
o.vertex = UnityObjectToClipPos( v.vertex + offset);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
//绘制纯色
return _OutLineColor;
}
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
}
这种实现方式有点瑕疵,不仅会造成近大远小的透视问题,并且还出现一些多余的黑面片。
有些三角面是正面,有些三角面是反面,用cull Front会剔除正面,保留反面。所以会留下这种黑面片。默认是开启了写入深度缓存zwrite。这些多余的黑面片恰好又在前面,正常的颜色绘制时就通不过深度测试ztest。
如果在第一个pass关闭深度缓存:ZWrite Off ,发现多余的黑面片没了,但是又缺失了一些描边。
在第一个pass中再特殊处理一下这些黑面的z轴。
v2f vert (appdata v)
{
v2f o;
//float3 offset = v.normal * _OutLinePower;
//o.vertex = UnityObjectToClipPos( v.vertex + offset);
//将顶点转化到观察空间中
float4 pos = mul( UNITY_MATRIX_MV, v.vertex);
//将法向转化到观察空间中
//如果用UNITY_MATRIX_MV不用UNITY_MATRIX_IT_MV,将不会再垂直原来的面了
float3 normal = mul( (float3x3)UNITY_MATRIX_IT_MV, v.normal);
//会把太靠前的黑面反向拉一下
normal.z -= 3;
pos = pos + float4(normalize(normal),0) * _OutLinePower;
//将顶点转化到投影空间中
o.vertex = mul(UNITY_MATRIX_P, pos);
return o;
}