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
This commit is contained in:
parent
ae085e301c
commit
3558bb8eae
Notes:
blender-bot
2023-03-17 09:53:02 +01:00
Referenced by commit 6aa29549e8
, Fix T103887: Line Art Vertex Weight Transfer to target group broken
Referenced by issue #103887, Regression: Line Art - Vertex Weight Transfer to a target group doesn't work
Referenced by issue #87739, Line Art further improvement list
Referenced by issue #89477, Crash and/or stall with some geometry
Referenced by issue #105640, Vertex Weight Proximity not working for Grease Pencil Thickness Modifier
|
@ -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(
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue