思路:利用Tessellation Shader(曲面细分着色器)来细化模型的三角面,保证后面生成的毛发足够细,足够密,利用Geometry shader(几何着色器)在细化后的三角面上额外生成向外突出的锥体来模拟毛发,该思路也可以实现其他类似的效果,性能消耗极少。
Shader "Unlit/Tessellation"
{
Properties
{
_Color("MainColor",COLOR)=(1,1,1,1)
_TesseLevel ("Edge length", Range(2,50)) = 20
_Length("Length", Range(0.01, 10)) = 0.02
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex tessvert
#pragma fragment frag
#pragma hull hs
#pragma domain ds
#pragma geometry geom
#pragma target 4.0
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "Tessellation.cginc"
struct Tesse_appdata
{
float4 vertex : INTERNALTESSPOS;
float3 normal : NORMAL;
};
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 vertex : SV_POSITION;
float3 normal : NORMAL;
};
fixed4 _Color;
float _TesseLevel;
float _Length;
Tesse_appdata tessvert (appdata v) {
Tesse_appdata o;
o.vertex = v.vertex;
o.normal = v.normal;
return o;
}
v2f vert (appdata v)
{
v2f o;
o.vertex= v.vertex;
o.normal=v.normal;
return o;
}
float4 tessEdge (float4 v0, float4 v1, float4 v2)
{
return UnityEdgeLengthBasedTess (v0, v1, v2, _TesseLevel);//来自Tessellation.cginc
}
//========Tessellation Shader部分(细分并平滑三角面)
UnityTessellationFactors hsconst(InputPatch<Tesse_appdata,3> v) {
UnityTessellationFactors o;
float4 tf;
tf = tessEdge(v[0].vertex, v[1].vertex, v[2].vertex);
o.edge[0] = tf.x;
o.edge[1] = tf.y;
o.edge[2] = tf.z;
o.inside = tf.w;
return o;
}
[UNITY_domain("tri")]
[UNITY_partitioning("fractional_odd")]
[UNITY_outputtopology("triangle_cw")]
[UNITY_patchconstantfunc("hsconst")]
[UNITY_outputcontrolpoints(3)]
Tesse_appdata hs (InputPatch<Tesse_appdata,3> v, uint id : SV_OutputControlPointID) {
return v[id];
}
[UNITY_domain("tri")]
v2f ds (UnityTessellationFactors tessFactors, const OutputPatch<Tesse_appdata,3> vi, float3 bary : SV_DomainLocation) {
appdata v;
v.vertex = vi[0].vertex*bary.x + vi[1].vertex*bary.y + vi[2].vertex*bary.z;
//------顶点平滑计算,沿法线方向修正顶点位置
float3 pp[3];
pp[0] = v.vertex.xyz - vi[0].normal * (dot(v.vertex.xyz, vi[0].normal) - dot(vi[0].vertex.xyz, vi[0].normal));
pp[1] = v.vertex.xyz - vi[1].normal * (dot(v.vertex.xyz, vi[1].normal) - dot(vi[1].vertex.xyz, vi[1].normal));
pp[2] = v.vertex.xyz - vi[2].normal * (dot(v.vertex.xyz, vi[2].normal) - dot(vi[2].vertex.xyz, vi[2].normal));
v.vertex.xyz = 0.5 * (pp[0]*bary.x + pp[1]*bary.y + pp[2]*bary.z) + (1.0f-0.5) * v.vertex.xyz;
//------
v.normal = vi[0].normal*bary.x + vi[1].normal*bary.y + vi[2].normal*bary.z;
//新的参数=p1的参数*bary.x+p2的参数*bary.y+p3的参数*bary.z;(三点插值算法)
v2f o = vert(v);
return o;
}
//========
void ADD_VERT(float3 v,v2f o,inout TriangleStream<v2f> tristream)
{
o.vertex = UnityObjectToClipPos(v);
tristream.Append(o);
}
void ADD_TRI(float3 p0,float3 p1,float3 p2,v2f o,inout TriangleStream<v2f> tristream)
{
ADD_VERT(p0,o,tristream);
ADD_VERT(p1,o,tristream);
ADD_VERT(p2,o,tristream);
tristream.RestartStrip();
}
//======Geometry shader部分(在细分之后的三角面基础上额外生成向外突出的椎体)
[maxvertexcount(9)]
void geom(triangle appdata IN[3], inout TriangleStream<v2f> tristream)
{
v2f o;
//--------计算原模型三角面的法线
float3 edgeA = IN[1].vertex - IN[0].vertex;
float3 edgeB = IN[2].vertex - IN[0].vertex;
float3 normalFace = normalize(cross(edgeA, edgeB));
//-------
o.normal=-normalFace;
//根据模型三角面信息额外生成一个向外突出的锥体
float3 v0 = IN[0].vertex;
float3 v1 = IN[1].vertex;
float3 v2 = IN[2].vertex;
float3 v3 = (IN[0].vertex+IN[1].vertex+IN[2].vertex)/3 + normalFace * _Length;
ADD_TRI(v0,v1,v2,o,tristream);
ADD_TRI(v0,v1,v3,o,tristream);
ADD_TRI(v2,v3,v1,o,tristream);
}
//======
fixed4 frag (v2f i) : SV_Target
{
//处理光照等等
float3 lightDir=normalize(_WorldSpaceLightPos0.xyz);
float4 diffuseColor=_LightColor0*max(dot(i.normal,lightDir),0);
return _Color*diffuseColor;
}
ENDCG
}
}
}