From 87b8e2e18d5cfce4b73fd5dfc8a67f917a224503 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 5 Jul 2023 12:35:01 -0400 Subject: [PATCH] Fix #109471: BMesh to Mesh conversion invalid UV boolean attribute data First we copied the entire BMesh custom data layout to the Mesh, then we decided not to copy some boolean layers like UV pinning if every value was false. But that left the layers uninitialized. Instead, copy the custom data layout _after_ finding which layers to skip. --- .../bmesh/intern/bmesh_mesh_convert.cc | 71 ++++++++++--------- 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc index 31a2143a467..0fb8dbc831f 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc @@ -1151,7 +1151,7 @@ static void bm_face_loop_table_build(BMesh &bm, bool &need_hide_poly, bool &need_sharp_face, bool &need_material_index, - Vector &ldata_layers_marked_nocopy) + Vector &loop_layers_not_to_copy) { const CustomData &ldata = bm.ldata; Vector vert_sel_layers; @@ -1226,20 +1226,17 @@ static void bm_face_loop_table_build(BMesh &bm, for (const int i : vert_sel_layers.index_range()) { if (!need_vert_sel[i]) { - ldata.layers[vert_sel_layers[i]].flag |= CD_FLAG_NOCOPY; - ldata_layers_marked_nocopy.append(vert_sel_layers[i]); + loop_layers_not_to_copy.append(vert_sel_layers[i]); } } for (const int i : edge_sel_layers.index_range()) { if (!need_edge_sel[i]) { - ldata.layers[edge_sel_layers[i]].flag |= CD_FLAG_NOCOPY; - ldata_layers_marked_nocopy.append(edge_sel_layers[i]); + loop_layers_not_to_copy.append(edge_sel_layers[i]); } } for (const int i : pin_layers.index_range()) { if (!need_pin[i]) { - ldata.layers[pin_layers[i]].flag |= CD_FLAG_NOCOPY; - ldata_layers_marked_nocopy.append(pin_layers[i]); + loop_layers_not_to_copy.append(pin_layers[i]); } } } @@ -1419,15 +1416,6 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const BMeshToMeshParams me->totpoly = bm->totface; me->act_face = -1; - { - CustomData_MeshMasks mask = CD_MASK_MESH; - CustomData_MeshMasks_update(&mask, ¶ms->cd_mask_extra); - CustomData_copy_layout(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert); - CustomData_copy_layout(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge); - CustomData_copy_layout(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop); - CustomData_copy_layout(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly); - } - bool need_select_vert = false; bool need_select_edge = false; bool need_select_poly = false; @@ -1442,7 +1430,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const BMeshToMeshParams Array edge_table; Array face_table; Array loop_table; - Vector ldata_layers_marked_nocopy; + Vector loop_layers_not_to_copy; threading::parallel_invoke( me->totface > 1024, [&]() { @@ -1464,10 +1452,22 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const BMeshToMeshParams need_hide_poly, need_sharp_face, need_material_index, - ldata_layers_marked_nocopy); + loop_layers_not_to_copy); + for (const int i : loop_layers_not_to_copy) { + bm->ldata.layers[i].flag |= CD_FLAG_NOCOPY; + } }); bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE | BM_LOOP); + { + CustomData_MeshMasks mask = CD_MASK_MESH; + CustomData_MeshMasks_update(&mask, ¶ms->cd_mask_extra); + CustomData_copy_layout(&bm->vdata, &me->vdata, mask.vmask, CD_CONSTRUCT, me->totvert); + CustomData_copy_layout(&bm->edata, &me->edata, mask.emask, CD_CONSTRUCT, me->totedge); + CustomData_copy_layout(&bm->ldata, &me->ldata, mask.lmask, CD_CONSTRUCT, me->totloop); + CustomData_copy_layout(&bm->pdata, &me->pdata, mask.pmask, CD_CONSTRUCT, me->totpoly); + } + /* Add optional mesh attributes before parallel iteration. */ assert_bmesh_has_no_mesh_only_attributes(*bm); bke::MutableAttributeAccessor attrs = me->attributes_for_write(); @@ -1548,7 +1548,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const BMeshToMeshParams bm_to_mesh_loops(*bm, loop_table, *me); /* Topology could be changed, ensure #CD_MDISPS are ok. */ multires_topology_changed(me); - for (const int i : ldata_layers_marked_nocopy) { + for (const int i : loop_layers_not_to_copy) { bm->ldata.layers[i].flag &= ~CD_FLAG_NOCOPY; } }, @@ -1630,18 +1630,6 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * me->totloop = bm->totloop; me->totpoly = bm->totface; - /* Don't process shape-keys. We only feed them through the modifier stack as needed, - * e.g. for applying modifiers or the like. */ - CustomData_MeshMasks mask = CD_MASK_DERIVEDMESH; - if (cd_mask_extra != nullptr) { - CustomData_MeshMasks_update(&mask, cd_mask_extra); - } - mask.vmask &= ~CD_MASK_SHAPEKEY; - CustomData_merge_layout(&bm->vdata, &me->vdata, mask.vmask, CD_CONSTRUCT, me->totvert); - CustomData_merge_layout(&bm->edata, &me->edata, mask.emask, CD_CONSTRUCT, me->totedge); - CustomData_merge_layout(&bm->ldata, &me->ldata, mask.lmask, CD_CONSTRUCT, me->totloop); - CustomData_merge_layout(&bm->pdata, &me->pdata, mask.pmask, CD_CONSTRUCT, me->totpoly); - me->runtime->deformed_only = true; /* In a first pass, update indices of BMesh elements and build tables for easy iteration later. @@ -1661,7 +1649,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * Array edge_table; Array face_table; Array loop_table; - Vector ldata_layers_marked_nocopy; + Vector loop_layers_not_to_copy; threading::parallel_invoke( me->totface > 1024, [&]() { @@ -1683,10 +1671,25 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * need_hide_poly, need_sharp_face, need_material_index, - ldata_layers_marked_nocopy); + loop_layers_not_to_copy); + for (const int i : loop_layers_not_to_copy) { + bm->ldata.layers[i].flag |= CD_FLAG_NOCOPY; + } }); bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE | BM_LOOP); + /* Don't process shape-keys. We only feed them through the modifier stack as needed, + * e.g. for applying modifiers or the like. */ + CustomData_MeshMasks mask = CD_MASK_DERIVEDMESH; + if (cd_mask_extra != nullptr) { + CustomData_MeshMasks_update(&mask, cd_mask_extra); + } + mask.vmask &= ~CD_MASK_SHAPEKEY; + CustomData_merge_layout(&bm->vdata, &me->vdata, mask.vmask, CD_CONSTRUCT, me->totvert); + CustomData_merge_layout(&bm->edata, &me->edata, mask.emask, CD_CONSTRUCT, me->totedge); + CustomData_merge_layout(&bm->ldata, &me->ldata, mask.lmask, CD_CONSTRUCT, me->totloop); + CustomData_merge_layout(&bm->pdata, &me->pdata, mask.pmask, CD_CONSTRUCT, me->totpoly); + /* Add optional mesh attributes before parallel iteration. */ assert_bmesh_has_no_mesh_only_attributes(*bm); bke::MutableAttributeAccessor attrs = me->attributes_for_write(); @@ -1756,7 +1759,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * }, [&]() { bm_to_mesh_loops(*bm, loop_table, *me); - for (const int i : ldata_layers_marked_nocopy) { + for (const int i : loop_layers_not_to_copy) { bm->ldata.layers[i].flag &= ~CD_FLAG_NOCOPY; } });