LineArt: Filtering intersection lines using mask numbers

Mask value works just like transparency mask.

You are able to select intersection lines inside a
collection or, between collections.

Reviewed By: Sebastian Parborg (zeddb)

Differential Revision: https://developer.blender.org/D11309
This commit is contained in:
YimingWu 2021-06-29 20:47:55 +08:00
parent 5d5cf53081
commit d1e0059eac
Notes: blender-bot 2023-02-13 18:10:36 +01:00
Referenced by issue #102503, Regression: GPencil Line Art modifier creates extra (offset) strokes on collection instances
Referenced by issue #87739, Line Art further improvement list
11 changed files with 217 additions and 100 deletions

View File

@ -86,6 +86,13 @@ class COLLECTION_PT_lineart_collection(CollectionButtonsPanel, Panel):
row = layout.row()
row.prop(collection, "lineart_usage")
layout.prop(collection, "lineart_use_intersection_mask")
row = layout.row(align=True, heading="Masks")
row.active = collection.lineart_use_intersection_mask
for i in range(0,8):
row.prop(collection, "lineart_intersection_mask", index=i, text=str(i), toggle=True)
classes = (
COLLECTION_PT_collection_flags,

View File

@ -101,8 +101,9 @@ static void generate_strokes_actual(
lmd->use_multiple_levels ? lmd->level_end : lmd->level_start,
lmd->target_material ? BKE_gpencil_object_material_index_get(ob, lmd->target_material) : 0,
lmd->edge_types,
lmd->material_mask_flags,
lmd->mask_switches,
lmd->material_mask_bits,
lmd->intersection_mask,
lmd->thickness,
lmd->opacity,
lmd->source_vertex_group,
@ -462,6 +463,32 @@ static void material_mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(col, ptr, "use_material_mask_match", 0, IFACE_("Match All Masks"), ICON_NONE);
}
static void intersection_panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
const bool is_baked = RNA_boolean_get(ptr, "is_baked");
uiLayoutSetEnabled(layout, !is_baked);
uiLayoutSetPropSep(layout, true);
uiLayoutSetActive(layout, RNA_boolean_get(ptr, "use_intersection"));
uiLayout *row = uiLayoutRow(layout, true);
uiLayoutSetPropDecorate(row, false);
uiLayout *sub = uiLayoutRowWithHeading(row, true, IFACE_("Masks"));
char text[2] = "0";
PropertyRNA *prop = RNA_struct_find_property(ptr, "use_intersection_mask");
for (int i = 0; i < 8; i++, text[0]++) {
uiItemFullR(sub, ptr, prop, i, 0, UI_ITEM_R_TOGGLE, text, ICON_NONE);
}
uiItemL(row, "", ICON_BLANK1); /* Space for decorator. */
uiLayout *col = uiLayoutColumn(layout, true);
uiItemR(col, ptr, "use_intersection_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;
@ -626,6 +653,8 @@ static void panelRegister(ARegionType *region_type)
material_mask_panel_draw_header,
material_mask_panel_draw,
occlusion_panel);
gpencil_modifier_subpanel_register(
region_type, "intersection", "Intersection", NULL, intersection_panel_draw, panel_type);
gpencil_modifier_subpanel_register(
region_type, "face_mark", "", face_mark_panel_draw_header, face_mark_panel_draw, panel_type);
gpencil_modifier_subpanel_register(

View File

@ -52,8 +52,8 @@ typedef struct LineartTriangle {
/* first culled in line list to use adjacent triangle info, then go through triangle list. */
double gn[3];
/* Material flag is removed to save space. */
unsigned char material_mask_bits;
unsigned char intersection_mask;
unsigned char mat_occlusion;
unsigned char flags; /* #eLineartTriangleFlags */
@ -149,6 +149,7 @@ typedef struct LineartEdge {
/** Also for line type determination on chaining. */
unsigned char flags;
unsigned char intersection_mask;
/**
* Still need this entry because culled lines will not add to object
@ -174,6 +175,7 @@ typedef struct LineartEdgeChain {
/** Chain now only contains one type of segments */
int type;
unsigned char material_mask_bits;
unsigned char intersection_mask;
struct Object *object_ref;
} LineartEdgeChain;
@ -188,6 +190,7 @@ typedef struct LineartEdgeChainItem {
unsigned char line_type;
char occlusion;
unsigned char material_mask_bits;
unsigned char intersection_mask;
size_t index;
} LineartEdgeChainItem;
@ -377,6 +380,7 @@ typedef struct LineartObjectInfo {
double normal[4][4];
LineartElementLinkNode *v_eln;
int usage;
uint8_t override_intersection_mask;
int global_i_offset;
bool free_use_mesh;
@ -612,8 +616,9 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
int level_end,
int mat_nr,
short edge_types,
unsigned char material_mask_flags,
unsigned char mask_switches,
unsigned char material_mask_bits,
unsigned char intersection_mask,
short thickness,
float opacity,
const char *source_vgname,

View File

@ -38,7 +38,8 @@
static LineartEdge *lineart_line_get_connected(LineartBoundingArea *ba,
LineartVert *vt,
LineartVert **new_vt,
int match_flag)
int match_flag,
unsigned char match_isec_mask)
{
for (int i = 0; i < ba->line_count; i++) {
LineartEdge *n_e = ba->linked_lines[i];
@ -51,6 +52,10 @@ static LineartEdge *lineart_line_get_connected(LineartBoundingArea *ba,
continue;
}
if (n_e->intersection_mask != match_isec_mask) {
continue;
}
*new_vt = LRT_OTHER_VERT(n_e, vt);
if (*new_vt) {
return n_e;
@ -112,11 +117,11 @@ static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb,
/* Because the new chain point is overlapping, just replace the type and occlusion level of the
* current point. This makes it so that the line to the point after this one has the correct
* type and level. */
LineartEdgeChainItem *old_rlci = ec->chain.last;
old_rlci->line_type = type;
old_rlci->occlusion = level;
old_rlci->material_mask_bits = material_mask_bits;
return old_rlci;
LineartEdgeChainItem *old_eci = ec->chain.last;
old_eci->line_type = type;
old_eci->occlusion = level;
old_eci->material_mask_bits = material_mask_bits;
return old_eci;
}
eci = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChainItem));
@ -194,9 +199,10 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
ec = lineart_chain_create(rb);
/* One chain can only have one object_ref,
* so we assign it based on the first segment we found. */
/* One chain can only have one object_ref and intersection_mask,
* so we assign them based on the first segment we found. */
ec->object_ref = e->object_ref;
ec->intersection_mask = e->intersection_mask;
LineartEdge *new_e;
LineartVert *new_vt;
@ -230,7 +236,8 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
es->occlusion,
es->material_mask_bits,
e->v1_obindex);
while (ba && (new_e = lineart_line_get_connected(ba, new_vt, &new_vt, e->flags))) {
while (ba && (new_e = lineart_line_get_connected(
ba, new_vt, &new_vt, e->flags, e->intersection_mask))) {
new_e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED;
if (new_e->t1 || new_e->t2) {
@ -360,7 +367,8 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
/* Step 3: grow right. */
ba = MOD_lineart_get_bounding_area(rb, e->v2->fbcoord[0], e->v2->fbcoord[1]);
new_vt = e->v2;
while (ba && (new_e = lineart_line_get_connected(ba, new_vt, &new_vt, e->flags))) {
while (ba && (new_e = lineart_line_get_connected(
ba, new_vt, &new_vt, e->flags, e->intersection_mask))) {
new_e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED;
if (new_e->t1 || new_e->t2) {
@ -560,8 +568,8 @@ static void lineart_bounding_area_link_chain(LineartRenderBuffer *rb, LineartEdg
void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
{
LineartEdgeChain *ec, *new_rlc;
LineartEdgeChainItem *eci, *next_rlci;
LineartEdgeChain *ec, *new_ec;
LineartEdgeChainItem *eci, *next_eci;
ListBase swap = {0};
swap.first = rb->chains.first;
@ -572,16 +580,16 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
while ((ec = BLI_pophead(&swap)) != NULL) {
ec->next = ec->prev = NULL;
BLI_addtail(&rb->chains, ec);
LineartEdgeChainItem *first_rlci = (LineartEdgeChainItem *)ec->chain.first;
int fixed_occ = first_rlci->occlusion;
unsigned char fixed_mask = first_rlci->material_mask_bits;
LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first;
int fixed_occ = first_eci->occlusion;
unsigned char fixed_mask = first_eci->material_mask_bits;
ec->level = fixed_occ;
ec->material_mask_bits = fixed_mask;
for (eci = first_rlci->next; eci; eci = next_rlci) {
next_rlci = eci->next;
for (eci = first_eci->next; eci; eci = next_eci) {
next_eci = eci->next;
if (eci->occlusion != fixed_occ || eci->material_mask_bits != fixed_mask) {
if (next_rlci) {
if (lineart_point_overlapping(next_rlci, eci->pos[0], eci->pos[1], 1e-5)) {
if (next_eci) {
if (lineart_point_overlapping(next_eci, eci->pos[0], eci->pos[1], 1e-5)) {
continue;
}
}
@ -593,9 +601,9 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
/* No need to split at the last point anyway. */
break;
}
new_rlc = lineart_chain_create(rb);
new_rlc->chain.first = eci;
new_rlc->chain.last = ec->chain.last;
new_ec = lineart_chain_create(rb);
new_ec->chain.first = eci;
new_ec->chain.last = ec->chain.last;
ec->chain.last = eci->prev;
((LineartEdgeChainItem *)ec->chain.last)->next = 0;
eci->prev = 0;
@ -610,9 +618,10 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
fixed_occ,
fixed_mask,
eci->index);
new_rlc->object_ref = ec->object_ref;
new_rlc->type = ec->type;
ec = new_rlc;
new_ec->object_ref = ec->object_ref;
new_ec->type = ec->type;
new_ec->intersection_mask = ec->intersection_mask;
ec = new_ec;
fixed_occ = eci->occlusion;
fixed_mask = eci->material_mask_bits;
ec->level = fixed_occ;
@ -684,6 +693,7 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
LineartEdgeChainItem *eci,
int occlusion,
unsigned char material_mask_bits,
unsigned char isec_mask,
float dist,
float *result_new_len,
LineartBoundingArea *caller_ba)
@ -712,7 +722,8 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
continue;
}
if (cre->ec == ec || (!cre->ec->chain.first) || (cre->ec->level != occlusion) ||
(cre->ec->material_mask_bits != material_mask_bits)) {
(cre->ec->material_mask_bits != material_mask_bits) ||
(cre->ec->intersection_mask != isec_mask)) {
continue;
}
if (!rb->fuzzy_everything) {
@ -748,8 +759,16 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
if (dist_to < dist && dist_to > 0) { \
LISTBASE_FOREACH (LinkData *, ld, list) { \
LineartBoundingArea *sba = (LineartBoundingArea *)ld->data; \
adjacent_closest = lineart_chain_get_closest_cre( \
rb, sba, ec, eci, occlusion, material_mask_bits, dist, &adjacent_new_len, ba); \
adjacent_closest = lineart_chain_get_closest_cre(rb, \
sba, \
ec, \
eci, \
occlusion, \
material_mask_bits, \
isec_mask, \
dist, \
&adjacent_new_len, \
ba); \
if (adjacent_new_len < dist) { \
dist = adjacent_new_len; \
closest_cre = adjacent_closest; \
@ -776,13 +795,13 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
{
LineartEdgeChain *ec;
LineartEdgeChainItem *rlci_l, *rlci_r;
LineartEdgeChainItem *eci_l, *eci_r;
LineartBoundingArea *ba_l, *ba_r;
LineartChainRegisterEntry *closest_cre_l, *closest_cre_r, *closest_cre;
float dist = rb->chaining_image_threshold;
float dist_l, dist_r;
int occlusion, reverse_main;
unsigned char material_mask_bits;
unsigned char material_mask_bits, isec_mask;
ListBase swap = {0};
if (rb->chaining_image_threshold < 0.0001) {
@ -807,15 +826,16 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
occlusion = ec->level;
material_mask_bits = ec->material_mask_bits;
isec_mask = ec->intersection_mask;
rlci_l = ec->chain.first;
rlci_r = ec->chain.last;
while ((ba_l = lineart_bounding_area_get_end_point(rb, rlci_l)) &&
(ba_r = lineart_bounding_area_get_end_point(rb, rlci_r))) {
eci_l = ec->chain.first;
eci_r = ec->chain.last;
while ((ba_l = lineart_bounding_area_get_end_point(rb, eci_l)) &&
(ba_r = lineart_bounding_area_get_end_point(rb, eci_r))) {
closest_cre_l = lineart_chain_get_closest_cre(
rb, ba_l, ec, rlci_l, occlusion, material_mask_bits, dist, &dist_l, NULL);
rb, ba_l, ec, eci_l, occlusion, material_mask_bits, isec_mask, dist, &dist_l, NULL);
closest_cre_r = lineart_chain_get_closest_cre(
rb, ba_r, ec, rlci_r, occlusion, material_mask_bits, dist, &dist_r, NULL);
rb, ba_r, ec, eci_r, occlusion, material_mask_bits, isec_mask, dist, &dist_r, NULL);
if (closest_cre_l && closest_cre_r) {
if (dist_l < dist_r) {
closest_cre = closest_cre_l;
@ -847,8 +867,8 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
lineart_chain_connect(rb, ec, closest_cre->ec, reverse_main, 1);
}
BLI_remlink(&swap, closest_cre->ec);
rlci_l = ec->chain.first;
rlci_r = ec->chain.last;
eci_l = ec->chain.first;
eci_r = ec->chain.last;
}
ec->picked = 1;
}
@ -876,9 +896,9 @@ float MOD_lineart_chain_compute_length(LineartEdgeChain *ec)
void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold)
{
LineartEdgeChain *ec, *next_rlc;
for (ec = rb->chains.first; ec; ec = next_rlc) {
next_rlc = ec->next;
LineartEdgeChain *ec, *next_ec;
for (ec = rb->chains.first; ec; ec = next_ec) {
next_ec = ec->next;
if (MOD_lineart_chain_compute_length(ec) < threshold) {
BLI_remlink(&rb->chains, ec);
}
@ -910,8 +930,8 @@ void MOD_lineart_chain_clear_picked_flag(LineartCache *lc)
*/
void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad)
{
LineartEdgeChain *ec, *new_rlc;
LineartEdgeChainItem *eci, *next_rlci, *prev_rlci;
LineartEdgeChain *ec, *new_ec;
LineartEdgeChainItem *eci, *next_eci, *prev_eci;
ListBase swap = {0};
swap.first = rb->chains.first;
@ -922,21 +942,21 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol
while ((ec = BLI_pophead(&swap)) != NULL) {
ec->next = ec->prev = NULL;
BLI_addtail(&rb->chains, ec);
LineartEdgeChainItem *first_rlci = (LineartEdgeChainItem *)ec->chain.first;
for (eci = first_rlci->next; eci; eci = next_rlci) {
next_rlci = eci->next;
prev_rlci = eci->prev;
LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first;
for (eci = first_eci->next; eci; eci = next_eci) {
next_eci = eci->next;
prev_eci = eci->prev;
float angle = M_PI;
if (next_rlci && prev_rlci) {
angle = angle_v2v2v2(prev_rlci->pos, eci->pos, next_rlci->pos);
if (next_eci && prev_eci) {
angle = angle_v2v2v2(prev_eci->pos, eci->pos, next_eci->pos);
}
else {
break; /* No need to split at the last point anyway. */
}
if (angle < angle_threshold_rad) {
new_rlc = lineart_chain_create(rb);
new_rlc->chain.first = eci;
new_rlc->chain.last = ec->chain.last;
new_ec = lineart_chain_create(rb);
new_ec->chain.first = eci;
new_ec->chain.last = ec->chain.last;
ec->chain.last = eci->prev;
((LineartEdgeChainItem *)ec->chain.last)->next = 0;
eci->prev = 0;
@ -951,11 +971,11 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol
ec->level,
eci->material_mask_bits,
eci->index);
new_rlc->object_ref = ec->object_ref;
new_rlc->type = ec->type;
new_rlc->level = ec->level;
new_rlc->material_mask_bits = ec->material_mask_bits;
ec = new_rlc;
new_ec->object_ref = ec->object_ref;
new_ec->type = ec->type;
new_ec->level = ec->level;
new_ec->material_mask_bits = ec->material_mask_bits;
ec = new_ec;
}
}
}

View File

@ -875,7 +875,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
* (!in0) means "when point 0 is visible".
* conditions for point 1, 2 are the same idea.
*
* \code{.txt}
* \code{.txt}identify
* 1-----|-------0
* | | ---
* | |---
@ -1807,6 +1807,8 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu
mat->lineart.mat_occlusion :
1);
tri->intersection_mask = obi->override_intersection_mask;
double gn[3];
copy_v3db_v3fl(gn, f->no);
mul_v3_mat3_m4v3_db(tri->gn, normal, gn);
@ -1945,13 +1947,30 @@ static bool _lineart_object_not_in_source_collection(Collection *source, Object
return true;
}
static uchar lineart_intersection_mask_check(Collection *c, Object *ob)
{
LISTBASE_FOREACH (CollectionChild *, cc, &c->children) {
uchar result = lineart_intersection_mask_check(cc->collection, ob);
if (result) {
return result;
}
}
if (c->children.first == NULL) {
if (BKE_collection_has_object(c, (Object *)(ob->id.orig_id))) {
if (c->lineart_flags & COLLECTION_LRT_USE_INTERSECTION_MASK) {
return c->lineart_intersection_mask;
}
}
}
return 0;
}
/**
* See if this object in such collection is used for generating line art,
* Disabling a collection for line art will doable all objects inside.
* `_rb` is used to provide source selection info.
* See the definition of `rb->_source_type` for details.
*/
static int lineart_usage_check(Collection *c, Object *ob, LineartRenderBuffer *_rb)
static int lineart_usage_check(Collection *c, Object *ob)
{
if (!c) {
@ -1981,29 +2000,15 @@ static int lineart_usage_check(Collection *c, Object *ob, LineartRenderBuffer *_
}
return ob->lineart.usage;
}
return OBJECT_LRT_INHERIT;
}
LISTBASE_FOREACH (CollectionChild *, cc, &c->children) {
int result = lineart_usage_check(cc->collection, ob, _rb);
int result = lineart_usage_check(cc->collection, ob);
if (result > OBJECT_LRT_INHERIT) {
return result;
}
}
/* Temp solution to speed up calculation in the modifier without cache. See the definition of
* rb->_source_type for details. */
if (_rb->_source_type == LRT_SOURCE_OBJECT) {
if (ob != _rb->_source_object && ob->id.orig_id != (ID *)_rb->_source_object) {
return OBJECT_LRT_OCCLUSION_ONLY;
}
}
else if (_rb->_source_type == LRT_SOURCE_COLLECTION) {
if (_lineart_object_not_in_source_collection(_rb->_source_collection, ob)) {
return OBJECT_LRT_OCCLUSION_ONLY;
}
}
return OBJECT_LRT_INHERIT;
}
@ -2123,7 +2128,9 @@ static void lineart_main_load_geometries(
DEG_OBJECT_ITER_BEGIN (depsgraph, ob, flags) {
LineartObjectInfo *obi = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartObjectInfo));
obi->usage = lineart_usage_check(scene->master_collection, ob, rb);
obi->usage = lineart_usage_check(scene->master_collection, ob);
obi->override_intersection_mask = lineart_intersection_mask_check(scene->master_collection,
ob);
Mesh *use_mesh;
if (obi->usage == OBJECT_LRT_EXCLUDE) {
@ -2841,6 +2848,7 @@ static LineartEdge *lineart_triangle_intersect(LineartRenderBuffer *rb,
BLI_addtail(&result->segments, es);
/* Don't need to OR flags right now, just a type mark. */
result->flags = LRT_EDGE_FLAG_INTERSECTION;
result->intersection_mask = (tri->intersection_mask | testing->intersection_mask);
lineart_prepend_edge_direct(&rb->intersection.first, result);
int r1, r2, c1, c2, row, col;
@ -4191,8 +4199,9 @@ static void lineart_gpencil_generate(LineartCache *cache,
Object *source_object,
Collection *source_collection,
int types,
uchar material_mask_flags,
uchar mask_switches,
uchar material_mask_bits,
uchar intersection_mask,
short thickness,
float opacity,
const char *source_vgname,
@ -4248,8 +4257,8 @@ static void lineart_gpencil_generate(LineartCache *cache,
continue;
}
}
if (material_mask_flags & LRT_GPENCIL_MATERIAL_MASK_ENABLE) {
if (material_mask_flags & LRT_GPENCIL_MATERIAL_MASK_MATCH) {
if (mask_switches & LRT_GPENCIL_MATERIAL_MASK_ENABLE) {
if (mask_switches & LRT_GPENCIL_MATERIAL_MASK_MATCH) {
if (ec->material_mask_bits != material_mask_bits) {
continue;
}
@ -4260,6 +4269,18 @@ static void lineart_gpencil_generate(LineartCache *cache,
}
}
}
if (types & LRT_EDGE_FLAG_INTERSECTION) {
if (mask_switches & LRT_GPENCIL_INTERSECTION_MATCH) {
if (ec->intersection_mask != intersection_mask) {
continue;
}
}
else {
if ((intersection_mask) && !(ec->intersection_mask & intersection_mask)) {
continue;
}
}
}
/* Preserved: If we ever do asynchronous generation, this picked flag should be set here. */
// ec->picked = 1;
@ -4354,8 +4375,9 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
int level_end,
int mat_nr,
short edge_types,
uchar material_mask_flags,
uchar mask_switches,
uchar material_mask_bits,
uchar intersection_mask,
short thickness,
float opacity,
const char *source_vgname,
@ -4403,8 +4425,9 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
source_object,
source_collection,
use_types,
material_mask_flags,
mask_switches,
material_mask_bits,
intersection_mask,
thickness,
opacity,
source_vgname,

View File

@ -143,8 +143,9 @@ static bool bake_strokes(Object *ob,
lmd->use_multiple_levels ? lmd->level_end : lmd->level_start,
lmd->target_material ? BKE_gpencil_object_material_index_get(ob, lmd->target_material) : 0,
lmd->edge_types,
lmd->material_mask_flags,
lmd->mask_switches,
lmd->material_mask_bits,
lmd->intersection_mask,
lmd->thickness,
lmd->opacity,
lmd->source_vertex_group,

View File

@ -46,9 +46,6 @@ typedef struct CollectionChild {
struct Collection *collection;
} CollectionChild;
/**
* \warning while the values seem to be flags, they aren't treated as flags.
*/
enum eCollectionLineArt_Usage {
COLLECTION_LRT_INCLUDE = 0,
COLLECTION_LRT_OCCLUSION_ONLY = (1 << 0),
@ -57,6 +54,10 @@ enum eCollectionLineArt_Usage {
COLLECTION_LRT_NO_INTERSECTION = (1 << 3),
};
enum eCollectionLineArt_Flags {
COLLECTION_LRT_USE_INTERSECTION_MASK = (1 << 0),
};
typedef struct Collection {
ID id;
@ -74,8 +75,10 @@ typedef struct Collection {
/* Runtime-only, always cleared on file load. */
short tag;
/** Line Art engine specific */
short lineart_usage;
short lineart_usage; /* eCollectionLineArt_Usage */
unsigned char lineart_flags; /* eCollectionLineArt_Flags */
unsigned char lineart_intersection_mask;
char _pad[6];
int16_t color_tag;

View File

@ -883,11 +883,14 @@ typedef enum eLineArtGPencilModifierFlags {
LRT_GPENCIL_USE_CACHE = (1 << 4),
} eLineArtGPencilModifierFlags;
typedef enum eLineartGpencilMaterialMaskFlags {
typedef enum eLineartGpencilMaskSwitches {
LRT_GPENCIL_MATERIAL_MASK_ENABLE = (1 << 0),
/** When set, material mask bit comparisons are done with bit wise "AND" instead of "OR". */
LRT_GPENCIL_MATERIAL_MASK_MATCH = (1 << 1),
} eLineartGpencilMaterialMaskFlags;
LRT_GPENCIL_INTERSECTION_MATCH = (1 << 2),
} eLineartGpencilMaskSwitches;
struct LineartCache;
struct LineartCache;
@ -918,8 +921,11 @@ typedef struct LineartGpencilModifierData {
float opacity;
short thickness;
unsigned char material_mask_flags; /* eLineartGpencilMaterialMaskFlags */
unsigned char mask_switches; /* eLineartGpencilMaskSwitches */
unsigned char material_mask_bits;
unsigned char intersection_mask;
char _pad[7];
/** `0..1` range for cosine angle */
float crease_threshold;

View File

@ -134,6 +134,6 @@ DNA_STRUCT_RENAME_ELEM(RigidBodyWorld, steps_per_second, substeps_per_frame)
* global_areas. See D9442. */
DNA_STRUCT_RENAME_ELEM(wmWindow, global_area_map, global_areas)
DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, line_types, edge_types)
DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_flags, material_mask_flags)
DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_flags, mask_switches)
DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_mask, material_mask_bits)
DNA_STRUCT_RENAME_ELEM(MaterialLineArt, transparency_mask, material_mask_bits)

View File

@ -548,6 +548,19 @@ void RNA_def_collections(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Usage", "How to use this collection in line art");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "lineart_use_intersection_mask", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "lineart_flags", 1);
RNA_def_property_ui_text(
prop, "Use Intersection Masks", "Use custom intersection mask for faces in this collection");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "lineart_intersection_mask", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "lineart_intersection_mask", 1);
RNA_def_property_array(prop, 8);
RNA_def_property_ui_text(
prop, "Masks", "Intersection generated by this collection will have this mask value");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "color_tag", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "color_tag");
RNA_def_property_enum_funcs(

View File

@ -2997,15 +2997,13 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "use_material_mask", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(
prop, NULL, "material_mask_flags", LRT_GPENCIL_MATERIAL_MASK_ENABLE);
RNA_def_property_boolean_sdna(prop, NULL, "mask_switches", LRT_GPENCIL_MATERIAL_MASK_ENABLE);
RNA_def_property_ui_text(
prop, "Use Material Mask", "Use material masks to filter out occluded strokes");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "use_material_mask_match", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(
prop, NULL, "material_mask_flags", LRT_GPENCIL_MATERIAL_MASK_MATCH);
RNA_def_property_boolean_sdna(prop, NULL, "mask_switches", LRT_GPENCIL_MATERIAL_MASK_MATCH);
RNA_def_property_ui_text(
prop, "Match Masks", "Require matching all material masks instead of just one");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
@ -3013,7 +3011,19 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_material_mask_bits", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "material_mask_bits", 1);
RNA_def_property_array(prop, 8);
RNA_def_property_ui_text(prop, "Mask", "");
RNA_def_property_ui_text(prop, "Masks", "Mask bits to match from Material Line Art settings");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "use_intersection_match", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mask_switches", LRT_GPENCIL_INTERSECTION_MATCH);
RNA_def_property_ui_text(
prop, "Match Intersection", "Require matching all intersection masks instead of just one");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "use_intersection_mask", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "intersection_mask", 1);
RNA_def_property_array(prop, 8);
RNA_def_property_ui_text(prop, "Masks", "Mask bits to match from Collection Line Art settings");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
RNA_define_lib_overridable(false);