- Home /
Cutout toon shader
Hi, I made a cutout toon/outline shader. It works fine, but there are some artifacts that cant get rid of. Am I doing something wrong or is this a natural side effect of this kind of tooning?
SubShader {
Tags { "ForceNoShadowCasting"="True" "Queue"="AlphaTest" "RenderType"="TransparentCutout" }
Pass {
Cull Front
ZWrite On
Tags { "LightMode" = "Always" }
CGPROGRAM
#pragma exclude_renderers gles flash d3d11 xbox360
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
struct tv2f {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
float4 color : COLOR;
float4 vpos : TEXCOORD1;
float2 texcoord : TEXCOORD0;
};
uniform float _Outline;
uniform float4 _OutlineColor;
uniform sampler2D _MainTex;
uniform float _Cutout;
tv2f vert(a2v v) {
tv2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.vpos = v.vertex;
float3 norm = mul ((float3x3)UNITY_MATRIX_MV, v.normal);
float2 offset = TransformViewToProjection(norm.xy);
o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
o.pos.xy += offset * o.pos.z * _Outline;
o.color = _OutlineColor;
return o;
}
float4 frag(tv2f i) : COLOR {
clip(tex2D(_MainTex, i.texcoord).a - _Cutout);
return i.color;
}
ENDCG
}
Pass {
Cull Back
ZWrite On
Tags { "LightMode" = "Always" }
CGPROGRAM
#pragma exclude_renderers gles flash d3d11 xbox360
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
uniform float _Outline;
uniform float4 _OutlineColor;
uniform float4 _Color;
uniform sampler2D _MainTex;
uniform samplerCUBE _ToonShade;
uniform float _Cutout;
struct tv2f {
float4 pos : POSITION;
float2 texcoord : TEXCOORD0;
float3 cubenormal : TEXCOORD1;
float4 vpos : TEXCOORD2;
};
tv2f vert(a2v v) {
tv2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.vpos = v.vertex;
o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
o.cubenormal = mul (UNITY_MATRIX_MV, float4(v.normal,0));
return o;
}
float4 frag(tv2f i) : COLOR {
clip(tex2D(_MainTex, i.texcoord).a - _Cutout);
float4 col = _Color * tex2D(_MainTex, i.texcoord);
float4 cube = texCUBE(_ToonShade, i.cubenormal);
return float4(2.0f * cube.rgb * col.rgb, col.a);
}
ENDCG
}
}
Show a screenshot of the artefacts you're getting. Artefacts can be one of a huge number of things, so more specifics would be good.
The problem lies in the fact that it extrudes along the normal. Replacing the normal with a custom value might work.
Answer by CHPedersen · Sep 30, 2013 at 12:15 PM
This problem is common: It occurs in all outline shaders that extrude along the normal, as Kajos said in a comment. It happens on parts of the model where vertices are doubled to produce crease (hard) edges.
I made a small example to illustrate precisely what's going on. Compare this sphere to the cube:
Both are shaded with the standard outline toon shader you can get from Assets->Import Package. You'll notice that the sphere is fine, but the cube clearly suffers the same artifact your buildings also experience. That's because the sphere is entirely smooth - it has no hard edges, so no two vertices share a position in order to have different normals in the same location. The box doesn't have this luxury. It has 3 vertices in each corner, because each corner connects to three faces, and each face must have its own normal, or else, the box won't have hard edges. But when outline shaded in this simple way, the vertex extrusion along the normal vector splits the model apart - each face that the model is actually composed of gets pushes away from the others, and then those gaps appear.
If you wish to fix it, you have to either make sure your model doesn't have any hard edges (impractical) or you have to come up with a different way to create outlines than the one the standard Toon shader uses.
One way is to do screen space silhouette detection as an image effect. Another is to keep extruding vertices, but choose some other direction than the normal vector, e.g. vector to the object's center, for example. Doing so would fix the problem for the box while also working for the sphere, but requires the mesh to be a convex hull, which complex geometry almost never is. Your buildings most certainly aren't.
I ended up using the following:
float2 xz = normalize(v.vertex.xz);
float3 norm = mul ((float3x3)UNITY_$$anonymous$$ATRIX_$$anonymous$$V, float3(xz.x, 1, xz.y));
It doesn't give an outline at the bottom, but it works fine for most models, as they're most likely centered along 0.
I just want to say that I love this $$anonymous$$ajos guy,nohomo.
Your answer
Follow this Question
Related Questions
Silhouette Toon Shader 0 Answers
Toon shader shows outlines in editor, but not in game views 1 Answer
how i can make toon shader like that 2 Answers
Toon Lit Outline Outline Transparent on Air 0 Answers
Reflective toon (outline+ramp) shader 3 Answers