diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.cc b/source/blender/bmesh/intern/bmesh_mesh_normals.cc index 87b041a857f..f3d142179eb 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_normals.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_normals.cc @@ -1877,14 +1877,73 @@ void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor) #endif } +/** + * Make sure the corner fan (tangent space) style custom normals exist on the BMesh. If free vector + * custom normals exist, they'll be converted. This is often necessary for BMesh editing tools that + * don't (yet) support free normals. + */ +static void bm_lnorspace_ensure_from_free_normals(BMesh *bm) +{ + /* Zero values tell the normals calculation code to use the automatic normals (rather than any + * custom normal vector). */ + Array lnors(bm->totloop, float3(0)); + const int vert_free_offset = CustomData_get_offset_named( + &bm->vdata, CD_PROP_FLOAT3, "custom_normal"); + const int edge_free_offset = CustomData_get_offset_named( + &bm->edata, CD_PROP_FLOAT3, "custom_normal"); + const int face_free_offset = CustomData_get_offset_named( + &bm->pdata, CD_PROP_FLOAT3, "custom_normal"); + const int loop_free_offset = CustomData_get_offset_named( + &bm->ldata, CD_PROP_FLOAT3, "custom_normal"); + if (vert_free_offset != -1) { + int loop_index = 0; + BMFace *f; + BMLoop *l; + BMIter fiter, liter; + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + lnors[loop_index++] = float3(BM_ELEM_CD_GET_FLOAT_P(l->v, vert_free_offset)); + } + } + BM_data_layer_free_named(bm, &bm->vdata, "custom_normal"); + } + else if (edge_free_offset != -1) { + BM_data_layer_free_named(bm, &bm->edata, "custom_normal"); + } + else if (face_free_offset != -1) { + int loop_index = 0; + BMFace *f; + BMLoop *l; + BMIter fiter, liter; + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + lnors[loop_index++] = float3(BM_ELEM_CD_GET_FLOAT_P(f, face_free_offset)); + } + } + BM_data_layer_free_named(bm, &bm->pdata, "custom_normal"); + } + else if (loop_free_offset != -1) { + int loop_index = 0; + BMFace *f; + BMLoop *l; + BMIter fiter, liter; + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + lnors[loop_index++] = float3(BM_ELEM_CD_GET_FLOAT_P(l, loop_free_offset)); + } + } + BM_data_layer_free_named(bm, &bm->ldata, "custom_normal"); + } + BM_lnorspacearr_store(bm, lnors); +} + void BM_lnorspace_update(BMesh *bm) { if (bm->lnor_spacearr == nullptr) { bm->lnor_spacearr = MEM_callocN(__func__); } if (bm->lnor_spacearr->lspacearr == nullptr) { - Array lnors(bm->totloop, float3(0)); - BM_lnorspacearr_store(bm, lnors); + bm_lnorspace_ensure_from_free_normals(bm); } else if (bm->spacearr_dirty & (BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL)) { BM_lnorspace_rebuild(bm, false); diff --git a/source/blender/bmesh/tools/bmesh_bevel.cc b/source/blender/bmesh/tools/bmesh_bevel.cc index 9326d749834..ee45d3fce46 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.cc +++ b/source/blender/bmesh/tools/bmesh_bevel.cc @@ -2675,6 +2675,12 @@ static void bevel_harden_normals(BevelParams *bp, BMesh *bm) cd_clnors_offset = CustomData_get_offset_named(&bm->ldata, CD_PROP_INT16_2D, "custom_normal"); } + /* If the custom normals attribute still hasn't been added with the correct type, at least don't + * crash. */ + if (cd_clnors_offset == -1) { + return; + } + BMIter fiter; BMFace *f; BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {