From c3ef1c15f5653ac323f4d077c7faf7b46f3eee0d Mon Sep 17 00:00:00 2001 From: YimingWu Date: Tue, 26 Oct 2021 22:55:27 +0800 Subject: LineArt: Stroke offset towards camera. Allows the user to turn off in_front option for grease pencil object and offset strokes towards camera to allow depth interaction of the rest of the scene. Reviewed By: Antonio Vazquez (antoniov) Differential Revision: https://developer.blender.org/D12046 --- source/blender/editors/object/object_add.c | 24 +++++++--- .../gpencil_modifiers/intern/MOD_gpencillineart.c | 52 +++++++++++++++++++--- .../gpencil_modifiers/intern/lineart/MOD_lineart.h | 4 +- .../intern/lineart/lineart_chain.c | 38 ++++++++++++++-- .../gpencil_modifiers/intern/lineart/lineart_cpu.c | 7 ++- .../gpencil_modifiers/intern/lineart/lineart_ops.c | 4 +- .../makesdna/DNA_gpencil_modifier_defaults.h | 1 + .../blender/makesdna/DNA_gpencil_modifier_types.h | 4 +- .../blender/makesrna/intern/rna_gpencil_modifier.c | 8 ++++ 9 files changed, 121 insertions(+), 21 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 629f40e0ae9..8fc1c119d0c 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1323,6 +1323,7 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op) const bool use_in_front = RNA_boolean_get(op->ptr, "use_in_front"); const bool use_lights = RNA_boolean_get(op->ptr, "use_lights"); const int stroke_depth_order = RNA_enum_get(op->ptr, "stroke_depth_order"); + const float stroke_depth_offset = RNA_float_get(op->ptr, "stroke_depth_offset"); ushort local_view_bits; float loc[3], rot[3]; @@ -1454,6 +1455,7 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op) if (stroke_depth_order == GP_DRAWMODE_3D) { gpd->draw_mode = GP_DRAWMODE_3D; } + md->stroke_depth_offset = stroke_depth_offset; } break; @@ -1491,9 +1493,10 @@ static void object_add_ui(bContext *UNUSED(C), wmOperator *op) uiItemR(layout, op->ptr, "use_lights", 0, NULL, ICON_NONE); uiItemR(layout, op->ptr, "use_in_front", 0, NULL, ICON_NONE); bool in_front = RNA_boolean_get(op->ptr, "use_in_front"); - uiLayout *row = uiLayoutRow(layout, false); - uiLayoutSetActive(row, !in_front); - uiItemR(row, op->ptr, "stroke_depth_order", 0, NULL, ICON_NONE); + uiLayout *col = uiLayoutColumn(layout, false); + uiLayoutSetActive(col, !in_front); + uiItemR(col, op->ptr, "stroke_depth_offset", 0, NULL, ICON_NONE); + uiItemR(col, op->ptr, "stroke_depth_order", 0, NULL, ICON_NONE); } } @@ -1532,9 +1535,18 @@ void OBJECT_OT_gpencil_add(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_gpencil_type_items, 0, "Type", ""); RNA_def_boolean(ot->srna, "use_in_front", - false, - "In Front", + true, + "Show In Front", "Show line art grease pencil in front of everything"); + RNA_def_float(ot->srna, + "stroke_depth_offset", + 0.05f, + 0.0f, + 0.0f, + "Stroke Offset", + "Stroke offset for the line art modifier", + 0.0f, + 0.5f); RNA_def_boolean( ot->srna, "use_lights", false, "Use Lights", "Use lights for this grease pencil object"); RNA_def_enum( @@ -1543,7 +1555,7 @@ void OBJECT_OT_gpencil_add(wmOperatorType *ot) rna_enum_gpencil_add_stroke_depth_order_items, GP_DRAWMODE_3D, "Stroke Depth Order", - "Defines how the strokes are ordered in 3D space for objects not displayed 'In Front'"); + "Defines how the strokes are ordered in 3D space for objects not displayed 'In Front')"); } /** \} */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c index c5ccf1d8229..a7164e5bf2c 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); } @@ -412,14 +415,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 +459,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 +669,27 @@ 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); + + if (show_in_front) { + uiItemL(layout, IFACE_("Object is shown in front"), ICON_ERROR); + } + + uiLayout *row = uiLayoutRow(layout, false); + uiLayoutSetActive(row, !show_in_front); + + uiItemR(row, ptr, "stroke_depth_offset", UI_ITEM_R_SLIDER, IFACE_("Depth Offset"), ICON_NONE); +} + static void panelRegister(ARegionType *region_type) { PanelType *panel_type = gpencil_modifier_panel_register( @@ -681,6 +717,8 @@ static void panelRegister(ARegionType *region_type) region_type, "chaining", "Chaining", NULL, chaining_panel_draw, panel_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/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h index c00f34185dd..d170a6033fa 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h +++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h @@ -595,13 +595,15 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb); void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold); 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); 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..57eeeb96541 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c @@ -926,9 +926,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 +944,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; } } @@ -1008,3 +1008,35 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol } } } + +void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb, float dist) +{ + 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 (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..f8dda2f9174 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -4076,7 +4076,8 @@ 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); @@ -4189,6 +4190,10 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, 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); + } + /* 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); diff --git a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h index 11299ae9717..1ad884bee8f 100644 --- a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h +++ b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h @@ -319,6 +319,7 @@ .angle_splitting_threshold = DEG2RAD(60.0f), \ .chaining_image_threshold = 0.001f, \ .chain_smooth_tolerance = 0.2f,\ + .stroke_depth_offset = 0.05,\ } #define _DNA_DEFAULT_LengthGpencilModifierData \ diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h index c7a93080f7c..6ea07163ca8 100644 --- a/source/blender/makesdna/DNA_gpencil_modifier_types.h +++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h @@ -1042,7 +1042,6 @@ typedef struct LineartGpencilModifierData { /** Strength for smoothing jagged chains. */ float chain_smooth_tolerance; - int _pad1; /* CPU mode */ float chaining_image_threshold; @@ -1053,6 +1052,9 @@ typedef struct LineartGpencilModifierData { /* #eLineArtGPencilModifierFlags, modifier internal state. */ int flags; + /* Move strokes towards camera to avoid clipping while preserve depth for the viewport. */ + float stroke_depth_offset; + /* Runtime data. */ /* Because we can potentially only compute features lines once per modifier stack (Use Cache), we diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index 631d5822c5e..29689a2b281 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -3200,6 +3200,14 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna) "separate stroke for each overlapping type"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + prop = RNA_def_property(srna, "stroke_depth_offset", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_ui_text(prop, + "Stroke Depth Offset", + "Move strokes slightly towards the camera to avoid clipping while " + "preserve depth for the viewport"); + RNA_def_property_ui_range(prop, 0.0f, 0.5f, 0.001f, 4); + RNA_def_property_update(prop, NC_SCENE, "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"); -- cgit v1.2.3