diff options
author | YimingWu <xp8110@outlook.com> | 2022-01-22 11:13:44 +0300 |
---|---|---|
committer | YimingWu <xp8110@outlook.com> | 2022-01-22 11:13:44 +0300 |
commit | 5ae76fae90da795891e7edccc14bccf36f93da54 (patch) | |
tree | 17b18e69bb7fcc46fd49151942fbb591e3b6e58b /source/blender/gpencil_modifiers/intern | |
parent | e88d966737c1e4c246f92d21fbe31c4eb702678c (diff) |
LineArt: Noise tolerant chaining.
Instead of splitting it at each occlusion change, it tolerates short segments of "zig-zag" occlusion incoherence and doesn't split the chain at these points, thus creating a much smoother result.
Reviewed By: Antonio Vazquez (antoniov), Aleš Jelovčan (frogstomp)
Differential Revision: https://developer.blender.org/D13851
Diffstat (limited to 'source/blender/gpencil_modifiers/intern')
4 files changed, 63 insertions, 0 deletions
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c index 59937bb0757..1dc6816980c 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c @@ -607,6 +607,7 @@ static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemR(col, ptr, "use_fuzzy_all", 0, NULL, ICON_NONE); uiItemR(col, ptr, "use_loose_edge_chain", 0, IFACE_("Loose Edges"), ICON_NONE); uiItemR(col, ptr, "use_loose_as_contour", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_detail_preserve", 0, NULL, ICON_NONE); uiItemR(col, ptr, "use_geometry_space_chain", 0, IFACE_("Geometry Space"), ICON_NONE); uiItemR(layout, diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h index 8c5820c9667..2691dcc8408 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h +++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h @@ -308,6 +308,8 @@ typedef struct LineartRenderBuffer { bool force_crease; bool sharp_as_crease; + bool chain_preserve_details; + /* Keep an copy of these data so when line art is running it's self-contained. */ bool cam_is_persp; float cam_obmat[4][4]; diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c index 0deb8b1c335..78ad895c93e 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c @@ -571,6 +571,57 @@ static void lineart_bounding_area_link_chain(LineartRenderBuffer *rb, LineartEdg } } +static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec, + LineartEdgeChainItem *last_matching_eci, + float distance_threshold, + bool preserve_details, + LineartEdgeChainItem **r_next_eci) +{ + float dist_accum = 0; + + int fixed_occ = last_matching_eci->occlusion; + unsigned char fixed_mask = last_matching_eci->material_mask_bits; + + LineartEdgeChainItem *can_skip_to = NULL; + LineartEdgeChainItem *last_eci = last_matching_eci; + for (LineartEdgeChainItem *eci = last_matching_eci->next; eci; eci = eci->next) { + dist_accum += len_v2v2(last_eci->pos, eci->pos); + if (dist_accum > distance_threshold) { + break; + } + last_eci = eci; + /* The reason for this is because we don't want visible segments to be "skipped" into + * connecting with invisible segments. */ + if (eci->occlusion < fixed_occ) { + break; + } + if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ) { + can_skip_to = eci; + } + } + if (can_skip_to) { + /* Either mark all in-between segments with the same occlusion and mask or delete those + * different ones. */ + LineartEdgeChainItem *next_eci; + for (LineartEdgeChainItem *eci = last_matching_eci->next; eci != can_skip_to; eci = next_eci) { + next_eci = eci->next; + if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ) { + continue; + } + if (preserve_details) { + eci->material_mask_bits = fixed_mask; + eci->occlusion = fixed_occ; + } + else { + BLI_remlink(&ec->chain, eci); + } + } + *r_next_eci = can_skip_to; + return true; + } + return false; +} + void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb) { LineartEdgeChain *ec, *new_ec; @@ -597,6 +648,13 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb) if (lineart_point_overlapping(next_eci, eci->pos[0], eci->pos[1], 1e-5)) { continue; } + if (lineart_chain_fix_ambiguous_segments(ec, + eci->prev, + rb->chaining_image_threshold, + rb->chain_preserve_details, + &next_eci)) { + continue; + } } else { /* Set the same occlusion level for the end vertex, so when further connection is needed diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index 5461b80cad1..923646a133a 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -3158,6 +3158,8 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene, rb->force_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SMOOTH_SURFACES) != 0; rb->sharp_as_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SHARP_EDGES) != 0; + rb->chain_preserve_details = (lmd->calculation_flags & LRT_CHAIN_PRESERVE_DETAILS) != 0; + int16_t edge_types = lmd->edge_types_override; rb->use_contour = (edge_types & LRT_EDGE_FLAG_CONTOUR) != 0; |