From 5e96d1e608c4bbe4397fb9b393829497e709455c Mon Sep 17 00:00:00 2001 From: ffreyer Date: Thu, 18 Jan 2024 16:03:10 +0100 Subject: [PATCH] add patterns --- GLMakie/assets/shader/lines.frag | 47 +++++++++++++++++------ GLMakie/assets/shader/lines.geom | 64 ++++++++++++++++++++++++++++---- 2 files changed, 92 insertions(+), 19 deletions(-) diff --git a/GLMakie/assets/shader/lines.frag b/GLMakie/assets/shader/lines.frag index 20e9570d093..67c81d5b913 100644 --- a/GLMakie/assets/shader/lines.frag +++ b/GLMakie/assets/shader/lines.frag @@ -10,7 +10,9 @@ in vec4 f_color; in vec4 f_quad_sdf; in vec2 f_joint_cutoff; // in float f_line_width; -in float f_cumulative_length; +// in float f_cumulative_length; +in vec2 f_uv; +flat in vec4 f_pattern_overwrite; flat in uvec2 f_id; // in vec2 f_rect_sdf; @@ -19,11 +21,11 @@ flat in uvec2 f_id; // flat in float f_line_offset; {{pattern_type}} pattern; - uniform float pattern_length; uniform bool fxaa; // Half width of antialiasing smoothstep +#define AA_THICKNESS 4 #define ANTIALIAS_RADIUS 0.8 float aastep(float threshold1, float dist) { @@ -31,24 +33,39 @@ float aastep(float threshold1, float dist) { } // Pattern sampling -float get_pattern_sdf(sampler2D pattern, vec2 uv){ - // make this texture repeating - // TODO - // vec2 uv2 = vec2((uv.x + f_line_offset) / pattern_length, 0.5 * uv.y / f_line_width); - return texture(pattern, uv).x; +float get_pattern_sdf(sampler2D pattern){ + return texture(pattern, f_uv).x; } -float get_pattern_sdf(sampler1D pattern, vec2 uv){ - // make this texture repeating - return texture(pattern, uv.x / pattern_length).x; +float get_pattern_sdf(sampler1D pattern){ + float sdf_offset, x; + if (f_uv.x <= f_pattern_overwrite.x) { + sdf_offset = max(f_pattern_overwrite.y * texture(pattern, f_pattern_overwrite.x).x, -AA_THICKNESS); + return f_pattern_overwrite.y * ( // +- pos ... 0 + pattern_length * (f_pattern_overwrite.x - f_uv.x) + // pos ... 0 + sdf_offset + ); + // subtract at most AA_THICKNES + // if texture > -AA_THICKNESS start from there + // return f_pattern_overwrite.y * (pattern_length * (f_pattern_overwrite.x - f_uv.x) - AA_THICKNESS); + } else if (f_uv.x >= f_pattern_overwrite.z) { + sdf_offset = max(f_pattern_overwrite.w * texture(pattern, f_pattern_overwrite.z).x, -AA_THICKNESS); + return f_pattern_overwrite.w * ( // +- pos ... 0 + pattern_length * (f_uv.x - f_pattern_overwrite.z) + // pos ... 0 + sdf_offset + ); + // return f_pattern_overwrite.w * (pattern_length * (f_uv.x - f_pattern_overwrite.z) - AA_THICKNESS); + + } else + return texture(pattern, f_uv.x).x; } -float get_pattern_sdf(Nothing _, vec2 uv){ +float get_pattern_sdf(Nothing _){ return -10.0; } void write2framebuffer(vec4 color, uvec2 id); -#define DEBUG +// #define DEBUG void main(){ // Metrics we need: @@ -75,6 +92,8 @@ void main(){ // sdf = max(sdf, abs(f_quad_sdf.z) - f_line_width); sdf = max(sdf, max(f_quad_sdf.z, f_quad_sdf.w)); + sdf = max(sdf, get_pattern_sdf(pattern)); + // draw vec4 color = f_color; @@ -144,6 +163,10 @@ void main(){ color.r += 0.3; color.gb -= vec2(0.3); } + + // show pattern by reducing alpha heavily on off-parts + if (get_pattern_sdf(pattern) > 0) + color.a *= 0.2; #endif diff --git a/GLMakie/assets/shader/lines.geom b/GLMakie/assets/shader/lines.geom index c99f2af39dd..88835717bfd 100644 --- a/GLMakie/assets/shader/lines.geom +++ b/GLMakie/assets/shader/lines.geom @@ -21,12 +21,16 @@ out vec4 f_color; out vec4 f_quad_sdf; // smooth edges (along length and width) out vec2 f_joint_cutoff; // hard edges (joint) // out float f_line_width; -out float f_cumulative_length; +// out float f_cumulative_length; +out vec2 f_uv; +flat out vec4 f_pattern_overwrite; flat out uvec2 f_id; out vec3 o_view_pos; out vec3 o_view_normal; +{{pattern_type}} pattern; +uniform float pattern_length; uniform vec2 resolution; // Constants @@ -59,14 +63,57 @@ struct LineData { bool is_start, is_end; }; +void process_pattern(Nothing pattern, LineData line) { + // do not adjust stuff + f_pattern_overwrite = vec4(1e5, 1.0, -1e5, 1.0); +} +void process_pattern(sampler2D pattern, LineData line) { + // TODO + // This is not a case that's used at all yet. Maybe consider it in the future... + f_pattern_overwrite = vec4(1e5, 1.0, -1e5, 1.0); +} + +void process_pattern(sampler1D pattern, LineData line) { + float pattern_sample; + + // line segment start + if (line.is_start) { + // get sample slightly further along + pattern_sample = texture(pattern, (g_lastlen[1] + AA_THICKNESS) / pattern_length).x; + // extend this value into the AA gap + f_pattern_overwrite.x = (g_lastlen[1] + AA_THICKNESS) / pattern_length; + f_pattern_overwrite.y = sign(pattern_sample); + } else { + // sample at "center" of corner/joint + pattern_sample = texture(pattern, g_lastlen[1] / pattern_length).x; + // overwrite until one AA gap past the corner/joint + f_pattern_overwrite.x = (g_lastlen[1] + abs(line.extrusion_a) + AA_THICKNESS) / pattern_length; + // using the sign of the sample to decide between drawing or not drawing + f_pattern_overwrite.y = sign(pattern_sample); + } + + // and again for the end of the segment + if (line.is_end) { + pattern_sample = texture(pattern, (g_lastlen[2] - AA_THICKNESS) / pattern_length).x; + f_pattern_overwrite.z = (g_lastlen[2] - AA_THICKNESS) / pattern_length; + f_pattern_overwrite.w = sign(pattern_sample); + } else { + pattern_sample = texture(pattern, g_lastlen[2] / pattern_length).x; + f_pattern_overwrite.z = (g_lastlen[2] - abs(line.extrusion_b) - AA_THICKNESS) / pattern_length; + f_pattern_overwrite.w = sign(pattern_sample); + } +} + void emit_vertex(vec3 origin, vec2 center, LineData line, int index, vec2 geom_offset) { vec3 position = origin + geom_offset.x * line.v + vec3(geom_offset.y * line.n, 0); // sdf prototyping + // joint hard cutoff // TODO Problem: this can cut the whole line even if the next segment does // fill that space (due to being short for example) - // joint hard cutoff + // Options: + // - don't do this for truncated join -> overlap, need to clean extra corner generated by extrusion // if line start/end move hard cutoff out so smooth rect cutoff can act vec2 VP1 = position.xy - line.p1.xy; vec2 VP2 = position.xy - line.p2.xy; @@ -160,14 +207,14 @@ void emit_vertex(vec3 origin, vec2 center, LineData line, int index, vec2 geom_o edge_normal = vec2(-edge_vector.y, edge_vector.x); f_quad_sdf.w = dot(position.xy - corner1, -edge_normal); - - // f_line_length = 0.5 * line.segment_length; - // f_line_width = 0.5 * g_thickness[index]; f_color = g_color[index]; gl_Position = vec4((2.0 * position.xy / resolution) - 1.0, position.z, 1.0); f_id = g_id[index]; - // f_line_offset = 0.5 * (g_lastlen[1] + g_lastlen[2]); // rect_sdf.x is centered - f_cumulative_length = g_lastlen[index]; // TODO + // TODO: pattern sampling + f_uv = vec2( + (g_lastlen[index] + geom_offset.x) / pattern_length, + 0.5 + geom_offset.y / g_thickness[index] + ); EmitVertex(); } @@ -175,6 +222,9 @@ void emit_quad(LineData line) { vec2 center = 0.5 * (line.p1.xy + line.p2.xy); float geom_linewidth = 0.5 * max(g_thickness[1], g_thickness[2]) + AA_THICKNESS; + // set up pattern overwrites at joints + process_pattern(pattern, line); + emit_vertex(line.p1, center, line, 1, vec2(- (abs(line.extrusion_a) + AA_THICKNESS), -geom_linewidth)); emit_vertex(line.p1, center, line, 1, vec2(- (abs(line.extrusion_a) + AA_THICKNESS), +geom_linewidth)); emit_vertex(line.p2, center, line, 2, vec2(+ (abs(line.extrusion_b) + AA_THICKNESS), -geom_linewidth));