效果比较好的头发shader

效果如下:

渲染头发时可能会遇到如下问题:

1. 因为头发本质上是一个一个的透明的面片,理所当然会想到使用 blend 混合方式来渲染。

但当由于用 blend 时,要关闭Z缓存写,即执行 Zwirte Off,不然透明的区域也会遮挡后面的像素。

此时就会出现问题,头发之间的层级会完全混乱,因为头发是多个面片穿插在一起的。

2. 因此不能使用blend的方式,就只能使用 Alpha Test 的方式来强制丢弃透明的像素。

但 Alpha Test 的问题的边缘部分不够平滑,剧齿感明显。

解决此问题的思路是,一个通道执行 Alpha Test,把透明区域直接丢弃掉。

另一个通道执行 Blend 混合,把 Alpha Test 丢弃的像素再重新渲染一遍。

示例代码如下:

  1 Shader "Character/Example-Diffuse-Hair"
  2 {
  3     Properties
  4     {
  5         _Color ("Main Color", Color) = (1,1,1,1)
  6         _MainTex ("Base (RGB)", 2D) = "white" {}
  7         _Cutoff( "Cutoff", Range (0,1)) = 0.5
  8     }
  9 
 10     SubShader
 11     {
 12         Tags 
 13         {
 14             "RenderType" = "Transparent"
 15             "IgnoreProjector" = "True"
 16             "Queue" = "Transparent+100"
 17         }
 18         LOD 200
 19 
 20         Pass
 21         {
 22             Tags
 23             {
 24                 "LightMode" = "ForwardBase"
 25             }
 26             Blend SrcAlpha OneMinusSrcAlpha
 27             Cull Off
 28 
 29             CGPROGRAM
 30             #pragma vertex vert
 31             #pragma fragment frag
 32             #pragma multi_compile_fwdbase
 33 
 34             #include "UnityCG.cginc"
 35             #include "AutoLight.cginc"
 36             #include "Lighting.cginc"
 37 
 38             fixed4 _Color;
 39             sampler2D _MainTex;
 40             float _Cutoff;
 41             
 42             struct appdata
 43             {
 44                 float4 vertex : POSITION;
 45                 float2 uv : TEXCOORD0;
 46                 float3 normal : NORMAL;
 47             };
 48 
 49             struct v2f
 50             {
 51                 float4 pos : SV_POSITION;
 52                 float2 uv : TEXCOORD0;
 53                 float3 worldPos : TEXCOORD1;
 54                 float3 worldNormal : TEXCOORD2;
 55             };
 56 
 57             v2f vert(appdata v)
 58             {
 59                 v2f o;
 60                 o.pos = UnityObjectToClipPos(v.vertex);
 61                 o.uv = v.uv;
 62                 o.worldPos = mul(unity_ObjectToWorld, v.vertex);
 63                 o.worldNormal = UnityObjectToWorldNormal(v.normal);
 64                 return o;
 65             }
 66 
 67             fixed4 frag(v2f i) : SV_TARGET
 68             {
 69                 fixed4 albedo = tex2D(_MainTex, i.uv) * _Color;
 70                 clip(albedo.a - _Cutoff);
 71 
 72                 fixed3 ambient = albedo.rgb * UNITY_LIGHTMODEL_AMBIENT.rgb;
 73 
 74                 fixed3 worldLight = UnityWorldSpaceLightDir(i.worldPos);
 75                 float d = dot(worldLight, i.worldNormal) * 0.5 + 0.5;
 76                 fixed3 diffuse = albedo.rgb * _LightColor0.rgb * d;
 77                 
 78                 fixed4 col = fixed4(ambient + diffuse * 2, albedo.a);
 79 
 80                 return col;
 81             }
 82 
 83             ENDCG
 84         }
 85 
 86         Pass
 87         {
 88             Tags
 89             {
 90                 "LightMode" = "ForwardBase"
 91             }
 92             Blend SrcAlpha OneMinusSrcAlpha
 93             ZWrite Off
 94 
 95             CGPROGRAM
 96             #pragma vertex vert
 97             #pragma fragment frag
 98             #pragma multi_compile_fwdbase
 99 
100             #include "UnityCG.cginc"
101             #include "AutoLight.cginc"
102             #include "Lighting.cginc"
103 
104             fixed4 _Color;
105             sampler2D _MainTex;
106             float _Cutoff;
107             
108             struct appdata
109             {
110                 float4 vertex : POSITION;
111                 float2 uv : TEXCOORD0;
112                 float3 normal : NORMAL;
113             };
114 
115             struct v2f
116             {
117                 float4 pos : SV_POSITION;
118                 float2 uv : TEXCOORD0;
119                 float3 worldPos : TEXCOORD1;
120                 float3 worldNormal : TEXCOORD2;
121             };
122 
123             v2f vert(appdata v)
124             {
125                 v2f o;
126                 o.pos = UnityObjectToClipPos(v.vertex);
127                 o.uv = v.uv;
128                 o.worldPos = mul(unity_ObjectToWorld, v.vertex);
129                 o.worldNormal = UnityObjectToWorldNormal(v.normal);
130                 return o;
131             }
132 
133             fixed4 frag(v2f i) : SV_TARGET
134             {
135                 fixed4 albedo = tex2D(_MainTex, i.uv) * _Color;
136                 clip(_Cutoff - albedo.a);
137 
138                 fixed3 ambient = albedo.rgb * UNITY_LIGHTMODEL_AMBIENT.rgb;
139 
140                 fixed3 worldLight = normalize(UnityWorldSpaceLightDir(i.worldPos));
141                 float d = dot(worldLight, i.worldNormal) * 0.5 + 0.5;
142                 fixed3 diffuse = albedo.rgb * _LightColor0.rgb * d;
143                 
144                 fixed4 col = fixed4(ambient + diffuse * 2, albedo.a);
145 
146                 return col;
147             }
148 
149             ENDCG
150         }
151         
152         
153     } 
154 
155     Fallback "Diffuse"
156 }

转载请注明出处:https://www.cnblogs.com/jietian331/p/12621455.html

原文地址:https://www.cnblogs.com/jietian331/p/12621455.html