From 80f7bc6d8e7e7a5e543df5418313c04df5140c43 Mon Sep 17 00:00:00 2001 From: YimingWu Date: Sun, 26 Sep 2021 19:43:12 +0800 Subject: LineArt: Smooth tolerance value for chaining. smooth out jaggy lines with a given threshold. For each point in a stroke, the ones with in a given distance of its previous segment will be removed, thus "zig-zag" artefacts can be cleaned up. Reviewed By: Antonio Vazquez (antoniov) Differential Revision: https://developer.blender.org/D12050 --- source/blender/blenloader/intern/versioning_300.c | 9 +++++++ .../gpencil_modifiers/intern/MOD_gpencillineart.c | 1 + .../gpencil_modifiers/intern/lineart/MOD_lineart.h | 3 +++ .../intern/lineart/lineart_chain.c | 28 ++++++++++++++++++++++ .../gpencil_modifiers/intern/lineart/lineart_cpu.c | 10 +++++++- .../makesdna/DNA_gpencil_modifier_defaults.h | 2 +- .../blender/makesdna/DNA_gpencil_modifier_types.h | 6 ++++- source/blender/makesdna/DNA_gpencil_types.h | 2 ++ .../blender/makesrna/intern/rna_gpencil_modifier.c | 9 +++++++ source/tools | 2 +- 10 files changed, 68 insertions(+), 4 deletions(-) (limited to 'source') diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index caba972c744..692c114d206 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -1127,6 +1127,15 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } + if (ob->type == OB_GPENCIL) { + LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { + if (md->type == eGpencilModifierType_Lineart) { + LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md; + lmd->flags |= LRT_GPENCIL_USE_CACHE; + lmd->chain_smooth_tolerance = 0.2f; + } + } + } } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c index 01488a8b2de..c5ccf1d8229 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c @@ -587,6 +587,7 @@ static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel) is_geom ? IFACE_("Geometry Threshold") : NULL, ICON_NONE); + uiItemR(layout, ptr, "smooth_tolerance", UI_ITEM_R_SLIDER, NULL, ICON_NONE); uiItemR(layout, ptr, "split_angle", UI_ITEM_R_SLIDER, NULL, ICON_NONE); } diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h index 134d9707ade..c00f34185dd 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h +++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h @@ -317,6 +317,8 @@ typedef struct LineartRenderBuffer { float chaining_image_threshold; float angle_splitting_threshold; + float chain_smooth_tolerance; + /* FIXME(Yiming): Temporary solution for speeding up calculation by not including lines that * are not in the selected source. This will not be needed after we have a proper scene-wise * cache running because multiple modifiers can then select results from that without further @@ -592,6 +594,7 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb); void MOD_lineart_chain_connect(LineartRenderBuffer *rb); void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold); void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad); +void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance); int MOD_lineart_chain_count(const LineartEdgeChain *ec); void MOD_lineart_chain_clear_picked_flag(LineartCache *lc); diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c index d86253e7fe0..8935bdd1870 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c @@ -924,6 +924,34 @@ void MOD_lineart_chain_clear_picked_flag(LineartCache *lc) } } +void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance) +{ + LISTBASE_FOREACH (LineartEdgeChain *, rlc, &rb->chains) { + LineartEdgeChainItem *next_eci; + for (LineartEdgeChainItem *eci = rlc->chain.first; eci; eci = next_eci) { + next_eci = eci->next; + LineartEdgeChainItem *eci2, *eci3, *eci4; + + /* Not enough point to do simplify. */ + if ((!(eci2 = eci->next)) || (!(eci3 = eci2->next))) { + continue; + } + + /* No need to care for different line types/occlusion and so on, because at this stage they + * are all the same within a chain. */ + + /* If p3 is within the p1-p2 segment of a width of "tolerance" */ + if (dist_to_line_segment_v2(eci3->pos, eci->pos, eci2->pos) < tolerance) { + /* And if p4 is on the extension of p1-p2 , we remove p3. */ + if ((eci4 = eci3->next) && (dist_to_line_v2(eci4->pos, eci->pos, eci2->pos) < tolerance)) { + BLI_remlink(&rlc->chain, eci3); + next_eci = eci; + } + } + } + } +} + /** * This should always be the last stage!, see the end of * #MOD_lineart_chain_split_for_fixed_occlusion(). diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index 725cc0741f0..5b878a4326f 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -3056,8 +3056,9 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene, rb->shift_y /= (1 + rb->overscan); rb->crease_threshold = cos(M_PI - lmd->crease_threshold); - rb->angle_splitting_threshold = lmd->angle_splitting_threshold; rb->chaining_image_threshold = lmd->chaining_image_threshold; + rb->angle_splitting_threshold = lmd->angle_splitting_threshold; + rb->chain_smooth_tolerance = lmd->chain_smooth_tolerance; rb->fuzzy_intersections = (lmd->calculation_flags & LRT_INTERSECTION_AS_CONTOUR) != 0; rb->fuzzy_everything = (lmd->calculation_flags & LRT_EVERYTHING_AS_CONTOUR) != 0; @@ -4172,6 +4173,13 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, /* This configuration ensures there won't be accidental lost of short unchained segments. */ MOD_lineart_chain_discard_short(rb, MIN2(*t_image, 0.001f) - FLT_EPSILON); + if (rb->chain_smooth_tolerance > FLT_EPSILON) { + /* Keeping UI range of 0-1 for ease of read while scaling down the actual value for best + * effective range in image-space (Coordinate only goes from -1 to 1). This value is somewhat + * arbitrary, but works best for the moment. */ + MOD_lineart_smooth_chains(rb, rb->chain_smooth_tolerance / 50); + } + if (rb->angle_splitting_threshold > FLT_EPSILON) { MOD_lineart_chain_split_angle(rb, rb->angle_splitting_threshold); } diff --git a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h index 2a3c6f4e3db..11299ae9717 100644 --- a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h +++ b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h @@ -318,7 +318,7 @@ .calculation_flags = LRT_ALLOW_DUPLI_OBJECTS | LRT_ALLOW_CLIPPING_BOUNDARIES | LRT_USE_CREASE_ON_SHARP_EDGES, \ .angle_splitting_threshold = DEG2RAD(60.0f), \ .chaining_image_threshold = 0.001f, \ - .overscan = 0.1f,\ + .chain_smooth_tolerance = 0.2f,\ } #define _DNA_DEFAULT_LengthGpencilModifierData \ diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h index 8d967a38808..ea5c81761c6 100644 --- a/source/blender/makesdna/DNA_gpencil_modifier_types.h +++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h @@ -1040,7 +1040,11 @@ typedef struct LineartGpencilModifierData { /** `0..PI` angle, for splitting strokes at sharp points. */ float angle_splitting_threshold; - /* Doubles as geometry threshold when geometry space chaining is enabled */ + /** Strength for smoothing jagged chains. */ + float chain_smooth_tolerance; + int _pad1; + + /* CPU mode */ float chaining_image_threshold; /* Ported from SceneLineArt flags. */ diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index 68bd2961f23..0f570f8603d 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -49,6 +49,8 @@ struct MDeformVert; #define GPENCIL_MIN_FILL_FAC 0.05f #define GPENCIL_MAX_FILL_FAC 8.0f +#define GPENCIL_MAX_THICKNESS 5000 + /* ***************************************** */ /* GP Stroke Points */ diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index 5817a200192..675cff3e58c 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -26,6 +26,7 @@ #include "DNA_brush_types.h" #include "DNA_cachefile_types.h" #include "DNA_gpencil_modifier_types.h" +#include "DNA_gpencil_types.h" #include "DNA_mesh_types.h" #include "DNA_object_force_types.h" #include "DNA_object_types.h" @@ -3125,6 +3126,14 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna) RNA_def_property_range(prop, 0.0f, DEG2RAD(180.0f)); RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update"); + prop = RNA_def_property(srna, "smooth_tolerance", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "chain_smooth_tolerance"); + RNA_def_property_ui_text( + prop, "Smooth Tolerance", "Strength of smoothing applied on jagged chains"); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.05f, 4); + RNA_def_property_range(prop, 0.0f, 30.0f); + RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update"); + prop = RNA_def_property(srna, "use_remove_doubles", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_REMOVE_DOUBLES); RNA_def_property_ui_text( diff --git a/source/tools b/source/tools index 723b24841df..01f51a0e551 160000 --- a/source/tools +++ b/source/tools @@ -1 +1 @@ -Subproject commit 723b24841df1ed8478949bca20c73878fab00dca +Subproject commit 01f51a0e551ab730f0934dc6488613690ac4bf8f -- cgit v1.2.3