Squiggle Pen – Canvas Post-process

This post-process shader helps emulate a hand-drawn look. I added a few examples on how to set up 2D and 3D scenes below.

These two shaders were modified to achieve the final effect:

Squigglevision

Line art

Shader code
shader_type canvas_item;
render_mode world_vertex_coords;

uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;

group_uniforms Lines;
uniform float weight = 0.07;
uniform float line_thickness : hint_range(0.0, 6.0, 1.0) = 1.0;
uniform vec3 color : source_color;
uniform float opacity : hint_range(0.0, 1.0, 0.01) = 1.0;
uniform sampler2D background_texture : hint_default_transparent;

group_uniforms Squiggle;
/**
 * Noise texture scale
 * By default, the noise texture's size in world coordinates is set by its resolution
*/
uniform vec2 scale = vec2(10.0, 10.0);
uniform float strength = 0.5;

uniform float fps = 6.0; // Number of squiggle frames per second
uniform sampler2D noise : filter_linear, repeat_enable;
group_uniforms;

varying vec4 modulate;
varying vec2 noise_uv;

void vertex() {
	modulate = COLOR;
	
	// Use world coordinates for scale-independent squiggles, offset by position to keep pattern attached to object
	noise_uv = (VERTEX - MODEL_MATRIX[3].xy) / (vec2(textureSize(noise, 0)) * scale);
}

// Use irrational constants for unique squiggles every frame
#define offset_multiplier vec2(PI, E)

void fragment() {
	vec2 noise_offset = vec2(floor(TIME * fps)) * offset_multiplier;
	float noise_sample = texture(noise, noise_uv + noise_offset).r * 4.0 * PI;
	vec2 direction = vec2(cos(noise_sample), sin(noise_sample));
	vec2 squiggle_uv = SCREEN_UV + direction * strength * 0.005;
	
	vec3 current_color = texture(SCREEN_TEXTURE, squiggle_uv).rgb;
	vec3 right_color = texture(SCREEN_TEXTURE, squiggle_uv + vec2(SCREEN_PIXEL_SIZE.x * line_thickness, 0)).rgb;
	vec3 bottom_color = texture(SCREEN_TEXTURE, squiggle_uv - vec2(0, SCREEN_PIXEL_SIZE.y * line_thickness)).rgb;
	float r_distance = length(current_color - right_color);
	float b_distance = length(current_color - bottom_color);
	 
	vec4 background_color = texture(background_texture, UV);
	vec4 solid_line = vec4(color.rgb, 1.0);
	vec4 line_texture = (r_distance > weight || b_distance > weight) ? mix(background_color, solid_line, opacity) : background_color;
	
	COLOR = line_texture;
}
Live Preview
Tags
cartoon, distortion, doodle, drawing, hand drawn, line art, pen, post, postprocessing, scribble, shimmer, sketch, squiggle, toon, wiggle
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

guest

0 Comments
Oldest
Newest Most Voted