Unity Tessellation Shader+Geometry shader实现毛发效果

思路:利用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
        }
    }
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值