LineArt: Prioritize connecting chains from the same contour loop

This change allows the chaining function to select edges
from the same contour loop first, thus reduced rouge chain
connections (connected different objects instead of chaining
inside the same object first) and improved chaining quality.

This patch also included the default value change for chain
split threshold (Now don't split by default to make initial
result as smooth as possible)

Reviewed By: Sebastian Parborg (zeddb)

Differential Revision: https://developer.blender.org/D14950
This commit is contained in:
YimingWu 2022-05-18 15:23:43 +08:00
parent c8edc458d1
commit 2719869a2a
Notes: blender-bot 2023-02-14 09:24:53 +01:00
Referenced by issue #87739, Line Art further improvement list
3 changed files with 42 additions and 7 deletions

View File

@ -158,6 +158,8 @@ typedef struct LineartEdgeChain {
/** Chain now only contains one type of segments */
int type;
/** Will only connect chains that has the same loop id. */
int loop_id;
unsigned char material_mask_bits;
unsigned char intersection_mask;

View File

@ -617,9 +617,14 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
rb->chains.last = rb->chains.first = NULL;
int loop_id = 0;
while ((ec = BLI_pophead(&swap)) != NULL) {
ec->next = ec->prev = NULL;
BLI_addtail(&rb->chains, ec);
ec->loop_id = loop_id;
loop_id++;
LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first;
int fixed_occ = first_eci->occlusion;
unsigned char fixed_mask = first_eci->material_mask_bits;
@ -651,6 +656,7 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
new_ec = lineart_chain_create(rb);
new_ec->chain.first = eci;
new_ec->chain.last = ec->chain.last;
new_ec->loop_id = loop_id;
ec->chain.last = eci->prev;
((LineartEdgeChainItem *)ec->chain.last)->next = 0;
eci->prev = 0;
@ -743,6 +749,7 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
int occlusion,
unsigned char material_mask_bits,
unsigned char isec_mask,
int loop_id,
float dist,
float *result_new_len,
LineartBoundingArea *caller_ba)
@ -791,7 +798,11 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
float new_len = rb->use_geometry_space_chain ? len_v3v3(cre->eci->gpos, eci->gpos) :
len_v2v2(cre->eci->pos, eci->pos);
if (new_len < dist) {
/* Even if the vertex is not from the same contour loop, we try to chain it still if the
* distance is small enough. This way we can better chain smaller loops and smooth them out
* later. */
if (((cre->ec->loop_id == loop_id) && (new_len < dist)) ||
((cre->ec->loop_id != loop_id) && (new_len < dist / 10))) {
closest_cre = cre;
dist = new_len;
if (result_new_len) {
@ -815,6 +826,7 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
occlusion, \
material_mask_bits, \
isec_mask, \
loop_id, \
dist, \
&adjacent_new_len, \
ba); \
@ -844,7 +856,7 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
LineartChainRegisterEntry *closest_cre_l, *closest_cre_r, *closest_cre;
float dist = rb->chaining_image_threshold;
float dist_l, dist_r;
int occlusion, reverse_main;
int occlusion, reverse_main, loop_id;
unsigned char material_mask_bits, isec_mask;
ListBase swap = {0};
@ -863,6 +875,7 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
continue;
}
BLI_addtail(&rb->chains, ec);
loop_id = ec->loop_id;
if (ec->type == LRT_EDGE_FLAG_LOOSE && (!rb->use_loose_edge_chain)) {
continue;
@ -876,10 +889,28 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
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, eci_l, occlusion, material_mask_bits, isec_mask, dist, &dist_l, NULL);
closest_cre_r = lineart_chain_get_closest_cre(
rb, ba_r, ec, eci_r, occlusion, material_mask_bits, isec_mask, dist, &dist_r, NULL);
closest_cre_l = lineart_chain_get_closest_cre(rb,
ba_l,
ec,
eci_l,
occlusion,
material_mask_bits,
isec_mask,
loop_id,
dist,
&dist_l,
NULL);
closest_cre_r = lineart_chain_get_closest_cre(rb,
ba_r,
ec,
eci_r,
occlusion,
material_mask_bits,
isec_mask,
loop_id,
dist,
&dist_r,
NULL);
if (closest_cre_l && closest_cre_r) {
if (dist_l < dist_r) {
closest_cre = closest_cre_l;
@ -1192,6 +1223,8 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol
new_ec->object_ref = ec->object_ref;
new_ec->type = ec->type;
new_ec->level = ec->level;
new_ec->loop_id = ec->loop_id;
new_ec->intersection_mask = ec->intersection_mask;
new_ec->material_mask_bits = ec->material_mask_bits;
ec = new_ec;
}

View File

@ -303,7 +303,7 @@
.crease_threshold = DEG2RAD(140.0f), \
.calculation_flags = LRT_ALLOW_DUPLI_OBJECTS | LRT_ALLOW_CLIPPING_BOUNDARIES | \
LRT_USE_CREASE_ON_SHARP_EDGES | LRT_FILTER_FACE_MARK_KEEP_CONTOUR, \
.angle_splitting_threshold = DEG2RAD(60.0f), \
.angle_splitting_threshold = 0.0f, /* Do not split by default, this is for better chaining quality. */ \
.chaining_image_threshold = 0.001f, \
.chain_smooth_tolerance = 0.2f,\
.stroke_depth_offset = 0.05,\