效果比较好的头发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 }

 

以下是带高光的头发shader,头发的高光比较特殊,是一圈一圈的高光,如下图效果,故不能用普通的高光算法。

 

 

代码如下:

  1 Shader "America/Character/America-Diffuse-Specular-Hair2"
  2 {
  3     Properties
  4     {
  5         _Color ("Main Color", Color) = (1,1,1,1)
  6         _MainTex ("Base (RGB)", 2D) = "white" {}
  7         _Ramp ("Toon Ramp (RGB)", 2D) = "gray" {}
  8         _Cutoff( "Cutoff", Range (0,1)) = 0.5
  9         
 10         _OverlyingColor("Overlying Color", Color) = (0.5, 0.5, 0.5, 1)
 11         
 12         _SpecularGloss ("Specular Gloss", float) = 20
 13         _AnisotropyBias("Anisotropy-Bias", Range( -1 , 1)) = -1
 14         _DiffuseRate ("Diffuse Rate", float) = 2
 15         _SpecularRate ("Specular Rate", float) = 0.6
 16     }
 17 
 18     SubShader
 19     {
 20         Tags 
 21         {
 22             "RenderType" = "Transparent"
 23             "IgnoreProjector" = "True"
 24             "Queue" = "Transparent+100"
 25         }
 26         LOD 200
 27 
 28         Pass
 29         {
 30             Tags
 31             {
 32                 "LightMode" = "ForwardBase"
 33             }
 34             Blend SrcAlpha OneMinusSrcAlpha
 35             Cull Off
 36 
 37             CGPROGRAM
 38             #pragma vertex vert
 39             #pragma fragment frag
 40             #pragma multi_compile_fwdbase
 41 
 42             #include "UnityCG.cginc"
 43             #include "AutoLight.cginc"
 44             #include "Lighting.cginc"
 45             
 46             #include "../AmericaCG.cginc"
 47 
 48             fixed4 _Color;
 49             sampler2D _MainTex;
 50             sampler2D _Ramp;
 51             float _Cutoff;
 52             fixed4 _OverlyingColor;
 53             float _SpecularGloss;
 54             half _AnisotropyBias;
 55             float _DiffuseRate;
 56             float _SpecularRate;
 57             
 58             struct appdata
 59             {
 60                 float4 vertex : POSITION;
 61                 float2 uv : TEXCOORD0;
 62                 float3 normal : NORMAL;
 63                 float4 tangent : TANGENT;
 64             };
 65 
 66             struct v2f
 67             {
 68                 float4 pos : SV_POSITION;
 69                 float2 uv : TEXCOORD0;
 70                 float4 T2W1 : TEXCOORD1;
 71                 float4 T2W2 : TEXCOORD2;
 72                 float4 T2W3 : TEXCOORD3;
 73             };
 74 
 75             v2f vert(appdata v)
 76             {
 77                 v2f o;
 78                 o.pos = UnityObjectToClipPos(v.vertex);
 79                 o.uv = v.uv;
 80                 
 81                 float3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
 82                 float3 worldNormal = UnityObjectToWorldNormal(v.normal);
 83                 float3 binormal = cross(normalize(worldNormal), normalize(worldTangent)) * v.tangent.w;
 84                 float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
 85                 o.T2W1 = float4(worldTangent.x, binormal.x, worldNormal.x, worldPos.x);
 86                 o.T2W2 = float4(worldTangent.y, binormal.y, worldNormal.y, worldPos.y);
 87                 o.T2W3 = float4(worldTangent.z, binormal.z, worldNormal.z, worldPos.z);
 88                 return o;
 89             }
 90 
 91             fixed4 frag(v2f i) : SV_TARGET
 92             {
 93                 float3 worldPos = float3(i.T2W1.w, i.T2W2.w, i.T2W3.w);
 94                 float3 worldNormal = float3(i.T2W1.z, i.T2W2.z, i.T2W3.z);
 95                 //float3 worldTangent = float3(i.T2W1.x, i.T2W2.x, i.T2W3.x);
 96                 float3 worldBitangent = float3(i.T2W1.y, i.T2W2.y, i.T2W3.y);
 97                 
 98                 float3 worldLight = normalize(UnityWorldSpaceLightDir(worldPos));
 99                 float3 worldView = normalize(UnityWorldSpaceViewDir(worldPos));
100                 
101                 fixed4 albedo = tex2D(_MainTex, i.uv) * _Color;
102                 clip(albedo.a - _Cutoff);
103 
104                 fixed3 ambient = albedo.rgb * UNITY_LIGHTMODEL_AMBIENT.rgb;
105 
106                 float d = dot(worldLight, worldNormal) * 0.5 + 0.5;
107                 fixed3 rampCol = tex2D(_Ramp, float2(d, d)).rgb;
108                 fixed3 diffuse = albedo.rgb * _LightColor0.rgb * rampCol;
109                 
110                 // spec
111                 float clampSpec = clamp(albedo.r + albedo.g * _AnisotropyBias - 0.2 , -1.0 , 1.33);
112                 float dotSpec = dot(worldBitangent + worldNormal * clampSpec, worldView);
113                 fixed3 specular = _LightColor0.rgb * pow(1 - dotSpec * dotSpec, _SpecularGloss);
114                 specular = clamp(specular, float3(0,0,0), half3(1.51,1.51,1.51));
115 
116                 fixed4 col = fixed4(ambient + diffuse * _DiffuseRate + specular * _SpecularRate, albedo.a);
117                 col.rgb = Overlay(col, _OverlyingColor);
118 
119                 return col;
120             }
121 
122             ENDCG
123         }
124 
125         Pass
126         {
127             Tags
128             {
129                 "LightMode" = "ForwardBase"
130             }
131             Blend SrcAlpha OneMinusSrcAlpha
132             ZWrite Off
133 
134             CGPROGRAM
135             #pragma vertex vert
136             #pragma fragment frag
137             #pragma multi_compile_fwdbase
138 
139             #include "UnityCG.cginc"
140             #include "AutoLight.cginc"
141             #include "Lighting.cginc"
142 
143             #include "../AmericaCG.cginc"
144             
145             fixed4 _Color;
146             sampler2D _MainTex;
147             sampler2D _Ramp;
148             float _Cutoff;
149             fixed4 _OverlyingColor;
150             float _DiffuseRate;
151             
152             struct appdata
153             {
154                 float4 vertex : POSITION;
155                 float2 uv : TEXCOORD0;
156                 float3 normal : NORMAL;
157             };
158 
159             struct v2f
160             {
161                 float4 pos : SV_POSITION;
162                 float2 uv : TEXCOORD0;
163                 float3 worldPos : TEXCOORD1;
164                 float3 worldNormal : TEXCOORD2;
165             };
166 
167             v2f vert(appdata v)
168             {
169                 v2f o;
170                 o.pos = UnityObjectToClipPos(v.vertex);
171                 o.uv = v.uv;
172                 o.worldPos = mul(unity_ObjectToWorld, v.vertex);
173                 o.worldNormal = UnityObjectToWorldNormal(v.normal);
174                 return o;
175             }
176 
177             fixed4 frag(v2f i) : SV_TARGET
178             {
179                 fixed4 albedo = tex2D(_MainTex, i.uv) * _Color;
180                 clip(_Cutoff - albedo.a);
181 
182                 fixed3 ambient = albedo.rgb * UNITY_LIGHTMODEL_AMBIENT.rgb;
183 
184                 fixed3 worldLight = normalize(UnityWorldSpaceLightDir(i.worldPos));
185                 float d = dot(worldLight, i.worldNormal) * 0.5 + 0.5;
186                 fixed3 rampCol = tex2D(_Ramp, float2(d, d)).rgb;
187                 fixed3 diffuse = albedo.rgb * _LightColor0.rgb * rampCol;
188                 
189                 fixed4 col = fixed4(ambient + diffuse * _DiffuseRate, albedo.a);
190                 col.rgb = Overlay(col, _OverlyingColor);
191 
192                 return col;
193             }
194 
195             ENDCG
196         }
197         
198         
199     } 
200 
201     Fallback "Diffuse"
202 }

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

posted @ 2020-04-02 18:01  孤独の巡礼  阅读(2673)  评论(0编辑  收藏  举报