diff options
Diffstat (limited to 'source/blender/gpencil_modifiers/intern')
9 files changed, 287 insertions, 40 deletions
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c index 595a0c1cc5e..9ea146c77f2 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c @@ -156,7 +156,7 @@ float get_modifier_point_weight(MDeformVert *dvert, bool inverse, int def_nr) MDeformWeight *dw = BKE_defvert_find_index(dvert, def_nr); weight = dw ? dw->weight : -1.0f; if ((weight >= 0.0f) && (inverse)) { - return -1.0f; + return 1.0f - weight; } if ((weight < 0.0f) && (!inverse)) { diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c index ba33edd6a94..33cc3094a36 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c @@ -255,7 +255,7 @@ static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Objec BKE_gpencil_frame_active_set(depsgraph, gpd); bGPDframe *gpf = gpl->actframe; if (gpf == NULL) { - return; + continue; } apply_dash_for_frame(ob, gpl, gpd, gpf, (DashGpencilModifierData *)md); } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c index c5ccf1d8229..fa31aec2b5b 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c @@ -160,12 +160,14 @@ static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Objec LineartCache *local_lc = gpd->runtime.lineart_cache; if (!gpd->runtime.lineart_cache) { - MOD_lineart_compute_feature_lines(depsgraph, lmd, &gpd->runtime.lineart_cache); + MOD_lineart_compute_feature_lines( + depsgraph, lmd, &gpd->runtime.lineart_cache, (!(ob->dtx & OB_DRAW_IN_FRONT))); MOD_lineart_destroy_render_data(lmd); } else { if (!(lmd->flags & LRT_GPENCIL_USE_CACHE)) { - MOD_lineart_compute_feature_lines(depsgraph, lmd, &local_lc); + MOD_lineart_compute_feature_lines( + depsgraph, lmd, &local_lc, (!(ob->dtx & OB_DRAW_IN_FRONT))); MOD_lineart_destroy_render_data(lmd); } MOD_lineart_chain_clear_picked_flag(local_lc); @@ -210,7 +212,8 @@ static void bakeModifier(Main *UNUSED(bmain), lmd->edge_types_override = lmd->edge_types; lmd->level_end_override = lmd->level_end; - MOD_lineart_compute_feature_lines(depsgraph, lmd, &gpd->runtime.lineart_cache); + MOD_lineart_compute_feature_lines( + depsgraph, lmd, &gpd->runtime.lineart_cache, (!(ob->dtx & OB_DRAW_IN_FRONT))); MOD_lineart_destroy_render_data(lmd); } @@ -261,7 +264,13 @@ static void updateDepsgraph(GpencilModifierData *md, else { add_this_collection(ctx->scene->master_collection, ctx, mode); } - if (ctx->scene->camera) { + if (lmd->calculation_flags & LRT_USE_CUSTOM_CAMERA && lmd->source_camera) { + DEG_add_object_relation( + ctx->node, lmd->source_camera, DEG_OB_COMP_TRANSFORM, "Line Art Modifier"); + DEG_add_object_relation( + ctx->node, lmd->source_camera, DEG_OB_COMP_PARAMETERS, "Line Art Modifier"); + } + else if (ctx->scene->camera) { DEG_add_object_relation( ctx->node, ctx->scene->camera, DEG_OB_COMP_TRANSFORM, "Line Art Modifier"); DEG_add_object_relation( @@ -277,6 +286,7 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, walk(userData, ob, (ID **)&lmd->source_collection, IDWALK_CB_NOP); walk(userData, ob, (ID **)&lmd->source_object, IDWALK_CB_NOP); + walk(userData, ob, (ID **)&lmd->source_camera, IDWALK_CB_NOP); } static void panel_draw(const bContext *UNUSED(C), Panel *panel) @@ -382,7 +392,12 @@ static void options_panel_draw(const bContext *UNUSED(C), Panel *panel) return; } - uiItemR(layout, ptr, "overscan", 0, NULL, ICON_NONE); + uiLayout *row = uiLayoutRowWithHeading(layout, false, IFACE_("Custom Camera")); + uiItemR(row, ptr, "use_custom_camera", 0, "", 0); + uiLayout *subrow = uiLayoutRow(row, true); + uiLayoutSetActive(subrow, RNA_boolean_get(ptr, "use_custom_camera")); + uiLayoutSetPropSep(subrow, true); + uiItemR(subrow, ptr, "source_camera", 0, "", ICON_OBJECT_DATA); uiLayout *col = uiLayoutColumn(layout, true); @@ -391,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) @@ -412,14 +427,23 @@ static void style_panel_draw(const bContext *UNUSED(C), Panel *panel) static void occlusion_panel_draw(const bContext *UNUSED(C), Panel *panel) { uiLayout *layout = panel->layout; - PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL); + PointerRNA ob_ptr; + PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr); const bool is_baked = RNA_boolean_get(ptr, "is_baked"); + const bool use_multiple_levels = RNA_boolean_get(ptr, "use_multiple_levels"); + const bool show_in_front = RNA_boolean_get(&ob_ptr, "show_in_front"); + uiLayoutSetPropSep(layout, true); uiLayoutSetEnabled(layout, !is_baked); - const bool use_multiple_levels = RNA_boolean_get(ptr, "use_multiple_levels"); + if (!show_in_front) { + uiItemL(layout, IFACE_("Object is not in front"), ICON_INFO); + } + + layout = uiLayoutColumn(layout, false); + uiLayoutSetActive(layout, show_in_front); uiItemR(layout, ptr, "use_multiple_levels", 0, IFACE_("Range"), ICON_NONE); @@ -447,11 +471,14 @@ static bool anything_showing_through(PointerRNA *ptr) static void material_mask_panel_draw_header(const bContext *UNUSED(C), Panel *panel) { uiLayout *layout = panel->layout; - PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL); + PointerRNA ob_ptr; + PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr); const bool is_baked = RNA_boolean_get(ptr, "is_baked"); + const bool show_in_front = RNA_boolean_get(&ob_ptr, "show_in_front"); + uiLayoutSetEnabled(layout, !is_baked); - uiLayoutSetActive(layout, anything_showing_through(ptr)); + uiLayoutSetActive(layout, show_in_front && anything_showing_through(ptr)); uiItemR(layout, ptr, "use_material_mask", 0, IFACE_("Material Mask"), ICON_NONE); } @@ -654,6 +681,32 @@ static void bake_panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemO(col, NULL, ICON_NONE, "OBJECT_OT_lineart_clear_all"); } +static void composition_panel_draw(const bContext *UNUSED(C), Panel *panel) +{ + PointerRNA ob_ptr; + PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr); + + uiLayout *layout = panel->layout; + + const bool show_in_front = RNA_boolean_get(&ob_ptr, "show_in_front"); + + 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); + } + + uiLayout *col = uiLayoutColumn(layout, false); + uiLayoutSetActive(col, !show_in_front); + + uiItemR(col, ptr, "stroke_depth_offset", UI_ITEM_R_SLIDER, IFACE_("Depth Offset"), ICON_NONE); + uiItemR( + col, ptr, "use_offset_towards_custom_camera", 0, IFACE_("Towards Custom Camera"), ICON_NONE); +} + static void panelRegister(ARegionType *region_type) { PanelType *panel_type = gpencil_modifier_panel_register( @@ -682,6 +735,8 @@ static void panelRegister(ARegionType *region_type) gpencil_modifier_subpanel_register( region_type, "vgroup", "Vertex Weight Transfer", NULL, vgroup_panel_draw, panel_type); gpencil_modifier_subpanel_register( + region_type, "composition", "Composition", NULL, composition_panel_draw, panel_type); + gpencil_modifier_subpanel_register( region_type, "bake", "Bake", NULL, bake_panel_draw, panel_type); } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c index fb75b1e99ac..2e55369ea97 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c @@ -240,10 +240,10 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemR(layout, ptr, "hardness", 0, NULL, ICON_NONE); } else { - const bool is_normalized = RNA_boolean_get(ptr, "normalize_opacity"); + const bool is_normalized = RNA_boolean_get(ptr, "use_normalized_opacity"); const bool is_weighted = RNA_boolean_get(ptr, "use_weight_factor"); - uiItemR(layout, ptr, "normalize_opacity", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_normalized_opacity", 0, NULL, ICON_NONE); const char *text = (is_normalized) ? IFACE_("Strength") : IFACE_("Opacity Factor"); uiLayout *row = uiLayoutRow(layout, true); diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c index cac700e15f4..233992bbd31 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c @@ -191,8 +191,8 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) uiLayoutSetPropSep(layout, true); - uiItemR(layout, ptr, "normalize_thickness", 0, NULL, ICON_NONE); - if (RNA_boolean_get(ptr, "normalize_thickness")) { + uiItemR(layout, ptr, "use_normalized_thickness", 0, NULL, ICON_NONE); + if (RNA_boolean_get(ptr, "use_normalized_thickness")) { uiItemR(layout, ptr, "thickness", 0, NULL, ICON_NONE); } else { diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h index c00f34185dd..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; @@ -311,6 +312,7 @@ typedef struct LineartRenderBuffer { bool cam_is_persp; float cam_obmat[4][4]; double camera_pos[3]; + double active_camera_pos[3]; /* Stroke offset calculation may use active or selected camera. */ double near_clip, far_clip; float shift_x, shift_y; float crease_threshold; @@ -593,15 +595,20 @@ 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, + float dist, + bool use_custom_camera); int MOD_lineart_chain_count(const LineartEdgeChain *ec); void MOD_lineart_chain_clear_picked_flag(LineartCache *lc); bool MOD_lineart_compute_feature_lines(struct Depsgraph *depsgraph, struct LineartGpencilModifierData *lmd, - LineartCache **cached_result); + struct LineartCache **cached_result, + bool enable_stroke_offset); struct Scene; diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c index 8935bdd1870..f3110cf87b6 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, @@ -926,9 +931,9 @@ void MOD_lineart_chain_clear_picked_flag(LineartCache *lc) void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance) { - LISTBASE_FOREACH (LineartEdgeChain *, rlc, &rb->chains) { + LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) { LineartEdgeChainItem *next_eci; - for (LineartEdgeChainItem *eci = rlc->chain.first; eci; eci = next_eci) { + for (LineartEdgeChainItem *eci = ec->chain.first; eci; eci = next_eci) { next_eci = eci->next; LineartEdgeChainItem *eci2, *eci3, *eci4; @@ -944,7 +949,7 @@ void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance) if (dist_to_line_segment_v2(eci3->pos, eci->pos, eci2->pos) < tolerance) { /* And if p4 is on the extension of p1-p2 , we remove p3. */ if ((eci4 = eci3->next) && (dist_to_line_v2(eci4->pos, eci->pos, eci2->pos) < tolerance)) { - BLI_remlink(&rlc->chain, eci3); + BLI_remlink(&ec->chain, eci3); next_eci = eci; } } @@ -952,6 +957,116 @@ 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; + } + /* 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(). @@ -1008,3 +1123,45 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol } } } + +void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb, + float dist, + bool use_custom_camera) +{ + float dir[3]; + float cam[3]; + float view[3]; + float view_clamp[3]; + copy_v3fl_v3db(cam, rb->camera_pos); + copy_v3fl_v3db(view, rb->view_vector); + + if (use_custom_camera) { + copy_v3fl_v3db(cam, rb->camera_pos); + } + else { + copy_v3fl_v3db(cam, rb->active_camera_pos); + } + + if (rb->cam_is_persp) { + LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) { + LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) { + sub_v3_v3v3(dir, cam, eci->gpos); + float orig_len = len_v3(dir); + normalize_v3(dir); + mul_v3_fl(dir, MIN2(dist, orig_len - rb->near_clip)); + add_v3_v3(eci->gpos, dir); + } + } + } + else { + LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) { + LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) { + sub_v3_v3v3(dir, cam, eci->gpos); + float len_lim = dot_v3v3(view, dir) - rb->near_clip; + normalize_v3_v3(view_clamp, view); + mul_v3_fl(view_clamp, MIN2(dist, len_lim)); + add_v3_v3(eci->gpos, view_clamp); + } + } + } +} diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index 6660da79b40..93e9062e910 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -2998,7 +2998,7 @@ void MOD_lineart_destroy_render_data(LineartGpencilModifierData *lmd) } } -static LineartCache *lineart_init_cache() +static LineartCache *lineart_init_cache(void) { LineartCache *lc = MEM_callocN(sizeof(LineartCache), "Lineart Cache"); return lc; @@ -3016,6 +3016,8 @@ void MOD_lineart_clear_cache(struct LineartCache **lc) static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene, LineartGpencilModifierData *lmd, + Object *camera, + Object *active_camera, LineartCache *lc) { LineartRenderBuffer *rb = MEM_callocN(sizeof(LineartRenderBuffer), "Line Art render buffer"); @@ -3024,10 +3026,10 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene, lmd->render_buffer_ptr = rb; lc->rb_edge_types = lmd->edge_types_override; - if (!scene || !scene->camera || !lc) { + if (!scene || !camera || !lc) { return NULL; } - Camera *c = scene->camera->data; + Camera *c = camera->data; double clipping_offset = 0; if (lmd->calculation_flags & LRT_ALLOW_CLIPPING_BOUNDARIES) { @@ -3035,8 +3037,11 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene, clipping_offset = 0.0001; } - copy_v3db_v3fl(rb->camera_pos, scene->camera->obmat[3]); - copy_m4_m4(rb->cam_obmat, scene->camera->obmat); + copy_v3db_v3fl(rb->camera_pos, camera->obmat[3]); + if (active_camera) { + copy_v3db_v3fl(rb->active_camera_pos, active_camera->obmat[3]); + } + copy_m4_m4(rb->cam_obmat, camera->obmat); rb->cam_is_persp = (c->type == CAM_PERSP); rb->near_clip = c->clip_start + clipping_offset; rb->far_clip = c->clip_end - clipping_offset; @@ -3072,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; @@ -4076,11 +4083,13 @@ static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this */ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, LineartGpencilModifierData *lmd, - LineartCache **cached_result) + LineartCache **cached_result, + bool enable_stroke_depth_offset) { LineartRenderBuffer *rb; Scene *scene = DEG_get_evaluated_scene(depsgraph); int intersections_only = 0; /* Not used right now, but preserve for future. */ + Object *use_camera; double t_start; @@ -4090,14 +4099,24 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, BKE_scene_camera_switch_update(scene); - if (!scene->camera) { - return false; + if (lmd->calculation_flags & LRT_USE_CUSTOM_CAMERA) { + if (!lmd->source_camera || + (use_camera = DEG_get_evaluated_object(depsgraph, lmd->source_camera))->type != + OB_CAMERA) { + return false; + } + } + else { + if (!scene->camera) { + return false; + } + use_camera = scene->camera; } LineartCache *lc = lineart_init_cache(); *cached_result = lc; - rb = lineart_create_render_buffer(scene, lmd, lc); + rb = lineart_create_render_buffer(scene, lmd, use_camera, scene->camera, lc); /* Triangle thread testing data size varies depending on the thread count. * See definition of LineartTriangleThread for details. */ @@ -4117,7 +4136,7 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, /* Get view vector before loading geometries, because we detect feature lines there. */ lineart_main_get_view_vector(rb); lineart_main_load_geometries( - depsgraph, scene, scene->camera, rb, lmd->calculation_flags & LRT_ALLOW_DUPLI_OBJECTS); + depsgraph, scene, use_camera, rb, lmd->calculation_flags & LRT_ALLOW_DUPLI_OBJECTS); if (!rb->vertex_buffer_pointers.first) { /* No geometry loaded, return early. */ @@ -4185,10 +4204,19 @@ 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); } + if (enable_stroke_depth_offset && lmd->stroke_depth_offset > FLT_EPSILON) { + MOD_lineart_chain_offset_towards_camera( + rb, lmd->stroke_depth_offset, lmd->flags & LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA); + } + /* Finally transfer the result list into cache. */ memcpy(&lc->chains, &rb->chains, sizeof(ListBase)); diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c index 988c90483a6..b74499daf6b 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c @@ -118,12 +118,12 @@ static bool bake_strokes(Object *ob, } LineartCache *local_lc = *lc; if (!(*lc)) { - MOD_lineart_compute_feature_lines(dg, lmd, lc); + MOD_lineart_compute_feature_lines(dg, lmd, lc, (!(ob->dtx & OB_DRAW_IN_FRONT))); MOD_lineart_destroy_render_data(lmd); } else { if (is_first || (!(lmd->flags & LRT_GPENCIL_USE_CACHE))) { - MOD_lineart_compute_feature_lines(dg, lmd, &local_lc); + MOD_lineart_compute_feature_lines(dg, lmd, &local_lc, (!(ob->dtx & OB_DRAW_IN_FRONT))); MOD_lineart_destroy_render_data(lmd); } MOD_lineart_chain_clear_picked_flag(local_lc); |