Better bevel normal hardening when some faces were smooth.
authorHoward Trickey <howard.trickey@gmail.com>
Sun, 6 Jan 2019 23:12:00 +0000 (18:12 -0500)
committerHoward Trickey <howard.trickey@gmail.com>
Sun, 6 Jan 2019 23:12:00 +0000 (18:12 -0500)
Harden normals causes normal splitting, which will not give the
appearance expected due to autosmooth unless some edges are sharpened,
so this change fixes that. Also bevel tool will turn on autosmooth
if not already on if hardening normals.

release/scripts/addons
release/scripts/addons_contrib
source/blender/bmesh/intern/bmesh_opdefines.c
source/blender/bmesh/operators/bmo_bevel.c
source/blender/bmesh/tools/bmesh_bevel.c
source/blender/bmesh/tools/bmesh_bevel.h
source/blender/editors/mesh/editmesh_bevel.c
source/blender/modifiers/intern/MOD_bevel.c
source/tools

index 25ae9e1..4034083 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 25ae9e134472c5bca62add0a1db3cdfc2d86aaa7
+Subproject commit 40340832e3992f46034b470aef1af6f7a3a4410f
index 4c5ddae..272b1a4 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 4c5ddaeb2d1953ea9db10b2fdde2f93e19b1d6d7
+Subproject commit 272b1a4ef07717beb3d0bfcb7380c2164fd008a3
index 2cae6fb..db4985c 100644 (file)
@@ -1765,6 +1765,7 @@ static BMOpDefine bmo_bevel_def = {
         {"harden_normals", BMO_OP_SLOT_BOOL},  /* harden normals */
         {"face_strength_mode", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM},
                bmo_enum_bevel_face_strength_type}, /* whether to set face strength, and which faces to set if so */
+        {"smoothresh", BMO_OP_SLOT_FLT},       /* for passing mesh's smoothresh, used in hardening */
         {{'\0'}},
        },
        /* slots_out */
index 1ef8531..3277824 100644 (file)
@@ -47,6 +47,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
        const bool      mark_sharp        = BMO_slot_bool_get(op->slots_in, "mark_sharp");
        const bool  harden_normals = BMO_slot_bool_get(op->slots_in, "harden_normals");
        const int   face_strength_mode = BMO_slot_int_get(op->slots_in, "face_strength_mode");
+       const float smoothresh    = BMO_slot_float_get(op->slots_in, "smoothresh");
 
        if (offset > 0) {
                BMOIter siter;
@@ -72,7 +73,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
 
                BM_mesh_bevel(
                        bm, offset, offset_type, seg, profile, vonly, false, clamp_overlap, NULL, -1, material,
-                       loop_slide, mark_seam, mark_sharp, harden_normals, face_strength_mode);
+                       loop_slide, mark_seam, mark_sharp, harden_normals, face_strength_mode, smoothresh);
 
                BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG);
                BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "edges.out", BM_EDGE, BM_ELEM_TAG);
index 7149df7..452dfa2 100644 (file)
@@ -222,6 +222,7 @@ typedef struct BevelParams {
        int vertex_group;       /* vertex group index, maybe set if vertex_only */
        int mat_nr;             /* if >= 0, material number for bevel; else material comes from adjacent faces */
        int face_strength_mode; /* setting face strength if > 0 */
+       float smoothresh;               /* mesh's smoothresh, used if hardening */
 } BevelParams;
 
 // #pragma GCC diagnostic ignored "-Wpadded"
@@ -1703,6 +1704,33 @@ static void bevel_extend_edge_data(BevVert *bv)
        } while (bcur != start);
 }
 
+/* Mark edges as sharp if they are between a smooth recon face and a new face. */
+static void bevel_edges_sharp_boundary(BMesh *bm, BevelParams *bp)
+{
+       BMIter fiter, liter;
+       BMFace *f, *fother;
+       BMLoop *l, *lother;
+       FKind fkind;
+
+       BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
+               if (!BM_elem_flag_test(f, BM_ELEM_SMOOTH))
+                       continue;
+               if (get_face_kind(bp, f) != F_RECON)
+                       continue;
+               BM_ITER_ELEM(l, &liter, f, BM_LOOPS_OF_FACE) {
+                       /* cases we care about will have exactly one adjacent face */
+                       lother = l->radial_next;
+                       fother = lother->f;
+                       if (lother != l && fother) {
+                               fkind = get_face_kind(bp, lother->f);
+                               if (ELEM(fkind, F_EDGE, F_VERT)) {
+                                       BM_elem_flag_disable(l->e, BM_ELEM_SMOOTH);
+                               }
+                       }
+               }
+       }
+}
+
 /*
  * Harden normals for bevel.
  * The desired effect is that the newly created F_EDGE and F_VERT faces appear smoothly shaded
@@ -1725,11 +1753,25 @@ static void bevel_harden_normals(BMesh *bm, BevelParams *bp)
                return;
 
        /* recalculate all face and vertex normals; side effect: ensures vertex, edge, face indices */
+       /* I suspect this is not necessary: TODO: test that guess */
        BM_mesh_normals_update(bm);
 
+       cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
+
+       /* If there is not already a custom split normal layer then making one (with BM_lnorspace_update)
+        * will not respect the autosmooth angle between smooth faces. To get that to happen, we have
+        * to mark the sharpen the edges that are only sharp because of the angle test -- otherwise would be smooth.
+        */
+       if (cd_clnors_offset == -1) {
+               BM_edges_sharp_from_angle_set(bm, bp->smoothresh);
+               bevel_edges_sharp_boundary(bm, bp);
+       }
+
        /* ensure that bm->lnor_spacearr has properly stored loop normals; side effect: ensures loop indices */
        BM_lnorspace_update(bm);
-       cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
+
+       if (cd_clnors_offset == -1)
+               cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
 
        BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
                fkind = get_face_kind(bp, f);
@@ -5677,7 +5719,7 @@ void BM_mesh_bevel(
         const bool vertex_only, const bool use_weights, const bool limit_offset,
         const struct MDeformVert *dvert, const int vertex_group, const int mat,
         const bool loop_slide, const bool mark_seam, const bool mark_sharp,
-        const bool harden_normals, const int face_strength_mode)
+        const bool harden_normals, const int face_strength_mode, const float smoothresh)
 {
        BMIter iter, liter;
        BMVert *v, *v_next;
@@ -5704,6 +5746,7 @@ void BM_mesh_bevel(
        bp.mark_sharp = mark_sharp;
        bp.harden_normals = harden_normals;
        bp.face_strength_mode = face_strength_mode;
+       bp.smoothresh = smoothresh;
        bp.face_hash = NULL;
 
        if (profile >= 0.950f) {  /* r ~ 692, so PRO_SQUARE_R is 1e4 */
index 2bfa2be..36a80ee 100644 (file)
@@ -34,6 +34,6 @@ void BM_mesh_bevel(
         const float profile, const bool vertex_only, const bool use_weights,
         const bool limit_offset, const struct MDeformVert *dvert, const int vertex_group,
         const int mat, const bool loop_slide, const bool mark_seam, const bool mark_sharp,
-        const bool harden_normals, const int face_strength_mode);
+        const bool harden_normals, const int face_strength_mode, const float smoothresh);
 
 #endif /* __BMESH_BEVEL_H__ */
index ff259f0..0d99c43 100644 (file)
@@ -41,6 +41,8 @@
 #include "BKE_layer.h"
 #include "BKE_mesh.h"
 
+#include "DNA_mesh_types.h"
+
 #include "RNA_define.h"
 #include "RNA_access.h"
 
@@ -231,6 +233,7 @@ static bool edbm_bevel_calc(wmOperator *op)
        const bool harden_normals = RNA_boolean_get(op->ptr, "harden_normals");
        const int face_strength_mode = RNA_enum_get(op->ptr, "face_strength_mode");
 
+
        for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
                em = opdata->ob_store[ob_index].em;
 
@@ -243,12 +246,21 @@ static bool edbm_bevel_calc(wmOperator *op)
                        material = CLAMPIS(material, -1, em->ob->totcol - 1);
                }
 
+               Mesh *me = em->ob->data;
+
+               if (harden_normals && !(me->flag & ME_AUTOSMOOTH)) {
+                       /* harden_normals only has a visible effect if autosmooth is on, so turn it on */
+                       me->flag |= ME_AUTOSMOOTH;
+               }
+
                EDBM_op_init(
                        em, &bmop, op,
                        "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f clamp_overlap=%b "
-                       "material=%i loop_slide=%b mark_seam=%b mark_sharp=%b harden_normals=%b face_strength_mode=%i",
+                       "material=%i loop_slide=%b mark_seam=%b mark_sharp=%b harden_normals=%b face_strength_mode=%i "
+                               "smoothresh=%f",
                        BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile,
-                       clamp_overlap, material, loop_slide, mark_seam, mark_sharp, harden_normals, face_strength_mode);
+                               clamp_overlap, material, loop_slide, mark_seam, mark_sharp, harden_normals, face_strength_mode,
+                                       me->smoothresh);
 
                BMO_op_exec(em->bm, &bmop);
 
index e63b540..363cdb0 100644 (file)
@@ -116,7 +116,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
        const bool loop_slide = (bmd->flags & MOD_BEVEL_EVEN_WIDTHS) == 0;
        const bool mark_seam = (bmd->edge_flags & MOD_BEVEL_MARK_SEAM);
        const bool mark_sharp = (bmd->edge_flags & MOD_BEVEL_MARK_SHARP);
-       const bool harden_normals = (bmd->flags & MOD_BEVEL_HARDEN_NORMALS);
+       bool harden_normals = (bmd->flags & MOD_BEVEL_HARDEN_NORMALS);
        const int face_strength_mode = bmd->face_str_mode;
 
        bm = BKE_mesh_to_bmesh_ex(
@@ -187,10 +187,15 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
                }
        }
 
+       if (harden_normals && !(((Mesh *)ctx->object->data)->flag & ME_AUTOSMOOTH)) {
+               modifier_setError(md, "Enable 'Auto Smooth' option in mesh settings for hardening");
+               harden_normals = false;
+       }
+
        BM_mesh_bevel(bm, bmd->value, offset_type, bmd->res, bmd->profile,
                      vertex_only, bmd->lim_flags & MOD_BEVEL_WEIGHT, do_clamp,
                      dvert, vgroup, mat, loop_slide, mark_seam, mark_sharp,
-                     harden_normals, face_strength_mode);
+                     harden_normals, face_strength_mode, mesh->smoothresh);
 
        result = BKE_mesh_from_bmesh_for_eval_nomain(bm, 0);
 
index 279c373..aef8f32 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 279c373280e54388ede50abea9d11d5cdaa1d567
+Subproject commit aef8f32086b9393d286c49cbe5a51ae465fe0589