Cheaper* Edge Detection Post-Processing

Unlike the popular sobel filter that uses 9 texture samples, this uses only 5.

However, this is the 2D version of the shader. Apply this as a post processing effect using a ColorRect node. Since, its the 2D version, it only calculates a difference in color in order to draw an edge.

 

What are the parameters?:

  • Edge Color: What color should the edge be
  • Threshold: Color Difference threshold of where to draw edges
  • Blend: Basically softens up the edges
Shader code
// NekotoArts YouTube: https://www.youtube.com/channel/UCD7K_FECPHTF0z5okAVlh0g
// Adapted from https://www.shadertoy.com/view/ldsfRn

shader_type canvas_item;

uniform vec4 edge_color : hint_color = vec4(0.0, 0.0, 0.0, 1.0);
uniform float threshold = 0.0;
uniform float blend = 0.01;

float getGrayScale(sampler2D sampler, vec2 coods){
	vec4 color = texture(sampler,coods);
	float gray = (color.r + color.g + color.b)/3.0;
	return gray;
}

void fragment(){
	vec2 delta = vec2(0.0,0.003);
	vec2 iResolution = 1.0 / SCREEN_PIXEL_SIZE;
	float m = max(iResolution.x,iResolution.y);
	vec2 texCoords = SCREEN_UV;
	
	vec3 screen_color = texture(SCREEN_TEXTURE, SCREEN_UV).rgb;
	
	float c1y = getGrayScale(SCREEN_TEXTURE, texCoords.xy-delta/2.0);
	float c2y = getGrayScale(SCREEN_TEXTURE, texCoords.xy+delta/2.0);
	
	float c1x = getGrayScale(SCREEN_TEXTURE, texCoords.xy-delta.yx/2.0);
	float c2x = getGrayScale(SCREEN_TEXTURE, texCoords.xy+delta.yx/2.0);
	
	float dcdx = (c2x - c1x)/(delta.y*10.0);
	float dcdy = (c2y - c1y)/(delta.y*10.0);
	
	vec2 dcdi = vec2(dcdx,dcdy);
	float edge = length(dcdi)/10.0;
	edge = 1.0 - edge;
	edge = smoothstep(threshold, threshold + blend, edge);
	
	COLOR.rgb = mix(edge_color.rgb, screen_color.rgb, edge);
}
Tags
borderlands, edge, edge detection, outline, Post processing, Sobel
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 NekotoArts

HQ4X Shader (like in Emulators)

3D Edge Detection Shader (Borderlands-Style)

Basic Vector Sprite Upscaling

Related shaders

Sobel Edge Detection Post Process

Depth-based Edge Detection with Sobel Operator – Screenspace

Normal-based Edge Detection with Sobel Operator -Screenspace

Subscribe
Notify of
guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
eric85
eric85
7 months ago

Updated for Godot 4

// NekotoArts YouTube: https://www.youtube.com/channel/UCD7K_FECPHTF0z5okAVlh0g
// Adapted from https://www.shadertoy.com/view/ldsfRn


shader_type canvas_item;


uniform vec4 edge_color : source_color = vec4(0.0, 0.0, 0.0, 1.0);
uniform float threshold = 0.0;
uniform float blend = 0.01;
uniform sampler2D screen_texture : hint_screen_texture;


float getGrayScale(sampler2D sampler, vec2 coods){
	vec4 color = texture(sampler,coods);
	float gray = (color.r + color.g + color.b)/3.0;
	return gray;
}


void fragment(){
	vec2 delta = vec2(0.0,0.003);
	vec2 iResolution = 1.0 / SCREEN_PIXEL_SIZE;
	float m = max(iResolution.x,iResolution.y);
	vec2 texCoords = SCREEN_UV;
	
	vec3 screen_color = texture(screen_texture, SCREEN_UV).rgb;
	
	float c1y = getGrayScale(screen_texture, texCoords.xy-delta/2.0);
	float c2y = getGrayScale(screen_texture, texCoords.xy+delta/2.0);
	
	float c1x = getGrayScale(screen_texture, texCoords.xy-delta.yx/2.0);
	float c2x = getGrayScale(screen_texture, texCoords.xy+delta.yx/2.0);
	
	float dcdx = (c2x - c1x)/(delta.y*10.0);
	float dcdy = (c2y - c1y)/(delta.y*10.0);
	
	vec2 dcdi = vec2(dcdx,dcdy);
	float edge = length(dcdi)/10.0;
	edge = 1.0 - edge;
	edge = smoothstep(threshold, threshold + blend, edge);
	
	COLOR.rgb = mix(edge_color.rgb, screen_color.rgb, edge);
}