From 3558bb8eae758aa7e6483d0a6fc00dc83407d4cf Mon Sep 17 00:00:00 2001 From: YimingWu Date: Fri, 25 Jun 2021 18:48:20 +0800 Subject: LineArt: Filtering feature lines with face mask User can specify filtering options inside line art modifier, like inverting selection and including face mark region border. Reviewed By: Sebastian Parborg (zeddb) Differential Revision: https://developer.blender.org/D11307 --- .../gpencil_modifiers/intern/MOD_gpencillineart.c | 47 ++++++++++++ .../gpencil_modifiers/intern/lineart/MOD_lineart.h | 4 + .../gpencil_modifiers/intern/lineart/lineart_cpu.c | 88 ++++++++++++++++------ .../blender/makesdna/DNA_gpencil_modifier_types.h | 3 +- source/blender/makesdna/DNA_lineart_types.h | 7 +- .../blender/makesrna/intern/rna_gpencil_modifier.c | 40 +++++++--- 6 files changed, 148 insertions(+), 41 deletions(-) diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c index 1f70ecb4595..b87ed9e431a 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c @@ -449,6 +449,51 @@ static void transparency_panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemR(col, ptr, "use_transparency_match", 0, IFACE_("Match All Masks"), ICON_NONE); } +static void face_mark_panel_draw_header(const bContext *UNUSED(C), Panel *panel) +{ + uiLayout *layout = panel->layout; + PointerRNA ob_ptr; + PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr); + + const bool is_baked = RNA_boolean_get(ptr, "is_baked"); + const bool use_cache = RNA_boolean_get(ptr, "use_cache"); + const bool is_first = BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data); + + if (!use_cache || is_first) { + uiLayoutSetEnabled(layout, !is_baked); + uiItemR(layout, ptr, "use_face_mark", 0, IFACE_("Face Mark Filtering"), ICON_NONE); + } + else { + uiItemL(layout, IFACE_("Face Mark Filtering"), ICON_NONE); + } +} + +static void face_mark_panel_draw(const bContext *UNUSED(C), Panel *panel) +{ + uiLayout *layout = panel->layout; + PointerRNA ob_ptr; + PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr); + + const bool is_baked = RNA_boolean_get(ptr, "is_baked"); + const bool use_mark = RNA_boolean_get(ptr, "use_face_mark"); + const bool use_cache = RNA_boolean_get(ptr, "use_cache"); + const bool is_first = BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data); + + uiLayoutSetEnabled(layout, !is_baked); + + if (use_cache && !is_first) { + uiItemL(layout, "Cached from the first line art modifier.", ICON_INFO); + return; + } + + uiLayoutSetPropSep(layout, true); + + uiLayoutSetActive(layout, use_mark); + + uiItemR(layout, ptr, "use_face_mark_invert", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_face_mark_boundaries", 0, NULL, ICON_NONE); +} + static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel) { PointerRNA ob_ptr; @@ -566,6 +611,8 @@ static void panelRegister(ARegionType *region_type) transparency_panel_draw_header, transparency_panel_draw, occlusion_panel); + gpencil_modifier_subpanel_register( + region_type, "face_mark", "", face_mark_panel_draw_header, face_mark_panel_draw, panel_type); gpencil_modifier_subpanel_register( region_type, "chaining", "Chaining", NULL, chaining_panel_draw, panel_type); gpencil_modifier_subpanel_register( diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h index a7f4231e4aa..d78cd862383 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h +++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h @@ -299,6 +299,10 @@ typedef struct LineartRenderBuffer { bool chain_floating_edges; bool chain_geometry_space; + bool filter_face_mark; + bool filter_face_mark_invert; + bool filter_face_mark_boundaries; + /* 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_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index f2d1f6776ab..ebf9bcc17e2 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -1438,34 +1438,51 @@ static LineartTriangle *lineart_triangle_from_index(LineartRenderBuffer *rb, return (LineartTriangle *)b; } -static char lineart_identify_feature_line(LineartRenderBuffer *rb, - BMEdge *e, - LineartTriangle *rt_array, - LineartVert *rv_array, - float crease_threshold, - bool no_crease, - bool count_freestyle, - BMesh *bm_if_freestyle) +static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb, + BMEdge *e, + LineartTriangle *rt_array, + LineartVert *rv_array, + float crease_threshold, + bool no_crease, + bool use_freestyle_edge, + bool use_freestyle_face, + BMesh *bm_if_freestyle) { BMLoop *ll, *lr = NULL; + ll = e->l; if (ll) { lr = e->l->radial_next; } - if (!ll && !lr) { - if (!rb->floating_as_contour) { - return LRT_EDGE_FLAG_FLOATING; - } - } - + FreestyleEdge *fel, *fer; + bool face_mark_filtered = false; uint16_t edge_flag_result = 0; - if (count_freestyle && rb->use_edge_marks) { - FreestyleEdge *fe; - fe = CustomData_bmesh_get(&bm_if_freestyle->edata, e->head.data, CD_FREESTYLE_EDGE); - if (fe->flag & FREESTYLE_EDGE_MARK) { - edge_flag_result |= LRT_EDGE_FLAG_EDGE_MARK; + if (use_freestyle_face && rb->filter_face_mark) { + fel = CustomData_bmesh_get(&bm_if_freestyle->pdata, ll->f->head.data, CD_FREESTYLE_FACE); + if (ll != lr && lr) { + fer = CustomData_bmesh_get(&bm_if_freestyle->pdata, lr->f->head.data, CD_FREESTYLE_FACE); + } + else { + /* Handles mesh boundary case */ + fer = fel; + } + if (rb->filter_face_mark_boundaries ^ rb->filter_face_mark_invert) { + if ((fel->flag & FREESTYLE_FACE_MARK) || (fer->flag & FREESTYLE_FACE_MARK)) { + face_mark_filtered = true; + } + } + else { + if ((fel->flag & FREESTYLE_FACE_MARK) && (fer->flag & FREESTYLE_FACE_MARK) && (fer != fel)) { + face_mark_filtered = true; + } + } + if (rb->filter_face_mark_invert) { + face_mark_filtered = !face_mark_filtered; + } + if (!face_mark_filtered) { + return 0; } } @@ -1507,11 +1524,16 @@ static char lineart_identify_feature_line(LineartRenderBuffer *rb, edge_flag_result |= LRT_EDGE_FLAG_CREASE; } } - if (rb->use_material && (ll->f->mat_nr != lr->f->mat_nr)) { edge_flag_result |= LRT_EDGE_FLAG_MATERIAL; } - + if (use_freestyle_edge && rb->use_edge_marks) { + FreestyleEdge *fe; + fe = CustomData_bmesh_get(&bm_if_freestyle->edata, e->head.data, CD_FREESTYLE_EDGE); + if (fe->flag & FREESTYLE_EDGE_MARK) { + edge_flag_result |= LRT_EDGE_FLAG_EDGE_MARK; + } + } return edge_flag_result; } @@ -1628,7 +1650,8 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu LineartEdgeSegment *o_la_s; LineartTriangle *ort; Object *orig_ob; - int CanFindFreestyle = 0; + bool can_find_freestyle_edge = false; + bool can_find_freestyle_face = false; int i; float use_crease = 0; @@ -1684,7 +1707,10 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu BM_mesh_elem_index_ensure(bm, BM_VERT | BM_EDGE | BM_FACE); if (CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE)) { - CanFindFreestyle = 1; + can_find_freestyle_edge = 1; + } + if (CustomData_has_layer(&bm->pdata, CD_FREESTYLE_FACE)) { + can_find_freestyle_face = true; } /* If we allow duplicated edges, one edge should get added multiple times if is has been @@ -1787,8 +1813,15 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu e = BM_edge_at_index(bm, i); /* Because e->head.hflag is char, so line type flags should not exceed positive 7 bits. */ - char eflag = lineart_identify_feature_line( - rb, e, ort, orv, use_crease, orig_ob->type == OB_FONT, CanFindFreestyle, bm); + char eflag = lineart_identify_feature_line(rb, + e, + ort, + orv, + use_crease, + orig_ob->type == OB_FONT, + can_find_freestyle_edge, + can_find_freestyle_face, + bm); if (eflag) { /* Only allocate for feature lines (instead of all lines) to save memory. * If allow duplicated edges, one edge gets added multiple times if it has multiple types. */ @@ -3006,6 +3039,11 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene, rb->use_intersections = (edge_types & LRT_EDGE_FLAG_INTERSECTION) != 0; rb->use_floating = (edge_types & LRT_EDGE_FLAG_FLOATING) != 0; + rb->filter_face_mark_invert = (lmd->calculation_flags & LRT_FILTER_FACE_MARK_INVERT) != 0; + rb->filter_face_mark = (lmd->calculation_flags & LRT_FILTER_FACE_MARK) != 0; + rb->filter_face_mark_boundaries = (lmd->calculation_flags & LRT_FILTER_FACE_MARK_BOUNDARIES) != + 0; + rb->chain_data_pool = &lc->chain_data_pool; BLI_spin_init(&rb->lock_task); diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h index c0768c9a077..7c0679d38a9 100644 --- a/source/blender/makesdna/DNA_gpencil_modifier_types.h +++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h @@ -873,6 +873,7 @@ typedef enum eLineartGpencilModifierSource { LRT_SOURCE_SCENE = 2, } eLineartGpencilModifierSource; +/* This enumis for modifier internal state only. */ typedef enum eLineArtGPencilModifierFlags { /* These two moved to eLineartMainFlags to keep consistent with flag variable purpose. */ /* LRT_GPENCIL_INVERT_SOURCE_VGROUP = (1 << 0), */ @@ -932,7 +933,7 @@ typedef struct LineartGpencilModifierData { /* Ported from SceneLineArt flags. */ int calculation_flags; - /* Additional Switches. */ + /* eLineArtGPencilModifierFlags, modifier internal state. */ int flags; /* Runtime data. */ diff --git a/source/blender/makesdna/DNA_lineart_types.h b/source/blender/makesdna/DNA_lineart_types.h index bbb3bd29197..3a3af622dd5 100644 --- a/source/blender/makesdna/DNA_lineart_types.h +++ b/source/blender/makesdna/DNA_lineart_types.h @@ -39,6 +39,7 @@ * Edge flags and usage flags are used by with scene/object/gpencil modifier bits, and those values * needs to stay consistent throughout. */ +/* These flags are used for 1 time calculation, not stroke selection afterwards. */ typedef enum eLineartMainFlags { LRT_INTERSECTION_AS_CONTOUR = (1 << 0), LRT_EVERYTHING_AS_CONTOUR = (1 << 1), @@ -52,9 +53,9 @@ typedef enum eLineartMainFlags { LRT_FILTER_FACE_MARK = (1 << 9), LRT_FILTER_FACE_MARK_INVERT = (1 << 10), LRT_FILTER_FACE_MARK_BOUNDARIES = (1 << 11), - LRT_CHAIN_FLOATING_EDGES = (1 << 11), - LRT_CHAIN_GEOMETRY_SPACE = (1 << 12), - LRT_ALLOW_OVERLAP_EDGE_TYPES = (1 << 13), + LRT_CHAIN_FLOATING_EDGES = (1 << 12), + LRT_CHAIN_GEOMETRY_SPACE = (1 << 13), + LRT_ALLOW_OVERLAP_EDGE_TYPES = (1 << 14), } eLineartMainFlags; typedef enum eLineartEdgeFlag { diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index 4c890895446..baa37f84f9d 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -2814,10 +2814,36 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna) prop = RNA_def_property(srna, "floating_as_contour", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_FLOATING_AS_CONTOUR); - RNA_def_property_ui_text( - prop, "Floating As Contour", "Floating edges will be classified as contour lines"); + RNA_def_property_ui_text(prop, "Floating As Contour", "Floating edges will have contour type"); RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update"); + prop = RNA_def_property(srna, "invert_source_vertex_group", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_GPENCIL_INVERT_SOURCE_VGROUP); + RNA_def_property_ui_text(prop, "Invert Vertex Group", "Invert source vertex group values"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "use_output_vertex_group_match_by_name", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_GPENCIL_MATCH_OUTPUT_VGROUP); + RNA_def_property_ui_text(prop, "Match Output", "Match output vertex group based on name"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "use_face_mark", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_FILTER_FACE_MARK); + RNA_def_property_ui_text( + prop, "Filter Face Marks", "Filter feature lines using freestyle face marks"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "use_face_mark_invert", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_FILTER_FACE_MARK_INVERT); + RNA_def_property_ui_text(prop, "Invert", "Invert face mark filtering"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "use_face_mark_boundaries", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_FILTER_FACE_MARK_BOUNDARIES); + RNA_def_property_ui_text( + prop, "Boundaries", "Filtering feature lines on face mark boundaries as well"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + prop = RNA_def_property(srna, "chaining_image_threshold", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_ui_text( prop, @@ -2946,16 +2972,6 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for selected strokes"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - prop = RNA_def_property(srna, "invert_source_vertex_group", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_GPENCIL_INVERT_SOURCE_VGROUP); - RNA_def_property_ui_text(prop, "Invert Vertex Group", "Invert source vertex group values"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - - prop = RNA_def_property(srna, "use_output_vertex_group_match_by_name", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_GPENCIL_MATCH_OUTPUT_VGROUP); - RNA_def_property_ui_text(prop, "Match Output", "Match output vertex group based on name"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - prop = RNA_def_property(srna, "is_baked", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_GPENCIL_IS_BAKED); RNA_def_property_ui_text(prop, "Is Baked", "This modifier has baked data"); -- cgit v1.2.3