Sobel Edge Outline shader per-object

Use this shader for add per-object edges in your project.

Based on this shader (look more info at this link):


  1. Create new MeshInstance3D in your 3D scene and don’t forget add any mesh
  2. Add new StandartMaterial3D for this mesh. For example in Geometry->Material Override section
  3. In next pass of created material, create new Shader Material and add this shader to it


Use this shader only in next pass of another material, else it doesn’t work.


Shader code
shader_type spatial;

uniform sampler2D SCREEN_TEXTURE: hint_screen_texture, filter_linear;
uniform sampler2D NORMAL_TEXTURE: hint_normal_roughness_texture, filter_linear;

uniform float outline_threshold = 0.2;
uniform vec3 outline_color: source_color = vec3(0.043, 0.282, 0.467);

const mat3 sobel_y = mat3(
	vec3(1.0, 0.0, -1.0),
	vec3(2.0, 0.0, -2.0),
	vec3(1.0, 0.0, -1.0)

const mat3 sobel_x = mat3(
	vec3(1.0, 2.0, 1.0),
	vec3(0.0, 0.0, 0.0),
	vec3(-1.0, -2.0, -1.0)

bool is_edge(in vec2 uv, in vec3 normal, in vec2 offset) {
	vec3 n = texture(NORMAL_TEXTURE, uv + vec2(0.0, -offset.y)).rgb;
	vec3 s = texture(NORMAL_TEXTURE, uv + vec2(0.0, offset.y)).rgb;
	vec3 e = texture(NORMAL_TEXTURE, uv + vec2(offset.x, 0.0)).rgb;
	vec3 w = texture(NORMAL_TEXTURE, uv + vec2(-offset.x, 0.0)).rgb;
	vec3 nw = texture(NORMAL_TEXTURE, uv + vec2(-offset.x, -offset.y)).rgb;
	vec3 ne = texture(NORMAL_TEXTURE, uv + vec2(offset.x, -offset.y)).rgb;
	vec3 sw = texture(NORMAL_TEXTURE, uv + vec2(-offset.x, offset.y)).rgb;
	vec3 se = texture(NORMAL_TEXTURE, uv + vec2(offset.x, offset.y)).rgb;

	mat3 surrounding_pixels = mat3(
		vec3(length(nw-normal), length(n-normal), length(ne-normal)),
		vec3(length(w-normal), length(normal-normal), length(e-normal)),
		vec3(length(sw-normal), length(s-normal), length(se-normal))

	float edge_x = dot(sobel_x[0], surrounding_pixels[0]) + dot(sobel_x[1], surrounding_pixels[1]) + dot(sobel_x[2], surrounding_pixels[2]);
	float edge_y = dot(sobel_y[0], surrounding_pixels[0]) + dot(sobel_y[1], surrounding_pixels[1]) + dot(sobel_y[2], surrounding_pixels[2]);

	float edge = sqrt(pow(edge_x, 2.0)+pow(edge_y, 2.0));

	return edge > outline_threshold;

void fragment() {
	vec2 uv = SCREEN_UV;
	vec3 screen_color = texture(SCREEN_TEXTURE, uv).rgb;
	vec3 screen_normal = texture(NORMAL_TEXTURE, uv).rgb;
	screen_normal = screen_normal * 2.0 - 1.0;
	vec2 offset = 1.0 / VIEWPORT_SIZE;
	if (is_edge(uv, screen_normal, offset)) {
		ALBEDO = outline_color;
	} else {
		ALBEDO = screen_color;
edge, outline, 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.

Related shaders

Depth Buffer Object Edge Dissolve

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

Edge Detection (Sobel Filter and Gaussian Blur)

Notify of

1 Comment
Newest Most Voted
Inline Feedbacks
View all comments
2 months ago

Hi, nice shader. In this image, you can see the top face of the right cube not drawing correctly when viewed from above.

I’ve added one viewed from underneath, which works fine.

I’m new to shaders – is there something I can do here to make it show the outline on the top of the cube?