post process outline

An outline effect that works for meshes with flat shadows.

Shader code
shader_type spatial;
render_mode blend_mix, unshaded, cull_back;

uniform sampler2D depth_texture : hint_depth_texture;
uniform float thickness : hint_range(0.5, 20.0, 0.1) = 2.0;
uniform vec4 outline_color : source_color = vec4(0.0, 0.0, 0.0, 1.0);
uniform int samples : hint_range(4, 32) = 4;

uniform float sensitivity : hint_range(0.01, 1.0, 0.01) = 0.1;
uniform float edge_fade : hint_range(0.0, 0.1, 0.001) = 0.015;

void fragment() {
	vec2 pixel_size = 1.0 / VIEWPORT_SIZE;
	vec2 step_size = pixel_size * thickness;
	
	float angle_step = TAU / float(samples);
	
	vec3 avg_dx = vec3(0.0);
	vec3 avg_dy = vec3(0.0);
	
	// Pre-calculate screen UV adjustments
	vec2 screen_uv_normalized = SCREEN_UV * 2.0 - 1.0;
	
	// Sample in a circle around the pixel
	for (int i = 0; i < samples; i++) {
		float angle = float(i) * angle_step;
		vec2 dir = vec2(cos(angle), sin(angle));
		vec2 offset = dir * step_size;
		
		vec2 uv1 = SCREEN_UV + offset;
		vec2 uv2 = SCREEN_UV - offset;
		
		float d1 = texture(depth_texture, uv1).r;
		float d2 = texture(depth_texture, uv2).r;
		
		// Optimized inverse projection
		vec2 uv1_norm = uv1 * 2.0 - 1.0;
		vec2 uv2_norm = uv2 * 2.0 - 1.0;
		
		vec4 up1 = INV_PROJECTION_MATRIX * vec4(uv1_norm, d1, 1.0);
		vec4 up2 = INV_PROJECTION_MATRIX * vec4(uv2_norm, d2, 1.0);
		
		// Combine division and difference calculation
		vec3 diff = (up1.xyz / up1.w) - (up2.xyz / up2.w);
		
		// Accumulate weighted by direction
		avg_dx += diff * dir.x;
		avg_dy += diff * dir.y;
	}
	
	// Combine normalization with inverse samples
	float inv_samples = 1.0 / float(samples);
	avg_dx *= inv_samples;
	avg_dy *= inv_samples;
	
	// Edge detection
	vec3 normal = normalize(cross(avg_dy, avg_dx));
	float edge = 1.0 - smoothstep(sensitivity, sensitivity + 0.05, abs(dot(normal, VIEW)));
	
	// Optimized viewport edge fade
	vec2 screen_center_dist = abs(SCREEN_UV - 0.5) * 2.0;
	float max_dist = max(screen_center_dist.x, screen_center_dist.y);
	float vignette = smoothstep(0.0, edge_fade * thickness, 1.0 - max_dist);
	
	ALBEDO = outline_color.rgb;
	ALPHA = edge * vignette * outline_color.a;
}
Live Preview
Tags
3d, highligh, outline
The shader code and all code snippets in this post are under MIT license and can be used freely. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from Merovingen

Related shaders

guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments