Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Parborg <darkdefende@gmail.com>2020-05-14 22:16:16 +0300
committerSebastian Parborg <darkdefende@gmail.com>2020-05-14 22:17:33 +0300
commit516e1b4031f8c13dd6764ac794734ad966c09f13 (patch)
tree92ffff9be276e14156a203ca0e9abaa619050460 /source/blender/editors/mesh
parent2efe77ca5119300f84a021faa572e1ee9fdc5d7e (diff)
Fix T76025: Flip/recalc steep custom normals produces wrong result
The issue was the custom loop normal data would be mangled when we reversed the face loops. The flip face code will now correctly flip the custom face normals so they are not left in an undefined state. Reviewed By: Bastien Differential Revision: http://developer.blender.org/D7528
Diffstat (limited to 'source/blender/editors/mesh')
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c135
1 files changed, 131 insertions, 4 deletions
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 5c7c95b59d7..bfd88de4c66 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -1970,6 +1970,84 @@ void MESH_OT_duplicate(wmOperatorType *ot)
RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
}
+static BMLoopNorEditDataArray *flip_custom_normals_init_data(BMesh *bm)
+{
+ BMLoopNorEditDataArray *lnors_ed_arr = NULL;
+ if (CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
+ /* The mesh has custom normal data, update these too.
+ * Otherwise they will be left in a mangled state.
+ */
+ BM_lnorspace_update(bm);
+ lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, true);
+ }
+
+ return lnors_ed_arr;
+}
+
+static bool flip_custom_normals(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr)
+{
+ if (!lnors_ed_arr) {
+ return false;
+ }
+
+ if (lnors_ed_arr->totloop == 0) {
+ /* No loops normals to flip, exit early! */
+ return false;
+ }
+
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
+ BM_lnorspace_update(bm);
+
+ /* We need to recreate the custom normal array because the clnors_data will
+ * be mangled because we swapped the loops around when we flipped the faces. */
+ BMLoopNorEditDataArray *lnors_ed_arr_new_full = BM_loop_normal_editdata_array_init(bm, true);
+
+ {
+ /* We need to recalculate all loop normals in the affected area. Even the ones that are not
+ * going to be flipped because the clnors data is mangled. */
+
+ BMLoopNorEditData *lnor_ed_new_full = lnors_ed_arr_new_full->lnor_editdata;
+ for (int i = 0; i < lnors_ed_arr_new_full->totloop; i++, lnor_ed_new_full++) {
+
+ BMLoopNorEditData *lnor_ed =
+ lnors_ed_arr->lidx_to_lnor_editdata[lnor_ed_new_full->loop_index];
+
+ BLI_assert(lnor_ed != NULL);
+
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[lnor_ed_new_full->loop_index],
+ lnor_ed->nloc,
+ lnor_ed_new_full->clnors_data);
+ }
+ }
+
+ BMFace *f;
+ BMLoop *l;
+ BMIter iter_f, iter_l;
+ BM_ITER_MESH (f, &iter_f, bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ continue;
+ }
+ /* Flip all the custom loop normals on the selected faces. */
+
+ BM_ITER_ELEM (l, &iter_l, f, BM_LOOPS_OF_FACE) {
+
+ int loop_index = BM_elem_index_get(l);
+
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lidx_to_lnor_editdata[loop_index];
+ BMLoopNorEditData *lnor_ed_new = lnors_ed_arr_new_full->lidx_to_lnor_editdata[loop_index];
+ BLI_assert(lnor_ed != NULL && lnor_ed_new != NULL);
+
+ negate_v3(lnor_ed->nloc);
+
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[loop_index], lnor_ed->nloc, lnor_ed_new->clnors_data);
+ }
+ }
+ BM_loop_normal_editdata_array_free(lnors_ed_arr_new_full);
+ return true;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1977,6 +2055,8 @@ void MESH_OT_duplicate(wmOperatorType *ot)
* \{ */
static int edbm_flip_normals_exec(bContext *C, wmOperator *op)
{
+ const bool only_clnors = RNA_boolean_get(op->ptr, "only_clnors");
+
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
@@ -1986,15 +2066,45 @@ static int edbm_flip_normals_exec(bContext *C, wmOperator *op)
Object *obedit = objects[ob_index];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (em->bm->totfacesel == 0) {
+ if (only_clnors) {
+ if (CustomData_has_layer(&em->bm->ldata, CD_CUSTOMLOOPNORMAL)) {
+ /* The mesh has custom normal data, flip them. */
+ BMesh *bm = em->bm;
+
+ BM_lnorspace_update(bm);
+ BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
+
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ negate_v3(lnor_ed->nloc);
+
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index],
+ lnor_ed->nloc,
+ lnor_ed->clnors_data);
+ }
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ EDBM_update_generic(obedit->data, true, false);
+ }
continue;
}
- if (!EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true)) {
+ if (em->bm->totfacesel == 0) {
continue;
}
- EDBM_update_generic(obedit->data, true, false);
+ bool has_flipped_faces = false;
+
+ /* See if we have any custom normals to flip. */
+ BMLoopNorEditDataArray *lnors_ed_arr = flip_custom_normals_init_data(em->bm);
+
+ if (EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true)) {
+ has_flipped_faces = true;
+ }
+
+ if (flip_custom_normals(em->bm, lnors_ed_arr) || has_flipped_faces) {
+ EDBM_update_generic(obedit->data, true, false);
+ }
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
}
MEM_freeN(objects);
@@ -2014,6 +2124,12 @@ void MESH_OT_flip_normals(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna,
+ "only_clnors",
+ false,
+ "Custom Normals Only",
+ "Only flip the custom loop normals of the selected elements");
}
/** \} */
@@ -2276,6 +2392,7 @@ void MESH_OT_reveal(wmOperatorType *ot)
static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
+ const bool inside = RNA_boolean_get(op->ptr, "inside");
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
@@ -2288,11 +2405,21 @@ static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op)
continue;
}
+ BMLoopNorEditDataArray *lnors_ed_arr = NULL;
+
+ if (inside) {
+ /* Save custom normal data for later so we can flip them correctly. */
+ lnors_ed_arr = flip_custom_normals_init_data(em->bm);
+ }
+
if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf", BM_ELEM_SELECT)) {
continue;
}
- if (RNA_boolean_get(op->ptr, "inside")) {
+
+ if (inside) {
EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true);
+ flip_custom_normals(em->bm, lnors_ed_arr);
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
}
EDBM_update_generic(obedit->data, true, false);