From 2ef27684c56c87158d89073afebb062e6c1081fd Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 20 Jun 2023 16:32:15 -0400 Subject: [PATCH] Fix #108930: Mirror modifier handles custom normals incorrectly Before 17d161f56537d424d369, the "vec_lnor" stored the automatically computed normal without any influence from custom normals. But after, the normals were used from the final output corner normals array, which did have the custom normal data factored in at the end. This fix is to revert part of that commit, storing the automatically computed normal per space like before. --- source/blender/blenkernel/BKE_mesh.hh | 9 ++--- .../blender/blenkernel/intern/mesh_mirror.cc | 7 ++-- .../blender/blenkernel/intern/mesh_normals.cc | 35 +++++++++---------- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/source/blender/blenkernel/BKE_mesh.hh b/source/blender/blenkernel/BKE_mesh.hh index f966c34454a4..2c40f2701e56 100644 --- a/source/blender/blenkernel/BKE_mesh.hh +++ b/source/blender/blenkernel/BKE_mesh.hh @@ -91,13 +91,15 @@ void normals_calc_poly_vert(Span vert_positions, * a regular #float3 format. */ struct CornerNormalSpace { - /** Reference vector, orthogonal to corner normal. */ + /** The automatically computed face corner normal, not including influence of custom normals. */ + float3 vec_lnor; + /** Reference vector, orthogonal to #vec_lnor. */ float3 vec_ref; - /** Third vector, orthogonal to corner normal and #vec_ref. */ + /** Third vector, orthogonal to #vec_lnor and #vec_ref. */ float3 vec_ortho; /** Reference angle around #vec_ortho, in [0, pi] range (0.0 marks space as invalid). */ float ref_alpha; - /** Reference angle around corner normal, in [0, 2pi] range (0.0 marks space as invalid). */ + /** Reference angle around #vec_lnor, in [0, 2pi] range (0.0 marks space as invalid). */ float ref_beta; }; @@ -129,7 +131,6 @@ struct CornerNormalSpaceArray { }; void lnor_space_custom_normal_to_data(const CornerNormalSpace *lnor_space, - float3 lnor_no_custom, const float custom_lnor[3], short r_clnor_data[2]); diff --git a/source/blender/blenkernel/intern/mesh_mirror.cc b/source/blender/blenkernel/intern/mesh_mirror.cc index 4cecb3430079..19abeadfbb12 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.cc +++ b/source/blender/blenkernel/intern/mesh_mirror.cc @@ -431,15 +431,12 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, mirrorj += result_polys[mirror_i].size() - (j - src_poly.start()); } - const blender::float3 orig_normal = loop_normals[mirrorj]; copy_v3_v3(loop_normals[mirrorj], loop_normals[j]); mul_m4_v3(mtx_nor, loop_normals[mirrorj]); const int space_index = lnors_spacearr.corner_space_indices[mirrorj]; - blender::bke::mesh::lnor_space_custom_normal_to_data(&lnors_spacearr.spaces[space_index], - orig_normal, - loop_normals[mirrorj], - clnors[mirrorj]); + blender::bke::mesh::lnor_space_custom_normal_to_data( + &lnors_spacearr.spaces[space_index], loop_normals[mirrorj], clnors[mirrorj]); } } } diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 545c180d2ff1..2e997ebf3d14 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -488,6 +488,8 @@ static void lnor_space_define(CornerNormalSpace *lnor_space, return; } + lnor_space->vec_lnor = lnor; + /* Compute ref alpha, average angle of all available edge vectors to lnor. */ if (!edge_vectors.is_empty()) { float alpha = 0.0f; @@ -542,7 +544,7 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, using namespace blender::bke::mesh; CornerNormalSpace space{}; lnor_space_define(&space, lnor, vec_ref, vec_other, edge_vectors); - copy_v3_v3(lnor_space->vec_lnor, lnor); + copy_v3_v3(lnor_space->vec_lnor, space.vec_lnor); copy_v3_v3(lnor_space->vec_ref, space.vec_ref); copy_v3_v3(lnor_space->vec_ortho, space.vec_ortho); lnor_space->ref_alpha = space.ref_alpha; @@ -586,13 +588,12 @@ MINLINE short unit_float_to_short(const float val) namespace blender::bke::mesh { static void lnor_space_custom_data_to_normal(const CornerNormalSpace *lnor_space, - const float3 lnor_no_custom, const short clnor_data[2], float r_custom_lnor[3]) { /* NOP custom normal data or invalid lnor space, return. */ if (clnor_data[0] == 0 || lnor_space->ref_alpha == 0.0f || lnor_space->ref_beta == 0.0f) { - copy_v3_v3(r_custom_lnor, lnor_no_custom); + copy_v3_v3(r_custom_lnor, lnor_space->vec_lnor); return; } @@ -605,7 +606,7 @@ static void lnor_space_custom_data_to_normal(const CornerNormalSpace *lnor_space alphafac; const float betafac = unit_short_to_float(clnor_data[1]); - mul_v3_v3fl(r_custom_lnor, lnor_no_custom, cosf(alpha)); + mul_v3_v3fl(r_custom_lnor, lnor_space->vec_lnor, cosf(alpha)); if (betafac == 0.0f) { madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinf(alpha)); @@ -627,29 +628,29 @@ void BKE_lnor_space_custom_data_to_normal(const MLoopNorSpace *lnor_space, { using namespace blender::bke::mesh; CornerNormalSpace space; + space.vec_lnor = lnor_space->vec_lnor; space.vec_ref = lnor_space->vec_ref; space.vec_ortho = lnor_space->vec_ortho; space.ref_alpha = lnor_space->ref_alpha; space.ref_beta = lnor_space->ref_beta; - lnor_space_custom_data_to_normal(&space, lnor_space->vec_lnor, clnor_data, r_custom_lnor); + lnor_space_custom_data_to_normal(&space, clnor_data, r_custom_lnor); } namespace blender::bke::mesh { void lnor_space_custom_normal_to_data(const CornerNormalSpace *lnor_space, - const float3 lnor_no_custom, const float custom_lnor[3], short r_clnor_data[2]) { /* We use nullptr vector as NOP custom normal (can be simpler than giving auto-computed `lnor`). */ - if (is_zero_v3(custom_lnor) || compare_v3v3(lnor_no_custom, custom_lnor, 1e-4f)) { + if (is_zero_v3(custom_lnor) || compare_v3v3(lnor_space->vec_lnor, custom_lnor, 1e-4f)) { r_clnor_data[0] = r_clnor_data[1] = 0; return; } { const float pi2 = float(M_PI * 2.0); - const float cos_alpha = dot_v3v3(lnor_no_custom, custom_lnor); + const float cos_alpha = dot_v3v3(lnor_space->vec_lnor, custom_lnor); float vec[3], cos_beta; float alpha; @@ -664,7 +665,7 @@ void lnor_space_custom_normal_to_data(const CornerNormalSpace *lnor_space, } /* Project custom lnor on (vec_ref, vec_ortho) plane. */ - mul_v3_v3fl(vec, lnor_no_custom, -cos_alpha); + mul_v3_v3fl(vec, lnor_space->vec_lnor, -cos_alpha); add_v3_v3(vec, custom_lnor); normalize_v3(vec); @@ -696,11 +697,12 @@ void BKE_lnor_space_custom_normal_to_data(const MLoopNorSpace *lnor_space, { using namespace blender::bke::mesh; CornerNormalSpace space; + space.vec_lnor = lnor_space->vec_lnor; space.vec_ref = lnor_space->vec_ref; space.vec_ortho = lnor_space->vec_ortho; space.ref_alpha = lnor_space->ref_alpha; space.ref_beta = lnor_space->ref_beta; - lnor_space_custom_normal_to_data(&space, lnor_space->vec_lnor, custom_lnor, r_clnor_data); + lnor_space_custom_normal_to_data(&space, custom_lnor, r_clnor_data); } namespace blender::bke::mesh { @@ -917,10 +919,8 @@ static void lnor_space_for_single_fan(LoopSplitTaskDataCommon *common_data, lnors_spacearr->corner_space_indices[ml_curr_index] = space_index; if (!clnors_data.is_empty()) { - lnor_space_custom_data_to_normal(lnor_space, - loop_normals[ml_curr_index], - clnors_data[ml_curr_index], - loop_normals[ml_curr_index]); + lnor_space_custom_data_to_normal( + lnor_space, clnors_data[ml_curr_index], loop_normals[ml_curr_index]); } if (!lnors_spacearr->corners_by_space.is_empty()) { @@ -1100,7 +1100,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, /* Extra bonus: since small-stack is local to this function, * no more need to empty it at all cost! */ - lnor_space_custom_data_to_normal(lnor_space, lnor, *clnor_ref, lnor); + lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor); } } @@ -1616,8 +1616,7 @@ static void mesh_normals_loop_custom_set(Span positions, float *nor = r_custom_loop_normals[nidx]; const int space_index = lnors_spacearr.corner_space_indices[i]; - lnor_space_custom_normal_to_data( - &lnors_spacearr.spaces[space_index], loop_normals[i], nor, r_clnors_data[i]); + lnor_space_custom_normal_to_data(&lnors_spacearr.spaces[space_index], nor, r_clnors_data[i]); done_loops[i].reset(); } else { @@ -1634,7 +1633,7 @@ static void mesh_normals_loop_custom_set(Span positions, mul_v3_fl(avg_nor, 1.0f / float(fan_corners.size())); short2 clnor_data_tmp; lnor_space_custom_normal_to_data( - &lnors_spacearr.spaces[space_index], loop_normals[i], avg_nor, clnor_data_tmp); + &lnors_spacearr.spaces[space_index], avg_nor, clnor_data_tmp); r_clnors_data.fill_indices(fan_corners, clnor_data_tmp); }