Sketch/distressed outline with material texture

Godot Version 4

Question

I’m trying to develop a sort of sketchy/noise/distressed edge shader for 3d objects. Kind of to give it a hard drawn effect, that makes the outside edges of the object distressed/sketchy based on a noise texture or a paintbrush-like texture. See below for a mockup example.

I made the below shader, but it obviously distorts the entire model, not just the outline.

shader_type spatial;
render_mode unshaded,cull_disabled;

uniform float alpha : hint_range(0.0, 1.0) = 0.0;
uniform sampler2D albedo_texture : source_color, filter_linear,repeat_disable;
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_nearest,repeat_disable;

uniform sampler2D noise_texture;

uniform float speed : hint_range(0.0, 2.0, 0.005) = 0.5;
uniform float distortion : hint_range(0.0, 0.3, 0.005) = 0.03;

uniform vec3 uv1_scale = vec3(1,1,1);
uniform vec3 uv1_offset;


void vertex() {
	UV=UV*uv1_scale.xy+uv1_offset.xy;
	
}

void fragment() {
	vec2 noiseValue  = (texture(noise_texture, UV + (TIME * speed)).rg * 2.0) - 1.0; // Range: -1.0 to 1.0
	
	vec2 noiseDistortion = (noiseValue * distortion);

	vec4 color = texture(SCREEN_TEXTURE, SCREEN_UV + noiseDistortion);
	
    ALBEDO = vec3(color.rgb);
	ALPHA = alpha * texture(albedo_texture, UV).r;
}

Have you looked into how spatial outline shaders identify the edges?

Yeah, I figure I’ll need to use a combination of a screenspace sobel-shader and then doing some distortion/masking of the edges but I don’t know how to combine those two concepts. I’ve tried a bunch of stuff but feeling really stuck!

Any help would be appreciated.

IDK if I know the best way to do this and this is untested code… I would get a bool for whether near an edge or not (using the edge shader examples to make that func) then use it to pick whether to use the distorted UV or the original UV. Putting it in your fragment code could look like this:

vec2 noiseDistortion = (noiseValue * distortion);
bool on_edge = get_whether_on_edge(UV);
vec4 color = texture(SCREEN_TEXTURE, SCREEN_UV + noiseDistortion * float(edge));

Or you might want nearness to edge to be a float so it’s not all or nothing but a smoother transition.

vec2 noiseDistortion = (noiseValue * distortion);
float edge_dist = get_dist_to_edge(UV);
vec4 color = texture(SCREEN_TEXTURE, SCREEN_UV + noiseDistortion * clamp(1. - edge_dist, 0, 1));

Thanks. I’ll need to study shaders some more in order to understand and use this.

1 Like

Render distressed objects into a transparent offscreen buffer. Gaussian blur the alpha, Composit into main viewport using the blurred mask sample as a threshold for randomly skipping samples and/or as sample displacement magnitude.

1 Like