LineArt: More type & related chaining improvements

This patch includes: Floating edge type support,
Special chaining option for floating edge,
Chaining option for reducing jagged edges when floating
edges are involved.

Reviewed By: Sebastian Parborg (zeddb)

Differential Revision: https://developer.blender.org/D11306
This commit is contained in:
YimingWu 2021-06-25 13:15:25 +08:00
parent 3d7021b4ec
commit 841df831e8
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 #105640, Vertex Weight Proximity not working for Grease Pencil Thickness Modifier
8 changed files with 202 additions and 58 deletions

View File

@ -305,6 +305,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayout *col = uiLayoutColumnWithHeading(layout, true, IFACE_("Edge Types"));
uiItemR(col, ptr, "use_contour", 0, IFACE_("Contour"), ICON_NONE);
uiItemR(col, ptr, "use_floating", 0, IFACE_("Floating"), ICON_NONE);
uiItemR(col, ptr, "use_material", 0, IFACE_("Material Borders"), ICON_NONE);
uiItemR(col, ptr, "use_edge_mark", 0, IFACE_("Edge Marks"), ICON_NONE);
uiItemR(col, ptr, "use_intersection", 0, IFACE_("Intersections"), ICON_NONE);
@ -312,7 +313,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayout *sub = uiLayoutRowWithHeading(col, false, IFACE_("Crease"));
uiItemR(sub, ptr, "use_crease", 0, "", ICON_NONE);
uiLayout *entry = uiLayoutRow(sub, false);
uiLayoutSetActive(entry, RNA_boolean_get(ptr, "use_crease") || is_first);
uiLayoutSetEnabled(entry, RNA_boolean_get(ptr, "use_crease") || is_first);
if (use_cache && !is_first) {
uiItemL(entry, IFACE_("Angle Cached"), ICON_INFO);
}
@ -368,6 +369,7 @@ static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(col, ptr, "use_edge_overlap", 0, IFACE_("Overlapping Edges As Contour"), ICON_NONE);
uiItemR(col, ptr, "use_object_instances", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_clip_plane_boundaries", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "allow_overlap_edge_types", 0, NULL, ICON_NONE);
}
static void style_panel_draw(const bContext *UNUSED(C), Panel *panel)
@ -430,7 +432,7 @@ static void transparency_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetPropSep(layout, true);
uiLayoutSetActive(layout, RNA_boolean_get(ptr, "use_transparency"));
uiLayoutSetEnabled(layout, RNA_boolean_get(ptr, "use_transparency"));
uiLayout *row = uiLayoutRow(layout, true);
uiLayoutSetPropDecorate(row, false);
@ -457,6 +459,7 @@ static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel)
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);
const bool is_geom = RNA_boolean_get(ptr, "chain_geometry_space");
uiLayoutSetPropSep(layout, true);
uiLayoutSetEnabled(layout, !is_baked);
@ -469,8 +472,16 @@ static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayout *col = uiLayoutColumnWithHeading(layout, true, IFACE_("Chain"));
uiItemR(col, ptr, "use_fuzzy_intersections", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_fuzzy_all", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "chain_floating_edges", 0, IFACE_("Floating Edges"), ICON_NONE);
uiItemR(col, ptr, "floating_as_contour", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "chain_geometry_space", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "chaining_image_threshold", 0, NULL, ICON_NONE);
uiItemR(layout,
ptr,
"chaining_image_threshold",
0,
is_geom ? IFACE_("Geometry Threshold") : NULL,
ICON_NONE);
uiItemR(layout, ptr, "split_angle", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}

View File

@ -189,7 +189,7 @@ typedef struct LineartEdgeChainItem {
/** For restoring position to 3d space */
float gpos[3];
float normal[3];
char line_type;
unsigned char line_type;
char occlusion;
unsigned char transparency_mask;
size_t index;
@ -267,6 +267,7 @@ typedef struct LineartRenderBuffer {
ListBase crease;
ListBase material;
ListBase edge_mark;
ListBase floating;
ListBase chains;
@ -287,11 +288,16 @@ typedef struct LineartRenderBuffer {
bool use_material;
bool use_edge_marks;
bool use_intersections;
bool use_floating;
bool fuzzy_intersections;
bool fuzzy_everything;
bool allow_boundaries;
bool allow_overlapping_edges;
bool allow_duplicated_types;
bool remove_doubles;
bool floating_as_contour;
bool chain_floating_edges;
bool chain_geometry_space;
/* Keep an copy of these data so when line art is running it's self-contained. */
bool cam_is_persp;
@ -358,11 +364,10 @@ typedef struct LineartRenderTaskInfo {
ListBase crease;
ListBase material;
ListBase edge_mark;
ListBase floating;
} LineartRenderTaskInfo;
struct BMesh;
typedef struct LineartObjectInfo {
struct LineartObjectInfo *next;
struct Object *original_ob;
@ -370,7 +375,7 @@ typedef struct LineartObjectInfo {
double model_view_proj[4][4];
double model_view[4][4];
double normal[4][4];
LineartElementLinkNode *v_reln;
LineartElementLinkNode *v_eln;
int usage;
int global_i_offset;

View File

@ -729,7 +729,8 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
}
}
float new_len = len_v2v2(cre->eci->pos, eci->pos);
float new_len = rb->chain_geometry_space ? len_v3v3(cre->eci->gpos, eci->gpos) :
len_v2v2(cre->eci->pos, eci->pos);
if (new_len < dist) {
closest_cre = cre;
dist = new_len;
@ -800,6 +801,10 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
}
BLI_addtail(&rb->chains, ec);
if (ec->type == LRT_EDGE_FLAG_FLOATING && (!rb->chain_floating_edges)) {
continue;
}
occlusion = ec->level;
transparency_mask = ec->transparency_mask;

View File

@ -430,6 +430,7 @@ static int lineart_occlusion_make_task_info(LineartRenderBuffer *rb, LineartRend
LRT_ASSIGN_OCCLUSION_TASK(crease);
LRT_ASSIGN_OCCLUSION_TASK(material);
LRT_ASSIGN_OCCLUSION_TASK(edge_mark);
LRT_ASSIGN_OCCLUSION_TASK(floating);
#undef LRT_ASSIGN_OCCLUSION_TASK
@ -464,6 +465,10 @@ static void lineart_occlusion_worker(TaskPool *__restrict UNUSED(pool), LineartR
for (eip = rti->edge_mark.first; eip && eip != rti->edge_mark.last; eip = eip->next) {
lineart_occlusion_single_line(rb, eip, rti->thread_id);
}
for (eip = rti->floating.first; eip && eip != rti->floating.last; eip = eip->next) {
lineart_occlusion_single_line(rb, eip, rti->thread_id);
}
}
}
@ -486,6 +491,7 @@ static void lineart_main_occlusion_begin(LineartRenderBuffer *rb)
rb->intersection.last = rb->intersection.first;
rb->material.last = rb->material.first;
rb->edge_mark.last = rb->edge_mark.first;
rb->floating.last = rb->floating.first;
TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH);
@ -720,6 +726,7 @@ static void lineart_triangle_post(LineartTriangle *tri, LineartTriangle *orig)
/* Just re-assign normal and set cull flag. */
copy_v3_v3_db(tri->gn, orig->gn);
tri->flags = LRT_CULL_GENERATED;
tri->transparency_mask = orig->transparency_mask;
}
static void lineart_triangle_set_cull_flag(LineartTriangle *tri, uchar flag)
@ -735,6 +742,16 @@ static bool lineart_edge_match(LineartTriangle *tri, LineartEdge *e, int v1, int
(tri->v[v2] == e->v1 && tri->v[v1] == e->v2));
}
static void lineart_discard_duplicated_edges(LineartEdge *old_e, int v1id, int v2id)
{
LineartEdge *e = old_e;
e++;
while (e->v1_obindex == v1id && e->v2_obindex == v2id) {
e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED;
e++;
}
}
/**
* Does near-plane cut on 1 triangle only. When cutting with far-plane, the camera vectors gets
* reversed by the caller so don't need to implement one in a different direction.
@ -800,6 +817,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
old_e = ta->e[e_num]; \
new_flag = old_e->flags; \
old_e->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
lineart_discard_duplicated_edges(old_e, old_e->v1_obindex, old_e->v2_obindex); \
INCREASE_EDGE \
e->v1 = (v1_link); \
e->v2 = (v2_link); \
@ -820,12 +838,15 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
#define REMOVE_TRIANGLE_EDGE \
if (ta->e[0]) { \
ta->e[0]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
lineart_discard_duplicated_edges(ta->e[0], ta->e[0]->v1_obindex, ta->e[0]->v2_obindex); \
} \
if (ta->e[1]) { \
ta->e[1]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
lineart_discard_duplicated_edges(ta->e[1], ta->e[1]->v1_obindex, ta->e[1]->v2_obindex); \
} \
if (ta->e[2]) { \
ta->e[2]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
lineart_discard_duplicated_edges(ta->e[2], ta->e[2]->v1_obindex, ta->e[2]->v2_obindex); \
}
switch (in0 + in1 + in2) {
@ -1432,8 +1453,25 @@ static char lineart_identify_feature_line(LineartRenderBuffer *rb,
lr = e->l->radial_next;
}
if (ll == lr || !lr) {
return LRT_EDGE_FLAG_CONTOUR;
if (!ll && !lr) {
if (!rb->floating_as_contour) {
return LRT_EDGE_FLAG_FLOATING;
}
}
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;
}
}
/* Mesh boundary */
if (!lr || ll == lr) {
return (edge_flag_result | LRT_EDGE_FLAG_CONTOUR);
}
LineartTriangle *tri1, *tri2;
@ -1449,7 +1487,6 @@ static char lineart_identify_feature_line(LineartRenderBuffer *rb,
double *view_vector = vv;
double dot_1 = 0, dot_2 = 0;
double result;
FreestyleEdge *fe;
if (rb->cam_is_persp) {
sub_v3_v3v3_db(view_vector, l->gloc, rb->camera_pos);
@ -1462,24 +1499,20 @@ static char lineart_identify_feature_line(LineartRenderBuffer *rb,
dot_2 = dot_v3v3_db(view_vector, tri2->gn);
if ((result = dot_1 * dot_2) <= 0 && (dot_1 + dot_2)) {
return LRT_EDGE_FLAG_CONTOUR;
edge_flag_result |= LRT_EDGE_FLAG_CONTOUR;
}
if (rb->use_crease && (dot_v3v3_db(tri1->gn, tri2->gn) < crease_threshold)) {
if (!no_crease) {
return LRT_EDGE_FLAG_CREASE;
edge_flag_result |= LRT_EDGE_FLAG_CREASE;
}
}
else if (rb->use_material && (ll->f->mat_nr != lr->f->mat_nr)) {
return LRT_EDGE_FLAG_MATERIAL;
if (rb->use_material && (ll->f->mat_nr != lr->f->mat_nr)) {
edge_flag_result |= LRT_EDGE_FLAG_MATERIAL;
}
else if (count_freestyle && rb->use_edge_marks) {
fe = CustomData_bmesh_get(&bm_if_freestyle->edata, e->head.data, CD_FREESTYLE_EDGE);
if (fe->flag & FREESTYLE_EDGE_MARK) {
return LRT_EDGE_FLAG_EDGE_MARK;
}
}
return 0;
return edge_flag_result;
}
static void lineart_add_edge_to_list(LineartRenderBuffer *rb, LineartEdge *e)
@ -1527,6 +1560,9 @@ static void lineart_add_edge_to_list_thread(LineartObjectInfo *obi, LineartEdge
case LRT_EDGE_FLAG_INTERSECTION:
LRT_ASSIGN_EDGE(intersection);
break;
case LRT_EDGE_FLAG_FLOATING:
LRT_ASSIGN_EDGE(floating);
break;
}
#undef LRT_ASSIGN_EDGE
}
@ -1543,6 +1579,7 @@ static void lineart_finalize_object_edge_list(LineartRenderBuffer *rb, LineartOb
LRT_OBI_TO_RB(material);
LRT_OBI_TO_RB(edge_mark);
LRT_OBI_TO_RB(intersection);
LRT_OBI_TO_RB(floating);
#undef LRT_OBI_TO_RB
}
@ -1561,6 +1598,17 @@ static void lineart_triangle_adjacent_assign(LineartTriangle *tri,
}
}
static int lineart_edge_type_duplication_count(char eflag)
{
int count = 0;
/* See eLineartEdgeFlag for details. */
for (int i = 0; i < LRT_EDGE_FLAG_FLOATING; i++) {
if (eflag & (1 << i)) {
count++;
}
}
return count;
}
static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBuffer *rb)
{
BMesh *bm;
@ -1639,8 +1687,9 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu
CanFindFreestyle = 1;
}
/* Only allocate memory for verts and tris as we don't know how many lines we will generate
* yet. */
/* If we allow duplicated edges, one edge should get added multiple times if is has been
* classified as more than one edge type. This is so we can create multiple different line type
* chains containing the same edge. */
orv = lineart_mem_acquire_thread(&rb->render_data_pool, sizeof(LineartVert) * bm->totvert);
ort = lineart_mem_acquire_thread(&rb->render_data_pool, bm->totface * rb->triangle_size);
@ -1653,7 +1702,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu
eln->element_count = bm->totvert;
eln->object_ref = orig_ob;
obi->v_reln = eln;
obi->v_eln = eln;
if (orig_ob->lineart.flags & OBJECT_LRT_OWN_CREASE) {
use_crease = cosf(M_PI - orig_ob->lineart.crease_threshold);
@ -1741,8 +1790,9 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu
char eflag = lineart_identify_feature_line(
rb, e, ort, orv, use_crease, orig_ob->type == OB_FONT, CanFindFreestyle, bm);
if (eflag) {
/* Only allocate for feature lines (instead of all lines) to save memory. */
allocate_la_e++;
/* 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. */
allocate_la_e += rb->allow_duplicated_types ? lineart_edge_type_duplication_count(eflag) : 1;
}
/* Here we just use bm's flag for when loading actual lines, then we don't need to call
* lineart_identify_feature_line() again, e->head.hflag deleted after loading anyway. Always
@ -1770,30 +1820,50 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu
continue;
}
la_e->v1 = &orv[BM_elem_index_get(e->v1)];
la_e->v2 = &orv[BM_elem_index_get(e->v2)];
la_e->v1_obindex = la_e->v1->index;
la_e->v2_obindex = la_e->v2->index;
if (e->l) {
int findex = BM_elem_index_get(e->l->f);
la_e->t1 = lineart_triangle_from_index(rb, ort, findex);
lineart_triangle_adjacent_assign(la_e->t1, &orta[findex], la_e);
if (e->l->radial_next && e->l->radial_next != e->l) {
findex = BM_elem_index_get(e->l->radial_next->f);
la_e->t2 = lineart_triangle_from_index(rb, ort, findex);
lineart_triangle_adjacent_assign(la_e->t2, &orta[findex], la_e);
bool edge_added = false;
/* See eLineartEdgeFlag for details. */
for (int flag_bit = 0; flag_bit < LRT_EDGE_FLAG_FLOATING; flag_bit++) {
char use_type = 1 << flag_bit;
if (!(use_type & e->head.hflag)) {
continue;
}
la_e->v1 = &orv[BM_elem_index_get(e->v1)];
la_e->v2 = &orv[BM_elem_index_get(e->v2)];
la_e->v1_obindex = la_e->v1->index;
la_e->v2_obindex = la_e->v2->index;
if (e->l) {
int findex = BM_elem_index_get(e->l->f);
la_e->t1 = lineart_triangle_from_index(rb, ort, findex);
if (!edge_added) {
lineart_triangle_adjacent_assign(la_e->t1, &orta[findex], la_e);
}
if (e->l->radial_next && e->l->radial_next != e->l) {
findex = BM_elem_index_get(e->l->radial_next->f);
la_e->t2 = lineart_triangle_from_index(rb, ort, findex);
if (!edge_added) {
lineart_triangle_adjacent_assign(la_e->t2, &orta[findex], la_e);
}
}
}
la_e->flags = use_type;
la_e->object_ref = orig_ob;
BLI_addtail(&la_e->segments, la_s);
if (usage == OBJECT_LRT_INHERIT || usage == OBJECT_LRT_INCLUDE ||
usage == OBJECT_LRT_NO_INTERSECTION) {
lineart_add_edge_to_list_thread(obi, la_e);
}
edge_added = true;
la_e++;
la_s++;
if (!rb->allow_duplicated_types) {
break;
}
}
la_e->flags = e->head.hflag;
la_e->object_ref = orig_ob;
BLI_addtail(&la_e->segments, la_s);
if (usage == OBJECT_LRT_INHERIT || usage == OBJECT_LRT_INCLUDE ||
usage == OBJECT_LRT_NO_INTERSECTION) {
lineart_add_edge_to_list_thread(obi, la_e);
}
la_e++;
la_s++;
}
/* always free bm as it's a copy from before threading */
@ -1803,9 +1873,8 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu
static void lineart_object_load_worker(TaskPool *__restrict UNUSED(pool),
LineartObjectLoadTaskInfo *olti)
{
LineartRenderBuffer *rb = olti->rb;
for (LineartObjectInfo *obi = olti->pending; obi; obi = obi->next) {
lineart_geometry_object_load(obi, rb);
lineart_geometry_object_load(obi, olti->rb);
}
}
@ -1948,7 +2017,6 @@ static void lineart_main_load_geometries(
{
double proj[4][4], view[4][4], result[4][4];
float inv[4][4];
Camera *cam = camera->data;
float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
int fit = BKE_camera_sensor_fit(cam->sensor_fit, rb->w, rb->h);
@ -2071,11 +2139,11 @@ static void lineart_main_load_geometries(
for (int i = 0; i < thread_count; i++) {
for (LineartObjectInfo *obi = olti[i].pending; obi; obi = obi->next) {
if (!obi->v_reln) {
if (!obi->v_eln) {
continue;
}
LineartVert *v = (LineartVert *)obi->v_reln->pointer;
int v_count = obi->v_reln->element_count;
LineartVert *v = (LineartVert *)obi->v_eln->pointer;
int v_count = obi->v_eln->element_count;
for (int vi = 0; vi < v_count; vi++) {
v[vi].index += global_i;
}
@ -2823,6 +2891,7 @@ static void lineart_destroy_render_data(LineartRenderBuffer *rb)
memset(&rb->intersection, 0, sizeof(ListBase));
memset(&rb->edge_mark, 0, sizeof(ListBase));
memset(&rb->material, 0, sizeof(ListBase));
memset(&rb->floating, 0, sizeof(ListBase));
BLI_listbase_clear(&rb->chains);
BLI_listbase_clear(&rb->wasted_cuts);
@ -2919,10 +2988,15 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
rb->fuzzy_everything = (lmd->calculation_flags & LRT_EVERYTHING_AS_CONTOUR) != 0;
rb->allow_boundaries = (lmd->calculation_flags & LRT_ALLOW_CLIPPING_BOUNDARIES) != 0;
rb->remove_doubles = (lmd->calculation_flags & LRT_REMOVE_DOUBLES) != 0;
rb->floating_as_contour = (lmd->calculation_flags & LRT_FLOATING_AS_CONTOUR) != 0;
rb->chain_floating_edges = (lmd->calculation_flags & LRT_CHAIN_FLOATING_EDGES) != 0;
rb->chain_geometry_space = (lmd->calculation_flags & LRT_CHAIN_GEOMETRY_SPACE) != 0;
/* See lineart_edge_from_triangle() for how this option may impact performance. */
rb->allow_overlapping_edges = (lmd->calculation_flags & LRT_ALLOW_OVERLAPPING_EDGES) != 0;
rb->allow_duplicated_types = (lmd->calculation_flags & LRT_ALLOW_OVERLAP_EDGE_TYPES) != 0;
int16_t edge_types = lmd->edge_types_override;
rb->use_contour = (edge_types & LRT_EDGE_FLAG_CONTOUR) != 0;
@ -2930,6 +3004,7 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
rb->use_material = (edge_types & LRT_EDGE_FLAG_MATERIAL) != 0;
rb->use_edge_marks = (edge_types & LRT_EDGE_FLAG_EDGE_MARK) != 0;
rb->use_intersections = (edge_types & LRT_EDGE_FLAG_INTERSECTION) != 0;
rb->use_floating = (edge_types & LRT_EDGE_FLAG_FLOATING) != 0;
rb->chain_data_pool = &lc->chain_data_pool;
@ -4043,6 +4118,7 @@ static int UNUSED_FUNCTION(lineart_rb_edge_types)(LineartRenderBuffer *rb)
types |= rb->use_material ? LRT_EDGE_FLAG_MATERIAL : 0;
types |= rb->use_edge_marks ? LRT_EDGE_FLAG_EDGE_MARK : 0;
types |= rb->use_intersections ? LRT_EDGE_FLAG_INTERSECTION : 0;
types |= rb->use_floating ? LRT_EDGE_FLAG_FLOATING : 0;
return types;
}

View File

@ -98,6 +98,9 @@ void lineart_count_and_print_render_buffer_memory(struct LineartRenderBuffer *rb
if (!e) { \
e = rb->intersection.first; \
} \
if (!e) { \
e = rb->floating.first; \
} \
for (current_head = &rb->contour.first; e; e = next_e) { \
next_e = e->next;
@ -115,6 +118,9 @@ void lineart_count_and_print_render_buffer_memory(struct LineartRenderBuffer *rb
else if (current_head == &rb->edge_mark.first) { \
current_head = &rb->intersection.first; \
} \
else if (current_head == &rb->intersection.first) { \
current_head = &rb->floating.first; \
} \
else { \
break; \
} \

View File

@ -874,8 +874,9 @@ typedef enum eLineartGpencilModifierSource {
} eLineartGpencilModifierSource;
typedef enum eLineArtGPencilModifierFlags {
LRT_GPENCIL_INVERT_SOURCE_VGROUP = (1 << 0),
LRT_GPENCIL_MATCH_OUTPUT_VGROUP = (1 << 1),
/* These two moved to eLineartMainFlags to keep consistent with flag variable purpose. */
/* LRT_GPENCIL_INVERT_SOURCE_VGROUP = (1 << 0), */
/* LRT_GPENCIL_MATCH_OUTPUT_VGROUP = (1 << 1), */
LRT_GPENCIL_BINARY_WEIGHTS = (1 << 2) /* Deprecated, this is removed for lack of use case. */,
LRT_GPENCIL_IS_BAKED = (1 << 3),
LRT_GPENCIL_USE_CACHE = (1 << 4),
@ -925,7 +926,7 @@ typedef struct LineartGpencilModifierData {
/** `0..PI` angle, for splitting strokes at sharp points. */
float angle_splitting_threshold;
/* CPU mode */
/* Doubles as geometry threshold when geometry space chaining is enabled */
float chaining_image_threshold;
/* Ported from SceneLineArt flags. */

View File

@ -46,6 +46,15 @@ typedef enum eLineartMainFlags {
LRT_ALLOW_OVERLAPPING_EDGES = (1 << 3),
LRT_ALLOW_CLIPPING_BOUNDARIES = (1 << 4),
LRT_REMOVE_DOUBLES = (1 << 5),
LRT_FLOATING_AS_CONTOUR = (1 << 6),
LRT_GPENCIL_INVERT_SOURCE_VGROUP = (1 << 7),
LRT_GPENCIL_MATCH_OUTPUT_VGROUP = (1 << 8),
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),
} eLineartMainFlags;
typedef enum eLineartEdgeFlag {

View File

@ -2812,6 +2812,12 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
prop, "Remove Doubles", "Remove doubles from the source geometry before generating stokes");
RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
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_update(prop, NC_SCENE, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "chaining_image_threshold", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_ui_text(
prop,
@ -2821,6 +2827,26 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 0.3f);
RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "chain_floating_edges", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_CHAIN_FLOATING_EDGES);
RNA_def_property_ui_text(
prop, "Chain Floating Edges", "Allow floating edges to be chained together");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "chain_geometry_space", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_CHAIN_GEOMETRY_SPACE);
RNA_def_property_ui_text(
prop, "Use Geometry Space", "Use geometry distance for chaining instead of image space.");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "allow_overlap_edge_types", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_ALLOW_OVERLAP_EDGE_TYPES);
RNA_def_property_ui_text(prop,
"Overlapping Edge Types",
"Allow an edge to have multiple overlapping types. This will create an "
"individual stroke for each overlapping type");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "source_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, modifier_lineart_source_type);
RNA_def_property_ui_text(prop, "Source Type", "Line art stroke source type");
@ -2846,6 +2872,11 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use Contour", "Generate strokes from contours lines");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "use_floating", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "edge_types", LRT_EDGE_FLAG_FLOATING);
RNA_def_property_ui_text(prop, "Use Floating", "Generate strokes from floating edges");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "use_crease", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "edge_types", LRT_EDGE_FLAG_CREASE);
RNA_def_property_ui_text(prop, "Use Crease", "Generate strokes from creased edges");