diff options
author | YimingWu <xp8110@outlook.com> | 2021-10-26 19:10:25 +0300 |
---|---|---|
committer | YimingWu <xp8110@outlook.com> | 2021-10-26 19:10:49 +0300 |
commit | ec831ce5df86cbdbed8030d8a056f8a9b4eb0273 (patch) | |
tree | 8383daaf47fc9c59456f11b3e812109fe56d2cd5 /source/blender/gpencil_modifiers/intern | |
parent | 3371a4c472eef06d1c9e15451b245cb4575d667f (diff) |
LineArt: Trimming edges right at the image border
This option allows the edge to end right at the border
instead of extending beyond.
Useful when having multiple camera setup where you
want the border to be clean.
Also moved overscan option down inside "Composition" sub panel
so it makes more sense.
Reviewed By: Antonio Vazquez (antoniov)
Differential Revision: https://developer.blender.org/D12126
Diffstat (limited to 'source/blender/gpencil_modifiers/intern')
4 files changed, 137 insertions, 9 deletions
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c index 4ce1a903269..c6bc5a9e53e 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c @@ -406,7 +406,7 @@ static void options_panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemR(col, ptr, "use_object_instances", 0, NULL, ICON_NONE); uiItemR(col, ptr, "use_clip_plane_boundaries", 0, NULL, ICON_NONE); uiItemR(col, ptr, "use_crease_on_smooth", 0, IFACE_("Crease On Smooth"), ICON_NONE); - uiItemR(layout, ptr, "use_crease_on_sharp", 0, IFACE_("Crease On Sharp"), ICON_NONE); + uiItemR(col, ptr, "use_crease_on_sharp", 0, IFACE_("Crease On Sharp"), ICON_NONE); } static void style_panel_draw(const bContext *UNUSED(C), Panel *panel) @@ -692,6 +692,9 @@ static void composition_panel_draw(const bContext *UNUSED(C), Panel *panel) uiLayoutSetPropSep(layout, true); + uiItemR(layout, ptr, "overscan", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_image_boundary_trimming", 0, NULL, ICON_NONE); + if (show_in_front) { uiItemL(layout, IFACE_("Object is shown in front"), ICON_ERROR); } diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h index 727de381fa4..d8926a63307 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h +++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h @@ -182,9 +182,9 @@ typedef struct LineartEdgeChain { typedef struct LineartEdgeChainItem { struct LineartEdgeChainItem *next, *prev; - /** Need z value for fading */ - float pos[3]; - /** For restoring position to 3d space */ + /** Need z value for fading, w value for image frame clipping. */ + float pos[4]; + /** For restoring position to 3d space. */ float gpos[3]; float normal[3]; unsigned char line_type; @@ -299,6 +299,7 @@ typedef struct LineartRenderBuffer { bool use_loose_as_contour; bool use_loose_edge_chain; bool use_geometry_space_chain; + bool use_image_boundary_trimming; bool filter_face_mark; bool filter_face_mark_invert; @@ -594,6 +595,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb); void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb); void MOD_lineart_chain_connect(LineartRenderBuffer *rb); void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold); +void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb); void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad); void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance); void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb, diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c index 8b7f53b8a36..85b801eece2 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c @@ -126,7 +126,7 @@ static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb, eci = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChainItem)); - copy_v2_v2(eci->pos, fbcoord); + copy_v4_v4(eci->pos, fbcoord); copy_v3_v3(eci->gpos, gpos); eci->index = index; copy_v3_v3(eci->normal, normal); @@ -156,7 +156,7 @@ static LineartEdgeChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb eci = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChainItem)); - copy_v2_v2(eci->pos, fbcoord); + copy_v4_v4(eci->pos, fbcoord); copy_v3_v3(eci->gpos, gpos); eci->index = index; copy_v3_v3(eci->normal, normal); @@ -177,15 +177,15 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) int last_occlusion; unsigned char last_transparency; /* Used when converting from double. */ - float use_fbcoord[2]; + float use_fbcoord[4]; float use_gpos[3]; #define VERT_COORD_TO_FLOAT(a) \ - copy_v2fl_v2db(use_fbcoord, (a)->fbcoord); \ + copy_v4fl_v4db(use_fbcoord, (a)->fbcoord); \ copy_v3fl_v3db(use_gpos, (a)->gloc); #define POS_TO_FLOAT(lpos, gpos) \ - copy_v2fl_v2db(use_fbcoord, lpos); \ + copy_v3fl_v3db(use_fbcoord, lpos); \ copy_v3fl_v3db(use_gpos, gpos); LRT_ITER_ALL_LINES_BEGIN @@ -262,6 +262,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]); interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at); interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at); + use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at); POS_TO_FLOAT(lpos, gpos) lineart_chain_prepend_point(rb, ec, @@ -287,6 +288,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]); interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at); interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at); + use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at); POS_TO_FLOAT(lpos, gpos) lineart_chain_prepend_point(rb, ec, @@ -340,6 +342,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]); interp_v3_v3v3_db(lpos, e->v1->fbcoord, e->v2->fbcoord, es->at); interp_v3_v3v3_db(gpos, e->v1->gloc, e->v2->gloc, global_at); + use_fbcoord[3] = interpf(e->v2->fbcoord[3], e->v1->fbcoord[3], global_at); POS_TO_FLOAT(lpos, gpos) lineart_chain_append_point(rb, ec, @@ -403,6 +406,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]); interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at); interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at); + use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at); last_occlusion = es->prev ? es->prev->occlusion : last_occlusion; last_transparency = es->prev ? es->prev->material_mask_bits : last_transparency; POS_TO_FLOAT(lpos, gpos) @@ -430,6 +434,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]); interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at); interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at); + use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at); POS_TO_FLOAT(lpos, gpos) lineart_chain_append_point(rb, ec, @@ -952,6 +957,118 @@ void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance) } } +static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartRenderBuffer *rb, + LineartEdgeChainItem *eci_inside, + LineartEdgeChainItem *eci_outside) +{ + float isec[2]; + float LU[2] = {-1.0f, 1.0f}, LB[2] = {-1.0f, -1.0f}, RU[2] = {1.0f, 1.0f}, RB[2] = {1.0f, -1.0f}; + bool found = false; + LineartEdgeChainItem *eci2 = eci_outside, *eci1 = eci_inside; + if (eci2->pos[0] < -1.0f) { + found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, LU, LB, isec) > 0); + } + if (!found && eci2->pos[0] > 1.0f) { + found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, RU, RB, isec) > 0); + } + if (!found && eci2->pos[1] < -1.0f) { + found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, LB, RB, isec) > 0); + } + if (!found && eci2->pos[1] > 1.0f) { + found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, LU, RU, isec) > 0); + } + + if (UNLIKELY(!found)) { + return NULL; + } + + float ratio = (fabs(eci2->pos[0] - eci1->pos[0]) > fabs(eci2->pos[1] - eci1->pos[1])) ? + ratiof(eci1->pos[0], eci2->pos[0], isec[0]) : + ratiof(eci1->pos[1], eci2->pos[1], isec[1]); + float gratio = eci1->pos[3] * ratio / (ratio * eci1->pos[3] + (1 - ratio) * eci2->pos[3]); + + LineartEdgeChainItem *eci = lineart_mem_acquire(rb->chain_data_pool, + sizeof(LineartEdgeChainItem)); + memcpy(eci, eci1, sizeof(LineartEdgeChainItem)); + interp_v3_v3v3(eci->gpos, eci1->gpos, eci2->gpos, gratio); + interp_v3_v3v3(eci->pos, eci1->pos, eci2->pos, ratio); + eci->pos[3] = interpf(eci2->pos[3], eci1->pos[3], gratio); + eci->next = eci->prev = NULL; + return eci; +} + +#define LRT_ECI_INSIDE(eci) \ + ((eci)->pos[0] >= -1.0f && (eci)->pos[0] <= 1.0f && (eci)->pos[1] >= -1.0f && \ + (eci)->pos[1] <= 1.0f) + +void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb) +{ + LineartEdgeChain *ec; + LineartEdgeChainItem *eci, *next_eci, *prev_eci, *new_eci; + bool is_inside, new_inside; + ListBase swap = {0}; + swap.first = rb->chains.first; + swap.last = rb->chains.last; + + rb->chains.last = rb->chains.first = NULL; + while ((ec = BLI_pophead(&swap)) != NULL) { + bool ec_added = false; + LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first; + is_inside = LRT_ECI_INSIDE(first_eci) ? true : false; + if (!is_inside) { + ec->picked = true; + } + for (eci = first_eci->next; eci; eci = next_eci) { + next_eci = eci->next; + prev_eci = eci->prev; + + /* We only need to do something if the edge crossed from outside to the inside or from inside + * to the outside. */ + if ((new_inside = LRT_ECI_INSIDE(eci)) != is_inside) { + if (new_inside == false) { + /* Stroke goes out. */ + new_eci = lineart_chain_create_crossing_point(rb, prev_eci, eci); + + LineartEdgeChain *new_ec = lineart_mem_acquire(rb->chain_data_pool, + sizeof(LineartEdgeChain)); + memcpy(new_ec, ec, sizeof(LineartEdgeChain)); + new_ec->chain.first = next_eci; + eci->prev = NULL; + prev_eci->next = NULL; + ec->chain.last = prev_eci; + BLI_addtail(&ec->chain, new_eci); + BLI_addtail(&rb->chains, ec); + ec_added = true; + ec = new_ec; + + next_eci = eci->next; + is_inside = new_inside; + continue; + } + else { + /* Stroke comes in. */ + new_eci = lineart_chain_create_crossing_point(rb, eci, prev_eci); + + ec->chain.first = eci; + eci->prev = NULL; + + BLI_addhead(&ec->chain, new_eci); + + ec_added = false; + + next_eci = eci->next; + is_inside = new_inside; + continue; + } + } + } + + if ((!ec_added) && is_inside) { + BLI_addtail(&rb->chains, ec); + } + } +} + /** * This should always be the last stage!, see the end of * #MOD_lineart_chain_split_for_fixed_occlusion(). diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index ea2619a9328..93e9062e910 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -3077,6 +3077,8 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene, rb->use_loose_as_contour = (lmd->calculation_flags & LRT_LOOSE_AS_CONTOUR) != 0; rb->use_loose_edge_chain = (lmd->calculation_flags & LRT_CHAIN_LOOSE_EDGES) != 0; rb->use_geometry_space_chain = (lmd->calculation_flags & LRT_CHAIN_GEOMETRY_SPACE) != 0; + rb->use_image_boundary_trimming = (lmd->calculation_flags & LRT_USE_IMAGE_BOUNDARY_TRIMMING) != + 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; @@ -4202,6 +4204,10 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, MOD_lineart_smooth_chains(rb, rb->chain_smooth_tolerance / 50); } + if (rb->use_image_boundary_trimming) { + MOD_lineart_chain_clip_at_border(rb); + } + if (rb->angle_splitting_threshold > FLT_EPSILON) { MOD_lineart_chain_split_angle(rb, rb->angle_splitting_threshold); } |