描边的方式有好几种
一种是根据法线方向扩展模型的方式,这种方式最简单,但效果不好。
第二种是将法线转到投影空间后,再扩展顶点,这种方式比第一种好一点点,但是模型的线还是会有断面
第三种是在第二种基础上,重新计算法线,防止断线,而重新计算的法线数据,可以存入模型的切线数据中,这种出来的描边效果最好。
下面主要是第三种的实现方式:
重新计算法线的方法:
private void WirteAverageNormalToTangent(Mesh mesh)
{
var vertics = mesh.vertices;
var normals = mesh.normals;
var averageNormalHash = new System.Collections.Generic.Dictionary<Vector3, Vector3>();
for (var j = 0; j < mesh.vertexCount; j++)
{
if (!averageNormalHash.ContainsKey(vertics[j]))
{
averageNormalHash.Add(vertics[j], normals[j]);
}
else
{
averageNormalHash[vertics[j]] =
(averageNormalHash[vertics[j]] + normals[j]).normalized;
}
}
var averageNormals = new Vector3[mesh.vertexCount];
for (var j = 0; j < mesh.vertexCount; j++)
{
averageNormals[j] = averageNormalHash[vertics[j]];
}
var tangents = new Vector4[mesh.vertexCount];
for (var j = 0; j < mesh.vertexCount; j++)
{
tangents[j] = new Vector4(averageNormals[j].x, averageNormals[j].y, averageNormals[j].z, 0);
}
mesh.tangents = tangents;
}
下面是Shader的主要部分(非完整的shader),注意有两个外部参数,一个是描边的粗细,一个是描边的颜色
Pass
{
Tags { "Queue" = "Geometry-1" }
Cull Front
Zwrite Off
CGPROGRAM
#include "UnityCG.cginc"
#include "GPUSkinningInclude.cginc"
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_instancing
#pragma multi_compile ROOTON_BLENDOFF ROOTON_BLENDON_CROSSFADEROOTON ROOTON_BLENDON_CROSSFADEROOTOFF ROOTOFF_BLENDOFF ROOTOFF_BLENDON_CROSSFADEROOTON ROOTOFF_BLENDON_CROSSFADEROOTOFF
struct appdata
{
float4 vertex : POSITION;
float3 normal:NORMAL;
float2 uv : TEXCOORD0;
float4 uv2 : TEXCOORD1;
float4 uv3 : TEXCOORD2;
float4 tangent : TANGENT;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float4 pos:POSITION;
};
float4 _StrokeColor;
UNITY_INSTANCING_BUFFER_START(Prop)
UNITY_DEFINE_INSTANCED_PROP(float, _stroke)
UNITY_INSTANCING_BUFFER_END(Prop)
v2f vert(appdata v)
{
UNITY_SETUP_INSTANCE_ID(v);
v2f o;
float4 vertex = skin2(v.vertex, v.uv2, v.uv3);
float4 pos = UnityObjectToClipPos(vertex);
float3 norm = mul ((float3x3)UNITY_MATRIX_IT_MV, v.tangent.xyz);
float2 offset = normalize(TransformViewToProjection(norm.xy)*pos.w);
pos.xy += offset * UNITY_ACCESS_INSTANCED_PROP(Prop,_stroke) *0.01;//根据具体情况看这个里需要不需要*0.01
o.pos= pos;
return o;
}
fixed4 frag (v2f IN):COLOR
{
return _StrokeColor;
}
ENDCG
}