Cutout with Soft Edge / Cutout Bumped Specular

On http://wiki.unity3d.com/index.php/Transparent_Cutout_Soft_Edge_Unlit_Texture_Blend
I found solution that resolve problem with Soft Edge using two pass, and resolve many problems with render type,
and receive light.

So i srtart working on my Shader: Cutout Bumped Specular

Shader "TEST/Cutout Bumped Specular"
{
Properties {
	_Color ("Main Color", Color) = (1,1,1,1)
	_SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 0)
	_Shininess ("Shininess", Range (0.01, 1)) = 0.078125
	_MainTex ("Base (RGB) TransGloss (A)", 2D) = "white" {}
	_BumpMap ("Normalmap", 2D) = "bump" {}
	_SpecMap ("Specmap", 2D) = "white" {}
	_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
}

SubShader {
	Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
	LOD 400
	
CGPROGRAM
// Upgrade NOTE: excluded shader from OpenGL ES 2.0 because it does not contain a surface program or both vertex and fragment programs.
#pragma exclude_renderers gles
#pragma surface surf BlinnPhong2 alphatest:_Cutoff
#pragma exclude_renderers flash

sampler2D _MainTex;
sampler2D _BumpMap;
sampler2D _SpecMap;
fixed4 _Color;
half _Shininess;

struct SurfaceOutput2 {
	fixed3 Albedo;
	fixed3 Normal;
	fixed3 Emission;
	half Specular;
	half3 GlossColor;
	fixed Gloss;
	fixed Alpha;
};


// NOTE: some intricacy in shader compiler on some GLES2.0 platforms (iOS) needs 'viewDir'  'h'
// to be mediump instead of lowp, otherwise specular highlight becomes too bright.
inline fixed4 LightingBlinnPhong2 (SurfaceOutput2 s, fixed3 lightDir, half3 viewDir, fixed atten)
{
	half3 h = normalize (lightDir + viewDir);
	
	fixed diff = max (0, dot (s.Normal, lightDir));
	
	float nh = max (0, dot (s.Normal, h));
	float spec = pow (nh, s.Specular*256.0) * s.GlossColor;
	
	fixed4 c;
	c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * s.Gloss * spec) * (atten * 2);
	c.a = s.Alpha + _LightColor0.a * _SpecColor.a * spec * atten;
	return c;
}

inline fixed4 LightingBlinnPhong2_PrePass (SurfaceOutput2 s, half4 light)
{
	fixed spec = light.a * s.Gloss;
	fixed4 c;
	c.rgb = (s.Albedo * light.rgb + light.rgb * s.GlossColor * _SpecColor.rgb * spec);
	c.a = s.Alpha + spec * _SpecColor.a;
	return c;
}


struct Input {
	float2 uv_MainTex;
	float2 uv_BumpMap;
};

void surf (Input IN, inout SurfaceOutput2 o) {
	fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);
	fixed4 spec = tex2D(_SpecMap, IN.uv_MainTex);
	o.Albedo = tex.rgb * _Color.rgb;
	o.Gloss = tex.a;
	o.GlossColor = spec.rgb;
	o.Alpha = tex.a * _Color.a;
	o.Specular = _Shininess;
	o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
}
ENDCG
}

FallBack "Transparent/Cutout/VertexLit"
}

But the main problem i can’t add second pass like in http://wiki.unity3d.com/index.php/Transparent_Cutout_Soft_Edge_Unlit_Texture_Blend for Soft Edge, because i can’t split proper clip.

So how i can do that?
Thank you for your help.

Have you solved this? It would help me with my hair modelling endeavour :-p

This is what I use for my hair;

Shader "Exploration/Hair Soft Edge Surface" {
	Properties {
		_Color ("Main Color", Color) = (1,1,1,1)
		_MainTex ("Diffuse (RGB) Alpha (A)", 2D) = "gray" {}
		_SpecularTex ("Specular (R) Gloss (G) Null (B)", 2D) = "gray" {}
		_BumpMap ("Normal (Normal)", 2D) = "bump" {}
		_AnisoDirection ("Anisotropic Direction (RGB) Anisotropic Mask (A)", 2D) = "bump" {}
		_AnisoOffset ("Anisotropic Highlight Offset", Range(-0.5,0.5)) = -0.2
		_Cutoff ("Alpha Cut-Off Threshold", Range(0,1)) = 0.5
		_Fresnel ("Fresnel Value", Float) = 0.028
	}

	SubShader {
		Tags { "RenderType" = "TransparentCutout" }

		CGPROGRAM
			#pragma surface surf ExplorationSoftHair fullforwardshadows exclude_path:prepass nolightmap nodirlightmap
			#pragma target 3.0

			struct SurfaceOutputHair {
				fixed3 Albedo;
				fixed Alpha;
				fixed3 AnisoDir;
				fixed3 Normal;
				fixed2 Specular;
				fixed3 Emission;
			};

			struct Input
			{
				float2 uv_MainTex;
			};
			
			sampler2D _MainTex, _SpecularTex, _BumpMap, _AnisoDirection;
			float _Cutoff, _AnisoOffset, _Fresnel;
				
			void surf (Input IN, inout SurfaceOutputHair o)
			{
				float4 albedo = tex2D(_MainTex, IN.uv_MainTex);
				clip(albedo.a - _Cutoff);
				
				o.Albedo = albedo.rgb;
				o.Alpha = albedo.a;
				o.AnisoDir = tex2D(_AnisoDirection, IN.uv_MainTex).rgb * 2 - 1;
				o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex));
				o.Specular = tex2D(_SpecularTex, IN.uv_MainTex).rg;
				
				// Stop DX11 complaining.
				o.Emission = fixed3(0.0,0.0,0.0);
			}

			inline fixed4 LightingExplorationSoftHair (SurfaceOutputHair s, fixed3 lightDir, fixed3 viewDir, fixed atten)
			{
				viewDir = normalize(viewDir);
				lightDir = normalize(lightDir);
				s.Normal = normalize(s.Normal);
				float NdotL = dot(s.Normal, lightDir);
				float3 h = normalize(lightDir + viewDir);
				float VdotH = dot( viewDir, h );

				float fresnel = pow( 1.0 - VdotH, 5.0 );
				fresnel += _Fresnel * ( 1.0 - fresnel );
				float aniso = max(0, sin(radians( (dot(normalize(s.Normal + s.AnisoDir), h) + _AnisoOffset) * 180 ) ));
				float spec = pow( aniso, s.Specular.g * 128 ) * s.Specular.r * fresnel;
				
				fixed4 c;
				c.rgb = (s.Albedo * saturate(NdotL) * atten * _LightColor0.rgb + (spec * atten * _LightColor0.rgb) ) * 2;
				c.a = s.Alpha;
				
				return c;
			}
		ENDCG

		ZWrite Off

		CGPROGRAM
			#pragma surface surf ExplorationSoftHair fullforwardshadows exclude_path:prepass nolightmap nodirlightmap decal:blend
			#pragma target 3.0

			struct SurfaceOutputHair {
				fixed3 Albedo;
				fixed Alpha;
				fixed3 AnisoDir;
				fixed3 Normal;
				fixed2 Specular;
				fixed3 Emission;
			};

			struct Input
			{
				float2 uv_MainTex;
			};
			
			sampler2D _MainTex, _SpecularTex, _BumpMap, _AnisoDirection;
			float _Cutoff, _AnisoOffset, _Fresnel;
				
			void surf (Input IN, inout SurfaceOutputHair o)
			{
				float4 albedo = tex2D(_MainTex, IN.uv_MainTex);
				clip(-(albedo.a - _Cutoff));
				
				o.Albedo = albedo.rgb;
				o.Alpha = albedo.a;
				o.AnisoDir = tex2D(_AnisoDirection, IN.uv_MainTex).rgb * 2 - 1;
				o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex));
				o.Specular = tex2D(_SpecularTex, IN.uv_MainTex).rg;
				
				// Stop DX11 complaining.
				o.Emission = fixed3(0.0,0.0,0.0);
			}

			inline fixed4 LightingExplorationSoftHair (SurfaceOutputHair s, fixed3 lightDir, fixed3 viewDir, fixed atten)
			{
				viewDir = normalize(viewDir);
				lightDir = normalize(lightDir);
				s.Normal = normalize(s.Normal);
				float NdotL = dot(s.Normal, lightDir);
				float3 h = normalize(lightDir + viewDir);
				float VdotH = dot( viewDir, h );

				float fresnel = pow( 1.0 - VdotH, 5.0 );
				fresnel += _Fresnel * ( 1.0 - fresnel );
				float aniso = max(0, sin(radians( (dot(normalize(s.Normal + s.AnisoDir), h) + _AnisoOffset) * 180 ) ));
				float spec = pow( aniso, s.Specular.g * 128 ) * s.Specular.r * fresnel;
				
				fixed4 c;
				c.rgb = (s.Albedo * saturate(NdotL) * atten * _LightColor0.rgb + (spec * atten * _LightColor0.rgb) ) * 2;
				c.a = s.Alpha;
				
				return c;
			}
		ENDCG
	}
	FallBack "Transparent/Cutout/VertexLit"
}

It’s expensive, though. I’m not sure I’d recommend using it in a real game.

I worked up a cheaper version of it here, but the quality isn’t quite as good.

Shader "Exploration/Hair Soft Edge Surface ZPrimed" {
	Properties {
		_Color ("Main Color", Color) = (1,1,1,1)
		_MainTex ("Diffuse (RGB) Alpha (A)", 2D) = "gray" {}
		_SpecularTex ("Specular (R) Gloss (G) Null (B)", 2D) = "gray" {}
		_BumpMap ("Normal (Normal)", 2D) = "bump" {}
		_AnisoDirection ("Anisotropic Direction (RGB) Anisotropic Mask (A)", 2D) = "bump" {}
		_AnisoOffset ("Anisotropic Highlight Offset", Range(-0.5,0.5)) = -0.2
		_Cutoff ("Alpha Cut-Off Threshold", Range(0,1)) = 0.5
		_Fresnel ("Fresnel Value", Float) = 0.028
	}

	SubShader {
		Tags { "RenderType" = "Opaque" "Queue" = "Geometry"}

		Pass {
			Name "Depth"
			Tags {"LightMode" = "Always"}
			ColorMask 0

			CGPROGRAM
				#pragma vertex vert
				#pragma fragment frag
				#pragma fragmentoption ARB_precision_hint_fastest

				#include "UnityCG.cginc"

				struct appdata {
				    float4 vertex : POSITION;
				    float4 texcoord : TEXCOORD0;
				};

				struct v2f
				{
					float4	pos : SV_POSITION;
					float2	uv : TEXCOORD0;
				}; 

				float4 _MainTex_ST;

				v2f vert (appdata v)
				{
					v2f o;
					o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
					o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
					return o;
				}

				sampler2D _MainTex;
				float _Cutoff;

				fixed4 frag(v2f IN) : COLOR
				{
					fixed alpha = tex2D(_MainTex, IN.uv).a;
					clip(alpha - _Cutoff);
					return fixed4(0.0,0.0,0.0,0.0);
				}
			ENDCG
		}

		ZWrite Off

		Blend SrcAlpha OneMinusSrcAlpha

		CGPROGRAM
			#pragma surface surf ExplorationSoftHair fullforwardshadows exclude_path:prepass nolightmap nodirlightmap
			#pragma target 3.0

			struct SurfaceOutputHair {
				fixed3 Albedo;
				fixed Alpha;
				fixed3 AnisoDir;
				fixed3 Normal;
				fixed2 Specular;
				fixed3 Emission;
			};

			struct Input
			{
				float2 uv_MainTex;
			};
			
			sampler2D _MainTex, _SpecularTex, _BumpMap, _AnisoDirection;
			float _Cutoff, _AnisoOffset, _Fresnel;
				
			void surf (Input IN, inout SurfaceOutputHair o)
			{
				float4 albedo = tex2D(_MainTex, IN.uv_MainTex);
				o.Albedo = albedo.rgb;
				o.Alpha = albedo.a;
				o.AnisoDir = tex2D(_AnisoDirection, IN.uv_MainTex).rgb * 2 - 1;
				o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex));
				o.Specular = tex2D(_SpecularTex, IN.uv_MainTex).rg;
				
				// Stop DX11 complaining.
				o.Emission = fixed3(0.0,0.0,0.0);
			}

			inline fixed4 LightingExplorationSoftHair (SurfaceOutputHair s, fixed3 lightDir, fixed3 viewDir, fixed atten)
			{
				viewDir = normalize(viewDir);
				lightDir = normalize(lightDir);
				s.Normal = normalize(s.Normal);
				float NdotL = dot(s.Normal, lightDir);
				float3 h = normalize(lightDir + viewDir);
				float VdotH = dot( viewDir, h );

				float fresnel = pow( 1.0 - VdotH, 5.0 );
				fresnel += _Fresnel * ( 1.0 - fresnel );
				float aniso = max(0, sin(radians( (dot(normalize(s.Normal + s.AnisoDir), h) + _AnisoOffset) * 180 ) ));
				
				float spec = pow( aniso, s.Specular.g * 128 ) * s.Specular.r * fresnel;

				#if !defined(UNITY_PASS_FORWARDBASE)
					// Make the resulting value black where the alpha is.
					// Otherwise it blends through on transparent parts.
					// Not required for forward base - only forwardadd.
					atten *= s.Alpha;
				#endif
				
				fixed4 c;
				c.rgb = ( ((s.Albedo * _LightColor0.rgb) * (saturate(NdotL) * atten)) + ((spec * atten) * _LightColor0.rgb) ) * 2;
				c.a = s.Alpha;
				
				return c;
			}
		ENDCG
	}
	FallBack "Transparent/Cutout/VertexLit"
}

Supports anisotropic highlights using a flow map, normal, specular, gloss and fresnel falloff.

8 Likes

Whoa nice!!! I’ll try it out right now!

Just dropping by to thank farfarer for sharing that shader. I’m using it for something completely unrelated, I needed smooth transparency that received shadows :slight_smile:

@Farfarer

Thank you SO MUCH for these shaders. They work a treat. I have been looking for a long time for a shader which allows transparent objects to receive shadows, but this is so much better than what I was hoping to get. Shadows, Fesnel… amazing! Thank you, thank you, thank you!

1 Like

Hey!How did you do to allow transparent objects to recieve shadow with @Farfarer shaders?

Try This

8422068–1114380–CutoutShadow.shader (3.12 KB)

1 Like