Per object depth-based outline

Per object depth-based outline. Works with other materials. Has to be added under a material’s “next pass” property.

Huge thanks to Alice (https://twitter.com/bottinogames) for the help.

Shader code
shader_type spatial;
render_mode unshaded, blend_mix;
uniform sampler2D depth_texture : hint_depth_texture;
uniform vec3 outline_color : source_color = vec3(0.0, 0.0, 0.0);

float linear_depth_projection(float depth_raw, vec2 screen_uv, mat4 inv_proj){
	vec3 ndc = vec3(screen_uv * 2.0 - 1.0, depth_raw);
	vec4 view = inv_proj * vec4(ndc, 1.0);
	view.xyz /= view.w;
	return -view.z;
}

float linear_depth(float depth_raw, float near, float far){
	return 1.0 / ((1.0 - far / near) * depth_raw + 1.0 / near);
}

void vertex() {
	VERTEX += NORMAL * 0.003;
}

void fragment() {
	float near = linear_depth_projection(0.0, SCREEN_UV, INV_PROJECTION_MATRIX);
	float far = linear_depth_projection(1.0, SCREEN_UV, INV_PROJECTION_MATRIX);
	
	float depth_raw = texture(depth_texture, SCREEN_UV).x;
	float depth_linear = linear_depth(depth_raw, near, far);
	
	vec2 pixel_size = (1.0 / depth_linear) / vec2(textureSize(depth_texture, 0));
	
	float neighbor1 = linear_depth(textureLod(depth_texture, SCREEN_UV + vec2(pixel_size.x, pixel_size.y) * vec2(-1, 1),  0).r, near, far);
	float neighbor2 = linear_depth(textureLod(depth_texture, SCREEN_UV + vec2(pixel_size.x, pixel_size.y) * vec2(0, 1),   0).r, near, far);
	float neighbor3 = linear_depth(textureLod(depth_texture, SCREEN_UV + vec2(pixel_size.x, pixel_size.y) * vec2(1, 1),   0).r, near, far);
	float neighbor4 = linear_depth(textureLod(depth_texture, SCREEN_UV + vec2(pixel_size.x, pixel_size.y) * vec2(-1, 0),  0).r, near, far);
	float neighbor5 = linear_depth(textureLod(depth_texture, SCREEN_UV + vec2(pixel_size.x, pixel_size.y) * vec2(1, 0),   0).r, near, far);
	float neighbor6 = linear_depth(textureLod(depth_texture, SCREEN_UV + vec2(pixel_size.x, pixel_size.y) * vec2(-1, -1), 0).r, near, far);
	float neighbor7 = linear_depth(textureLod(depth_texture, SCREEN_UV + vec2(pixel_size.x, pixel_size.y) * vec2(0, -1),  0).r, near, far);
	float neighbor8 = linear_depth(textureLod(depth_texture, SCREEN_UV + vec2(pixel_size.x, pixel_size.y) * vec2(-1, 1),  0).r, near, far);
	
	float max_dst = 0.075;
	
	float edge1 = step(max_dst, abs(neighbor1 - depth_linear));
	float edge2 = step(max_dst, abs(neighbor2 - depth_linear));
	float edge3 = step(max_dst, abs(neighbor3 - depth_linear));
	float edge4 = step(max_dst, abs(neighbor4 - depth_linear));
	float edge5 = step(max_dst, abs(neighbor5 - depth_linear));
	float edge6 = step(max_dst, abs(neighbor6 - depth_linear));
	float edge7 = step(max_dst, abs(neighbor7 - depth_linear));
	float edge8 = step(max_dst, abs(neighbor8 - depth_linear));
	
	float all_edges = edge1 + edge2 + edge3 + edge4 + edge5 + edge6 + edge7 + edge8;
	float edges = step(0.5, all_edges);
	
	ALBEDO = outline_color;
	ALPHA = edges;
}
Tags
depth based, depth outline, outline, per object outline
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from wriks

Gooch

Related shaders

Sobel Edge Outline shader per-object

3D Pixel art outline & highlight Shader (Post-processing/object)

Object Outline Shader

Subscribe
Notify of
guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Weenter
Weenter
15 days ago

Cool shader, it works better for my specific game than any others I found. Is there a way to increase the line thickness?