- Home /
How to Get Nice Thick Toon-Like Outlines On Non-Smooth Geometry?
I've been searching all over trying to find a good solution for this. Been through piles and piles of forum threads, answers on this site, and random blog posts. I've tried many free and non-free assets to no avail.
I want to have nice thick toon-style outlines on all the objects in my game.
I've tried tons of toon shaders but all of them that I can find suffer from the same problems. All your geometry has to be smooth in order for the extruded normals method (which almost all toon shaders use) to work correctly. Unfortunately that is not an option for my current project. Most of my geometry is sharp and I need it that way.
I've also been trying edge detection post effects, with limited success. The edge detection script included in the standard assets doesn't seem to want to do what I need. I've tried tons of different variations but I can't seem to get anything that looks good. If you try thick lines with that you get various other undesirable artifacts. If you tone it down to where the artifacts are less pronounced you can barely see the outlines. I've tried all the different modes offered by the script, but none of them seem to offer any real solution.
I even came across this at some point. However I'm not very sure on how to implement that, and it also might not be performant enough to work on every object in the game at the same time, which is what I need for my project.
I also read about using geometry shaders to do it, but from what I understand that can't be done in Unity currently because Unity does not provide adjacency information to shaders.
There is also plenty of theory posts out there in various places, that discuss how you might do it, but I really need more of a hands-on approach. Like, with code examples and such.
As I said, I've been through tons of searching and not found anything that solves my problem. Most of the stuff I can find is older posts which might be outdated by now. So, I figured I'd ask now to see if there is any new options in this area. Or perhaps there is a way to get one of the other options working and I just haven't seen it.
Sorry if this has been addressed somewhere before and I just missed it...
Answer by Namey5 · May 09, 2017 at 07:41 AM
This is a custom shader I wrote a while back that I generally use instead for this reason;
Shader "Custom/CustomOutline" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_Outline ("Outline Color", Color) = (0,0,0,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
_Size ("Outline Thickness", Float) = 1.5
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
Pass {
Cull Front
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
half _Size;
fixed4 _Outline;
struct v2f {
float4 pos : SV_POSITION;
};
v2f vert (appdata_base v) {
v2f o;
v.vertex.xyz *= _Size;
v.normal *= -1;
o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
return o;
}
half4 frag (v2f i) : SV_Target
{
return _Outline;
}
ENDCG
}
Cull Back
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
void surf (Input IN, inout SurfaceOutputStandard o) {
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
Rather than extrude along the normal, I figured it was a better idea to extrude based upon the vector from the origin towards the vertex position. An easy way of doing this is to simply multiply the local vertex position.
This will only work for some objects, however. If you want the distortion to be distributed equally for unsymmetrical objects, you can replace the displacement line with this;
v.vertex.xyz += normalize (v.vertex.xyz) * _Size;
I'm currently working on a proper post processing outline effect that doesn't rely on object normals and the such (similar to that used in things like Deus Ex), but it's a bit power intensive at the moment.
Thanks for the try, however it doesn't seem to work much better than the usual toon outline shaders, at least not with my geometry it seems...
I would definitely be interested in the post processing effect you mention though! I'd be happy to be a tester when you get it closer to a working solution, if you need it. ;)
https://www.youtube.com/watch?v=hNuhN033PPk
Here's a video showing off the outline effect in a more working state. Still relies on multiple per-pixel samples for full screen in order to look decent, but it works.
Looks interesting, but would it work with many objects all at the same time? In the video it seems more like a selection outline, for like highlighting one or two specific items, rather than something to outline all objects, like for an overall toon style for the game as a whole. That is more what I'm looking for. I would need to outline pretty much every single object in the scene at the same time for the effect I'm going for.
As I said in my initial post, there are many "options" out there but, all of the solutions I have tried so far fall short of what I would like.
Thanks for this shader, might come in handy some day :) Cheers!