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:
parent
5d5cf53081
commit
d1e0059eac
Notes:
blender-bot
2024-05-08 11:36:44 +02: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
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue