Hi guys, another question: I turned the fallback off, knowing i probably wouldn’t need it, and… my shadows vanished. oddly, turning it back on brings back the shadows! Anyone know what’s going on? My shader is a surface shader
Can’t quite remember off the top of my head but I think you need either Fallback Diffuse or VertexLit as a minimum to include the shadow collector/caster passes…
Really? Had no idea. Also surprised the VertexLit shader does it too.
Diffuse contains the FallBack of VertexLit.
The point being that the VertexLit shader contains the shadow caster and receiver passes. Without those, the shader can’t cast it receive shadows.
So you can copy/paste those in to your shader or just add in FallBack VertexLit…
I also found you can add a separate subshader with a shadow caster pass in it. not sure if shadow collector is needed though…
You need it for the mesh to receive shadows.
Very interested to see how you did that. Having to fallback on “Diffuse” for shadows makes me feel bad…really would like to know how to hook/write the passes which are needed for shadow caster/receiver.
You can open up the shader source for the VertexLit shader and just rip them out.
Shadows require a shader to have special passes to do shadow rendering (ShadowCaster & ShadowCollector; starting with 5.0 only ShadowCaster). By default they are not generated, and fetched from a fallback instead (since for most of shaders they would be exactly the same anyway).
If you don’t want a fallback, you can tell surface shader to generate the shadow passes for you, append a " addshadow" to the #pragma surface line. Unity - Manual: Writing Surface Shaders
@Aras : Really? Had no idea! Does it work with transparent cutout shaders too?
@Aras when does 5.0 come out
if i may piggyback on this thread
as you can see in the attached picture i’m using custom lightingModel to achieve a nice crisp cell shaded look. unfortunately tho, since i don’t all “dark side” from .5 onward, the artifacts are clearly visible.
now i’ve taken the shadowing passes of the vertexLit and put them into a single separate shadow to be used as fallback across the different iterations of the cell shader.
thing is… i think i should look inside the UnityCG.cginc file and futz around with some methods in there to get this to play together nicely… but i’m totally lost in there, could anybody with experience on the matter give me some pointers?
in case you’re interested this is the shader version you see in the image:
Shader "Graph/Cell"
{
Properties
{
_Color ("FilterColor", Color) = (1, 1, 1, 1)
_MainTex ("Albedo", 2D) = "white" {}
_Steps ("Steps", Color) = (0.95, 0.35, 0.05, 0)
}
SubShader
{
Tags
{
"Queue" = "Geometry"
"RenderType" = "Opaque"
}
LOD 150
CGPROGRAM
#pragma surface surf Cell nolightmap nodirlightmap halfasview
#pragma target 2.0
fixed4 _Color;
sampler2D _MainTex;
fixed4 _Steps;
half4 LightingCell (SurfaceOutput s, half3 lightDir, half atten)
{
#ifndef USING_DIRECTIONAL_LIGHT
lightDir = normalize(lightDir);
#endif
half diff = ((dot(s.Normal, lightDir)) * 0.5 + 0.5) * atten;
half4 c;
c.a = s.Alpha;
if (diff > _Steps.r)
c.rgb = s.Albedo * _LightColor0.rgb * (atten*2) * 1;
else if (diff > _Steps.g)
c.rgb = s.Albedo * _LightColor0.rgb * (atten*2) * 0.7;
else
c.rgb = s.Albedo * _LightColor0.rgb * (atten*2) * 0.25;
return c;
}
struct Input
{
float2 uv_MainTex : TEXCOORD0;
float3 viewDir;
};
void surf (Input IN, inout SurfaceOutput o)
{
o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb * (_Color.rgb+_Color.rgb);
}
ENDCG
}
FallBack "Graph/Shadow"
}
and for convenience’s sake the shadow shader:
Shader "Graph/Shadow"
{
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 80
// Pass to render object as a shadow caster
Pass
{
Name "ShadowCaster"
Tags { "LightMode" = "ShadowCaster" }
Fog {Mode Off}
ZWrite On ZTest LEqual Cull Off
Offset 1, 1
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#include "UnityCG.cginc"
struct v2f
{
V2F_SHADOW_CASTER;
};
v2f vert( appdata_base v )
{
v2f o;
TRANSFER_SHADOW_CASTER(o)
return o;
}
float4 frag( v2f i ) : SV_Target
{
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}
// Pass to render object as a shadow collector
// note: editor needs this pass as it has a collector pass.
Pass
{
Name "ShadowCollector"
Tags { "LightMode" = "ShadowCollector" }
Fog {Mode Off}
ZWrite On ZTest LEqual
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcollector
#define SHADOW_COLLECTOR_PASS
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
};
struct v2f
{
V2F_SHADOW_COLLECTOR;
};
v2f vert (appdata v)
{
v2f o;
TRANSFER_SHADOW_COLLECTOR(o)
return o;
}
fixed4 frag (v2f i) : SV_Target
{
SHADOW_COLLECTOR_FRAGMENT(i)
}
ENDCG
}
}
}
I definitely approve the toon lighting sir! I also noticed that you are using Atten*2 in all the albedo settings. try only using it on dark areas, and see what happens!
BTW, is shadow casting really that easy? Just kidding, I already sort of knew how to do that. Anyway, stuff that, I will fix it up for ya!
EDIT: Progress so far… well, the nice banding your shader has isn’t showing. how to set the colour? BTW, shadow attenuation is going well!
EDIT2: Ok, got it working. the challenge here? removing the horrid shadow attenuation…
Here you go man, how does this look:
Here’s the code BTW. give this a go in your scene!
Shader "Graph/Cell_ShadowAttenFix"
{
Properties
{
_Color ("FilterColor", Color) = (1, 1, 1, 1)
_MainTex ("Albedo", 2D) = "white" {}
_Steps ("Steps", Color) = (0.95, 0.35, 0.05, 0)
}
SubShader
{
Tags
{
"Queue" = "Geometry"
"RenderType" = "Opaque"
}
LOD 150
CGPROGRAM
#pragma surface surf Cell nolightmap nodirlightmap halfasview fullforwardshadows
#pragma target 2.0
fixed4 _Color;
sampler2D _MainTex;
fixed4 _Steps;
half4 LightingCell (SurfaceOutput s, half3 lightDir, half atten)
{
#ifndef USING_DIRECTIONAL_LIGHT
lightDir = normalize(lightDir);
#endif
half diff = ((dot(s.Normal, lightDir)) * 0.5 + 0.5);
half4 c;
c.a = s.Alpha;
if (diff > _Steps.r && atten < _Steps.r)
c.rgb = s.Albedo * _LightColor0.rgb + (s.Albedo * atten * 0.5);//
else if (diff > _Steps.r)
c.rgb = s.Albedo * _LightColor0.rgb * 2;//
else if (diff > _Steps.g && atten < _Steps.g-0.4)
c.rgb = s.Albedo * _LightColor0.rgb + (atten*0.5);
else if (diff > _Steps.g)
c.rgb = s.Albedo * _LightColor0.rgb * 1;
else
c.rgb = s.Albedo * _LightColor0.rgb * 0.5;
return c;
}
struct Input
{
float2 uv_MainTex : TEXCOORD0;
float3 viewDir;
};
void surf (Input IN, inout SurfaceOutput o)
{
o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb * (_Color.rgb+_Color.rgb);
}
ENDCG
}
FallBack "Diffuse"
}
BTW, I added fullforwardshadows in case you wanted to use this with Unity Pro point light shadows. The secret is (And Aras mentioned this on another thread, I am sure… ) you can use this to enable forward rendering point shadows.
EDIT: Also note I used the default diffuse as a fallback, feel free to include yours instead, it shouldn’t break the shader. I also aim to produce a version that has darker shadows which will help match the darker areas.
EDIT2: fixed a shadow attenuation bug with low-res shadows.
Here’s another screen:
Also updated code, look above. it fixes the white outlines seen on low-res shadows. (again… )
FINAL UPDATE: Fixed weird shadow outlines completely. shadows now fade quite smoothly! Code in above post.
very nice, thx a lot; this actually gave me a pretty good, new idea:
here it is:
Shader "Graph/Cell"
{
Properties
{
_Color ("FilterColor", Color) = (0.5, 0.5, 0.5, 1)
_MainTex ("Albedo", 2D) = "white" {}
_Blend ("Blend", float) = 0.04
_Steps ("Steps", Color) = (0.86, 0.61, 0)
_Shades ("Shades", Color) = (1, 0.59, 0)
}
SubShader
{
Tags
{
"Queue" = "Geometry"
"RenderType" = "Opaque"
}
LOD 200
CGPROGRAM
#pragma surface surf Cell nolightmap
#pragma target 2.0
#include "methods.cginc"
fixed4 _Color;
sampler2D _MainTex;
float _Blend = 0.03;
fixed3 _Steps;
fixed3 _Shades;
float CellShadeSmooth (half diff, float layerBleed, int numSteps, fixed3 steps, fixed3 shades)
{
float intensity = 0.0;
if(numSteps == 3)
{
intensity += smoothstep(_Steps.g, _Steps.g + layerBleed, diff) * _Shades.g;
intensity += smoothstep(_Steps.r, _Steps.r + layerBleed, diff) * (_Shades.r - _Shades.g);
}
else if(numSteps == 4)
{
intensity += smoothstep(_Steps.b, _Steps.b + layerBleed, diff) * _Shades.b;
intensity += smoothstep(_Steps.g, _Steps.g + layerBleed, diff) * (_Shades.g - _Shades.b);
intensity += smoothstep(_Steps.r, _Steps.r + layerBleed, diff) * (_Shades.r - _Shades.g);
}
else if(numSteps == 2)
{
intensity += smoothstep(_Steps.r, _Steps.r + layerBleed, diff) * _Shades.r;
}
return intensity;
}
half4 LightingCell (SurfaceOutput s, half3 lightDir, half atten)
{
#ifndef USING_DIRECTIONAL_LIGHT
lightDir = normalize(lightDir);
#endif
half diff = ((dot(s.Normal, lightDir)) * 0.5 + 0.5) * atten;
half4 c;
c.a = s.Alpha;
float intensity = CellShadeSmooth(diff, _Blend, 3, _Steps, _Shades);
c.rgb = s.Albedo * _LightColor0.rgb * (atten*2) * intensity;
return c;
}
struct Input
{
float2 uv_MainTex : TEXCOORD0;
};
void surf (Input IN, inout SurfaceOutput o)
{
o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb * (_Color.rgb + _Color.rgb);
}
ENDCG
}
FallBack "Diffuse"
}
THAT. IS AWESOME.
I actually see how you did it with smoothstep! well done!
thx; i think i might release this as a free asset to the store “Chibi Shader”, just don’t know what kind of character i should make to show off the various shading “styles” we need some cloth, some skin, hair… but maybe some metal aswell
here’s the latest iteration; i’ve removed the rim shading since the the outlining is quite a nice delimiter and would fight the rimming effect visually
for the detail map supply a mainly white, tiling paper texture to give the shading a little more structure and make it look more “drawn”
Shader "Graph/Cell"
{
Properties
{
_Color ("FilterColor", Color) = (1, 1, 1, 1)
_MainTex ("Albedo", 2D) = "white" {}
_Blend ("Blend", Range(0, 0.1)) = 0.1
_Blend2 ("Blend2", Range(0, 0.4)) = 0.5
_ShadeRangePower ("Range [XY] Power [ZW]", Color) = (0.9, 0.4, 1, 0.5)
_Detail ("Paper Weight", 2D) = "white" {}
_OutlineColor ("Outline Color", Color) = (0.117, 0.117, 0.117, 1)
}
SubShader
{
Tags
{
"Queue" = "Geometry"
"RenderType" = "Opaque"
}
UsePass "Graph/Outline/OUTLINE"
LOD 200
CGPROGRAM
#pragma surface surf Cell nolightmap
#pragma target 2.0
fixed4 _Color;
sampler2D _MainTex;
sampler2D _Detail;
fixed _Blend;
fixed _Blend2;
fixed4 _ShadeRangePower;
half4 LightingCell (SurfaceOutput s, half3 lightDir, half atten)
{
#ifndef USING_DIRECTIONAL_LIGHT
lightDir = normalize(lightDir);
#endif
half diff = (dot(s.Normal, lightDir) * 0.5 + 0.5) * atten;
fixed toonIntensity = 0;
toonIntensity += smoothstep(_ShadeRangePower.y, _ShadeRangePower.y + _Blend2, diff) * _ShadeRangePower.w;
toonIntensity += smoothstep(_ShadeRangePower.x, _ShadeRangePower.x + _Blend, diff) * (_ShadeRangePower.z - _ShadeRangePower.w);
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * (atten*2) * toonIntensity ;
c.a = s.Alpha;
return c;
}
struct Input
{
float2 uv_MainTex : TEXCOORD0;
fixed4 color: Color; // vert color
fixed4 screenPos;
};
void surf (Input IN, inout SurfaceOutput o)
{
fixed2 screenUV = IN.screenPos.xy / IN.screenPos.w;
screenUV *= fixed2(8,6);
o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;
o.Albedo *= IN.color.rgb * _Color.rgb;
o.Albedo *= tex2D (_Detail, screenUV).rgb;
}
ENDCG
}
//FallBack "Graph/Shadow"
FallBack "VertexLit"
}
@FuzzyQuills , you know your way around shaders well i take? (assuming that based on the indie effects)
What would be a nice cheap way to add specular only on/in the topmost additive toonShade? can i pass data from the lightingmodel to the surface? I really would like to not have to convert this to a vert/pixel shader
and here’s the outline… it’s a slight modification of the standard one but i’m gonna add some PS alphaTest masking to it later so we can have that nice rough inked quickly drawn stlye
Shader "Graph/Outline"
{
Properties
{
_OutlineColor ("Outline Color", Color) = (0.117, 0.117, 0.117, 1)
//_Outline ("Outline width", Range (.002, 0.03)) = .002
}
CGINCLUDE
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : POSITION;
float4 color : COLOR;
};
//static uniform float _Outline = .002;
static uniform float _Outline = .003;
uniform float4 _OutlineColor;
v2f vert(appdata v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
float3 norm = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal);
float2 offset = TransformViewToProjection(norm.xy);
float distance = min(length(mul(v.vertex, _Object2World) - _WorldSpaceCameraPos.xyz), 1.25);
o.pos.xy += (offset* distance) * o.pos.z * (_Outline );
o.color = _OutlineColor;
return o;
}
ENDCG
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
Name "OUTLINE"
Tags { "LightMode" = "Always" }
Cull Front
ZWrite On
ColorMask RGB
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
half4 frag(v2f i) :COLOR { return i.color; }
ENDCG
}
}
}
and heres the one with the alphaTested outlines:
Shader "Graph/Outline"
{
Properties
{
_OutlineColor ("Outline Color", Color) = (0.117, 0.117, 0.117, 1)
//_Outline ("Outline width", Range (.002, 0.03)) = .002
_OutlineMask ("Paper Weight", 2D) = "white" {}
}
CGINCLUDE
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 uv_MainTex : TEXCOORD0;
};
struct v2f
{
float4 pos : POSITION;
float4 color : COLOR;
float2 uv_MainTex : TEXCOORD0;
};
//static uniform float _Outline = .002;
static uniform float _Outline = .003;
uniform float4 _OutlineColor;
sampler2D _OutlineMask;
v2f vert(appdata v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
float3 norm = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal);
float2 offset = TransformViewToProjection(norm.xy);
float distance = min(length(mul(v.vertex, _Object2World) - _WorldSpaceCameraPos.xyz), 1.5);
o.pos.xy += (offset* distance) * o.pos.z * (_Outline );
o.color = _OutlineColor;
o.uv_MainTex = v.uv_MainTex;
return o;
}
ENDCG
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
Name "OUTLINE"
Tags { "LightMode" = "Always" }
Cull Front
ZWrite On
ColorMask RGB
//Blend SrcAlpha OneMinusSrcAlpha
AlphaTest Greater 0.5
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
half4 frag(v2f i) : COLOR
{
// add some PS alphaTest masking to it
// so we can have that nice rough inked quickly drawn style
half4 c = i.color;
c.a = tex2D(_OutlineMask, i.uv_MainTex).r;
return c;
}
ENDCG
}
}
}
just make sure to add the _OutlineMask (“Outline Mask”, 2D) = “white” {} property to the cell shader’s properties and note that all red lt .5 are used to cut away at the outline
@Graph : Yes, I do know my way around most shaders, in fact, I have found myself able to port HLSL and GLSL too. (But then again, that’s becuase companies and organizations are always stealing ideas… ;))
And I take it you only want the spec in the brightest shade. just calculate a specular color like… perhaps the example in the manual? Anyway, do that, but only do it in the section where you calculate the brightest shading. The example in the manual does it in the lighting model, BTW, so there’s another of your questions answered! (No need for an extra VF shader!)
You could also do something similar to the toon shading model in blender, it has a solid toon highlight over everything. I haven’t had the chance to test your outlines yet, but interesting ideas! Who’s up for SSB for 3DS-style outlines people? (I AM!!!)