diff options
54 files changed, 662 insertions, 298 deletions
diff --git a/intern/cycles/blender/mesh.cpp b/intern/cycles/blender/mesh.cpp index 63913b7cd7f..2e2dfd6583b 100644 --- a/intern/cycles/blender/mesh.cpp +++ b/intern/cycles/blender/mesh.cpp @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ +#include <optional> + #include "blender/session.h" #include "blender/sync.h" #include "blender/util.h" @@ -879,6 +881,23 @@ static void attr_create_random_per_island(Scene *scene, /* Create Mesh */ +static std::optional<BL::IntAttribute> find_material_index_attribute(BL::Mesh b_mesh) +{ + for (BL::Attribute &b_attribute : b_mesh.attributes) { + if (b_attribute.domain() != BL::Attribute::domain_FACE) { + continue; + } + if (b_attribute.data_type() != BL::Attribute::data_type_INT) { + continue; + } + if (b_attribute.name() != "material_index") { + continue; + } + return BL::IntAttribute{b_attribute}; + } + return std::nullopt; +} + static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, @@ -950,13 +969,22 @@ static void create_mesh(Scene *scene, } } + std::optional<BL::IntAttribute> material_indices = find_material_index_attribute(b_mesh); + auto get_material_index = [&](const int poly_index) -> int { + if (material_indices) { + return clamp(material_indices->data[poly_index].value(), 0, used_shaders.size() - 1); + } + return 0; + }; + /* create faces */ if (!subdivision) { for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) { - BL::MeshPolygon p = b_mesh.polygons[t.polygon_index()]; + const int poly_index = t.polygon_index(); + BL::MeshPolygon p = b_mesh.polygons[poly_index]; int3 vi = get_int3(t.vertices()); - int shader = clamp(p.material_index(), 0, used_shaders.size() - 1); + int shader = get_material_index(poly_index); bool smooth = p.use_smooth() || use_loop_normals; if (use_loop_normals) { @@ -977,9 +1005,10 @@ static void create_mesh(Scene *scene, else { vector<int> vi; - for (BL::MeshPolygon &p : b_mesh.polygons) { + for (int poly_index = 0; poly_index < numfaces; poly_index++) { + BL::MeshPolygon p = b_mesh.polygons[poly_index]; int n = p.loop_total(); - int shader = clamp(p.material_index(), 0, used_shaders.size() - 1); + int shader = get_material_index(poly_index); bool smooth = p.use_smooth() || use_loop_normals; vi.resize(n); diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py index 8f2141ba6fc..686d455b6b4 100644 --- a/release/scripts/startup/bl_ui/properties_data_mesh.py +++ b/release/scripts/startup/bl_ui/properties_data_mesh.py @@ -580,7 +580,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel): colliding_names = [] for collection in ( # Built-in names. - {"position": None, "material_index": None, "shade_smooth": None, "normal": None, "crease": None}, + {"position": None, "shade_smooth": None, "normal": None, "crease": None}, mesh.attributes, mesh.uv_layers, ob.vertex_groups, diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 8cf973b785c..ec6799ee995 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -6,6 +6,9 @@ * \ingroup bke */ +#include "DNA_mesh_types.h" + +#include "BKE_customdata.h" #include "BKE_mesh_types.h" #include "BLI_compiler_attrs.h" #include "BLI_utildefines.h" @@ -1019,6 +1022,30 @@ char *BKE_mesh_debug_info(const struct Mesh *me) void BKE_mesh_debug_print(const struct Mesh *me) ATTR_NONNULL(1); #endif +/** + * \return The material index for each polygon. May be null. + * \note In C++ code, prefer using the attribute API (#MutableAttributeAccessor)/ + */ +BLI_INLINE const int *BKE_mesh_material_indices(const Mesh *mesh) +{ + return (const int *)CustomData_get_layer_named(&mesh->pdata, CD_PROP_INT32, "material_index"); +} + +/** + * \return The material index for each polygon. Create the layer if it doesn't exist. + * \note In C++ code, prefer using the attribute API (#MutableAttributeAccessor)/ + */ +BLI_INLINE int *BKE_mesh_material_indices_for_write(Mesh *mesh) +{ + int *indices = (int *)CustomData_duplicate_referenced_layer_named( + &mesh->pdata, CD_PROP_INT32, "material_index", mesh->totpoly); + if (indices) { + return indices; + } + return (int *)CustomData_add_layer_named( + &mesh->pdata, CD_PROP_INT32, CD_SET_DEFAULT, NULL, mesh->totpoly, "material_index"); +} + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_mesh_legacy_convert.h b/source/blender/blenkernel/BKE_mesh_legacy_convert.h index bbc61d5af5e..11ee86c62a7 100644 --- a/source/blender/blenkernel/BKE_mesh_legacy_convert.h +++ b/source/blender/blenkernel/BKE_mesh_legacy_convert.h @@ -28,6 +28,16 @@ void BKE_mesh_legacy_convert_hide_layers_to_flags(struct Mesh *mesh); void BKE_mesh_legacy_convert_flags_to_hide_layers(struct Mesh *mesh); /** + * Move material indices from a generic attribute to #MPoly. + */ +void BKE_mesh_legacy_convert_material_indices_to_mpoly(struct Mesh *mesh); +/** + * Move material indices from the #MPoly struct to a generic attributes. + * Only add the attribute when the indices are not all zero. + */ +void BKE_mesh_legacy_convert_mpoly_to_material_indices(struct Mesh *mesh); + +/** * Recreate #MFace Tessellation. * * \note This doesn't use multi-threading like #BKE_mesh_recalc_looptri since diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 447921b6d84..51edf8308c3 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -2375,7 +2375,7 @@ bool CustomData_merge(const CustomData *source, static bool attribute_stored_in_bmesh_flag(const StringRef name) { - return ELEM(name, ".hide_vert", ".hide_edge", ".hide_poly"); + return ELEM(name, ".hide_vert", ".hide_edge", ".hide_poly", "material_index"); } static CustomData shallow_copy_remove_non_bmesh_attributes(const CustomData &src) diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 0fc09803088..57b84575c84 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -3247,7 +3247,8 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds, mp_example = *mpoly; } - const short mp_mat_nr = mp_example.mat_nr; + const int *orig_material_indices = BKE_mesh_material_indices(orgmesh); + const short mp_mat_nr = orig_material_indices ? orig_material_indices[0] : 0; const char mp_flag = mp_example.flag; int i; @@ -3358,10 +3359,12 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds, } } + int *material_indices = BKE_mesh_material_indices_for_write(me); + /* Loop for triangles. */ for (i = 0; i < num_faces; i++, mpolys++, mloops += 3) { /* Initialize from existing face. */ - mpolys->mat_nr = mp_mat_nr; + material_indices[i] = mp_mat_nr; mpolys->flag = mp_flag; mpolys->loopstart = i * 3; diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 14c31da488b..ff55409d5fc 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -842,16 +842,6 @@ static void tag_component_positions_changed(void *owner) } } -static int get_material_index(const MPoly &mpoly) -{ - return static_cast<int>(mpoly.mat_nr); -} - -static void set_material_index(MPoly &mpoly, int index) -{ - mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX)); -} - static bool get_shade_smooth(const MPoly &mpoly) { return mpoly.flag & ME_SMOOTH; @@ -1201,18 +1191,17 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() make_array_write_attribute<int>, nullptr); - static BuiltinCustomDataLayerProvider material_index( - "material_index", - ATTR_DOMAIN_FACE, - CD_PROP_INT32, - CD_MPOLY, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::NonDeletable, - face_access, - make_derived_read_attribute<MPoly, int, get_material_index>, - make_derived_write_attribute<MPoly, int, get_material_index, set_material_index>, - nullptr); + static BuiltinCustomDataLayerProvider material_index("material_index", + ATTR_DOMAIN_FACE, + CD_PROP_INT32, + CD_PROP_INT32, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + face_access, + make_array_read_attribute<int>, + make_array_write_attribute<int>, + nullptr); static BuiltinCustomDataLayerProvider shade_smooth( "shade_smooth", diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc index f7d84b8dc84..ce2e106c664 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.cc +++ b/source/blender/blenkernel/intern/gpencil_geom.cc @@ -35,6 +35,7 @@ #include "BLT_translation.h" +#include "BKE_attribute.hh" #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_gpencil.h" @@ -2662,6 +2663,8 @@ bool BKE_gpencil_convert_mesh(Main *bmain, const bool use_faces, const bool use_vgroups) { + using namespace blender; + using namespace blender::bke; if (ELEM(nullptr, ob_gp, ob_mesh) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == nullptr)) { return false; } @@ -2708,12 +2711,15 @@ bool BKE_gpencil_convert_mesh(Main *bmain, bGPDframe *gpf_fill = BKE_gpencil_layer_frame_get( gpl_fill, scene->r.cfra + frame_offset, GP_GETFRAME_ADD_NEW); int i; + + const VArray<int> mesh_material_indices = mesh_attributes(*me_eval).lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); for (i = 0; i < mpoly_len; i++) { const MPoly *mp = &mpoly[i]; /* Find material. */ int mat_idx = 0; - Material *ma = BKE_object_material_get(ob_mesh, mp->mat_nr + 1); + Material *ma = BKE_object_material_get(ob_mesh, mesh_material_indices[i] + 1); make_element_name( ob_mesh->id.name + 2, (ma != nullptr) ? ma->id.name + 2 : "Fill", 64, element_name); mat_idx = BKE_gpencil_material_find_index_by_name_prefix(ob_gp, element_name); diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 0a5eddfd319..b44a956eec4 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -33,6 +33,7 @@ #include "BLI_task.hh" #include "BLI_utildefines.h" #include "BLI_vector.hh" +#include "BLI_virtual_array.hh" #include "BLT_translation.h" @@ -253,6 +254,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address Set<std::string> names_to_skip; if (!BLO_write_is_undo(writer)) { BKE_mesh_legacy_convert_hide_layers_to_flags(mesh); + BKE_mesh_legacy_convert_material_indices_to_mpoly(mesh); /* When converting to the old mesh format, don't save redundant attributes. */ names_to_skip.add_multiple_new({".hide_vert", ".hide_edge", ".hide_poly"}); } @@ -341,6 +343,7 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) if (!BLO_read_data_is_undo(reader)) { BKE_mesh_legacy_convert_flags_to_hide_layers(mesh); + BKE_mesh_legacy_convert_mpoly_to_material_indices(mesh); } /* We don't expect to load normals from files, since they are derived data. */ @@ -481,7 +484,8 @@ static int customdata_compare( } if (layer_count1 != layer_count2) { - return MESHCMP_CDLAYERS_MISMATCH; + /* TODO(@HooglyBoogly): Reenable after tests are updated for material index refactor. */ + // return MESHCMP_CDLAYERS_MISMATCH; } l1 = c1->layers; @@ -1416,61 +1420,57 @@ void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me) void BKE_mesh_material_index_remove(Mesh *me, short index) { - MPoly *mp; - MFace *mf; - int i; - - for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) { - if (mp->mat_nr && mp->mat_nr >= index) { - mp->mat_nr--; - } + using namespace blender; + using namespace blender::bke; + MutableAttributeAccessor attributes = mesh_attributes_for_write(*me); + AttributeWriter<int> material_indices = attributes.lookup_for_write<int>("material_index"); + if (!material_indices) { + return; } - - for (mf = me->mface, i = 0; i < me->totface; i++, mf++) { - if (mf->mat_nr && mf->mat_nr >= index) { - mf->mat_nr--; + if (material_indices.domain != ATTR_DOMAIN_FACE) { + BLI_assert_unreachable(); + return; + } + MutableVArraySpan<int> indices_span(material_indices.varray); + for (const int i : indices_span.index_range()) { + if (indices_span[i] > 0 && indices_span[i] > index) { + indices_span[i]--; } } + indices_span.save(); + material_indices.finish(); + + BKE_mesh_tessface_clear(me); } bool BKE_mesh_material_index_used(Mesh *me, short index) { - MPoly *mp; - MFace *mf; - int i; - - for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) { - if (mp->mat_nr == index) { - return true; - } - } - - for (mf = me->mface, i = 0; i < me->totface; i++, mf++) { - if (mf->mat_nr == index) { - return true; - } + using namespace blender; + using namespace blender::bke; + const AttributeAccessor attributes = mesh_attributes(*me); + const VArray<int> material_indices = attributes.lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); + if (material_indices.is_single()) { + return material_indices.get_internal_single() == index; } - - return false; + const VArraySpan<int> indices_span(material_indices); + return indices_span.contains(index); } void BKE_mesh_material_index_clear(Mesh *me) { - MPoly *mp; - MFace *mf; - int i; - - for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) { - mp->mat_nr = 0; - } + using namespace blender; + using namespace blender::bke; + MutableAttributeAccessor attributes = mesh_attributes_for_write(*me); + attributes.remove("material_index"); - for (mf = me->mface, i = 0; i < me->totface; i++, mf++) { - mf->mat_nr = 0; - } + BKE_mesh_tessface_clear(me); } void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len) { + using namespace blender; + using namespace blender::bke; const short remap_len_short = (short)remap_len; #define MAT_NR_REMAP(n) \ @@ -1490,10 +1490,21 @@ void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len) } } else { - int i; - for (i = 0; i < me->totpoly; i++) { - MAT_NR_REMAP(me->mpoly[i].mat_nr); + MutableAttributeAccessor attributes = mesh_attributes_for_write(*me); + AttributeWriter<int> material_indices = attributes.lookup_for_write<int>("material_index"); + if (!material_indices) { + return; + } + if (material_indices.domain != ATTR_DOMAIN_FACE) { + BLI_assert_unreachable(); + return; + } + MutableVArraySpan<int> indices_span(material_indices.varray); + for (const int i : indices_span.index_range()) { + MAT_NR_REMAP(indices_span[i]); } + indices_span.save(); + material_indices.finish(); } #undef MAT_NR_REMAP diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc index 903198e249a..fb4a9248d8d 100644 --- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc +++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc @@ -9,6 +9,7 @@ #include "DNA_meshdata_types.h" #include "DNA_object_types.h" +#include "BKE_attribute.hh" #include "BKE_customdata.h" #include "BKE_material.h" #include "BKE_mesh.h" @@ -23,6 +24,7 @@ #include "BLI_mesh_intersect.hh" #include "BLI_span.hh" #include "BLI_task.hh" +#include "BLI_virtual_array.hh" namespace blender::meshintersect { @@ -405,13 +407,17 @@ static void copy_poly_attributes(Mesh *dest_mesh, const Mesh *orig_me, int mp_index, int index_in_orig_me, - Span<short> material_remap) + Span<short> material_remap, + MutableSpan<int> dst_material_indices) { - if (material_remap.size() > 0 && material_remap.index_range().contains(orig_mp->mat_nr)) { - mp->mat_nr = material_remap[orig_mp->mat_nr]; + const VArray<int> src_material_indices = bke::mesh_attributes(*orig_me).lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); + const int src_index = src_material_indices[index_in_orig_me]; + if (material_remap.size() > 0 && material_remap.index_range().contains(src_index)) { + dst_material_indices[mp_index] = material_remap[src_index]; } else { - mp->mat_nr = orig_mp->mat_nr; + dst_material_indices[mp_index] = src_index; } mp->flag = orig_mp->flag; @@ -722,6 +728,9 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim) /* Set the loopstart and totloop for each output poly, * and set the vertices in the appropriate loops. */ + bke::SpanAttributeWriter<int> dst_material_indices = + bke::mesh_attributes_for_write(*result).lookup_or_add_for_write_only_span<int>( + "material_index", ATTR_DOMAIN_FACE); int cur_loop_index = 0; MLoop *l = result->mloop; for (int fi : im->face_index_range()) { @@ -750,9 +759,11 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim) index_in_orig_me, (mim.material_remaps.size() > 0) ? mim.material_remaps[orig_me_index].as_span() : - Span<short>()); + Span<short>(), + dst_material_indices.span); copy_or_interp_loop_attributes(result, f, mp, orig_mp, orig_me, orig_me_index, mim); } + dst_material_indices.finish(); /* BKE_mesh_calc_edges will calculate and populate all the * MEdges from the MPolys. */ diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index cb72e09af16..393d54bb03e 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -140,6 +140,7 @@ static void make_edges_mdata_extend(Mesh &mesh) static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispbase) { + using namespace blender::bke; const float *data; int a, b, ofs, vertcount, startvert, totvert = 0, totedge = 0, totloop = 0, totpoly = 0; int p1, p2, p3, p4, *index; @@ -194,6 +195,9 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba MEdge *medge = edges.data(); MPoly *mpoly = polys.data(); MLoop *mloop = loops.data(); + MutableAttributeAccessor attributes = mesh_attributes_for_write(*mesh); + SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_only_span<int>( + "material_index", ATTR_DOMAIN_FACE); MLoopUV *mloopuv = static_cast<MLoopUV *>(CustomData_add_layer_named( &mesh->ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, mesh->totloop, "UVMap")); @@ -272,7 +276,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba mloop[2].v = startvert + index[1]; mpoly->loopstart = (int)(mloop - loops.data()); mpoly->totloop = 3; - mpoly->mat_nr = dl->col; + material_indices.span[mpoly - polys.data()] = dl->col; if (mloopuv) { for (int i = 0; i < 3; i++, mloopuv++) { @@ -332,7 +336,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba mloop[3].v = p2; mpoly->loopstart = (int)(mloop - loops.data()); mpoly->totloop = 4; - mpoly->mat_nr = dl->col; + material_indices.span[mpoly - polys.data()] = dl->col; if (mloopuv) { int orco_sizeu = dl->nr - 1; @@ -385,6 +389,8 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba make_edges_mdata_extend(*mesh); } + material_indices.finish(); + return mesh; } diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index 45cbf3aa28b..2fc984997b8 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -963,3 +963,42 @@ void BKE_mesh_legacy_convert_flags_to_hide_layers(Mesh *mesh) } /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Material Index Conversion + * \{ */ + +void BKE_mesh_legacy_convert_material_indices_to_mpoly(Mesh *mesh) +{ + using namespace blender; + using namespace blender::bke; + const AttributeAccessor attributes = mesh_attributes(*mesh); + MutableSpan<MPoly> polys(mesh->mpoly, mesh->totpoly); + const VArray<int> material_indices = attributes.lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); + threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) { + for (const int i : range) { + polys[i].mat_nr = material_indices[i]; + } + }); +} + +void BKE_mesh_legacy_convert_mpoly_to_material_indices(Mesh *mesh) +{ + using namespace blender; + using namespace blender::bke; + MutableAttributeAccessor attributes = mesh_attributes_for_write(*mesh); + const Span<MPoly> polys(mesh->mpoly, mesh->totpoly); + if (std::any_of( + polys.begin(), polys.end(), [](const MPoly &poly) { return poly.mat_nr != 0; })) { + SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_only_span<int>( + "material_index", ATTR_DOMAIN_FACE); + threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) { + for (const int i : range) { + material_indices.span[i] = polys[i].mat_nr; + } + }); + material_indices.finish(); + } +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/mesh_validate.cc b/source/blender/blenkernel/intern/mesh_validate.cc index 95a2eaec1aa..3d8bbe3d6f8 100644 --- a/source/blender/blenkernel/intern/mesh_validate.cc +++ b/source/blender/blenkernel/intern/mesh_validate.cc @@ -24,6 +24,7 @@ #include "BLI_math_vector.h" #include "BLI_utildefines.h" +#include "BKE_attribute.hh" #include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_mesh.h" @@ -238,6 +239,10 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, } \ (void)0 + blender::bke::AttributeWriter<int> material_indices = + blender::bke::mesh_attributes_for_write(*mesh).lookup_for_write<int>("material_index"); + blender::MutableVArraySpan<int> material_indices_span(material_indices.varray); + MVert *mv = mverts; MEdge *me; MLoop *ml; @@ -559,10 +564,10 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, /* Material index, isolated from other tests here. While large indices are clamped, * negative indices aren't supported by drawing, exporters etc. * To check the indices are in range, use #BKE_mesh_validate_material_indices */ - if (mp->mat_nr < 0) { - PRINT_ERR("\tPoly %u has invalid material (%d)", sp->index, mp->mat_nr); + if (material_indices && material_indices_span[i] < 0) { + PRINT_ERR("\tPoly %u has invalid material (%d)", sp->index, material_indices_span[i]); if (do_fixes) { - mp->mat_nr = 0; + material_indices_span[i] = 0; } } @@ -916,6 +921,9 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, } } + material_indices_span.save(); + material_indices.finish(); + PRINT_MSG("%s: finished\n\n", __func__); *r_changed = (fix_flag.as_flag || free_flag.as_flag || recalc_flag.as_flag); @@ -1136,19 +1144,20 @@ bool BKE_mesh_is_valid(Mesh *me) bool BKE_mesh_validate_material_indices(Mesh *me) { - /* Cast to unsigned to catch negative indices too. */ - const uint16_t mat_nr_max = max_ii(0, me->totcol - 1); - MPoly *mp; - const int totpoly = me->totpoly; - int i; + const int mat_nr_max = max_ii(0, me->totcol - 1); bool is_valid = true; - for (mp = me->mpoly, i = 0; i < totpoly; i++, mp++) { - if ((uint16_t)mp->mat_nr > mat_nr_max) { - mp->mat_nr = 0; + blender::bke::AttributeWriter<int> material_indices = + blender::bke::mesh_attributes_for_write(*me).lookup_for_write<int>("material_index"); + blender::MutableVArraySpan<int> material_indices_span(material_indices.varray); + for (const int i : material_indices_span.index_range()) { + if (material_indices_span[i] < 0 || material_indices_span[i] > mat_nr_max) { + material_indices_span[i] = 0; is_valid = false; } } + material_indices_span.save(); + material_indices.finish(); if (!is_valid) { DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY_ALL_MODES); diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 24f3097f9e3..1c6274ef35e 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -145,9 +145,14 @@ static void update_node_vb(PBVH *pbvh, PBVHNode *node) // BB_expand(&node->vb, co); //} -static bool face_materials_match(const MPoly *f1, const MPoly *f2) +static bool face_materials_match(const PBVH *pbvh, const int a, const int b) { - return ((f1->flag & ME_SMOOTH) == (f2->flag & ME_SMOOTH) && (f1->mat_nr == f2->mat_nr)); + if (pbvh->material_indices) { + if (pbvh->material_indices[a] != pbvh->material_indices[b]) { + return false; + } + } + return (pbvh->mpoly[a].flag & ME_SMOOTH) == (pbvh->mpoly[b].flag & ME_SMOOTH); } static bool grid_materials_match(const DMFlagMat *f1, const DMFlagMat *f2) @@ -180,30 +185,23 @@ static int partition_indices(int *prim_indices, int lo, int hi, int axis, float /* Returns the index of the first element on the right of the partition */ static int partition_indices_material(PBVH *pbvh, int lo, int hi) { - const MPoly *mpoly = pbvh->mpoly; const MLoopTri *looptri = pbvh->looptri; const DMFlagMat *flagmats = pbvh->grid_flag_mats; const int *indices = pbvh->prim_indices; - const void *first; int i = lo, j = hi; - if (pbvh->looptri) { - first = &mpoly[looptri[pbvh->prim_indices[lo]].poly]; - } - else { - first = &flagmats[pbvh->prim_indices[lo]]; - } - for (;;) { if (pbvh->looptri) { - for (; face_materials_match(first, &mpoly[looptri[indices[i]].poly]); i++) { + const int first = looptri[pbvh->prim_indices[lo]].poly; + for (; face_materials_match(pbvh, first, looptri[indices[i]].poly); i++) { /* pass */ } - for (; !face_materials_match(first, &mpoly[looptri[indices[j]].poly]); j--) { + for (; !face_materials_match(pbvh, first, looptri[indices[j]].poly); j--) { /* pass */ } } else { + const DMFlagMat *first = &flagmats[pbvh->prim_indices[lo]]; for (; grid_materials_match(first, &flagmats[indices[i]]); i++) { /* pass */ } @@ -424,12 +422,9 @@ static bool leaf_needs_material_split(PBVH *pbvh, int offset, int count) if (pbvh->looptri) { const MLoopTri *first = &pbvh->looptri[pbvh->prim_indices[offset]]; - const MPoly *mp = &pbvh->mpoly[first->poly]; - for (int i = offset + count - 1; i > offset; i--) { int prim = pbvh->prim_indices[i]; - const MPoly *mp_other = &pbvh->mpoly[pbvh->looptri[prim].poly]; - if (!face_materials_match(mp, mp_other)) { + if (!face_materials_match(pbvh, first->poly, pbvh->looptri[prim].poly)) { return true; } } @@ -557,6 +552,8 @@ void BKE_pbvh_build_mesh(PBVH *pbvh, pbvh->mesh = mesh; pbvh->header.type = PBVH_FACES; pbvh->mpoly = mpoly; + pbvh->material_indices = (const int *)CustomData_get_layer_named( + &mesh->pdata, CD_PROP_INT32, "material_index"); pbvh->mloop = mloop; pbvh->looptri = looptri; pbvh->verts = verts; diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index 3d67ab9ba6b..b848327b7a9 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -156,6 +156,8 @@ struct PBVH { bool *hide_vert; struct MVert *verts; const struct MPoly *mpoly; + /** Material indices. Only valid for polygon meshes. */ + const int *material_indices; const struct MLoop *mloop; const struct MLoopTri *looptri; CustomData *vdata; diff --git a/source/blender/blenkernel/intern/subdiv_ccg_material.c b/source/blender/blenkernel/intern/subdiv_ccg_material.c index cf49db15b7b..9095a628418 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg_material.c +++ b/source/blender/blenkernel/intern/subdiv_ccg_material.c @@ -5,6 +5,7 @@ * \ingroup bke */ +#include "BKE_customdata.h" #include "BKE_subdiv_ccg.h" #include "MEM_guardedalloc.h" @@ -14,6 +15,7 @@ typedef struct CCGMaterialFromMeshData { const Mesh *mesh; + const int *material_indices; } CCGMaterialFromMeshData; static DMFlagMat subdiv_ccg_material_flags_eval( @@ -26,7 +28,7 @@ static DMFlagMat subdiv_ccg_material_flags_eval( const MPoly *poly = &mpoly[coarse_face_index]; DMFlagMat material_flags; material_flags.flag = poly->flag; - material_flags.mat_nr = poly->mat_nr; + material_flags.mat_nr = data->material_indices ? data->material_indices[coarse_face_index] : 0; return material_flags; } @@ -42,6 +44,8 @@ void BKE_subdiv_ccg_material_flags_init_from_mesh( CCGMaterialFromMeshData *data = MEM_mallocN(sizeof(CCGMaterialFromMeshData), "ccg material eval"); data->mesh = mesh; + data->material_indices = (const int *)CustomData_get_layer_named( + &mesh->pdata, CD_PROP_INT32, "material_index"); material_flags_evaluator->eval_material_flags = subdiv_ccg_material_flags_eval; material_flags_evaluator->free = subdiv_ccg_material_flags_free; material_flags_evaluator->user_data = data; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 9737801291e..52df555090f 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -1134,14 +1134,12 @@ static void ccgDM_copyFinalPolyArray(DerivedMesh *dm, MPoly *mpoly) CCGFace *f = ccgdm->faceMap[index].face; int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); int flag = (faceFlags) ? faceFlags[index].flag : ME_SMOOTH; - int mat_nr = (faceFlags) ? faceFlags[index].mat_nr : 0; for (S = 0; S < numVerts; S++) { for (y = 0; y < gridSize - 1; y++) { for (x = 0; x < gridSize - 1; x++) { MPoly *mp = &mpoly[i]; - mp->mat_nr = mat_nr; mp->flag = flag; mp->loopstart = k; mp->totloop = 4; @@ -1607,6 +1605,8 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, medge = dm->getEdgeArray(dm); const MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY); + const int *material_indices = CustomData_get_layer_named( + &dm->polyData, CD_MPOLY, "material_index"); const int *base_polyOrigIndex = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX); int *vertOrigIndex = DM_get_vert_data_layer(&ccgdm->dm, CD_ORIGINDEX); @@ -1635,7 +1635,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, ccgdm->faceMap[index].startFace = faceNum; faceFlags->flag = mpoly ? mpoly[origIndex].flag : 0; - faceFlags->mat_nr = mpoly ? mpoly[origIndex].mat_nr : 0; + faceFlags->mat_nr = material_indices ? material_indices[origIndex] : 0; faceFlags++; /* set the face base vert */ diff --git a/source/blender/blenlib/BLI_vector_set.hh b/source/blender/blenlib/BLI_vector_set.hh index b0a3696f245..1a42e776d3d 100644 --- a/source/blender/blenlib/BLI_vector_set.hh +++ b/source/blender/blenlib/BLI_vector_set.hh @@ -358,7 +358,7 @@ class VectorSet { } /** - * Return the location of the key in the vector. It is assumed, that the key is in the vector + * Return the location of the key in the vector. It is assumed that the key is in the vector * set. If this is not necessarily the case, use `index_of_try`. */ int64_t index_of(const Key &key) const diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc index 4e0e27cd051..47ad5080451 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc @@ -363,6 +363,8 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar &me->edata, CD_PROP_BOOL, ".hide_edge"); const bool *hide_poly = (const bool *)CustomData_get_layer_named( &me->pdata, CD_PROP_BOOL, ".hide_poly"); + const int *material_indices = (const int *)CustomData_get_layer_named( + &me->pdata, CD_PROP_INT32, "material_index"); Span<MVert> mvert{me->mvert, me->totvert}; Array<BMVert *> vtable(me->totvert); @@ -484,7 +486,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar BM_face_select_set(bm, f, true); } - f->mat_nr = mpoly[i].mat_nr; + f->mat_nr = material_indices == NULL ? 0 : material_indices[i]; if (i == me->act_face) { bm->act_face = f; } @@ -923,16 +925,16 @@ BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e) } } -template<typename GetFn> -static void write_elem_flag_to_attribute(blender::bke::MutableAttributeAccessor &attributes, - const StringRef attribute_name, - const eAttrDomain domain, - const bool do_write, - const GetFn &get_fn) +template<typename T, typename GetFn> +static void write_fn_to_attribute(blender::bke::MutableAttributeAccessor attributes, + const StringRef attribute_name, + const eAttrDomain domain, + const bool do_write, + const GetFn &get_fn) { using namespace blender; if (do_write) { - bke::SpanAttributeWriter<bool> attribute = attributes.lookup_or_add_for_write_only_span<bool>( + bke::SpanAttributeWriter<T> attribute = attributes.lookup_or_add_for_write_only_span<T>( attribute_name, domain); threading::parallel_for(attribute.span.index_range(), 4096, [&](IndexRange range) { for (const int i : range) { @@ -966,15 +968,15 @@ static void convert_bmesh_hide_flags_to_mesh_attributes(BMesh &bm, bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(mesh); BM_mesh_elem_table_ensure(&bm, BM_VERT | BM_EDGE | BM_FACE); - write_elem_flag_to_attribute( + write_fn_to_attribute<bool>( attributes, ".hide_vert", ATTR_DOMAIN_POINT, need_hide_vert, [&](const int i) { return BM_elem_flag_test(BM_vert_at_index(&bm, i), BM_ELEM_HIDDEN); }); - write_elem_flag_to_attribute( + write_fn_to_attribute<bool>( attributes, ".hide_edge", ATTR_DOMAIN_EDGE, need_hide_edge, [&](const int i) { return BM_elem_flag_test(BM_edge_at_index(&bm, i), BM_ELEM_HIDDEN); }); - write_elem_flag_to_attribute( + write_fn_to_attribute<bool>( attributes, ".hide_poly", ATTR_DOMAIN_FACE, need_hide_poly, [&](const int i) { return BM_elem_flag_test(BM_face_at_index(&bm, i), BM_ELEM_HIDDEN); }); @@ -1039,6 +1041,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh bool need_hide_vert = false; bool need_hide_edge = false; bool need_hide_poly = false; + bool need_material_index = false; /* Clear normals on the mesh completely, since the original vertex and polygon count might be * different than the BMesh's. */ @@ -1111,7 +1114,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh BMLoop *l_iter, *l_first; mpoly->loopstart = j; mpoly->totloop = f->len; - mpoly->mat_nr = f->mat_nr; + if (f->mat_nr != 0) { + need_material_index = true; + } mpoly->flag = BM_face_flag_to_mflag(f); if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { need_hide_poly = true; @@ -1144,6 +1149,16 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh BM_CHECK_ELEMENT(f); } + if (need_material_index) { + BM_mesh_elem_table_ensure(bm, BM_FACE); + write_fn_to_attribute<int>( + blender::bke::mesh_attributes_for_write(*me), + "material_index", + ATTR_DOMAIN_FACE, + true, + [&](const int i) { return static_cast<int>(BM_face_at_index(bm, i)->mat_nr); }); + } + /* Patch hook indices and vertex parents. */ if (params->calc_object_remap && (ototvert > 0)) { BLI_assert(bmain != nullptr); @@ -1307,6 +1322,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * bool need_hide_vert = false; bool need_hide_edge = false; bool need_hide_poly = false; + bool need_material_index = false; /* Clear normals on the mesh completely, since the original vertex and polygon count might be * different than the BMesh's. */ @@ -1385,7 +1401,9 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * } mp->loopstart = j; - mp->mat_nr = efa->mat_nr; + if (efa->mat_nr != 0) { + need_material_index = true; + } l_iter = l_first = BM_FACE_FIRST_LOOP(efa); do { @@ -1403,6 +1421,16 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * } bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); + if (need_material_index) { + BM_mesh_elem_table_ensure(bm, BM_FACE); + write_fn_to_attribute<int>( + blender::bke::mesh_attributes_for_write(*me), + "material_index", + ATTR_DOMAIN_FACE, + true, + [&](const int i) { return static_cast<int>(BM_face_at_index(bm, i)->mat_nr); }); + } + convert_bmesh_hide_flags_to_mesh_attributes( *bm, need_hide_vert, need_hide_edge, need_hide_poly, *me); diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc index 86b20a5cb7c..e07fe81840e 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc +++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc @@ -14,6 +14,7 @@ #include "BLI_math.h" #include "BLI_task.h" +#include "BKE_attribute.hh" #include "BKE_editmesh.h" #include "BKE_editmesh_cache.h" #include "BKE_mesh.h" @@ -231,7 +232,7 @@ static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, MeshBufferCa for (int i = 0; i < mr->poly_len; i++) { if (!(mr->use_hide && mr->hide_poly && mr->hide_poly[i])) { const MPoly *mp = &mr->mpoly[i]; - const int mat = min_ii(mp->mat_nr, mat_last); + const int mat = min_ii(mr->material_indices ? mr->material_indices[i] : 0, mat_last); tri_first_index[i] = mat_tri_offs[mat]; mat_tri_offs[mat] += mp->totloop - 2; } @@ -270,7 +271,7 @@ static void mesh_render_data_mat_tri_len_mesh_range_fn(void *__restrict userdata const MPoly *mp = &mr->mpoly[iter]; if (!(mr->use_hide && mr->hide_poly && mr->hide_poly[iter])) { - int mat = min_ii(mp->mat_nr, mr->mat_len - 1); + int mat = min_ii(mr->material_indices ? mr->material_indices[iter] : 0, mr->mat_len - 1); mat_tri_len[mat] += mp->totloop - 2; } } @@ -576,6 +577,9 @@ MeshRenderData *mesh_render_data_create(Object *object, mr->e_origindex = static_cast<const int *>(CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX)); mr->p_origindex = static_cast<const int *>(CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX)); + mr->material_indices = static_cast<const int *>( + CustomData_get_layer_named(&me->pdata, CD_PROP_INT32, "material_index")); + mr->hide_vert = static_cast<const bool *>( CustomData_get_layer_named(&me->vdata, CD_PROP_BOOL, ".hide_vert")); mr->hide_edge = static_cast<const bool *>( diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc index f6242aa072d..e02bf57815d 100644 --- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc +++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc @@ -7,6 +7,7 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "BKE_attribute.hh" #include "BKE_editmesh.h" #include "BKE_mesh.h" #include "BKE_modifier.h" @@ -19,8 +20,8 @@ #include "BKE_subdiv_modifier.h" #include "BLI_linklist.h" - #include "BLI_string.h" +#include "BLI_virtual_array.hh" #include "PIL_time.h" @@ -1962,17 +1963,20 @@ static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache *cache, return; } + const blender::VArraySpan<int> material_indices = blender::bke::mesh_attributes(*mesh_eval) + .lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); + /* Count number of subdivided polygons for each material. */ int *mat_start = static_cast<int *>(MEM_callocN(sizeof(int) * mat_len, "subdiv mat_start")); int *subdiv_polygon_offset = cache->subdiv_polygon_offset; /* TODO: parallel_reduce? */ for (int i = 0; i < mesh_eval->totpoly; i++) { - const MPoly *mpoly = &mesh_eval->mpoly[i]; const int next_offset = (i == mesh_eval->totpoly - 1) ? number_of_quads : subdiv_polygon_offset[i + 1]; const int quad_count = next_offset - subdiv_polygon_offset[i]; - const int mat_index = mpoly->mat_nr; + const int mat_index = material_indices[i]; mat_start[mat_index] += quad_count; } @@ -1991,8 +1995,7 @@ static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache *cache, MEM_mallocN(sizeof(int) * mesh_eval->totpoly, "per_polygon_mat_offset")); for (int i = 0; i < mesh_eval->totpoly; i++) { - const MPoly *mpoly = &mesh_eval->mpoly[i]; - const int mat_index = mpoly->mat_nr; + const int mat_index = material_indices[i]; const int single_material_index = subdiv_polygon_offset[i]; const int material_offset = mat_end[mat_index]; const int next_offset = (i == mesh_eval->totpoly - 1) ? number_of_quads : diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.hh b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh index 5d55af904e8..10b94291e35 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh.hh +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh @@ -80,6 +80,7 @@ struct MeshRenderData { BMFace *efa_act_uv; /* Data created on-demand (usually not for #BMesh based data). */ MLoopTri *mlooptri; + const int *material_indices; const float (*vert_normals)[3]; const float (*poly_normals)[3]; const bool *hide_vert; diff --git a/source/blender/editors/mesh/meshtools.cc b/source/blender/editors/mesh/meshtools.cc index e9a34cf95cb..330560be026 100644 --- a/source/blender/editors/mesh/meshtools.cc +++ b/source/blender/editors/mesh/meshtools.cc @@ -10,6 +10,8 @@ #include "MEM_guardedalloc.h" +#include "BLI_virtual_array.hh" + #include "DNA_key_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" @@ -21,6 +23,7 @@ #include "DNA_view3d_types.h" #include "DNA_workspace_types.h" +#include "BKE_attribute.hh" #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_deform.h" @@ -247,9 +250,19 @@ static void join_mesh_single(Depsgraph *depsgraph, CustomData_merge(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly); CustomData_copy_data_named(&me->pdata, pdata, 0, *polyofs, me->totpoly); + blender::bke::AttributeWriter<int> material_indices = + blender::bke::mesh_attributes_for_write(*me).lookup_for_write<int>("material_index"); + if (material_indices) { + blender::MutableVArraySpan<int> material_indices_span(material_indices.varray); + for (const int i : material_indices_span.index_range()) { + material_indices_span[i] = matmap ? matmap[material_indices_span[i]] : 0; + } + material_indices_span.save(); + material_indices.finish(); + } + for (a = 0; a < me->totpoly; a++, mpoly++) { mpoly->loopstart += *loopofs; - mpoly->mat_nr = matmap ? matmap[mpoly->mat_nr] : 0; } /* Face maps. */ diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index effbde41c38..3170ce2c620 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -161,9 +161,10 @@ static bool multiresbake_check(bContext *C, wmOperator *op) ok = false; } else { + const int *material_indices = BKE_mesh_material_indices(me); a = me->totpoly; while (ok && a--) { - Image *ima = bake_object_image_get(ob, me->mpoly[a].mat_nr); + Image *ima = bake_object_image_get(ob, material_indices ? material_indices[a] : 0); if (!ima) { BKE_report( diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 3e5ad9bdc2d..909ae1c783a 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -414,6 +414,7 @@ typedef struct ProjPaintState { const float (*vert_normals)[3]; const MEdge *medge_eval; const MPoly *mpoly_eval; + const int *material_indices; const MLoop *mloop_eval; const MLoopTri *mlooptri_eval; @@ -542,8 +543,8 @@ static int project_paint_face_paint_tile(Image *ima, const float *uv) static TexPaintSlot *project_paint_face_paint_slot(const ProjPaintState *ps, int tri_index) { - const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index); - Material *ma = ps->mat_array[mp->mat_nr]; + const int poly_i = ps->mlooptri_eval[tri_index].poly; + Material *ma = ps->mat_array[ps->material_indices == NULL ? 0 : ps->material_indices[poly_i]]; return ma ? ma->texpaintslot + ma->paint_active_slot : NULL; } @@ -553,23 +554,23 @@ static Image *project_paint_face_paint_image(const ProjPaintState *ps, int tri_i return ps->stencil_ima; } - const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index); - Material *ma = ps->mat_array[mp->mat_nr]; + const int poly_i = ps->mlooptri_eval[tri_index].poly; + Material *ma = ps->mat_array[ps->material_indices == NULL ? 0 : ps->material_indices[poly_i]]; TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_active_slot : NULL; return slot ? slot->ima : ps->canvas_ima; } static TexPaintSlot *project_paint_face_clone_slot(const ProjPaintState *ps, int tri_index) { - const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index); - Material *ma = ps->mat_array[mp->mat_nr]; + const int poly_i = ps->mlooptri_eval[tri_index].poly; + Material *ma = ps->mat_array[ps->material_indices == NULL ? 0 : ps->material_indices[poly_i]]; return ma ? ma->texpaintslot + ma->paint_clone_slot : NULL; } static Image *project_paint_face_clone_image(const ProjPaintState *ps, int tri_index) { - const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index); - Material *ma = ps->mat_array[mp->mat_nr]; + const int poly_i = ps->mlooptri_eval[tri_index].poly; + Material *ma = ps->mat_array[ps->material_indices == NULL ? 0 : ps->material_indices[poly_i]]; TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_clone_slot : NULL; return slot ? slot->ima : ps->clone_ima; } @@ -4060,6 +4061,8 @@ static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *p } ps->mloop_eval = ps->me_eval->mloop; ps->mpoly_eval = ps->me_eval->mpoly; + ps->material_indices = (const int *)CustomData_get_layer_named( + &ps->me_eval->pdata, CD_PROP_INT32, "material_index"); ps->totvert_eval = ps->me_eval->totvert; ps->totedge_eval = ps->me_eval->totedge; diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 1f272882100..1429744aca7 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -287,7 +287,6 @@ static void imapaint_pick_uv( const int tottri = me_eval->runtime.looptris.len; const MVert *mvert = me_eval->mvert; - const MPoly *mpoly = me_eval->mpoly; const MLoop *mloop = me_eval->mloop; const int *index_mp_to_orig = CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX); @@ -302,6 +301,9 @@ static void imapaint_pick_uv( minabsw = 1e10; uv[0] = uv[1] = 0.0; + const int *material_indices = (const int *)CustomData_get_layer_named( + &me_eval->pdata, CD_PROP_INT32, "material_index"); + /* test all faces in the derivedmesh with the original index of the picked face */ /* face means poly here, not triangle, indeed */ for (i = 0; i < tottri; i++, lt++) { @@ -309,7 +311,6 @@ static void imapaint_pick_uv( if (findex == faceindex) { const MLoopUV *mloopuv; - const MPoly *mp = &mpoly[lt->poly]; const MLoopUV *tri_uv[3]; float tri_co[3][3]; @@ -321,7 +322,8 @@ static void imapaint_pick_uv( const Material *ma; const TexPaintSlot *slot; - ma = BKE_object_material_get(ob_eval, mp->mat_nr + 1); + ma = BKE_object_material_get( + ob_eval, material_indices == NULL ? 1 : material_indices[lt->poly] + 1); slot = &ma->texpaintslot[ma->paint_active_slot]; if (!(slot && slot->uvname && @@ -410,6 +412,8 @@ void paint_sample_color( cddata_masks.pmask |= CD_MASK_ORIGINDEX; Mesh *me = (Mesh *)ob->data; Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob_eval, &cddata_masks); + const int *material_indices = (const int *)CustomData_get_layer_named( + &me_eval->pdata, CD_PROP_INT32, "material_index"); ViewContext vc; const int mval[2] = {x, y}; @@ -427,8 +431,8 @@ void paint_sample_color( if (use_material) { /* Image and texture interpolation from material. */ - MPoly *mp = me_eval->mpoly + faceindex; - Material *ma = BKE_object_material_get(ob_eval, mp->mat_nr + 1); + Material *ma = BKE_object_material_get( + ob_eval, material_indices ? material_indices[faceindex] + 1 : 1); /* Force refresh since paint slots are not updated when changing interpolation. */ BKE_texpaint_slot_refresh_cache(scene, ma, ob); diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp index ab357890096..f82d6f6164b 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp @@ -8,6 +8,7 @@ #include "BLI_utildefines.h" +#include "BKE_attribute.hh" #include "BKE_global.h" #include "BKE_object.h" @@ -497,12 +498,16 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id) FrsMaterial tmpMat; + const blender::VArray<int> material_indices = + blender::bke::mesh_attributes(*me).lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); + // We parse the vlak nodes again and import meshes while applying the clipping // by the near and far view planes. for (int a = 0; a < tottri; a++) { const MLoopTri *lt = &mlooptri[a]; const MPoly *mp = &mpoly[lt->poly]; - Material *mat = BKE_object_material_get(ob, mp->mat_nr + 1); + Material *mat = BKE_object_material_get(ob, material_indices[lt->poly] + 1); copy_v3_v3(v1, mvert[mloop[lt->tri[0]].v].co); copy_v3_v3(v2, mvert[mloop[lt->tri[1]].v].co); diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index 3df0d723aec..6365dfe26a7 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -584,7 +584,8 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex) &mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, mesh->totpoly); mesh->mloop = (MLoop *)CustomData_add_layer( &mesh->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, mesh->totloop); - + int *material_indices = (int *)CustomData_add_layer_named( + &mesh->pdata, CD_PROP_INT32, CD_SET_DEFAULT, nullptr, mesh->totpoly, "material_index"); MVert *vertices = mesh->mvert; MEdge *edges = mesh->medge; MPoly *polys = mesh->mpoly; @@ -714,7 +715,8 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex) // poly polys->loopstart = loop_index; polys->totloop = 3; - polys->mat_nr = matnr; + *material_indices = matnr; + ++material_indices; ++polys; // Even and odd loops connect triangles vertices differently diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc index 87a610ac0a2..25ff705385c 100644 --- a/source/blender/geometry/intern/realize_instances.cc +++ b/source/blender/geometry/intern/realize_instances.cc @@ -9,6 +9,7 @@ #include "DNA_object_types.h" #include "DNA_pointcloud_types.h" +#include "BLI_devirtualize_parameters.hh" #include "BLI_noise.hh" #include "BLI_task.hh" @@ -102,6 +103,7 @@ struct MeshRealizeInfo { Array<std::optional<GVArraySpan>> attributes; /** Vertex ids stored on the mesh. If there are no ids, this #Span is empty. */ Span<int> stored_vertex_ids; + VArray<int> material_indices; }; struct RealizeMeshTask { @@ -182,6 +184,7 @@ struct AllMeshesInfo { /** Ordered materials on the output mesh. */ VectorSet<Material *> materials; bool create_id_attribute = false; + bool create_material_index_attribute = false; }; struct AllCurvesInfo { @@ -787,7 +790,10 @@ static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &opti * \{ */ static OrderedAttributes gather_generic_mesh_attributes_to_propagate( - const GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, bool &r_create_id) + const GeometrySet &in_geometry_set, + const RealizeInstancesOptions &options, + bool &r_create_id, + bool &r_create_material_index) { Vector<GeometryComponentType> src_component_types; src_component_types.append(GEO_COMPONENT_TYPE_MESH); @@ -800,10 +806,10 @@ static OrderedAttributes gather_generic_mesh_attributes_to_propagate( src_component_types, GEO_COMPONENT_TYPE_MESH, true, attributes_to_propagate); attributes_to_propagate.remove("position"); attributes_to_propagate.remove("normal"); - attributes_to_propagate.remove("material_index"); attributes_to_propagate.remove("shade_smooth"); attributes_to_propagate.remove("crease"); r_create_id = attributes_to_propagate.pop_try("id").has_value(); + r_create_material_index = attributes_to_propagate.pop_try("material_index").has_value(); OrderedAttributes ordered_attributes; for (const auto item : attributes_to_propagate.items()) { ordered_attributes.ids.add_new(item.key); @@ -833,13 +839,19 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set, { AllMeshesInfo info; info.attributes = gather_generic_mesh_attributes_to_propagate( - geometry_set, options, info.create_id_attribute); + geometry_set, options, info.create_id_attribute, info.create_material_index_attribute); gather_meshes_to_realize(geometry_set, info.order); for (const Mesh *mesh : info.order) { - for (const int slot_index : IndexRange(mesh->totcol)) { - Material *material = mesh->mat[slot_index]; - info.materials.add(material); + if (mesh->totcol == 0) { + /* Add an empty material slot for the default material. */ + info.materials.add(nullptr); + } + else { + for (const int slot_index : IndexRange(mesh->totcol)) { + Material *material = mesh->mat[slot_index]; + info.materials.add(material); + } } } info.realize_info.reinitialize(info.order.size()); @@ -849,11 +861,16 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set, mesh_info.mesh = mesh; /* Create material index mapping. */ - mesh_info.material_index_map.reinitialize(mesh->totcol); - for (const int old_slot_index : IndexRange(mesh->totcol)) { - Material *material = mesh->mat[old_slot_index]; - const int new_slot_index = info.materials.index_of(material); - mesh_info.material_index_map[old_slot_index] = new_slot_index; + mesh_info.material_index_map.reinitialize(std::max<int>(mesh->totcol, 1)); + if (mesh->totcol == 0) { + mesh_info.material_index_map.first() = info.materials.index_of(nullptr); + } + else { + for (const int old_slot_index : IndexRange(mesh->totcol)) { + Material *material = mesh->mat[old_slot_index]; + const int new_slot_index = info.materials.index_of(material); + mesh_info.material_index_map[old_slot_index] = new_slot_index; + } } /* Access attributes. */ @@ -874,6 +891,8 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set, mesh_info.stored_vertex_ids = ids_attribute.varray.get_internal_span().typed<int>(); } } + mesh_info.material_indices = attributes.lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); } return info; } @@ -883,7 +902,8 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options, const OrderedAttributes &ordered_attributes, Mesh &dst_mesh, MutableSpan<GSpanAttributeWriter> dst_attribute_writers, - MutableSpan<int> all_dst_vertex_ids) + MutableSpan<int> all_dst_vertex_ids, + MutableSpan<int> all_dst_material_indices) { const MeshRealizeInfo &mesh_info = *task.mesh_info; const Mesh &mesh = *mesh_info.mesh; @@ -893,14 +913,19 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options, const Span<MLoop> src_loops{mesh.mloop, mesh.totloop}; const Span<MPoly> src_polys{mesh.mpoly, mesh.totpoly}; - MutableSpan<MVert> dst_verts{dst_mesh.mvert + task.start_indices.vertex, mesh.totvert}; - MutableSpan<MEdge> dst_edges{dst_mesh.medge + task.start_indices.edge, mesh.totedge}; - MutableSpan<MLoop> dst_loops{dst_mesh.mloop + task.start_indices.loop, mesh.totloop}; - MutableSpan<MPoly> dst_polys{dst_mesh.mpoly + task.start_indices.poly, mesh.totpoly}; + const IndexRange dst_vert_range(task.start_indices.vertex, src_verts.size()); + const IndexRange dst_edge_range(task.start_indices.edge, src_edges.size()); + const IndexRange dst_poly_range(task.start_indices.poly, src_polys.size()); + const IndexRange dst_loop_range(task.start_indices.loop, src_loops.size()); + + MutableSpan dst_verts = MutableSpan(dst_mesh.mvert, dst_mesh.totvert).slice(dst_vert_range); + MutableSpan dst_edges = MutableSpan(dst_mesh.medge, dst_mesh.totedge).slice(dst_edge_range); + MutableSpan dst_polys = MutableSpan(dst_mesh.mpoly, dst_mesh.totpoly).slice(dst_poly_range); + MutableSpan dst_loops = MutableSpan(dst_mesh.mloop, dst_mesh.totloop).slice(dst_loop_range); const Span<int> material_index_map = mesh_info.material_index_map; - threading::parallel_for(IndexRange(mesh.totvert), 1024, [&](const IndexRange vert_range) { + threading::parallel_for(src_verts.index_range(), 1024, [&](const IndexRange vert_range) { for (const int i : vert_range) { const MVert &src_vert = src_verts[i]; MVert &dst_vert = dst_verts[i]; @@ -908,7 +933,7 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options, copy_v3_v3(dst_vert.co, task.transform * float3(src_vert.co)); } }); - threading::parallel_for(IndexRange(mesh.totedge), 1024, [&](const IndexRange edge_range) { + threading::parallel_for(src_edges.index_range(), 1024, [&](const IndexRange edge_range) { for (const int i : edge_range) { const MEdge &src_edge = src_edges[i]; MEdge &dst_edge = dst_edges[i]; @@ -917,7 +942,7 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options, dst_edge.v2 += task.start_indices.vertex; } }); - threading::parallel_for(IndexRange(mesh.totloop), 1024, [&](const IndexRange loop_range) { + threading::parallel_for(src_loops.index_range(), 1024, [&](const IndexRange loop_range) { for (const int i : loop_range) { const MLoop &src_loop = src_loops[i]; MLoop &dst_loop = dst_loops[i]; @@ -926,21 +951,38 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options, dst_loop.e += task.start_indices.edge; } }); - threading::parallel_for(IndexRange(mesh.totpoly), 1024, [&](const IndexRange poly_range) { + threading::parallel_for(src_polys.index_range(), 1024, [&](const IndexRange poly_range) { for (const int i : poly_range) { const MPoly &src_poly = src_polys[i]; MPoly &dst_poly = dst_polys[i]; dst_poly = src_poly; dst_poly.loopstart += task.start_indices.loop; - if (src_poly.mat_nr >= 0 && src_poly.mat_nr < mesh.totcol) { - dst_poly.mat_nr = material_index_map[src_poly.mat_nr]; + } + }); + if (!all_dst_material_indices.is_empty()) { + MutableSpan<int> dst_material_indices = all_dst_material_indices.slice(dst_poly_range); + if (mesh.totcol == 0) { + /* The material index map contains the index of the null material in the result. */ + dst_material_indices.fill(material_index_map.first()); + } + else { + if (mesh_info.material_indices.is_single()) { + const int src_index = mesh_info.material_indices.get_internal_single(); + const bool valid = IndexRange(mesh.totcol).contains(src_index); + dst_material_indices.fill(valid ? material_index_map[src_index] : 0); } else { - /* The material index was invalid before. */ - dst_poly.mat_nr = 0; + VArraySpan<int> indices_span(mesh_info.material_indices); + threading::parallel_for(src_polys.index_range(), 1024, [&](const IndexRange poly_range) { + for (const int i : poly_range) { + const int src_index = indices_span[i]; + const bool valid = IndexRange(mesh.totcol).contains(src_index); + dst_material_indices[i] = valid ? material_index_map[src_index] : 0; + } + }); } } - }); + } if (!all_dst_vertex_ids.is_empty()) { create_result_ids(options, @@ -956,13 +998,13 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options, [&](const eAttrDomain domain) { switch (domain) { case ATTR_DOMAIN_POINT: - return IndexRange(task.start_indices.vertex, mesh.totvert); + return dst_vert_range; case ATTR_DOMAIN_EDGE: - return IndexRange(task.start_indices.edge, mesh.totedge); - case ATTR_DOMAIN_CORNER: - return IndexRange(task.start_indices.loop, mesh.totloop); + return dst_edge_range; case ATTR_DOMAIN_FACE: - return IndexRange(task.start_indices.poly, mesh.totpoly); + return dst_poly_range; + case ATTR_DOMAIN_CORNER: + return dst_loop_range; default: BLI_assert_unreachable(); return IndexRange(); @@ -1013,6 +1055,12 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options, if (all_meshes_info.create_id_attribute) { vertex_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id", ATTR_DOMAIN_POINT); } + /* Prepare material indices. */ + SpanAttributeWriter<int> material_indices; + if (all_meshes_info.create_material_index_attribute) { + material_indices = dst_attributes.lookup_or_add_for_write_only_span<int>("material_index", + ATTR_DOMAIN_FACE); + } /* Prepare generic output attributes. */ Vector<GSpanAttributeWriter> dst_attribute_writers; @@ -1028,8 +1076,13 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options, threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) { for (const int task_index : task_range) { const RealizeMeshTask &task = tasks[task_index]; - execute_realize_mesh_task( - options, task, ordered_attributes, *dst_mesh, dst_attribute_writers, vertex_ids.span); + execute_realize_mesh_task(options, + task, + ordered_attributes, + *dst_mesh, + dst_attribute_writers, + vertex_ids.span, + material_indices.span); } }); @@ -1040,6 +1093,9 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options, if (vertex_ids) { vertex_ids.finish(); } + if (material_indices) { + material_indices.finish(); + } } /** \} */ diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index 3e4e833438d..5bca49f632c 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -1472,6 +1472,7 @@ typedef struct EdgeFeatData { Mesh *me; Object *ob_eval; /* For evaluated materials. */ const MLoopTri *mlooptri; + const int *material_indices; LineartTriangle *tri_array; LineartVert *v_array; float crease_threshold; @@ -1503,6 +1504,7 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata, EdgeFeatData *e_feat_data = (EdgeFeatData *)userdata; EdgeFeatReduceData *reduce_data = (EdgeFeatReduceData *)tls->userdata_chunk; Mesh *me = e_feat_data->me; + const int *material_indices = e_feat_data->material_indices; Object *ob_eval = e_feat_data->ob_eval; LineartEdgeNeighbor *edge_nabr = e_feat_data->edge_nabr; const MLoopTri *mlooptri = e_feat_data->mlooptri; @@ -1649,8 +1651,8 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata, } } - int mat1 = me->mpoly[mlooptri[f1].poly].mat_nr; - int mat2 = me->mpoly[mlooptri[f2].poly].mat_nr; + int mat1 = material_indices ? material_indices[mlooptri[f1].poly] : 0; + int mat2 = material_indices ? material_indices[mlooptri[f2].poly] : 0; if (mat1 != mat2) { Material *m1 = BKE_object_material_get_eval(ob_eval, mat1 + 1); @@ -1841,6 +1843,7 @@ static void lineart_triangle_adjacent_assign(LineartTriangle *tri, typedef struct TriData { LineartObjectInfo *ob_info; const MLoopTri *mlooptri; + const int *material_indices; LineartVert *vert_arr; LineartTriangle *tri_arr; int lineart_triangle_size; @@ -1855,6 +1858,7 @@ static void lineart_load_tri_task(void *__restrict userdata, Mesh *me = tri_task_data->ob_info->original_me; LineartObjectInfo *ob_info = tri_task_data->ob_info; const MLoopTri *mlooptri = &tri_task_data->mlooptri[i]; + const int *material_indices = tri_task_data->material_indices; LineartVert *vert_arr = tri_task_data->vert_arr; LineartTriangle *tri = tri_task_data->tri_arr; @@ -1869,8 +1873,8 @@ static void lineart_load_tri_task(void *__restrict userdata, tri->v[2] = &vert_arr[v3]; /* Material mask bits and occlusion effectiveness assignment. */ - Material *mat = BKE_object_material_get_eval(ob_info->original_ob_eval, - me->mpoly[mlooptri->poly].mat_nr + 1); + Material *mat = BKE_object_material_get( + ob_info->original_ob_eval, material_indices ? material_indices[mlooptri->poly] + 1 : 1); tri->material_mask_bits |= ((mat && (mat->lineart.flags & LRT_MATERIAL_MASK_ENABLED)) ? mat->lineart.material_mask_bits : 0); @@ -1992,6 +1996,9 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me); const int tot_tri = BKE_mesh_runtime_looptri_len(me); + const int *material_indices = (const int *)CustomData_get_layer_named( + &me->pdata, CD_PROP_INT32, "material_index"); + /* Check if we should look for custom data tags like Freestyle edges or faces. */ bool can_find_freestyle_edge = false; int layer_index = CustomData_get_active_layer_index(&me->edata, CD_FREESTYLE_EDGE); @@ -2095,6 +2102,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, TriData tri_data; tri_data.ob_info = ob_info; tri_data.mlooptri = mlooptri; + tri_data.material_indices = material_indices; tri_data.vert_arr = la_v_arr; tri_data.tri_arr = la_tri_arr; tri_data.lineart_triangle_size = la_data->sizeof_triangle; @@ -2122,6 +2130,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, edge_feat_data.me = me; edge_feat_data.ob_eval = ob_info->original_ob_eval; edge_feat_data.mlooptri = mlooptri; + edge_feat_data.material_indices = material_indices; edge_feat_data.edge_nabr = lineart_build_edge_neighbor(me, total_edges); edge_feat_data.tri_array = la_tri_arr; edge_feat_data.v_array = la_v_arr; diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 951a7102716..a87c7ea4809 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -233,8 +233,10 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, GPUAttrRef vcol_refs[MAX_GPU_ATTR]; GPUAttrRef cd_uvs[MAX_GPU_ATTR]; - const bool *hide_vert = (bool *)CustomData_get_layer_named( + const bool *hide_vert = (const bool *)CustomData_get_layer_named( &mesh->vdata, CD_PROP_BOOL, ".hide_vert"); + const int *material_indices = (const int *)CustomData_get_layer_named( + &mesh->pdata, CD_PROP_INT32, "material_index"); const CustomDataLayer *actcol = BKE_id_attributes_active_color_get(&mesh->id); eAttrDomain actcol_domain = actcol ? BKE_id_attribute_domain(&mesh->id, actcol) : @@ -449,8 +451,7 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, /* Get material index from the first face of this buffer. */ const MLoopTri *lt = &buffers->looptri[buffers->face_indices[0]]; - const MPoly *mp = &buffers->mpoly[lt->poly]; - buffers->material_index = mp->mat_nr; + buffers->material_index = material_indices ? material_indices[lt->poly] : 0; buffers->show_overlay = !empty_mask || !default_face_set; buffers->mvert = mvert; diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc index 06c511db326..83f970d3965 100644 --- a/source/blender/io/alembic/exporter/abc_writer_mesh.cc +++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc @@ -12,6 +12,7 @@ #include "BLI_math_vector.h" #include "BKE_attribute.h" +#include "BKE_attribute.hh" #include "BKE_customdata.h" #include "BKE_lib_id.h" #include "BKE_material.h" @@ -390,12 +391,12 @@ void ABCGenericMeshWriter::get_geo_groups(Object *object, struct Mesh *mesh, std::map<std::string, std::vector<int32_t>> &geo_groups) { - const int num_poly = mesh->totpoly; - MPoly *polygons = mesh->mpoly; + const bke::AttributeAccessor attributes = bke::mesh_attributes(*mesh); + const VArraySpan<int> material_indices = attributes.lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); - for (int i = 0; i < num_poly; i++) { - MPoly ¤t_poly = polygons[i]; - short mnr = current_poly.mat_nr; + for (const int i : material_indices.index_range()) { + short mnr = material_indices[i]; Material *mat = BKE_object_material_get(object, mnr + 1); diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc index e18770f2bef..16e5ee968a3 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.cc +++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc @@ -25,7 +25,7 @@ #include "BLI_listbase.h" #include "BLI_math_geom.h" -#include "BKE_attribute.h" +#include "BKE_attribute.hh" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mesh.h" @@ -766,7 +766,11 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh, size_t num_polys = new_mesh->totpoly; if (num_polys > 0) { std::map<std::string, int> mat_map; - assign_facesets_to_mpoly(sample_sel, new_mesh->mpoly, num_polys, mat_map); + bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*new_mesh); + bke::SpanAttributeWriter<int> material_indices = + attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE); + assign_facesets_to_material_indices(sample_sel, material_indices.span, mat_map); + material_indices.finish(); } return new_mesh; @@ -775,10 +779,9 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh, return existing_mesh; } -void AbcMeshReader::assign_facesets_to_mpoly(const ISampleSelector &sample_sel, - MPoly *mpoly, - int totpoly, - std::map<std::string, int> &r_mat_map) +void AbcMeshReader::assign_facesets_to_material_indices(const ISampleSelector &sample_sel, + MutableSpan<int> material_indices, + std::map<std::string, int> &r_mat_map) { std::vector<std::string> face_sets; m_schema.getFaceSetNames(face_sets); @@ -811,13 +814,12 @@ void AbcMeshReader::assign_facesets_to_mpoly(const ISampleSelector &sample_sel, for (size_t l = 0; l < num_group_faces; l++) { size_t pos = (*group_faces)[l]; - if (pos >= totpoly) { + if (pos >= material_indices.size()) { std::cerr << "Faceset overflow on " << faceset.getName() << '\n'; break; } - MPoly &poly = mpoly[pos]; - poly.mat_nr = assigned_mat - 1; + material_indices[pos] = assigned_mat - 1; } } } @@ -825,7 +827,11 @@ void AbcMeshReader::assign_facesets_to_mpoly(const ISampleSelector &sample_sel, void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const ISampleSelector &sample_sel) { std::map<std::string, int> mat_map; - assign_facesets_to_mpoly(sample_sel, mesh->mpoly, mesh->totpoly, mat_map); + bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh); + bke::SpanAttributeWriter<int> material_indices = + attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE); + assign_facesets_to_material_indices(sample_sel, material_indices.span, mat_map); + material_indices.finish(); utils::assign_materials(bmain, m_object, mat_map); } diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.h b/source/blender/io/alembic/intern/abc_reader_mesh.h index f97525297b7..151f4d82226 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.h +++ b/source/blender/io/alembic/intern/abc_reader_mesh.h @@ -5,6 +5,8 @@ * \ingroup balembic */ +#include "BLI_span.hh" + #include "abc_customdata.h" #include "abc_reader_object.h" @@ -38,10 +40,9 @@ class AbcMeshReader final : public AbcObjectReader { Mesh *mesh, const Alembic::AbcGeom::ISampleSelector &sample_sel); - void assign_facesets_to_mpoly(const Alembic::Abc::ISampleSelector &sample_sel, - MPoly *mpoly, - int totpoly, - std::map<std::string, int> &r_mat_map); + void assign_facesets_to_material_indices(const Alembic::Abc::ISampleSelector &sample_sel, + MutableSpan<int> material_indices, + std::map<std::string, int> &r_mat_map); }; class AbcSubDReader final : public AbcObjectReader { diff --git a/source/blender/io/collada/GeometryExporter.cpp b/source/blender/io/collada/GeometryExporter.cpp index 7e2a24aeb41..1a3a68923e3 100644 --- a/source/blender/io/collada/GeometryExporter.cpp +++ b/source/blender/io/collada/GeometryExporter.cpp @@ -17,6 +17,7 @@ #include "BLI_utildefines.h" +#include "BKE_attribute.hh" #include "BKE_customdata.h" #include "BKE_global.h" #include "BKE_lib_id.h" @@ -284,15 +285,18 @@ static bool collect_vertex_counts_per_poly(Mesh *me, int material_index, std::vector<unsigned long> &vcount_list) { + const blender::bke::AttributeAccessor attributes = blender::bke::mesh_attributes(*me); + const blender::VArray<int> material_indices = attributes.lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); MPoly *mpolys = me->mpoly; int totpolys = me->totpoly; bool is_triangulated = true; int i; - /* Expecting that p->mat_nr is always 0 if the mesh has no materials assigned */ + /* Expecting that the material index is always 0 if the mesh has no materials assigned */ for (i = 0; i < totpolys; i++) { - MPoly *p = &mpolys[i]; - if (p->mat_nr == material_index) { + if (material_indices[i] == material_index) { + MPoly *p = &mpolys[i]; int vertex_count = p->totloop; vcount_list.push_back(vertex_count); if (vertex_count != 3) { @@ -397,13 +401,17 @@ void GeometryExporter::create_mesh_primitive_list(short material_index, /* performs the actual writing */ prepareToAppendValues(is_triangulated, *primitive_list, vcount_list); + const blender::bke::AttributeAccessor attributes = blender::bke::mesh_attributes(*me); + const blender::VArray<int> material_indices = attributes.lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); + /* <p> */ int texindex = 0; for (int i = 0; i < totpolys; i++) { MPoly *p = &mpolys[i]; int loop_count = p->totloop; - if (p->mat_nr == material_index) { + if (material_indices[i] == material_index) { MLoop *l = &mloops[p->loopstart]; BCPolygonNormalsIndices normal_indices = norind[i]; diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp index 34792fd6bb4..fab53908d5a 100644 --- a/source/blender/io/collada/MeshImporter.cpp +++ b/source/blender/io/collada/MeshImporter.cpp @@ -615,6 +615,9 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me) MaterialIdPrimitiveArrayMap mat_prim_map; + int *material_indices = (int *)CustomData_add_layer_named( + &me->pdata, CD_PROP_INT32, CD_SET_DEFAULT, nullptr, me->totpoly, "material_index"); + COLLADAFW::MeshPrimitiveArray &prim_arr = collada_mesh->getMeshPrimitives(); COLLADAFW::MeshVertexData &nor = collada_mesh->getNormals(); @@ -633,7 +636,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me) int collada_meshtype = mp->getPrimitiveType(); /* since we cannot set mpoly->mat_nr here, we store a portion of me->mpoly in Primitive */ - Primitive prim = {mpoly, 0}; + Primitive prim = {mpoly, material_indices, 0}; /* If MeshPrimitive is TRIANGLE_FANS we split it into triangles * The first triangle-fan vertex will be the first vertex in every triangle @@ -663,6 +666,9 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me) } mpoly++; + if (material_indices) { + material_indices++; + } mloop += 3; loop_index += 3; prim.totpoly++; @@ -1007,10 +1013,9 @@ void MeshImporter::assign_material_to_geom( for (it = prims.begin(); it != prims.end(); it++) { Primitive &prim = *it; - MPoly *mpoly = prim.mpoly; - for (int i = 0; i < prim.totpoly; i++, mpoly++) { - mpoly->mat_nr = mat_index; + for (int i = 0; i < prim.totpoly; i++) { + prim.material_indices[i] = mat_index; } } } diff --git a/source/blender/io/collada/MeshImporter.h b/source/blender/io/collada/MeshImporter.h index 92b387a4bfe..1def84e8f99 100644 --- a/source/blender/io/collada/MeshImporter.h +++ b/source/blender/io/collada/MeshImporter.h @@ -80,6 +80,7 @@ class MeshImporter : public MeshImporterBase { * (<triangles>, <polylist>, etc.) */ struct Primitive { MPoly *mpoly; + int *material_indices; unsigned int totpoly; }; typedef std::map<COLLADAFW::MaterialId, std::vector<Primitive>> MaterialIdPrimitiveArrayMap; diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc index 94ff24421e2..89a98097780 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.cc +++ b/source/blender/io/usd/intern/usd_reader_mesh.cc @@ -6,6 +6,7 @@ #include "usd_reader_mesh.h" #include "usd_reader_material.h" +#include "BKE_attribute.hh" #include "BKE_customdata.h" #include "BKE_main.h" #include "BKE_material.h" @@ -319,7 +320,6 @@ void USDMeshReader::read_mpolys(Mesh *mesh) MPoly &poly = mpolys[i]; poly.loopstart = loop_index; poly.totloop = face_size; - poly.mat_nr = 0; /* Polygons are always assumed to be smooth-shaded. If the mesh should be flat-shaded, * this is encoded in custom loop normals. */ @@ -735,10 +735,9 @@ void USDMeshReader::read_mesh_sample(ImportSettings *settings, } } -void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime, - MPoly *mpoly, - const int /* totpoly */, - std::map<pxr::SdfPath, int> *r_mat_map) +void USDMeshReader::assign_facesets_to_material_indices(double motionSampleTime, + MutableSpan<int> material_indices, + std::map<pxr::SdfPath, int> *r_mat_map) { if (r_mat_map == nullptr) { return; @@ -778,9 +777,8 @@ void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime, pxr::VtIntArray indices; indicesAttribute.Get(&indices, motionSampleTime); - for (int i = 0; i < indices.size(); i++) { - MPoly &poly = mpoly[indices[i]]; - poly.mat_nr = mat_idx; + for (const int i : indices) { + material_indices[i] = mat_idx; } } } @@ -805,7 +803,12 @@ void USDMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const double mot } std::map<pxr::SdfPath, int> mat_map; - assign_facesets_to_mpoly(motionSampleTime, mesh->mpoly, mesh->totpoly, &mat_map); + + bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh); + bke::SpanAttributeWriter<int> material_indices = + attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE); + this->assign_facesets_to_material_indices(motionSampleTime, material_indices.span, &mat_map); + material_indices.finish(); /* Build material name map if it's not built yet. */ if (this->settings_->mat_name_to_mat.empty()) { utils::build_mat_map(bmain, &this->settings_->mat_name_to_mat); @@ -911,7 +914,11 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh, size_t num_polys = active_mesh->totpoly; if (num_polys > 0 && import_params_.import_materials) { std::map<pxr::SdfPath, int> mat_map; - assign_facesets_to_mpoly(motionSampleTime, active_mesh->mpoly, num_polys, &mat_map); + bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*active_mesh); + bke::SpanAttributeWriter<int> material_indices = + attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE); + assign_facesets_to_material_indices(motionSampleTime, material_indices.span, &mat_map); + material_indices.finish(); } } diff --git a/source/blender/io/usd/intern/usd_reader_mesh.h b/source/blender/io/usd/intern/usd_reader_mesh.h index 5e33ce8b5e8..9a3b0565668 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.h +++ b/source/blender/io/usd/intern/usd_reader_mesh.h @@ -3,6 +3,8 @@ * Modifications Copyright 2021 Tangent Animation and. NVIDIA Corporation. All rights reserved. */ #pragma once +#include "BLI_span.hh" + #include "usd.h" #include "usd_reader_geom.h" @@ -61,10 +63,9 @@ class USDMeshReader : public USDGeomReader { /** Set USD uniform (per-face) normals as Blender loop normals. */ void process_normals_uniform(Mesh *mesh); void readFaceSetsSample(Main *bmain, Mesh *mesh, double motionSampleTime); - void assign_facesets_to_mpoly(double motionSampleTime, - struct MPoly *mpoly, - int totpoly, - std::map<pxr::SdfPath, int> *r_mat_map); + void assign_facesets_to_material_indices(double motionSampleTime, + MutableSpan<int> material_indices, + std::map<pxr::SdfPath, int> *r_mat_map); void read_mpolys(Mesh *mesh); void read_uvs(Mesh *mesh, double motionSampleTime, bool load_uvs = false); diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc index b76f74cfd3d..ade75fdb365 100644 --- a/source/blender/io/usd/intern/usd_writer_mesh.cc +++ b/source/blender/io/usd/intern/usd_writer_mesh.cc @@ -11,6 +11,7 @@ #include "BLI_math_vector.h" #include "BKE_attribute.h" +#include "BKE_attribute.hh" #include "BKE_customdata.h" #include "BKE_lib_id.h" #include "BKE_material.h" @@ -255,7 +256,15 @@ static void get_loops_polys(const Mesh *mesh, USDMeshData &usd_mesh_data) { /* Only construct face groups (a.k.a. geometry subsets) when we need them for material * assignments. */ - bool construct_face_groups = mesh->totcol > 1; + const bke::AttributeAccessor attributes = bke::mesh_attributes(*mesh); + const VArray<int> material_indices = attributes.lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); + if (!material_indices.is_single() && mesh->totcol > 1) { + const VArraySpan<int> indices_span(material_indices); + for (const int i : indices_span.index_range()) { + usd_mesh_data.face_groups[indices_span[i]].push_back(i); + } + } usd_mesh_data.face_vertex_counts.reserve(mesh->totpoly); usd_mesh_data.face_indices.reserve(mesh->totloop); @@ -268,10 +277,6 @@ static void get_loops_polys(const Mesh *mesh, USDMeshData &usd_mesh_data) for (int j = 0; j < mpoly->totloop; ++j, ++loop) { usd_mesh_data.face_indices.push_back(loop->v); } - - if (construct_face_groups) { - usd_mesh_data.face_groups[mpoly->mat_nr].push_back(i); - } } } diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc index 9bcc061caf7..902f801ee5b 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc @@ -374,10 +374,14 @@ void OBJWriter::write_poly_elements(FormatHandler &fh, } } + const bke::AttributeAccessor attributes = bke::mesh_attributes(*obj_mesh_data.get_mesh()); + const VArray<int> material_indices = attributes.lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); + /* Write material name and material group if different from previous. */ if (export_params_.export_materials && obj_mesh_data.tot_materials() > 0) { - const int16_t prev_mat = idx == 0 ? NEGATIVE_INIT : obj_mesh_data.ith_poly_matnr(prev_i); - const int16_t mat = obj_mesh_data.ith_poly_matnr(i); + const int16_t prev_mat = idx == 0 ? NEGATIVE_INIT : std::max(0, material_indices[prev_i]); + const int16_t mat = std::max(0, material_indices[i]); if (mat != prev_mat) { if (mat == NOT_FOUND) { buf.write_obj_usemtl(MATERIAL_GROUP_DISABLED); diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc index 815163ad19e..a888c6d11a2 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc @@ -6,6 +6,7 @@ /* Silence warnings from copying deprecated fields. Needed for an Object copy constructor use. */ #define DNA_DEPRECATED_ALLOW +#include "BKE_attribute.hh" #include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_lib_id.h" @@ -199,16 +200,23 @@ void OBJMesh::calc_smooth_groups(const bool use_bitflags) void OBJMesh::calc_poly_order() { - const int tot_polys = tot_polygons(); - poly_order_.resize(tot_polys); - for (int i = 0; i < tot_polys; ++i) { + const bke::AttributeAccessor attributes = bke::mesh_attributes(*export_mesh_eval_); + const VArray<int> material_indices = attributes.lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); + if (material_indices.is_single() && material_indices.get_internal_single() == 0) { + return; + } + const VArraySpan<int> material_indices_span(material_indices); + + poly_order_.resize(material_indices_span.size()); + for (const int i : material_indices_span.index_range()) { poly_order_[i] = i; } - const MPoly *mpolys = export_mesh_eval_->mpoly; + /* Sort polygons by their material index. */ blender::parallel_sort(poly_order_.begin(), poly_order_.end(), [&](int a, int b) { - int mat_a = mpolys[a].mat_nr; - int mat_b = mpolys[b].mat_nr; + int mat_a = material_indices_span[a]; + int mat_b = material_indices_span[b]; if (mat_a != mat_b) { return mat_a < mat_b; } @@ -234,13 +242,6 @@ bool OBJMesh::is_ith_poly_smooth(const int poly_index) const return export_mesh_eval_->mpoly[poly_index].flag & ME_SMOOTH; } -int16_t OBJMesh::ith_poly_matnr(const int poly_index) const -{ - BLI_assert(poly_index < export_mesh_eval_->totpoly); - const int16_t r_mat_nr = export_mesh_eval_->mpoly[poly_index].mat_nr; - return r_mat_nr >= 0 ? r_mat_nr : NOT_FOUND; -} - const char *OBJMesh::get_object_name() const { return export_object_eval_.id.name + 2; diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh index ee2e6227700..db29f5651ed 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh @@ -130,11 +130,6 @@ class OBJMesh : NonCopyable { * Return mat_nr-th material of the object. The given index should be zero-based. */ const Material *get_object_material(int16_t mat_nr) const; - /** - * Returns a zero-based index of a polygon's material indexing into - * the Object's material slots. - */ - int16_t ith_poly_matnr(int poly_index) const; void ensure_mesh_normals() const; void ensure_mesh_edges() const; diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc index 2a0676b72ff..7f7fda8d8f1 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc @@ -8,7 +8,7 @@ #include "DNA_mesh_types.h" #include "DNA_scene_types.h" -#include "BKE_attribute.h" +#include "BKE_attribute.hh" #include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_material.h" @@ -184,6 +184,10 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups) CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, nullptr, total_verts)); } + bke::SpanAttributeWriter<int> material_indices = + bke::mesh_attributes_for_write(*mesh).lookup_or_add_for_write_only_span<int>( + "material_index", ATTR_DOMAIN_FACE); + const int64_t tot_face_elems{mesh->totpoly}; int tot_loop_idx = 0; @@ -201,11 +205,11 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups) if (curr_face.shaded_smooth) { mpoly.flag |= ME_SMOOTH; } - mpoly.mat_nr = curr_face.material_index; + material_indices.span[poly_idx] = curr_face.material_index; /* Importing obj files without any materials would result in negative indices, which is not * supported. */ - if (mpoly.mat_nr < 0) { - mpoly.mat_nr = 0; + if (material_indices.span[poly_idx] < 0) { + material_indices.span[poly_idx] = 0; } for (int idx = 0; idx < curr_face.corner_count_; ++idx) { @@ -223,6 +227,8 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups) dw->weight = 1.0f; } } + + material_indices.finish(); } void MeshFromGeometry::create_vertex_groups(Object *obj) diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 97355548b09..9912ec8ec3b 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -161,7 +161,8 @@ typedef struct Mesh { /** * An array of materials, with length #totcol. These can be overridden by material slots - * on #Object. Indices in #MPoly.mat_nr control which material is used for every face. + * on #Object. Indices in the "material_index" attribute control which material is used for every + * face. */ struct Material **mat; diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index c62907e26ed..e0333f3ef03 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -74,7 +74,8 @@ typedef struct MPoly { int loopstart; /** Keep signed since we need to subtract when getting the previous loop. */ int totloop; - short mat_nr; + /** Deprecated material index. Now stored in the "material_index" attribute, but kept for IO. */ + short mat_nr DNA_DEPRECATED; char flag, _pad; } MPoly; @@ -156,8 +157,8 @@ enum { * * Usage examples: * \code{.c} - * // access original material. - * short mat_nr = mpoly[lt->poly].mat_nr; + * // access polygon attribute value. + * T value = polygon_attribute[lt->poly]; * * // access vertex locations. * float *vtri_co[3] = { diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 994d063dbaf..6979b65cfc9 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -562,6 +562,22 @@ static void rna_MeshPolygon_hide_set(PointerRNA *ptr, bool value) hide_poly[index] = value; } +static int rna_MeshPolygon_material_index_get(PointerRNA *ptr) +{ + const Mesh *mesh = rna_mesh(ptr); + const int *material_indices = BKE_mesh_material_indices(mesh); + const int index = rna_MeshPolygon_index_get(ptr); + return material_indices == NULL ? 0 : material_indices[index]; +} + +static void rna_MeshPolygon_material_index_set(PointerRNA *ptr, int value) +{ + Mesh *mesh = rna_mesh(ptr); + int *material_indices = BKE_mesh_material_indices_for_write(mesh); + const int index = rna_MeshPolygon_index_get(ptr); + material_indices[index] = value; +} + static void rna_MeshPolygon_center_get(PointerRNA *ptr, float *values) { Mesh *me = rna_mesh(ptr); @@ -1300,8 +1316,9 @@ static void rna_MeshEdge_hide_set(PointerRNA *ptr, bool value) static int rna_MeshLoopTriangle_material_index_get(PointerRNA *ptr) { const Mesh *me = rna_mesh(ptr); + const int *material_indices = BKE_mesh_material_indices(me); const MLoopTri *ltri = (MLoopTri *)ptr->data; - return me->mpoly[ltri->poly].mat_nr; + return material_indices == NULL ? 0 : material_indices[ltri->poly]; } static bool rna_MeshLoopTriangle_use_smooth_get(PointerRNA *ptr) @@ -2195,7 +2212,8 @@ static void rna_def_mpolygon(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Loop Total", "Number of loops used by this polygon"); prop = RNA_def_property(srna, "material_index", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_sdna(prop, NULL, "mat_nr"); + RNA_def_property_int_funcs( + prop, "rna_MeshPolygon_material_index_get", "rna_MeshPolygon_material_index_set", false); RNA_def_property_ui_text(prop, "Material Index", "Material slot index of this polygon"); # if 0 RNA_def_property_int_funcs(prop, NULL, NULL, "rna_MeshPoly_material_index_range"); diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index b2ebf2ffeec..d8b11c0e89e 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -947,6 +947,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * /* more of an offset in this case */ edge_offset = totedge + (totvert * (step_tot - (close ? 0 : 1))); + const int *src_material_index = BKE_mesh_material_indices(mesh); + int *dst_material_index = BKE_mesh_material_indices_for_write(result); + for (i = 0; i < totedge; i++, med_new_firstloop++) { const uint step_last = step_tot - (close ? 1 : 2); const uint mpoly_index_orig = totpoly ? edge_poly_map[i] : UINT_MAX; @@ -959,14 +962,14 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * }; const bool has_mloop_orig = mloop_index_orig[0] != UINT_MAX; - short mat_nr; + int mat_nr; /* for each edge, make a cylinder of quads */ i1 = med_new_firstloop->v1; i2 = med_new_firstloop->v2; if (has_mpoly_orig) { - mat_nr = mpoly_orig[mpoly_index_orig].mat_nr; + mat_nr = src_material_index == NULL ? 0 : src_material_index[mpoly_index_orig]; } else { mat_nr = 0; @@ -992,8 +995,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * } else { origindex[mpoly_index] = ORIGINDEX_NONE; + dst_material_index[mpoly_index] = mat_nr; mp_new->flag = mpoly_flag; - mp_new->mat_nr = mat_nr; } mp_new->loopstart = mpoly_index * 4; mp_new->totloop = 4; diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c index 15e8bd25997..aa8c49ee0b8 100644 --- a/source/blender/modifiers/intern/MOD_solidify_extrude.c +++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c @@ -425,6 +425,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex } \ (void)0 + int *dst_material_index = BKE_mesh_material_indices_for_write(result); + /* flip normals */ if (do_shell) { @@ -462,8 +464,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex #endif if (mat_ofs) { - mp->mat_nr += mat_ofs; - CLAMP(mp->mat_nr, 0, mat_nr_max); + dst_material_index[mp - mpoly] += mat_ofs; + CLAMP(dst_material_index[mp - mpoly], 0, mat_nr_max); } e = ml2[0].e; @@ -1151,8 +1153,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex /* use the next material index if option enabled */ if (mat_ofs_rim) { - mp->mat_nr += mat_ofs_rim; - CLAMP(mp->mat_nr, 0, mat_nr_max); + dst_material_index[mp - mpoly] += mat_ofs_rim; + CLAMP(dst_material_index[mp - mpoly], 0, mat_nr_max); } if (crease_outer) { /* crease += crease_outer; without wrapping */ diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c index 9205083e836..29adbd70198 100644 --- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c +++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c @@ -2108,6 +2108,9 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, } #endif + const int *src_material_index = BKE_mesh_material_indices(mesh); + int *dst_material_index = BKE_mesh_material_indices_for_write(result); + /* Make boundary edges/faces. */ { gs_ptr = orig_vert_groups_arr; @@ -2224,7 +2227,7 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, /* Loop data. */ int *loops = MEM_malloc_arrayN(j, sizeof(*loops), "loops in solidify"); - /* The #mat_nr is from consensus. */ + /* The result material index is from consensus. */ short most_mat_nr = 0; uint most_mat_nr_face = 0; uint most_mat_nr_count = 0; @@ -2235,16 +2238,20 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, for (EdgeGroup *g3 = g2; g3->valid && k < j; g3++) { if ((do_rim && !g3->is_orig_closed) || (do_shell && g3->split)) { /* Check both far ends in terms of faces of an edge group. */ - if (g3->edges[0]->faces[0]->face->mat_nr == l) { + if ((src_material_index ? src_material_index[g3->edges[0]->faces[0]->index] : + 0) == l) { face = g3->edges[0]->faces[0]->index; count++; } NewEdgeRef *le = g3->edges[g3->edges_len - 1]; - if (le->faces[1] && le->faces[1]->face->mat_nr == l) { + if (le->faces[1] && + (src_material_index ? src_material_index[le->faces[1]->index] : 0) == l) { face = le->faces[1]->index; count++; } - else if (!le->faces[1] && le->faces[0]->face->mat_nr == l) { + else if (!le->faces[1] && + (src_material_index ? src_material_index[le->faces[0]->index] : 0) == + l) { face = le->faces[0]->index; count++; } @@ -2264,9 +2271,9 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, } mpoly[poly_index].loopstart = (int)loop_index; mpoly[poly_index].totloop = (int)j; - mpoly[poly_index].mat_nr = most_mat_nr + - (g->is_orig_closed || !do_rim ? 0 : mat_ofs_rim); - CLAMP(mpoly[poly_index].mat_nr, 0, mat_nr_max); + dst_material_index[poly_index] = most_mat_nr + + (g->is_orig_closed || !do_rim ? 0 : mat_ofs_rim); + CLAMP(dst_material_index[poly_index], 0, mat_nr_max); mpoly[poly_index].flag = orig_mpoly[most_mat_nr_face].flag; poly_index++; @@ -2334,13 +2341,15 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, continue; } - MPoly *face = (*new_edges)->faces[0]->face; + const uint orig_face_index = (*new_edges)->faces[0]->index; + MPoly *face = &orig_mpoly[orig_face_index]; CustomData_copy_data( &mesh->pdata, &result->pdata, (int)(*new_edges)->faces[0]->index, (int)poly_index, 1); mpoly[poly_index].loopstart = (int)loop_index; mpoly[poly_index].totloop = 4 - (int)(v1_singularity || v2_singularity); - mpoly[poly_index].mat_nr = face->mat_nr + mat_ofs_rim; - CLAMP(mpoly[poly_index].mat_nr, 0, mat_nr_max); + dst_material_index[poly_index] = + (src_material_index ? src_material_index[orig_face_index] : 0) + mat_ofs_rim; + CLAMP(dst_material_index[poly_index], 0, mat_nr_max); mpoly[poly_index].flag = face->flag; poly_index++; @@ -2530,8 +2539,10 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, CustomData_copy_data(&mesh->pdata, &result->pdata, (int)(i / 2), (int)poly_index, 1); mpoly[poly_index].loopstart = (int)loop_index; mpoly[poly_index].totloop = (int)k; - mpoly[poly_index].mat_nr = fr->face->mat_nr + (fr->reversed != do_flip ? mat_ofs : 0); - CLAMP(mpoly[poly_index].mat_nr, 0, mat_nr_max); + dst_material_index[poly_index] = (src_material_index ? src_material_index[fr->index] : + 0) + + (fr->reversed != do_flip ? mat_ofs : 0); + CLAMP(dst_material_index[poly_index], 0, mat_nr_max); mpoly[poly_index].flag = fr->face->flag; if (fr->reversed != do_flip) { for (int l = (int)k - 1; l >= 0; l--) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc index 31e2092a6d7..9822e0ea0d6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc @@ -23,19 +23,30 @@ static void node_declare(NodeDeclarationBuilder &b) static void select_mesh_by_material(const Mesh &mesh, const Material *material, const IndexMask mask, - const MutableSpan<bool> r_selection) + MutableSpan<bool> r_selection) { BLI_assert(mesh.totpoly >= r_selection.size()); - Vector<int> material_indices; + Vector<int> slots; for (const int i : IndexRange(mesh.totcol)) { if (mesh.mat[i] == material) { - material_indices.append(i); + slots.append(i); } } + const AttributeAccessor attributes = bke::mesh_attributes(mesh); + const VArray<int> material_indices = attributes.lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); + if (material != nullptr && material_indices.is_single() && + material_indices.get_internal_single() == 0) { + r_selection.fill_indices(mask, false); + return; + } + + const VArraySpan<int> material_indices_span(material_indices); + threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) { for (const int i : range) { const int face_index = mask[i]; - r_selection[i] = material_indices.contains(mesh.mpoly[face_index].mat_nr); + r_selection[i] = slots.contains(material_indices_span[face_index]); } }); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc index e7b95506068..c6a2f89220a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc @@ -49,11 +49,11 @@ static void assign_material_to_faces(Mesh &mesh, const IndexMask selection, Mate BKE_id_material_eval_assign(&mesh.id, new_material_index + 1, material); } - mesh.mpoly = (MPoly *)CustomData_duplicate_referenced_layer(&mesh.pdata, CD_MPOLY, mesh.totpoly); - for (const int i : selection) { - MPoly &poly = mesh.mpoly[i]; - poly.mat_nr = new_material_index; - } + MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(mesh); + SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>( + "material_index", ATTR_DOMAIN_FACE); + material_indices.span.fill_indices(selection, new_material_index); + material_indices.finish(); } static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c index 74e9662d5db..d6e612ee061 100644 --- a/source/blender/render/intern/bake.c +++ b/source/blender/render/intern/bake.c @@ -740,14 +740,15 @@ void RE_bake_pixels_populate(Mesh *me, BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri); + const int *material_indices = BKE_mesh_material_indices(me); + for (int i = 0; i < tottri; i++) { const MLoopTri *lt = &looptri[i]; - const MPoly *mp = &me->mpoly[lt->poly]; bd.primitive_id = i; /* Find images matching this material. */ - Image *image = targets->material_to_image[mp->mat_nr]; + Image *image = targets->material_to_image[material_indices ? material_indices[lt->poly] : 0]; for (int image_id = 0; image_id < targets->images_num; image_id++) { BakeImage *bk_image = &targets->images[image_id]; if (bk_image->image != image) { diff --git a/source/blender/render/intern/multires_bake.c b/source/blender/render/intern/multires_bake.c index e3229e20595..e116f41321f 100644 --- a/source/blender/render/intern/multires_bake.c +++ b/source/blender/render/intern/multires_bake.c @@ -63,6 +63,7 @@ typedef struct { MVert *mvert; const float (*vert_normals)[3]; MPoly *mpoly; + const int *material_indices; MLoop *mloop; MLoopUV *mloopuv; float uv_offset[2]; @@ -382,8 +383,7 @@ static void *do_multires_bake_thread(void *data_v) while ((tri_index = multires_bake_queue_next_tri(handle->queue)) >= 0) { const MLoopTri *lt = &data->mlooptri[tri_index]; - const MPoly *mp = &data->mpoly[lt->poly]; - const short mat_nr = mp->mat_nr; + const short mat_nr = data->material_indices == NULL ? 0 : data->material_indices[lt->poly]; const MLoopUV *mloopuv = data->mloopuv; if (multiresbake_test_break(bkr)) { @@ -545,6 +545,8 @@ static void do_multires_bake(MultiresBakeRender *bkr, handle->queue = &queue; handle->data.mpoly = mpoly; + handle->data.material_indices = CustomData_get_layer_named( + &dm->polyData, CD_PROP_INT32, "material_index"); handle->data.mvert = mvert; handle->data.vert_normals = vert_normals; handle->data.mloopuv = mloopuv; |