From 8dadc091d02a7a046a73f77757766ef6fdeffda9 Mon Sep 17 00:00:00 2001 From: YimingWu Date: Sat, 6 Aug 2022 11:06:34 +0800 Subject: [PATCH 1/2] LineArt: Usability improvement for "Enclosed Shapes". This patch removes the [rather confusing] separate checkbox for enclosed shapes in favour of integrating that option into illumination filtering, with the benefit of not limiting the selection to cached result. Reviewed By: Sebastian Parborg (zeddb) Differential Revision: https://developer.blender.org/D15327 --- .../intern/MOD_gpencillineart.c | 13 +++----- .../intern/lineart/MOD_lineart.h | 7 ++++- .../intern/lineart/lineart_cpu.c | 29 +++++++++++------ .../intern/lineart/lineart_shadow.c | 5 +-- .../makesdna/DNA_gpencil_modifier_types.h | 7 ++++- source/blender/makesdna/DNA_lineart_types.h | 1 - .../makesrna/intern/rna_gpencil_modifier.c | 31 +++++++++++++------ 7 files changed, 59 insertions(+), 34 deletions(-) diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c index 77616ae13b6..6bb59f29b98 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c @@ -373,19 +373,16 @@ static void edge_types_panel_draw(const bContext *UNUSED(C), Panel *panel) } sub = uiLayoutRow(col, false); - uiItemR(sub, ptr, "use_crease", 0, "", ICON_NONE); - entry = uiLayoutColumn(sub, false); - uiItemL(entry, IFACE_("Crease"), ICON_NONE); - uiLayoutSetActive(entry, RNA_boolean_get(ptr, "use_crease") || is_first); if (use_cache && !is_first) { - uiItemL(entry, IFACE_("Crease Angle Cached"), ICON_INFO); + uiItemR(sub, ptr, "use_crease", 0, IFACE_("Crease (Angle Cached)"), ICON_NONE); } else { - uiItemR(entry, + uiItemR(sub, ptr, "use_crease", 0, "", ICON_NONE); + uiItemR(sub, ptr, "crease_threshold", UI_ITEM_R_SLIDER | UI_ITEM_R_FORCE_BLANK_DECORATE, - IFACE_("Default Angle"), + NULL, ICON_NONE); } @@ -447,8 +444,6 @@ static void options_light_reference_draw(const bContext *UNUSED(C), Panel *panel uiLayout *col = uiLayoutColumn(remaining, true); uiItemR(col, ptr, "shadow_camera_near", 0, "Near", ICON_NONE); uiItemR(col, ptr, "shadow_camera_far", 0, "Far", ICON_NONE); - - uiItemR(layout, ptr, "use_shadow_enclosed_shapes", 0, IFACE_("Enclosed Shapes"), ICON_NONE); } static void options_panel_draw(const bContext *UNUSED(C), Panel *panel) diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h index 5dd833fb12b..224146d0032 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h +++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h @@ -439,12 +439,17 @@ typedef enum eLineartTriangleFlags { } eLineartTriangleFlags; #define LRT_SHADOW_MASK_UNDEFINED 0 -#define LRT_SHADOW_MASK_LIT (1 << 0) +#define LRT_SHADOW_MASK_ILLUMINATED (1 << 0) #define LRT_SHADOW_MASK_SHADED (1 << 1) #define LRT_SHADOW_MASK_ENCLOSED_SHAPE (1 << 2) #define LRT_SHADOW_MASK_INHIBITED (1 << 3) #define LRT_SHADOW_SILHOUETTE_ERASED_GROUP (1 << 4) #define LRT_SHADOW_SILHOUETTE_ERASED_OBJECT (1 << 5) +#define LRT_SHADOW_MASK_ILLUMINATED_SHAPE (1 << 6) + +#define LRT_SHADOW_TEST_SHAPE_BITS \ + (LRT_SHADOW_MASK_ILLUMINATED | LRT_SHADOW_MASK_SHADED | LRT_SHADOW_MASK_INHIBITED | \ + LRT_SHADOW_MASK_ILLUMINATED_SHAPE) /** * Controls how many edges a worker thread is processing at one request. diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index 874da3b88c9..011c79025c4 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -304,13 +304,12 @@ void lineart_edge_cut(LineartData *ld, /* The enclosed shape flag will override regular lit/shaded * flags. See LineartEdgeSegment::shadow_mask_bits for details. */ if (shadow_bits == LRT_SHADOW_MASK_ENCLOSED_SHAPE) { - if (seg->shadow_mask_bits & LRT_SHADOW_MASK_LIT || e->flags & LRT_EDGE_FLAG_LIGHT_CONTOUR) { - seg->shadow_mask_bits &= ~LRT_SHADOW_MASK_LIT; + if (seg->shadow_mask_bits & LRT_SHADOW_MASK_ILLUMINATED || + e->flags & LRT_EDGE_FLAG_LIGHT_CONTOUR) { seg->shadow_mask_bits |= LRT_SHADOW_MASK_INHIBITED; } else if (seg->shadow_mask_bits & LRT_SHADOW_MASK_SHADED) { - seg->shadow_mask_bits &= ~LRT_SHADOW_MASK_SHADED; - seg->shadow_mask_bits |= LRT_SHADOW_MASK_LIT; + seg->shadow_mask_bits |= LRT_SHADOW_MASK_ILLUMINATED_SHAPE; } } else { @@ -3643,7 +3642,8 @@ static LineartData *lineart_create_render_buffer(Scene *scene, (lmd->light_contour_object != NULL)); ld->conf.shadow_selection = lmd->shadow_selection_override; - ld->conf.shadow_enclose_shapes = (lmd->calculation_flags & LRT_SHADOW_ENCLOSED_SHAPES) != 0; + ld->conf.shadow_enclose_shapes = lmd->shadow_selection_override == + LRT_SHADOW_FILTER_ILLUMINATED_ENCLOSED_SHAPES; ld->conf.shadow_use_silhouette = lmd->shadow_use_silhouette_override != 0; ld->conf.use_back_face_culling = (lmd->calculation_flags & LRT_USE_BACK_FACE_CULLING) != 0; @@ -5227,13 +5227,22 @@ static void lineart_gpencil_generate(LineartCache *cache, } if (shaodow_selection) { if (ec->shadow_mask_bits != LRT_SHADOW_MASK_UNDEFINED) { - /* TODO(@Yiming): Give a behavior option for how to display undefined shadow info. */ - if ((shaodow_selection == LRT_SHADOW_FILTER_LIT && - (!(ec->shadow_mask_bits & LRT_SHADOW_MASK_LIT))) || - (shaodow_selection == LRT_SHADOW_FILTER_SHADED && - (!(ec->shadow_mask_bits & LRT_SHADOW_MASK_SHADED)))) { + /* TODO(Yiming): Give a behaviour option for how to display undefined shadow info. */ + if ((shaodow_selection == LRT_SHADOW_FILTER_ILLUMINATED && + (!(ec->shadow_mask_bits & LRT_SHADOW_MASK_ILLUMINATED)))) { continue; } + else if ((shaodow_selection == LRT_SHADOW_FILTER_SHADED && + (!(ec->shadow_mask_bits & LRT_SHADOW_MASK_SHADED)))) { + continue; + } + else if (shaodow_selection == LRT_SHADOW_FILTER_ILLUMINATED_ENCLOSED_SHAPES) { + uint32_t test_bits = ec->shadow_mask_bits & LRT_SHADOW_TEST_SHAPE_BITS; + if ((test_bits != LRT_SHADOW_MASK_ILLUMINATED) && + (test_bits != (LRT_SHADOW_MASK_SHADED | LRT_SHADOW_MASK_ILLUMINATED_SHAPE))) { + continue; + } + } } } if (silhouette_mode && (ec->type & (LRT_EDGE_FLAG_CONTOUR))) { diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c index ad0137fe0f0..24762ce921d 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c @@ -109,9 +109,10 @@ void lineart_register_shadow_cuts(LineartData *ld, LineartEdge *e, LineartEdge * la2 = la2 * e->v2->fbcoord[3] / (e->v1->fbcoord[3] - la2 * (e->v1->fbcoord[3] - e->v2->fbcoord[3])); unsigned char shadow_bits = (es->occlusion != 0) ? LRT_SHADOW_MASK_SHADED : - LRT_SHADOW_MASK_LIT; + LRT_SHADOW_MASK_ILLUMINATED; - if (lineart_contour_viewed_from_dark_side(ld, e) && shadow_bits == LRT_SHADOW_MASK_LIT) { + if (lineart_contour_viewed_from_dark_side(ld, e) && + shadow_bits == LRT_SHADOW_MASK_ILLUMINATED) { shadow_bits = LRT_SHADOW_MASK_SHADED; } diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h index 2bb95caddfb..7f8e436f007 100644 --- a/source/blender/makesdna/DNA_gpencil_modifier_types.h +++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h @@ -999,9 +999,14 @@ typedef enum eLineartGpencilModifierSource { } eLineartGpencilModifierSource; typedef enum eLineartGpencilModifierShadowFilter { + /* These options need to be ordered in this way because those latter options requires line art to + run a few extra stages. Having those values set up this way will allow + #BKE_gpencil_get_lineart_modifier_limits() to find out maximum stages needed in multiple + cached line art modifiers. */ LRT_SHADOW_FILTER_NONE = 0, - LRT_SHADOW_FILTER_LIT = 1, + LRT_SHADOW_FILTER_ILLUMINATED = 1, LRT_SHADOW_FILTER_SHADED = 2, + LRT_SHADOW_FILTER_ILLUMINATED_ENCLOSED_SHAPES = 3, } eLineartGpencilModifierShadowFilter; typedef enum eLineartGpencilModifierSilhouetteFilter { diff --git a/source/blender/makesdna/DNA_lineart_types.h b/source/blender/makesdna/DNA_lineart_types.h index 1ff656f85ed..05380325852 100644 --- a/source/blender/makesdna/DNA_lineart_types.h +++ b/source/blender/makesdna/DNA_lineart_types.h @@ -38,7 +38,6 @@ typedef enum eLineartMainFlags { LRT_USE_BACK_FACE_CULLING = (1 << 19), LRT_USE_IMAGE_BOUNDARY_TRIMMING = (1 << 20), LRT_CHAIN_PRESERVE_DETAILS = (1 << 22), - LRT_SHADOW_ENCLOSED_SHAPES = (1 << 23), LRT_SHADOW_USE_SILHOUETTE = (1 << 24), } eLineartMainFlags; diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index 0647bc62081..2dfd9d46665 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -3197,9 +3197,27 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna) }; static const EnumPropertyItem modifier_lineart_shadow_region_filtering[] = { - {LRT_SHADOW_FILTER_NONE, "NONE", 0, "None", ""}, - {LRT_SHADOW_FILTER_LIT, "LIT", 0, "Lit", ""}, - {LRT_SHADOW_FILTER_SHADED, "SHADED", 0, "Shaded", ""}, + {LRT_SHADOW_FILTER_NONE, + "NONE", + 0, + "None", + "Not filtering any lines based on illumination region"}, + {LRT_SHADOW_FILTER_ILLUMINATED, + "ILLUMINATED", + 0, + "Illuminated", + "Only selecting lines from illuminated regions"}, + {LRT_SHADOW_FILTER_SHADED, + "SHADED", + 0, + "Shaded", + "Only selecting lines from shaded regions"}, + {LRT_SHADOW_FILTER_ILLUMINATED_ENCLOSED_SHAPES, + "ILLUMINATED_ENCLOSED", + 0, + "Illuminated (Enclosed Shapes)", + "Selecting lines from lit regions, and make the combination of contour, light contour and " + "shadow lines into enclosed shapes"}, {0, NULL, 0, NULL, NULL}, }; @@ -3464,13 +3482,6 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna) "affect cast shadow and light contour since they are at the border"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update"); - prop = RNA_def_property(srna, "use_shadow_enclosed_shapes", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_SHADOW_ENCLOSED_SHAPES); - RNA_def_property_ui_text(prop, - "Shadow Enclosed Shapes", - "Reproject visible lines again to get enclosed shadow shapes"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - prop = RNA_def_property(srna, "silhouette_filtering", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "silhouette_selection"); RNA_def_property_enum_items(prop, modifier_lineart_silhouette_filtering); From d58476049e2ae2e407d66cbb4d5eac65b594509a Mon Sep 17 00:00:00 2001 From: Howard Trickey Date: Sat, 6 Aug 2022 12:40:11 -0400 Subject: [PATCH 2/2] Fix T98025: Revert "Fix Bevel intersection continuity." This reverts commit 94866ef84f1907116409f8fe9c1f313405 A number of reports of bevel regressions came after the commit to fix bevel intersection continuity. Since the fix for some of those regressions is not obvious we will revert the continuity improvement and do it as part of the Bevel V2 project. --- source/blender/bmesh/tools/bmesh_bevel.c | 140 +++++------------------ 1 file changed, 30 insertions(+), 110 deletions(-) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index fa852cdd6da..aa2c93f7c5a 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -437,16 +437,6 @@ static bool nearly_parallel_normalized(const float d1[3], const float d2[3]) return compare_ff(fabsf(direction_dot), 1.0f, BEVEL_EPSILON_ANG_DOT); } -/** - * calculate the determinant of a matrix formed by three vectors - * \return dot(a, cross(b, c)) = determinant(a, b, c) - */ -static float determinant_v3v3v3(const float a[3], const float b[3], const float c[3]) -{ - return a[0] * b[1] * c[2] + a[1] * b[2] * c[0] + a[2] * b[0] * c[1] - a[0] * b[2] * c[1] - - a[1] * b[0] * c[2] - a[2] * b[1] * c[0]; -} - /* Make a new BoundVert of the given kind, inserting it at the end of the circular linked * list with entry point bv->boundstart, and return it. */ static BoundVert *add_new_bound_vert(MemArena *mem_arena, VMesh *vm, const float co[3]) @@ -4134,114 +4124,44 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in) VMesh *vm_out = new_adj_vmesh(bp->mem_arena, n_boundary, ns_out, vm_in->boundstart); /* First we adjust the boundary vertices of the input mesh, storing in output mesh. */ - BoundVert *bndv = vm_in->boundstart; for (int i = 0; i < n_boundary; i++) { - float co1[3], co2[3], acc[3]; - EdgeHalf *e = bndv->elast; - /* Generate tangents. This is hacked together and would ideally be done elsewhere and then only - * used here. */ - float tangent[3], tangent2[3], normal[3]; - bool convex = true; - bool orthogonal = false; - float stretch = 0.0f; - if (e) { - /* Projection direction is direction of the edge. */ - sub_v3_v3v3(tangent, e->e->v1->co, e->e->v2->co); - if (e->is_rev) { - negate_v3(tangent); - } - normalize_v3(tangent); - if (bndv->is_arc_start || bndv->is_patch_start) { - BMFace *face = e->fnext; - if (face) { - copy_v3_v3(normal, face->no); - } - else { - zero_v3(normal); - } - madd_v3_v3v3fl(co2, bndv->profile.middle, normal, 0.1f); - } - if (bndv->is_arc_start || bp->affect_type == BEVEL_AFFECT_VERTICES) { - EdgeHalf *e1 = bndv->next->elast; - BLI_assert(e1); - sub_v3_v3v3(tangent2, e1->e->v1->co, e1->e->v2->co); - if (e1->is_rev) { - negate_v3(tangent2); - } - normalize_v3(tangent2); - - convex = determinant_v3v3v3(tangent2, tangent, normal) < 0; - - add_v3_v3(tangent2, tangent); - normalize_v3(tangent2); - copy_v3_v3(tangent, tangent2); - } - /* Calculate a factor which determines how much the interpolated mesh is - * going to be stretched out into the direction of the tangent. - * It is currently using the difference along the tangent of the - * central point on the profile and the current center vertex position. */ - get_profile_point(bp, &bndv->profile, ns_in2, ns_in, co); - stretch = dot_v3v3(tangent, mesh_vert(vm_in, i, ns_in2, ns_in2)->co) - dot_v3v3(tangent, co); - stretch = fabsf(stretch); - /* Scale the tangent by stretch. The divide by ns_in2 comes from the Levin Paper. */ - mul_v3_fl(tangent, stretch / ns_in2); - orthogonal = bndv->is_patch_start; - } - else if (bndv->prev->is_patch_start) { - /* If this is the second edge of a patch and therefore #e is NULL, - * then e->fprev has to be used/not NULL. */ - BLI_assert(bndv->prev->elast); - BMFace *face = bndv->prev->elast->fnext; - if (face) { - copy_v3_v3(normal, face->no); - } - else { - zero_v3(normal); - } - orthogonal = true; - } - else { - /** Should only come here from make_cube_corner_adj_vmesh. */ - sub_v3_v3v3(co1, mesh_vert(vm_in, i, 0, 0)->co, mesh_vert(vm_in, i, 0, 1)->co); - sub_v3_v3v3(co2, mesh_vert(vm_in, i, 0, 1)->co, mesh_vert(vm_in, i, 0, 2)->co); - cross_v3_v3v3(tangent, co1, co2); - /** The following constant is chosen to best match the old results. */ - normalize_v3_length(tangent, 1.5f / ns_out); - } - /** Copy corner vertex. */ copy_v3_v3(mesh_vert(vm_out, i, 0, 0)->co, mesh_vert(vm_in, i, 0, 0)->co); - /** Copy the rest of the boundary vertices. */ for (int k = 1; k < ns_in; k++) { copy_v3_v3(co, mesh_vert(vm_in, i, 0, k)->co); - copy_v3_v3(co1, mesh_vert(vm_in, i, 0, k - 1)->co); - copy_v3_v3(co2, mesh_vert(vm_in, i, 0, k + 1)->co); + /* Smooth boundary rule. Custom profiles shouldn't be smoothed. */ + if (bp->profile_type != BEVEL_PROFILE_CUSTOM) { + float co1[3], co2[3], acc[3]; + copy_v3_v3(co1, mesh_vert(vm_in, i, 0, k - 1)->co); + copy_v3_v3(co2, mesh_vert(vm_in, i, 0, k + 1)->co); - add_v3_v3v3(acc, co1, co2); - if (bndv->is_arc_start) { - sub_v3_v3(co1, co); - sub_v3_v3(co2, co); - normalize_v3(co1); - normalize_v3(co2); - add_v3_v3v3(tangent, co1, co2); - /* This is an empirical formula to make the result look good. */ - normalize_v3(tangent); - float dot = convex ? fminf(0, dot_v3v3(tangent2, tangent)) : 1.0f; - mul_v3_fl(tangent, stretch / ns_in * dot); + add_v3_v3v3(acc, co1, co2); + madd_v3_v3fl(acc, co, -2.0f); + madd_v3_v3fl(co, acc, -1.0f / 6.0f); } - else if (orthogonal) { - sub_v3_v3(co1, co); - cross_v3_v3v3(tangent, normal, co1); - /* This is an empirical formula to make the result look good. */ - normalize_v3_length(tangent, -bp->offset * 0.7071f / ns_in); - } - mul_v3_fl(co, 2.0f); - madd_v3_v3fl(co, acc, -0.25f); - madd_v3_v3fl(co, mesh_vert(vm_in, i, 1, k)->co, -0.5f); - add_v3_v3(co, tangent); copy_v3_v3(mesh_vert_canon(vm_out, i, 0, 2 * k)->co, co); } + } + /* Now adjust odd boundary vertices in output mesh, based on even ones. */ + BoundVert *bndv = vm_out->boundstart; + for (int i = 0; i < n_boundary; i++) { + for (int k = 1; k < ns_out; k += 2) { + get_profile_point(bp, &bndv->profile, k, ns_out, co); + + /* Smooth if using a non-custom profile. */ + if (bp->profile_type != BEVEL_PROFILE_CUSTOM) { + float co1[3], co2[3], acc[3]; + copy_v3_v3(co1, mesh_vert_canon(vm_out, i, 0, k - 1)->co); + copy_v3_v3(co2, mesh_vert_canon(vm_out, i, 0, k + 1)->co); + + add_v3_v3v3(acc, co1, co2); + madd_v3_v3fl(acc, co, -2.0f); + madd_v3_v3fl(co, acc, -1.0f / 6.0f); + } + + copy_v3_v3(mesh_vert_canon(vm_out, i, 0, k)->co, co); + } bndv = bndv->next; } vmesh_copy_equiv_verts(vm_out); @@ -4249,7 +4169,7 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in) /* Copy adjusted verts back into vm_in. */ for (int i = 0; i < n_boundary; i++) { for (int k = 0; k < ns_in; k++) { - copy_v3_v3(mesh_vert_canon(vm_in, i, 0, k)->co, mesh_vert_canon(vm_out, i, 0, 2 * k)->co); + copy_v3_v3(mesh_vert(vm_in, i, 0, k)->co, mesh_vert(vm_out, i, 0, 2 * k)->co); } } @@ -4334,7 +4254,7 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in) vmesh_copy_equiv_verts(vm_out); /* The center vertex is special. */ - gamma = sabin_gamma(n_boundary) * 0.5f; + gamma = sabin_gamma(n_boundary); beta = -gamma; /* Accumulate edge verts in co1, face verts in co2. */ float co1[3], co2[3];