Edge detection on overlapping meshes

Godot Version

4.5.stable

Question

Hi guys, I am having a bit of trouble working with a sobel edge detection shader. When two meshes are just next to each other or overlapping, the hidden edge generates some artifacts:

The SobelPostProcess node is just a MeshInstance3D with a shader material:

shader_type spatial;
render_mode unshaded, depth_test_disabled, depth_draw_never, cull_disabled;

uniform sampler2D screen_texture: hint_screen_texture;
uniform sampler2D depth_texture: hint_depth_texture;
uniform sampler2D normal_texture: hint_normal_roughness_texture;

uniform vec3 outline_color: source_color;
uniform float outline_threshold = 0.2;

const float sobel_x[8] = float[](
        -1.0,  0.0,  1.0,
        -2.0,        2.0,
        -1.0,  0.0,  1.0
    );
const float sobel_y[8] = float[](
        -1.0, -2.0, -1.0,
         0.0,        0.0,
         1.0,  2.0,  1.0
    );
const vec2 offset[8] = vec2[](
        vec2(-1, -1), vec2( 0, -1), vec2( 1, -1),
        vec2(-1,  0),               vec2( 1,  0),
        vec2(-1,  1), vec2( 0,  1), vec2( 1,  1)
    );

vec3 get_view_pos(vec2 uv, float depth, mat4 inv_proj_m){
	vec4 ncd = vec4((uv*2.0)-1.0,depth,1.0);
	vec4 veiw_pos = inv_proj_m*ncd;
	return veiw_pos.xyz /= veiw_pos.w;
}

void vertex() {
	POSITION = vec4(VERTEX.xy, 1.0, 1.0);
}

void fragment() {
	vec2 uv = SCREEN_UV;
	vec2 texel = 1.0 / vec2(textureSize(depth_texture, 0));
	vec3 screen_color = texture(screen_texture, uv).rgb;
	mat4 inv_proj_m = INV_PROJECTION_MATRIX;

	float center_depth = texture(depth_texture, uv).r;
	vec3 center_view = get_view_pos(uv, center_depth, inv_proj_m);
	vec3 center_normal = texture(normal_texture, uv).rgb * 2.0 - 1.0;

	float depth_edge_x = 0.0;
	float depth_edge_y = 0.0;

	float norm_edge_x = 0.0;
	float norm_edge_y = 0.0;

	for (int i = 0; i < 8; i++) {
		vec2 neighbor_uv = clamp(uv + offset[i] * texel, vec2(0.0), vec2(1.0));

		float neighbor_depth  = texture(depth_texture, neighbor_uv).r;
		vec3  neighbor_view   = get_view_pos(neighbor_uv, neighbor_depth, inv_proj_m);
		vec3  neighbor_normal = texture(normal_texture, neighbor_uv).rgb * 2.0 - 1.0;

		float dist = distance(center_view, neighbor_view);
		float diff = length(neighbor_normal - center_normal);

		depth_edge_x += dist * sobel_x[i];
		depth_edge_y += dist * sobel_y[i];

		norm_edge_x += diff * sobel_x[i];
		norm_edge_y += diff * sobel_y[i];
	}

	float depth_edge = sqrt(depth_edge_x * depth_edge_x + depth_edge_y * depth_edge_y)*10.0;
	depth_edge = clamp(depth_edge, 0.0, 1.0);

	float gradient = sqrt(norm_edge_x * norm_edge_x + norm_edge_y * norm_edge_y);
	float normal_edge = float(gradient > outline_threshold);

	float combined_edge = max(normal_edge, depth_edge);

	ALBEDO = mix(screen_color, outline_color, combined_edge);
	ALPHA = combined_edge;
}

This is the result on runtime (With an additional 1 bit shader I have down the pipeline):

Is there something I can do to alleviate this issue? Worst case scenario I’ll just plan around it but it would be great to have a solution.

Thank you very much in advance!

Try playing with thresholds.

Thanks for the tip but I am not sure I follow you, I am still quite new to shaders. You mean that I could add some kind of factor to some of the calculations? Something like multiplying the depth edge or the normal edge by a factor and see what happens?

Start with making sure the meshes are perfectly aligned.

Is there a way I can do that properly? The inspector decimals for the position V3 are capped at 3 and I cannot do any fine adjustment. Is there a way to move an object in the scene until it collides with an adjacent one (like Page Down for snapping to the floor)?

Maybe prepare your assets so they are modular and fit nicely into a grid or have otherwise modular dimensions that are easy to numerically align.

I can sadly not do that at the time being since I am using an asset pack but I tried with several simple geometries and there are no artifacts. I will mark this as the answer. Thanks again.

You can try lowering the value of that 10.0 here but if the mismatch in the scene is too large it may not have much effect.

Yes, I tried that but mid distance objects loose the edge and the problem is barely solved.

Tidying up the assets is your best bet then. You could get them in Blender and align the vertices of those top surfaces.

That is my current plan, I will just fuse the three cabinets in Blender after aligning them for the time being. I do not expect to find this issue more than a couple of times during development.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.