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:
parent
c8edc458d1
commit
2719869a2a
Notes:
blender-bot
2023-02-14 09:24:53 +01:00
Referenced by issue #87739, Line Art further improvement list
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,\
|
||||
|
|
Loading…
Reference in New Issue